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"
10 #include "content/child/indexed_db/indexed_db_dispatcher.h"
11 #include "content/child/indexed_db/indexed_db_key_builders.h"
12 #include "content/child/thread_safe_sender.h"
13 #include "content/common/indexed_db/indexed_db_messages.h"
16 using blink::WebIDBCallbacks
;
17 using blink::WebIDBKey
;
21 WebIDBCursorImpl::WebIDBCursorImpl(int32 ipc_cursor_id
,
23 ThreadSafeSender
* thread_safe_sender
)
24 : ipc_cursor_id_(ipc_cursor_id
),
25 transaction_id_(transaction_id
),
28 pending_onsuccess_callbacks_(0),
29 prefetch_amount_(kMinPrefetchAmount
),
30 thread_safe_sender_(thread_safe_sender
) {}
32 WebIDBCursorImpl::~WebIDBCursorImpl() {
33 // It's not possible for there to be pending callbacks that address this
34 // object since inside WebKit, they hold a reference to the object which owns
35 // this object. But, if that ever changed, then we'd need to invalidate
38 if (ipc_cursor_id_
!= kInvalidCursorId
) {
39 // Invalid ID used in tests to avoid really sending this message.
40 thread_safe_sender_
->Send(
41 new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_
));
43 IndexedDBDispatcher
* dispatcher
=
44 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
45 dispatcher
->CursorDestroyed(ipc_cursor_id_
);
48 void WebIDBCursorImpl::advance(unsigned long count
,
49 WebIDBCallbacks
* callbacks_ptr
) {
50 IndexedDBDispatcher
* dispatcher
=
51 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
52 scoped_ptr
<WebIDBCallbacks
> callbacks(callbacks_ptr
);
53 if (count
<= prefetch_keys_
.size()) {
54 CachedAdvance(count
, callbacks
.get());
58 dispatcher
->RequestIDBCursorAdvance(
59 count
, callbacks
.release(), ipc_cursor_id_
, transaction_id_
);
62 void WebIDBCursorImpl::continueFunction(const WebIDBKey
& key
,
63 WebIDBCallbacks
* callbacks_ptr
) {
64 continueFunction(key
, WebIDBKey::createNull(), callbacks_ptr
);
67 void WebIDBCursorImpl::continueFunction(const WebIDBKey
& key
,
68 const WebIDBKey
& primary_key
,
69 WebIDBCallbacks
* callbacks_ptr
) {
70 IndexedDBDispatcher
* dispatcher
=
71 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
72 scoped_ptr
<WebIDBCallbacks
> callbacks(callbacks_ptr
);
74 if (key
.keyType() == blink::WebIDBKeyTypeNull
&&
75 primary_key
.keyType() == blink::WebIDBKeyTypeNull
) {
76 // No key(s), so this would qualify for a prefetch.
79 if (!prefetch_keys_
.empty()) {
80 // We have a prefetch cache, so serve the result from that.
81 CachedContinue(callbacks
.get());
85 if (continue_count_
> kPrefetchContinueThreshold
) {
87 ++pending_onsuccess_callbacks_
;
88 dispatcher
->RequestIDBCursorPrefetch(
89 prefetch_amount_
, callbacks
.release(), ipc_cursor_id_
);
91 // Increase prefetch_amount_ exponentially.
92 prefetch_amount_
*= 2;
93 if (prefetch_amount_
> kMaxPrefetchAmount
)
94 prefetch_amount_
= kMaxPrefetchAmount
;
99 // Key argument supplied. We couldn't prefetch this.
100 ResetPrefetchCache();
103 dispatcher
->RequestIDBCursorContinue(IndexedDBKeyBuilder::Build(key
),
104 IndexedDBKeyBuilder::Build(primary_key
),
110 void WebIDBCursorImpl::postSuccessHandlerCallback() {
111 pending_onsuccess_callbacks_
--;
113 // If the onsuccess callback called continue()/advance() on the cursor
114 // again, and that request was served by the prefetch cache, then
115 // pending_onsuccess_callbacks_ would be incremented. If not, it means the
116 // callback did something else, or nothing at all, in which case we need to
119 if (pending_onsuccess_callbacks_
== 0)
120 ResetPrefetchCache();
123 void WebIDBCursorImpl::SetPrefetchData(
124 const std::vector
<IndexedDBKey
>& keys
,
125 const std::vector
<IndexedDBKey
>& primary_keys
,
126 const std::vector
<WebData
>& values
,
127 const std::vector
<blink::WebVector
<blink::WebBlobInfo
> >& blob_info
) {
128 prefetch_keys_
.assign(keys
.begin(), keys
.end());
129 prefetch_primary_keys_
.assign(primary_keys
.begin(), primary_keys
.end());
130 prefetch_values_
.assign(values
.begin(), values
.end());
131 prefetch_blob_info_
.assign(blob_info
.begin(), blob_info
.end());
133 used_prefetches_
= 0;
134 pending_onsuccess_callbacks_
= 0;
137 void WebIDBCursorImpl::CachedAdvance(unsigned long count
,
138 WebIDBCallbacks
* callbacks
) {
139 DCHECK_GE(prefetch_keys_
.size(), count
);
140 DCHECK_EQ(prefetch_primary_keys_
.size(), prefetch_keys_
.size());
141 DCHECK_EQ(prefetch_values_
.size(), prefetch_keys_
.size());
142 DCHECK_EQ(prefetch_blob_info_
.size(), prefetch_keys_
.size());
145 prefetch_keys_
.pop_front();
146 prefetch_primary_keys_
.pop_front();
147 prefetch_values_
.pop_front();
148 prefetch_blob_info_
.pop_front();
153 CachedContinue(callbacks
);
156 void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks
* callbacks
) {
157 DCHECK_GT(prefetch_keys_
.size(), 0ul);
158 DCHECK_EQ(prefetch_primary_keys_
.size(), prefetch_keys_
.size());
159 DCHECK_EQ(prefetch_values_
.size(), prefetch_keys_
.size());
160 DCHECK_EQ(prefetch_blob_info_
.size(), prefetch_keys_
.size());
162 IndexedDBKey key
= prefetch_keys_
.front();
163 IndexedDBKey primary_key
= prefetch_primary_keys_
.front();
164 WebData value
= prefetch_values_
.front();
165 blink::WebVector
<blink::WebBlobInfo
> blob_info
= prefetch_blob_info_
.front();
167 prefetch_keys_
.pop_front();
168 prefetch_primary_keys_
.pop_front();
169 prefetch_values_
.pop_front();
170 prefetch_blob_info_
.pop_front();
173 ++pending_onsuccess_callbacks_
;
175 if (!continue_count_
) {
176 // The cache was invalidated by a call to ResetPrefetchCache()
177 // after the RequestIDBCursorPrefetch() was made. Now that the
178 // initiating continue() call has been satisfied, discard
179 // the rest of the cache.
180 ResetPrefetchCache();
183 callbacks
->onSuccess(WebIDBKeyBuilder::Build(key
),
184 WebIDBKeyBuilder::Build(primary_key
),
189 void WebIDBCursorImpl::ResetPrefetchCache() {
191 prefetch_amount_
= kMinPrefetchAmount
;
193 if (!prefetch_keys_
.size()) {
194 // No prefetch cache, so no need to reset the cursor in the back-end.
198 // Ack any unused blobs.
199 std::vector
<std::string
> uuids
;
200 for (const auto& blobs
: prefetch_blob_info_
) {
201 for (size_t i
= 0, size
= blobs
.size(); i
< size
; ++i
)
202 uuids
.push_back(blobs
[i
].uuid().latin1());
205 thread_safe_sender_
->Send(new IndexedDBHostMsg_AckReceivedBlobs(uuids
));
207 // Reset the back-end cursor.
208 IndexedDBDispatcher
* dispatcher
=
209 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_
.get());
210 dispatcher
->RequestIDBCursorPrefetchReset(
211 used_prefetches_
, prefetch_keys_
.size(), ipc_cursor_id_
);
213 // Reset the prefetch cache.
214 prefetch_keys_
.clear();
215 prefetch_primary_keys_
.clear();
216 prefetch_values_
.clear();
217 prefetch_blob_info_
.clear();
219 pending_onsuccess_callbacks_
= 0;
222 } // namespace content