• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/child/indexed_db/webidbcursor_impl.h"
6 
7 #include <vector>
8 
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"
13 
14 using blink::WebData;
15 using blink::WebIDBCallbacks;
16 using blink::WebIDBKey;
17 
18 namespace content {
19 
WebIDBCursorImpl(int32 ipc_cursor_id,int64 transaction_id,ThreadSafeSender * thread_safe_sender)20 WebIDBCursorImpl::WebIDBCursorImpl(int32 ipc_cursor_id,
21                                    int64 transaction_id,
22                                    ThreadSafeSender* thread_safe_sender)
23     : ipc_cursor_id_(ipc_cursor_id),
24       transaction_id_(transaction_id),
25       continue_count_(0),
26       used_prefetches_(0),
27       pending_onsuccess_callbacks_(0),
28       prefetch_amount_(kMinPrefetchAmount),
29       thread_safe_sender_(thread_safe_sender) {}
30 
~WebIDBCursorImpl()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
35   // any such pointers.
36 
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_));
41   }
42   IndexedDBDispatcher* dispatcher =
43       IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
44   dispatcher->CursorDestroyed(ipc_cursor_id_);
45 }
46 
advance(unsigned long count,WebIDBCallbacks * callbacks_ptr)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());
54     return;
55   }
56   ResetPrefetchCache();
57   dispatcher->RequestIDBCursorAdvance(
58       count, callbacks.release(), ipc_cursor_id_, transaction_id_);
59 }
60 
continueFunction(const WebIDBKey & key,WebIDBCallbacks * callbacks_ptr)61 void WebIDBCursorImpl::continueFunction(const WebIDBKey& key,
62                                         WebIDBCallbacks* callbacks_ptr) {
63   continueFunction(key, WebIDBKey::createNull(), callbacks_ptr);
64 }
65 
continueFunction(const WebIDBKey & key,const WebIDBKey & primary_key,WebIDBCallbacks * 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);
72 
73   if (key.keyType() == blink::WebIDBKeyTypeNull &&
74       primary_key.keyType() == blink::WebIDBKeyTypeNull) {
75     // No key(s), so this would qualify for a prefetch.
76     ++continue_count_;
77 
78     if (!prefetch_keys_.empty()) {
79       // We have a prefetch cache, so serve the result from that.
80       CachedContinue(callbacks.get());
81       return;
82     }
83 
84     if (continue_count_ > kPrefetchContinueThreshold) {
85       // Request pre-fetch.
86       ++pending_onsuccess_callbacks_;
87       dispatcher->RequestIDBCursorPrefetch(
88           prefetch_amount_, callbacks.release(), ipc_cursor_id_);
89 
90       // Increase prefetch_amount_ exponentially.
91       prefetch_amount_ *= 2;
92       if (prefetch_amount_ > kMaxPrefetchAmount)
93         prefetch_amount_ = kMaxPrefetchAmount;
94 
95       return;
96     }
97   } else {
98     // Key argument supplied. We couldn't prefetch this.
99     ResetPrefetchCache();
100   }
101 
102   dispatcher->RequestIDBCursorContinue(IndexedDBKeyBuilder::Build(key),
103                                        IndexedDBKeyBuilder::Build(primary_key),
104                                        callbacks.release(),
105                                        ipc_cursor_id_,
106                                        transaction_id_);
107 }
108 
postSuccessHandlerCallback()109 void WebIDBCursorImpl::postSuccessHandlerCallback() {
110   pending_onsuccess_callbacks_--;
111 
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
116   // reset the cache.
117 
118   if (pending_onsuccess_callbacks_ == 0)
119     ResetPrefetchCache();
120 }
121 
SetPrefetchData(const std::vector<IndexedDBKey> & keys,const std::vector<IndexedDBKey> & primary_keys,const std::vector<WebData> & values,const std::vector<blink::WebVector<blink::WebBlobInfo>> & blob_info)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());
131 
132   used_prefetches_ = 0;
133   pending_onsuccess_callbacks_ = 0;
134 }
135 
CachedAdvance(unsigned long count,WebIDBCallbacks * callbacks)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());
142 
143   while (count > 1) {
144     prefetch_keys_.pop_front();
145     prefetch_primary_keys_.pop_front();
146     prefetch_values_.pop_front();
147     prefetch_blob_info_.pop_front();
148     ++used_prefetches_;
149     --count;
150   }
151 
152   CachedContinue(callbacks);
153 }
154 
CachedContinue(WebIDBCallbacks * 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());
160 
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();
165 
166   prefetch_keys_.pop_front();
167   prefetch_primary_keys_.pop_front();
168   prefetch_values_.pop_front();
169   prefetch_blob_info_.pop_front();
170   ++used_prefetches_;
171 
172   ++pending_onsuccess_callbacks_;
173 
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();
180   }
181 
182   callbacks->onSuccess(WebIDBKeyBuilder::Build(key),
183                        WebIDBKeyBuilder::Build(primary_key),
184                        value,
185                        blob_info);
186 }
187 
ResetPrefetchCache()188 void WebIDBCursorImpl::ResetPrefetchCache() {
189   continue_count_ = 0;
190   prefetch_amount_ = kMinPrefetchAmount;
191 
192   if (!prefetch_keys_.size()) {
193     // No prefetch cache, so no need to reset the cursor in the back-end.
194     return;
195   }
196 
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();
205 
206   pending_onsuccess_callbacks_ = 0;
207 }
208 
209 }  // namespace content
210