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/proxy_webidbcursor_impl.h"
9 #include "content/child/thread_safe_sender.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/common/indexed_db/indexed_db_messages.h"
14 using WebKit::WebData;
15 using WebKit::WebIDBCallbacks;
16 using WebKit::WebIDBKey;
20 RendererWebIDBCursorImpl::RendererWebIDBCursorImpl(
22 ThreadSafeSender* thread_safe_sender)
23 : ipc_cursor_id_(ipc_cursor_id),
26 pending_onsuccess_callbacks_(0),
27 prefetch_amount_(kMinPrefetchAmount),
28 thread_safe_sender_(thread_safe_sender) {}
30 RendererWebIDBCursorImpl::~RendererWebIDBCursorImpl() {
31 // It's not possible for there to be pending callbacks that address this
32 // object since inside WebKit, they hold a reference to the object which owns
33 // this object. But, if that ever changed, then we'd need to invalidate
36 if (ipc_cursor_id_ != kInvalidCursorId) {
37 // Invalid ID used in tests to avoid really sending this message.
38 thread_safe_sender_->Send(
39 new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_));
41 IndexedDBDispatcher* dispatcher =
42 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
43 dispatcher->CursorDestroyed(ipc_cursor_id_);
46 void RendererWebIDBCursorImpl::advance(unsigned long count,
47 WebIDBCallbacks* callbacks_ptr) {
48 IndexedDBDispatcher* dispatcher =
49 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
50 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
52 dispatcher->RequestIDBCursorAdvance(
53 count, callbacks.release(), ipc_cursor_id_);
56 void RendererWebIDBCursorImpl::continueFunction(
58 WebIDBCallbacks* callbacks_ptr) {
59 IndexedDBDispatcher* dispatcher =
60 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
61 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr);
63 if (key.keyType() == WebKit::WebIDBKeyTypeNull) {
64 // No key, so this would qualify for a prefetch.
67 if (!prefetch_keys_.empty()) {
68 // We have a prefetch cache, so serve the result from that.
69 CachedContinue(callbacks.get());
73 if (continue_count_ > kPrefetchContinueThreshold) {
75 ++pending_onsuccess_callbacks_;
76 dispatcher->RequestIDBCursorPrefetch(
77 prefetch_amount_, callbacks.release(), ipc_cursor_id_);
79 // Increase prefetch_amount_ exponentially.
80 prefetch_amount_ *= 2;
81 if (prefetch_amount_ > kMaxPrefetchAmount)
82 prefetch_amount_ = kMaxPrefetchAmount;
87 // Key argument supplied. We couldn't prefetch this.
91 dispatcher->RequestIDBCursorContinue(
92 IndexedDBKeyBuilder::Build(key), callbacks.release(), ipc_cursor_id_);
95 void RendererWebIDBCursorImpl::postSuccessHandlerCallback() {
96 pending_onsuccess_callbacks_--;
98 // If the onsuccess callback called continue() on the cursor again,
99 // and that continue was served by the prefetch cache, then
100 // pending_onsuccess_callbacks_ would be incremented.
101 // If not, it means the callback did something else, or nothing at all,
102 // in which case we need to reset the cache.
104 if (pending_onsuccess_callbacks_ == 0)
105 ResetPrefetchCache();
108 void RendererWebIDBCursorImpl::SetPrefetchData(
109 const std::vector<IndexedDBKey>& keys,
110 const std::vector<IndexedDBKey>& primary_keys,
111 const std::vector<WebData>& values) {
112 prefetch_keys_.assign(keys.begin(), keys.end());
113 prefetch_primary_keys_.assign(primary_keys.begin(), primary_keys.end());
114 prefetch_values_.assign(values.begin(), values.end());
116 used_prefetches_ = 0;
117 pending_onsuccess_callbacks_ = 0;
120 void RendererWebIDBCursorImpl::CachedContinue(WebIDBCallbacks* callbacks) {
121 DCHECK_GT(prefetch_keys_.size(), 0ul);
122 DCHECK(prefetch_primary_keys_.size() == prefetch_keys_.size());
123 DCHECK(prefetch_values_.size() == prefetch_keys_.size());
125 IndexedDBKey key = prefetch_keys_.front();
126 IndexedDBKey primary_key = prefetch_primary_keys_.front();
127 // this could be a real problem.. we need 2 CachedContinues
128 WebData value = prefetch_values_.front();
130 prefetch_keys_.pop_front();
131 prefetch_primary_keys_.pop_front();
132 prefetch_values_.pop_front();
135 pending_onsuccess_callbacks_++;
137 callbacks->onSuccess(WebIDBKeyBuilder::Build(key),
138 WebIDBKeyBuilder::Build(primary_key), value);
141 void RendererWebIDBCursorImpl::ResetPrefetchCache() {
143 prefetch_amount_ = kMinPrefetchAmount;
145 if (!prefetch_keys_.size()) {
146 // No prefetch cache, so no need to reset the cursor in the back-end.
150 IndexedDBDispatcher* dispatcher =
151 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
152 dispatcher->RequestIDBCursorPrefetchReset(
153 used_prefetches_, prefetch_keys_.size(), ipc_cursor_id_);
154 prefetch_keys_.clear();
155 prefetch_primary_keys_.clear();
156 prefetch_values_.clear();
158 pending_onsuccess_callbacks_ = 0;
161 } // namespace content