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
,
21 ThreadSafeSender
* thread_safe_sender
)
22 : ipc_cursor_id_(ipc_cursor_id
),
25 pending_onsuccess_callbacks_(0),
26 prefetch_amount_(kMinPrefetchAmount
),
27 thread_safe_sender_(thread_safe_sender
) {}
29 WebIDBCursorImpl::~WebIDBCursorImpl() {
30 // It's not possible for there to be pending callbacks that address this
31 // object since inside WebKit, they hold a reference to the object which owns
32 // this object. But, if that ever changed, then we'd need to invalidate
35 if (ipc_cursor_id_
!= kInvalidCursorId
) {
36 // Invalid ID used in tests to avoid really sending this message.
37 thread_safe_sender_
->Send(
38 new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_
));
40 IndexedDBDispatcher
* dispatcher
=
41 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
42 dispatcher
->CursorDestroyed(ipc_cursor_id_
);
45 void WebIDBCursorImpl::advance(unsigned long count
,
46 WebIDBCallbacks
* callbacks_ptr
) {
47 IndexedDBDispatcher
* dispatcher
=
48 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
49 scoped_ptr
<WebIDBCallbacks
> callbacks(callbacks_ptr
);
50 if (count
<= prefetch_keys_
.size()) {
51 CachedAdvance(count
, callbacks
.get());
55 dispatcher
->RequestIDBCursorAdvance(
56 count
, callbacks
.release(), ipc_cursor_id_
);
59 void WebIDBCursorImpl::continueFunction(const WebIDBKey
& key
,
60 WebIDBCallbacks
* callbacks_ptr
) {
61 continueFunction(key
, WebIDBKey::createNull(), callbacks_ptr
);
64 void WebIDBCursorImpl::continueFunction(const WebIDBKey
& key
,
65 const WebIDBKey
& primary_key
,
66 WebIDBCallbacks
* callbacks_ptr
) {
67 IndexedDBDispatcher
* dispatcher
=
68 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
69 scoped_ptr
<WebIDBCallbacks
> callbacks(callbacks_ptr
);
71 if (key
.keyType() == blink::WebIDBKeyTypeNull
&&
72 primary_key
.keyType() == blink::WebIDBKeyTypeNull
) {
73 // No key(s), so this would qualify for a prefetch.
76 if (!prefetch_keys_
.empty()) {
77 // We have a prefetch cache, so serve the result from that.
78 CachedContinue(callbacks
.get());
82 if (continue_count_
> kPrefetchContinueThreshold
) {
84 ++pending_onsuccess_callbacks_
;
85 dispatcher
->RequestIDBCursorPrefetch(
86 prefetch_amount_
, callbacks
.release(), ipc_cursor_id_
);
88 // Increase prefetch_amount_ exponentially.
89 prefetch_amount_
*= 2;
90 if (prefetch_amount_
> kMaxPrefetchAmount
)
91 prefetch_amount_
= kMaxPrefetchAmount
;
96 // Key argument supplied. We couldn't prefetch this.
100 dispatcher
->RequestIDBCursorContinue(IndexedDBKeyBuilder::Build(key
),
101 IndexedDBKeyBuilder::Build(primary_key
),
106 void WebIDBCursorImpl::postSuccessHandlerCallback() {
107 pending_onsuccess_callbacks_
--;
109 // If the onsuccess callback called continue()/advance() on the cursor
110 // again, and that request was served by the prefetch cache, then
111 // pending_onsuccess_callbacks_ would be incremented. If not, it means the
112 // callback did something else, or nothing at all, in which case we need to
115 if (pending_onsuccess_callbacks_
== 0)
116 ResetPrefetchCache();
119 void WebIDBCursorImpl::SetPrefetchData(
120 const std::vector
<IndexedDBKey
>& keys
,
121 const std::vector
<IndexedDBKey
>& primary_keys
,
122 const std::vector
<WebData
>& values
) {
123 prefetch_keys_
.assign(keys
.begin(), keys
.end());
124 prefetch_primary_keys_
.assign(primary_keys
.begin(), primary_keys
.end());
125 prefetch_values_
.assign(values
.begin(), values
.end());
127 used_prefetches_
= 0;
128 pending_onsuccess_callbacks_
= 0;
131 void WebIDBCursorImpl::CachedAdvance(unsigned long count
,
132 WebIDBCallbacks
* callbacks
) {
133 DCHECK_GE(prefetch_keys_
.size(), count
);
134 DCHECK_EQ(prefetch_primary_keys_
.size(), prefetch_keys_
.size());
135 DCHECK_EQ(prefetch_values_
.size(), prefetch_keys_
.size());
138 prefetch_keys_
.pop_front();
139 prefetch_primary_keys_
.pop_front();
140 prefetch_values_
.pop_front();
145 CachedContinue(callbacks
);
148 void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks
* callbacks
) {
149 DCHECK_GT(prefetch_keys_
.size(), 0ul);
150 DCHECK_EQ(prefetch_primary_keys_
.size(), prefetch_keys_
.size());
151 DCHECK_EQ(prefetch_values_
.size(), prefetch_keys_
.size());
153 IndexedDBKey key
= prefetch_keys_
.front();
154 IndexedDBKey primary_key
= prefetch_primary_keys_
.front();
155 WebData value
= prefetch_values_
.front();
157 prefetch_keys_
.pop_front();
158 prefetch_primary_keys_
.pop_front();
159 prefetch_values_
.pop_front();
162 ++pending_onsuccess_callbacks_
;
164 if (!continue_count_
) {
165 // The cache was invalidated by a call to ResetPrefetchCache()
166 // after the RequestIDBCursorPrefetch() was made. Now that the
167 // initiating continue() call has been satisfied, discard
168 // the rest of the cache.
169 ResetPrefetchCache();
172 callbacks
->onSuccess(WebIDBKeyBuilder::Build(key
),
173 WebIDBKeyBuilder::Build(primary_key
),
177 void WebIDBCursorImpl::ResetPrefetchCache() {
179 prefetch_amount_
= kMinPrefetchAmount
;
181 if (!prefetch_keys_
.size()) {
182 // No prefetch cache, so no need to reset the cursor in the back-end.
186 IndexedDBDispatcher
* dispatcher
=
187 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
188 dispatcher
->RequestIDBCursorPrefetchReset(
189 used_prefetches_
, prefetch_keys_
.size(), ipc_cursor_id_
);
190 prefetch_keys_
.clear();
191 prefetch_primary_keys_
.clear();
192 prefetch_values_
.clear();
194 pending_onsuccess_callbacks_
= 0;
197 } // namespace content