indexed_db_cursor.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/indexed_db/indexed_db_cursor.h"
6
7#include "base/logging.h"
8#include "content/browser/indexed_db/indexed_db_callbacks.h"
9#include "content/browser/indexed_db/indexed_db_database_error.h"
10#include "content/browser/indexed_db/indexed_db_tracing.h"
11#include "content/browser/indexed_db/indexed_db_transaction.h"
12
13namespace content {
14
15class IndexedDBCursor::CursorIterationOperation
16    : public IndexedDBTransaction::Operation {
17 public:
18  CursorIterationOperation(scoped_refptr<IndexedDBCursor> cursor,
19                           scoped_ptr<IndexedDBKey> key,
20                           scoped_refptr<IndexedDBCallbacks> callbacks)
21      : cursor_(cursor), key_(key.Pass()), callbacks_(callbacks) {}
22  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
23
24 private:
25  scoped_refptr<IndexedDBCursor> cursor_;
26  scoped_ptr<IndexedDBKey> key_;
27  scoped_refptr<IndexedDBCallbacks> callbacks_;
28};
29
30class IndexedDBCursor::CursorAdvanceOperation
31    : public IndexedDBTransaction::Operation {
32 public:
33  CursorAdvanceOperation(scoped_refptr<IndexedDBCursor> cursor,
34                         uint32 count,
35                         scoped_refptr<IndexedDBCallbacks> callbacks)
36      : cursor_(cursor), count_(count), callbacks_(callbacks) {}
37  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
38
39 private:
40  scoped_refptr<IndexedDBCursor> cursor_;
41  uint32 count_;
42  scoped_refptr<IndexedDBCallbacks> callbacks_;
43};
44
45class IndexedDBCursor::CursorPrefetchIterationOperation
46    : public IndexedDBTransaction::Operation {
47 public:
48  CursorPrefetchIterationOperation(scoped_refptr<IndexedDBCursor> cursor,
49                                   int number_to_fetch,
50                                   scoped_refptr<IndexedDBCallbacks> callbacks)
51      : cursor_(cursor),
52        number_to_fetch_(number_to_fetch),
53        callbacks_(callbacks) {}
54  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
55
56 private:
57  scoped_refptr<IndexedDBCursor> cursor_;
58  int number_to_fetch_;
59  scoped_refptr<IndexedDBCallbacks> callbacks_;
60};
61
62IndexedDBCursor::IndexedDBCursor(
63    scoped_ptr<IndexedDBBackingStore::Cursor> cursor,
64    indexed_db::CursorType cursor_type,
65    IndexedDBDatabase::TaskType task_type,
66    IndexedDBTransaction* transaction)
67    : task_type_(task_type),
68      cursor_type_(cursor_type),
69      transaction_(transaction),
70      cursor_(cursor.Pass()),
71      closed_(false) {
72  transaction_->RegisterOpenCursor(this);
73}
74
75IndexedDBCursor::~IndexedDBCursor() {
76  transaction_->UnregisterOpenCursor(this);
77}
78
79void IndexedDBCursor::Continue(scoped_ptr<IndexedDBKey> key,
80                               scoped_refptr<IndexedDBCallbacks> callbacks) {
81  IDB_TRACE("IndexedDBCursor::Continue");
82
83  transaction_->ScheduleTask(
84      task_type_, new CursorIterationOperation(this, key.Pass(), callbacks));
85}
86
87void IndexedDBCursor::Advance(uint32 count,
88                              scoped_refptr<IndexedDBCallbacks> callbacks) {
89  IDB_TRACE("IndexedDBCursor::Advance");
90
91  transaction_->ScheduleTask(
92      new CursorAdvanceOperation(this, count, callbacks));
93}
94
95void IndexedDBCursor::CursorAdvanceOperation::Perform(
96    IndexedDBTransaction* /*transaction*/) {
97  IDB_TRACE("CursorAdvanceOperation");
98  if (!cursor_->cursor_ || !cursor_->cursor_->Advance(count_)) {
99    cursor_->cursor_.reset();
100    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
101    return;
102  }
103
104  callbacks_->OnSuccess(
105      cursor_->key(), cursor_->primary_key(), cursor_->Value());
106}
107
108void IndexedDBCursor::CursorIterationOperation::Perform(
109    IndexedDBTransaction* /*transaction*/) {
110  IDB_TRACE("CursorIterationOperation");
111  if (!cursor_->cursor_ ||
112      !cursor_->cursor_->Continue(key_.get(),
113                                  IndexedDBBackingStore::Cursor::SEEK)) {
114    cursor_->cursor_.reset();
115    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
116    return;
117  }
118
119  callbacks_->OnSuccess(
120      cursor_->key(), cursor_->primary_key(), cursor_->Value());
121}
122
123void IndexedDBCursor::PrefetchContinue(
124    int number_to_fetch,
125    scoped_refptr<IndexedDBCallbacks> callbacks) {
126  IDB_TRACE("IndexedDBCursor::PrefetchContinue");
127
128  transaction_->ScheduleTask(
129      task_type_,
130      new CursorPrefetchIterationOperation(this, number_to_fetch, callbacks));
131}
132
133void IndexedDBCursor::CursorPrefetchIterationOperation::Perform(
134    IndexedDBTransaction* /*transaction*/) {
135  IDB_TRACE("CursorPrefetchIterationOperation");
136
137  std::vector<IndexedDBKey> found_keys;
138  std::vector<IndexedDBKey> found_primary_keys;
139  std::vector<std::string> found_values;
140
141  if (cursor_->cursor_)
142    cursor_->saved_cursor_.reset(cursor_->cursor_->Clone());
143  const size_t max_size_estimate = 10 * 1024 * 1024;
144  size_t size_estimate = 0;
145
146  for (int i = 0; i < number_to_fetch_; ++i) {
147    if (!cursor_->cursor_ || !cursor_->cursor_->Continue()) {
148      cursor_->cursor_.reset();
149      break;
150    }
151
152    found_keys.push_back(cursor_->cursor_->key());
153    found_primary_keys.push_back(cursor_->cursor_->primary_key());
154
155    switch (cursor_->cursor_type_) {
156      case indexed_db::CURSOR_KEY_ONLY:
157        found_values.push_back(std::string());
158        break;
159      case indexed_db::CURSOR_KEY_AND_VALUE: {
160        std::string value;
161        value.swap(*cursor_->cursor_->Value());
162        size_estimate += value.size();
163        found_values.push_back(value);
164        break;
165      }
166      default:
167        NOTREACHED();
168    }
169    size_estimate += cursor_->cursor_->key().size_estimate();
170    size_estimate += cursor_->cursor_->primary_key().size_estimate();
171
172    if (size_estimate > max_size_estimate)
173      break;
174  }
175
176  if (!found_keys.size()) {
177    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
178    return;
179  }
180
181  callbacks_->OnSuccessWithPrefetch(
182      found_keys, found_primary_keys, found_values);
183}
184
185void IndexedDBCursor::PrefetchReset(int used_prefetches, int) {
186  IDB_TRACE("IndexedDBCursor::PrefetchReset");
187  cursor_.swap(saved_cursor_);
188  saved_cursor_.reset();
189
190  if (closed_)
191    return;
192  if (cursor_) {
193    for (int i = 0; i < used_prefetches; ++i) {
194      bool ok = cursor_->Continue();
195      DCHECK(ok);
196    }
197  }
198}
199
200void IndexedDBCursor::Close() {
201  IDB_TRACE("IndexedDBCursor::Close");
202  closed_ = true;
203  cursor_.reset();
204  saved_cursor_.reset();
205}
206
207}  // namespace content
208