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