indexed_db_cursor.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_cursor.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_backing_store.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_callbacks_wrapper.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_database.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_database_error.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_tracing.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_transaction.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/common/indexed_db/indexed_db_key_range.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace content {
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class IndexedDBCursor::CursorIterationOperation
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : public IndexedDBTransaction::Operation {
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CursorIterationOperation(scoped_refptr<IndexedDBCursor> cursor,
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           scoped_ptr<IndexedDBKey> key,
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : cursor_(cursor), key_(key.Pass()), callbacks_(callbacks) {}
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBCursor> cursor_;
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<IndexedDBKey> key_;
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class IndexedDBCursor::CursorAdvanceOperation
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : public IndexedDBTransaction::Operation {
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CursorAdvanceOperation(scoped_refptr<IndexedDBCursor> cursor,
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         uint32 count,
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : cursor_(cursor), count_(count), callbacks_(callbacks) {}
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBCursor> cursor_;
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  uint32 count_;
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class IndexedDBCursor::CursorPrefetchIterationOperation
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : public IndexedDBTransaction::Operation {
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CursorPrefetchIterationOperation(
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      scoped_refptr<IndexedDBCursor> cursor,
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      int number_to_fetch,
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      scoped_refptr<IndexedDBCallbacksWrapper> callbacks)
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : cursor_(cursor),
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        number_to_fetch_(number_to_fetch),
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        callbacks_(callbacks) {}
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBCursor> cursor_;
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int number_to_fetch_;
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacksWrapper> callbacks_;
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBCursor::IndexedDBCursor(
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<IndexedDBBackingStore::Cursor> cursor,
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    indexed_db::CursorType cursor_type,
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBDatabase::TaskType task_type,
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBTransaction* transaction)
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : task_type_(task_type),
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cursor_type_(cursor_type),
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      transaction_(transaction),
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cursor_(cursor.Pass()),
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      closed_(false) {
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_->RegisterOpenCursor(this);
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBCursor::~IndexedDBCursor() {
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_->UnregisterOpenCursor(this);
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::ContinueFunction(
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<IndexedDBKey> key,
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("IndexedDBCursor::continue");
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_->ScheduleTask(
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      task_type_, new CursorIterationOperation(this, key.Pass(), callbacks));
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::Advance(
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    uint32 count,
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("IndexedDBCursor::advance");
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_->ScheduleTask(
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new CursorAdvanceOperation(this, count, callbacks));
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::CursorAdvanceOperation::Perform(
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBTransaction* /*transaction*/) {
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("CursorAdvanceOperation");
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!cursor_->cursor_ || !cursor_->cursor_->Advance(count_)) {
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    cursor_->cursor_.reset();
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callbacks_->OnSuccess(
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cursor_->key(), cursor_->primary_key(), cursor_->Value());
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::CursorIterationOperation::Perform(
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBTransaction* /*transaction*/) {
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("CursorIterationOperation");
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!cursor_->cursor_ || !cursor_->cursor_->ContinueFunction(key_.get())) {
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    cursor_->cursor_.reset();
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callbacks_->OnSuccess(
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cursor_->key(), cursor_->primary_key(), cursor_->Value());
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::PrefetchContinue(
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int number_to_fetch,
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_refptr<IndexedDBCallbacksWrapper> callbacks) {
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("IndexedDBCursor::prefetch_continue");
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction_->ScheduleTask(
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      task_type_,
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new CursorPrefetchIterationOperation(this, number_to_fetch, callbacks));
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::CursorPrefetchIterationOperation::Perform(
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBTransaction* /*transaction*/) {
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("CursorPrefetchIterationOperation");
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<IndexedDBKey> found_keys;
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<IndexedDBKey> found_primary_keys;
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<std::vector<char> > found_values;
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (cursor_->cursor_)
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    cursor_->saved_cursor_.reset(cursor_->cursor_->Clone());
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const size_t max_size_estimate = 10 * 1024 * 1024;
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  size_t size_estimate = 0;
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (int i = 0; i < number_to_fetch_; ++i) {
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!cursor_->cursor_ || !cursor_->cursor_->ContinueFunction(0)) {
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      cursor_->cursor_.reset();
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    found_keys.push_back(cursor_->cursor_->key());
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    found_primary_keys.push_back(cursor_->cursor_->primary_key());
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    switch (cursor_->cursor_type_) {
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case indexed_db::CURSOR_KEY_ONLY:
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        found_values.push_back(std::vector<char>());
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        break;
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      case indexed_db::CURSOR_KEY_AND_VALUE: {
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        std::vector<char> value;
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        value.swap(*cursor_->cursor_->Value());
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        size_estimate += value.size();
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        found_values.push_back(value);
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        break;
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      default:
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        NOTREACHED();
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_estimate += cursor_->cursor_->key().size_estimate();
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_estimate += cursor_->cursor_->primary_key().size_estimate();
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (size_estimate > max_size_estimate)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!found_keys.size()) {
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callbacks_->OnSuccessWithPrefetch(
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      found_keys, found_primary_keys, found_values);
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::PrefetchReset(int used_prefetches, int) {
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("IndexedDBCursor::prefetch_reset");
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  cursor_.swap(saved_cursor_);
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  saved_cursor_.reset();
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (closed_)
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (cursor_) {
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int i = 0; i < used_prefetches; ++i) {
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      bool ok = cursor_->ContinueFunction();
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(ok);
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBCursor::Close() {
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IDB_TRACE("IndexedDBCursor::close");
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  closed_ = true;
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  cursor_.reset();
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  saved_cursor_.reset();
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
212