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