Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_cursor.cc
blob9caf29d9019573db42d45906803a3a6e46c50ef9
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.
5 #include "content/browser/indexed_db/indexed_db_cursor.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "content/browser/indexed_db/indexed_db_callbacks.h"
10 #include "content/browser/indexed_db/indexed_db_database_error.h"
11 #include "content/browser/indexed_db/indexed_db_tracing.h"
12 #include "content/browser/indexed_db/indexed_db_transaction.h"
13 #include "content/browser/indexed_db/indexed_db_value.h"
15 namespace content {
17 IndexedDBCursor::IndexedDBCursor(
18 scoped_ptr<IndexedDBBackingStore::Cursor> cursor,
19 indexed_db::CursorType cursor_type,
20 IndexedDBDatabase::TaskType task_type,
21 IndexedDBTransaction* transaction)
22 : task_type_(task_type),
23 cursor_type_(cursor_type),
24 transaction_(transaction),
25 cursor_(cursor.Pass()),
26 closed_(false) {
27 transaction_->RegisterOpenCursor(this);
30 IndexedDBCursor::~IndexedDBCursor() {
31 transaction_->UnregisterOpenCursor(this);
34 void IndexedDBCursor::Continue(scoped_ptr<IndexedDBKey> key,
35 scoped_ptr<IndexedDBKey> primary_key,
36 scoped_refptr<IndexedDBCallbacks> callbacks) {
37 IDB_TRACE("IndexedDBCursor::Continue");
39 transaction_->ScheduleTask(
40 task_type_,
41 base::Bind(&IndexedDBCursor::CursorIterationOperation,
42 this,
43 base::Passed(&key),
44 base::Passed(&primary_key),
45 callbacks));
48 void IndexedDBCursor::Advance(uint32 count,
49 scoped_refptr<IndexedDBCallbacks> callbacks) {
50 IDB_TRACE("IndexedDBCursor::Advance");
52 transaction_->ScheduleTask(
53 task_type_,
54 base::Bind(
55 &IndexedDBCursor::CursorAdvanceOperation, this, count, callbacks));
58 void IndexedDBCursor::CursorAdvanceOperation(
59 uint32 count,
60 scoped_refptr<IndexedDBCallbacks> callbacks,
61 IndexedDBTransaction* /*transaction*/) {
62 IDB_TRACE("IndexedDBCursor::CursorAdvanceOperation");
63 leveldb::Status s;
64 // TODO(cmumford): Handle this error (crbug.com/363397). Although this will
65 // properly fail, caller will not know why, and any corruption
66 // will be ignored.
67 if (!cursor_ || !cursor_->Advance(count, &s)) {
68 cursor_.reset();
69 callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
70 return;
73 callbacks->OnSuccess(key(), primary_key(), Value());
76 void IndexedDBCursor::CursorIterationOperation(
77 scoped_ptr<IndexedDBKey> key,
78 scoped_ptr<IndexedDBKey> primary_key,
79 scoped_refptr<IndexedDBCallbacks> callbacks,
80 IndexedDBTransaction* /*transaction*/) {
81 IDB_TRACE("IndexedDBCursor::CursorIterationOperation");
82 leveldb::Status s;
83 // TODO(cmumford): Handle this error (crbug.com/363397). Although this will
84 // properly fail, caller will not know why, and any corruption
85 // will be ignored.
86 if (!cursor_ || !cursor_->Continue(key.get(),
87 primary_key.get(),
88 IndexedDBBackingStore::Cursor::SEEK,
89 &s) || !s.ok()) {
90 cursor_.reset();
91 callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
92 return;
95 callbacks->OnSuccess(this->key(), this->primary_key(), Value());
98 void IndexedDBCursor::PrefetchContinue(
99 int number_to_fetch,
100 scoped_refptr<IndexedDBCallbacks> callbacks) {
101 IDB_TRACE("IndexedDBCursor::PrefetchContinue");
103 transaction_->ScheduleTask(
104 task_type_,
105 base::Bind(&IndexedDBCursor::CursorPrefetchIterationOperation,
106 this,
107 number_to_fetch,
108 callbacks));
111 void IndexedDBCursor::CursorPrefetchIterationOperation(
112 int number_to_fetch,
113 scoped_refptr<IndexedDBCallbacks> callbacks,
114 IndexedDBTransaction* /*transaction*/) {
115 IDB_TRACE("IndexedDBCursor::CursorPrefetchIterationOperation");
117 std::vector<IndexedDBKey> found_keys;
118 std::vector<IndexedDBKey> found_primary_keys;
119 std::vector<IndexedDBValue> found_values;
121 saved_cursor_.reset();
122 const size_t max_size_estimate = 10 * 1024 * 1024;
123 size_t size_estimate = 0;
124 leveldb::Status s;
126 // TODO(cmumford): Handle this error (crbug.com/363397). Although this will
127 // properly fail, caller will not know why, and any corruption
128 // will be ignored.
129 for (int i = 0; i < number_to_fetch; ++i) {
130 if (!cursor_ || !cursor_->Continue(&s)) {
131 cursor_.reset();
132 break;
135 if (i == 0) {
136 // First prefetched result is always used, so that's the position
137 // a cursor should be reset to if the prefetch is invalidated.
138 saved_cursor_.reset(cursor_->Clone());
141 found_keys.push_back(cursor_->key());
142 found_primary_keys.push_back(cursor_->primary_key());
144 switch (cursor_type_) {
145 case indexed_db::CURSOR_KEY_ONLY:
146 found_values.push_back(IndexedDBValue());
147 break;
148 case indexed_db::CURSOR_KEY_AND_VALUE: {
149 IndexedDBValue value;
150 value.swap(*cursor_->value());
151 size_estimate += value.SizeEstimate();
152 found_values.push_back(value);
153 break;
155 default:
156 NOTREACHED();
158 size_estimate += cursor_->key().size_estimate();
159 size_estimate += cursor_->primary_key().size_estimate();
161 if (size_estimate > max_size_estimate)
162 break;
165 if (!found_keys.size()) {
166 callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
167 return;
170 callbacks->OnSuccessWithPrefetch(
171 found_keys, found_primary_keys, found_values);
174 leveldb::Status IndexedDBCursor::PrefetchReset(int used_prefetches,
175 int /* unused_prefetches */) {
176 IDB_TRACE("IndexedDBCursor::PrefetchReset");
177 cursor_.swap(saved_cursor_);
178 saved_cursor_.reset();
179 leveldb::Status s;
181 if (closed_)
182 return s;
183 if (cursor_) {
184 // First prefetched result is always used.
185 DCHECK_GT(used_prefetches, 0);
186 for (int i = 0; i < used_prefetches - 1; ++i) {
187 bool ok = cursor_->Continue(&s);
188 DCHECK(ok);
192 return s;
195 void IndexedDBCursor::Close() {
196 IDB_TRACE("IndexedDBCursor::Close");
197 closed_ = true;
198 cursor_.reset();
199 saved_cursor_.reset();
202 } // namespace content