1 // Copyright 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/child/indexed_db/webidbcursor_impl.h"
9 #include "content/child/indexed_db/indexed_db_dispatcher.h"
10 #include "content/child/indexed_db/indexed_db_key_builders.h"
11 #include "content/child/thread_safe_sender.h"
12 #include "content/common/indexed_db/indexed_db_messages.h"
15 using blink::WebIDBCallbacks
;
16 using blink::WebIDBKey
;
20 WebIDBCursorImpl::WebIDBCursorImpl(int32 ipc_cursor_id
,
22 ThreadSafeSender
* thread_safe_sender
)
23 : ipc_cursor_id_(ipc_cursor_id
),
24 transaction_id_(transaction_id
),
27 pending_onsuccess_callbacks_(0),
28 prefetch_amount_(kMinPrefetchAmount
),
29 thread_safe_sender_(thread_safe_sender
) {}
31 WebIDBCursorImpl::~WebIDBCursorImpl() {
32 // It's not possible for there to be pending callbacks that address this
33 // object since inside WebKit, they hold a reference to the object which owns
34 // this object. But, if that ever changed, then we'd need to invalidate
37 if (ipc_cursor_id_
!= kInvalidCursorId
) {
38 // Invalid ID used in tests to avoid really sending this message.
39 thread_safe_sender_
->Send(
40 new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_
));
42 IndexedDBDispatcher
* dispatcher
=
43 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
44 dispatcher
->CursorDestroyed(ipc_cursor_id_
);
47 void WebIDBCursorImpl::advance(unsigned long count
,
48 WebIDBCallbacks
* callbacks_ptr
) {
49 IndexedDBDispatcher
* dispatcher
=
50 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
51 scoped_ptr
<WebIDBCallbacks
> callbacks(callbacks_ptr
);
52 if (count
<= prefetch_keys_
.size()) {
53 CachedAdvance(count
, callbacks
.get());
57 dispatcher
->RequestIDBCursorAdvance(
58 count
, callbacks
.release(), ipc_cursor_id_
, transaction_id_
);
61 void WebIDBCursorImpl::continueFunction(const WebIDBKey
& key
,
62 WebIDBCallbacks
* callbacks_ptr
) {
63 continueFunction(key
, WebIDBKey::createNull(), callbacks_ptr
);
66 void WebIDBCursorImpl::continueFunction(const WebIDBKey
& key
,
67 const WebIDBKey
& primary_key
,
68 WebIDBCallbacks
* callbacks_ptr
) {
69 IndexedDBDispatcher
* dispatcher
=
70 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
71 scoped_ptr
<WebIDBCallbacks
> callbacks(callbacks_ptr
);
73 if (key
.keyType() == blink::WebIDBKeyTypeNull
&&
74 primary_key
.keyType() == blink::WebIDBKeyTypeNull
) {
75 // No key(s), so this would qualify for a prefetch.
78 if (!prefetch_keys_
.empty()) {
79 // We have a prefetch cache, so serve the result from that.
80 CachedContinue(callbacks
.get());
84 if (continue_count_
> kPrefetchContinueThreshold
) {
86 ++pending_onsuccess_callbacks_
;
87 dispatcher
->RequestIDBCursorPrefetch(
88 prefetch_amount_
, callbacks
.release(), ipc_cursor_id_
);
90 // Increase prefetch_amount_ exponentially.
91 prefetch_amount_
*= 2;
92 if (prefetch_amount_
> kMaxPrefetchAmount
)
93 prefetch_amount_
= kMaxPrefetchAmount
;
98 // Key argument supplied. We couldn't prefetch this.
102 dispatcher
->RequestIDBCursorContinue(IndexedDBKeyBuilder::Build(key
),
103 IndexedDBKeyBuilder::Build(primary_key
),
109 void WebIDBCursorImpl::postSuccessHandlerCallback() {
110 pending_onsuccess_callbacks_
--;
112 // If the onsuccess callback called continue()/advance() on the cursor
113 // again, and that request was served by the prefetch cache, then
114 // pending_onsuccess_callbacks_ would be incremented. If not, it means the
115 // callback did something else, or nothing at all, in which case we need to
118 if (pending_onsuccess_callbacks_
== 0)
119 ResetPrefetchCache();
122 void WebIDBCursorImpl::SetPrefetchData(
123 const std::vector
<IndexedDBKey
>& keys
,
124 const std::vector
<IndexedDBKey
>& primary_keys
,
125 const std::vector
<WebData
>& values
,
126 const std::vector
<blink::WebVector
<blink::WebBlobInfo
> >& blob_info
) {
127 prefetch_keys_
.assign(keys
.begin(), keys
.end());
128 prefetch_primary_keys_
.assign(primary_keys
.begin(), primary_keys
.end());
129 prefetch_values_
.assign(values
.begin(), values
.end());
130 prefetch_blob_info_
.assign(blob_info
.begin(), blob_info
.end());
132 used_prefetches_
= 0;
133 pending_onsuccess_callbacks_
= 0;
136 void WebIDBCursorImpl::CachedAdvance(unsigned long count
,
137 WebIDBCallbacks
* callbacks
) {
138 DCHECK_GE(prefetch_keys_
.size(), count
);
139 DCHECK_EQ(prefetch_primary_keys_
.size(), prefetch_keys_
.size());
140 DCHECK_EQ(prefetch_values_
.size(), prefetch_keys_
.size());
141 DCHECK_EQ(prefetch_blob_info_
.size(), prefetch_keys_
.size());
144 prefetch_keys_
.pop_front();
145 prefetch_primary_keys_
.pop_front();
146 prefetch_values_
.pop_front();
147 prefetch_blob_info_
.pop_front();
152 CachedContinue(callbacks
);
155 void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks
* callbacks
) {
156 DCHECK_GT(prefetch_keys_
.size(), 0ul);
157 DCHECK_EQ(prefetch_primary_keys_
.size(), prefetch_keys_
.size());
158 DCHECK_EQ(prefetch_values_
.size(), prefetch_keys_
.size());
159 DCHECK_EQ(prefetch_blob_info_
.size(), prefetch_keys_
.size());
161 IndexedDBKey key
= prefetch_keys_
.front();
162 IndexedDBKey primary_key
= prefetch_primary_keys_
.front();
163 WebData value
= prefetch_values_
.front();
164 blink::WebVector
<blink::WebBlobInfo
> blob_info
= prefetch_blob_info_
.front();
166 prefetch_keys_
.pop_front();
167 prefetch_primary_keys_
.pop_front();
168 prefetch_values_
.pop_front();
169 prefetch_blob_info_
.pop_front();
172 ++pending_onsuccess_callbacks_
;
174 if (!continue_count_
) {
175 // The cache was invalidated by a call to ResetPrefetchCache()
176 // after the RequestIDBCursorPrefetch() was made. Now that the
177 // initiating continue() call has been satisfied, discard
178 // the rest of the cache.
179 ResetPrefetchCache();
182 callbacks
->onSuccess(WebIDBKeyBuilder::Build(key
),
183 WebIDBKeyBuilder::Build(primary_key
),
188 void WebIDBCursorImpl::ResetPrefetchCache() {
190 prefetch_amount_
= kMinPrefetchAmount
;
192 if (!prefetch_keys_
.size()) {
193 // No prefetch cache, so no need to reset the cursor in the back-end.
197 IndexedDBDispatcher
* dispatcher
=
198 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
199 dispatcher
->RequestIDBCursorPrefetchReset(
200 used_prefetches_
, prefetch_keys_
.size(), ipc_cursor_id_
);
201 prefetch_keys_
.clear();
202 prefetch_primary_keys_
.clear();
203 prefetch_values_
.clear();
204 prefetch_blob_info_
.clear();
206 pending_onsuccess_callbacks_
= 0;
209 } // namespace content