indexed_db_cursor.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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::ContinueFunction(
80    scoped_ptr<IndexedDBKey> key,
81    scoped_refptr<IndexedDBCallbacks> callbacks) {
82  IDB_TRACE("IndexedDBCursor::Continue");
83
84  transaction_->ScheduleTask(
85      task_type_, new CursorIterationOperation(this, key.Pass(), callbacks));
86}
87
88void IndexedDBCursor::Advance(uint32 count,
89                              scoped_refptr<IndexedDBCallbacks> callbacks) {
90  IDB_TRACE("IndexedDBCursor::Advance");
91
92  transaction_->ScheduleTask(
93      new CursorAdvanceOperation(this, count, callbacks));
94}
95
96void IndexedDBCursor::CursorAdvanceOperation::Perform(
97    IndexedDBTransaction* /*transaction*/) {
98  IDB_TRACE("CursorAdvanceOperation");
99  if (!cursor_->cursor_ || !cursor_->cursor_->Advance(count_)) {
100    cursor_->cursor_.reset();
101    callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
102    return;
103  }
104
105  callbacks_->OnSuccess(
106      cursor_->key(), cursor_->primary_key(), cursor_->Value());
107}
108
109void IndexedDBCursor::CursorIterationOperation::Perform(
110    IndexedDBTransaction* /*transaction*/) {
111  IDB_TRACE("CursorIterationOperation");
112  if (!cursor_->cursor_ ||
113      !cursor_->cursor_->ContinueFunction(
114          key_.get(), IndexedDBBackingStore::Cursor::SEEK)) {
115    cursor_->cursor_.reset();
116    callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
117    return;
118  }
119
120  callbacks_->OnSuccess(
121      cursor_->key(), cursor_->primary_key(), cursor_->Value());
122}
123
124void IndexedDBCursor::PrefetchContinue(
125    int number_to_fetch,
126    scoped_refptr<IndexedDBCallbacks> callbacks) {
127  IDB_TRACE("IndexedDBCursor::PrefetchContinue");
128
129  transaction_->ScheduleTask(
130      task_type_,
131      new CursorPrefetchIterationOperation(this, number_to_fetch, callbacks));
132}
133
134void IndexedDBCursor::CursorPrefetchIterationOperation::Perform(
135    IndexedDBTransaction* /*transaction*/) {
136  IDB_TRACE("CursorPrefetchIterationOperation");
137
138  std::vector<IndexedDBKey> found_keys;
139  std::vector<IndexedDBKey> found_primary_keys;
140  std::vector<std::vector<char> > found_values;
141
142  if (cursor_->cursor_)
143    cursor_->saved_cursor_.reset(cursor_->cursor_->Clone());
144  const size_t max_size_estimate = 10 * 1024 * 1024;
145  size_t size_estimate = 0;
146
147  for (int i = 0; i < number_to_fetch_; ++i) {
148    if (!cursor_->cursor_ || !cursor_->cursor_->ContinueFunction()) {
149      cursor_->cursor_.reset();
150      break;
151    }
152
153    found_keys.push_back(cursor_->cursor_->key());
154    found_primary_keys.push_back(cursor_->cursor_->primary_key());
155
156    switch (cursor_->cursor_type_) {
157      case indexed_db::CURSOR_KEY_ONLY:
158        found_values.push_back(std::vector<char>());
159        break;
160      case indexed_db::CURSOR_KEY_AND_VALUE: {
161        std::vector<char> value;
162        value.swap(*cursor_->cursor_->Value());
163        size_estimate += value.size();
164        found_values.push_back(value);
165        break;
166      }
167      default:
168        NOTREACHED();
169    }
170    size_estimate += cursor_->cursor_->key().size_estimate();
171    size_estimate += cursor_->cursor_->primary_key().size_estimate();
172
173    if (size_estimate > max_size_estimate)
174      break;
175  }
176
177  if (!found_keys.size()) {
178    callbacks_->OnSuccess(static_cast<std::vector<char>*>(NULL));
179    return;
180  }
181
182  callbacks_->OnSuccessWithPrefetch(
183      found_keys, found_primary_keys, found_values);
184}
185
186void IndexedDBCursor::PrefetchReset(int used_prefetches, int) {
187  IDB_TRACE("IndexedDBCursor::PrefetchReset");
188  cursor_.swap(saved_cursor_);
189  saved_cursor_.reset();
190
191  if (closed_)
192    return;
193  if (cursor_) {
194    for (int i = 0; i < used_prefetches; ++i) {
195      bool ok = cursor_->ContinueFunction();
196      DCHECK(ok);
197    }
198  }
199}
200
201void IndexedDBCursor::Close() {
202  IDB_TRACE("IndexedDBCursor::Close");
203  closed_ = true;
204  cursor_.reset();
205  saved_cursor_.reset();
206}
207
208}  // namespace content
209