OLD | NEW |
| (Empty) |
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 <stddef.h> | |
8 | |
9 #include <string> | |
10 #include <vector> | |
11 | |
12 #include "content/child/indexed_db/indexed_db_dispatcher.h" | |
13 #include "content/child/indexed_db/indexed_db_key_builders.h" | |
14 #include "content/child/thread_safe_sender.h" | |
15 #include "content/common/indexed_db/indexed_db_messages.h" | |
16 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBValue.h" | |
17 | |
18 using blink::WebBlobInfo; | |
19 using blink::WebData; | |
20 using blink::WebIDBCallbacks; | |
21 using blink::WebIDBKey; | |
22 using blink::WebIDBValue; | |
23 | |
24 namespace content { | |
25 | |
26 WebIDBCursorImpl::WebIDBCursorImpl(int32_t ipc_cursor_id, | |
27 int64_t transaction_id, | |
28 ThreadSafeSender* thread_safe_sender) | |
29 : ipc_cursor_id_(ipc_cursor_id), | |
30 transaction_id_(transaction_id), | |
31 continue_count_(0), | |
32 used_prefetches_(0), | |
33 pending_onsuccess_callbacks_(0), | |
34 prefetch_amount_(kMinPrefetchAmount), | |
35 thread_safe_sender_(thread_safe_sender) {} | |
36 | |
37 WebIDBCursorImpl::~WebIDBCursorImpl() { | |
38 // It's not possible for there to be pending callbacks that address this | |
39 // object since inside WebKit, they hold a reference to the object which owns | |
40 // this object. But, if that ever changed, then we'd need to invalidate | |
41 // any such pointers. | |
42 | |
43 if (ipc_cursor_id_ != kInvalidCursorId) { | |
44 // Invalid ID used in tests to avoid really sending this message. | |
45 thread_safe_sender_->Send( | |
46 new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_)); | |
47 } | |
48 IndexedDBDispatcher* dispatcher = | |
49 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); | |
50 dispatcher->CursorDestroyed(ipc_cursor_id_); | |
51 } | |
52 | |
53 void WebIDBCursorImpl::advance(unsigned long count, | |
54 WebIDBCallbacks* callbacks_ptr) { | |
55 IndexedDBDispatcher* dispatcher = | |
56 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); | |
57 std::unique_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); | |
58 if (count <= prefetch_keys_.size()) { | |
59 CachedAdvance(count, callbacks.get()); | |
60 return; | |
61 } | |
62 ResetPrefetchCache(); | |
63 dispatcher->RequestIDBCursorAdvance( | |
64 count, callbacks.release(), ipc_cursor_id_, transaction_id_); | |
65 } | |
66 | |
67 void WebIDBCursorImpl::continueFunction(const WebIDBKey& key, | |
68 WebIDBCallbacks* callbacks_ptr) { | |
69 continueFunction(key, WebIDBKey::createNull(), callbacks_ptr); | |
70 } | |
71 | |
72 void WebIDBCursorImpl::continueFunction(const WebIDBKey& key, | |
73 const WebIDBKey& primary_key, | |
74 WebIDBCallbacks* callbacks_ptr) { | |
75 IndexedDBDispatcher* dispatcher = | |
76 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); | |
77 std::unique_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); | |
78 | |
79 if (key.keyType() == blink::WebIDBKeyTypeNull && | |
80 primary_key.keyType() == blink::WebIDBKeyTypeNull) { | |
81 // No key(s), so this would qualify for a prefetch. | |
82 ++continue_count_; | |
83 | |
84 if (!prefetch_keys_.empty()) { | |
85 // We have a prefetch cache, so serve the result from that. | |
86 CachedContinue(callbacks.get()); | |
87 return; | |
88 } | |
89 | |
90 if (continue_count_ > kPrefetchContinueThreshold) { | |
91 // Request pre-fetch. | |
92 ++pending_onsuccess_callbacks_; | |
93 dispatcher->RequestIDBCursorPrefetch( | |
94 prefetch_amount_, callbacks.release(), ipc_cursor_id_); | |
95 | |
96 // Increase prefetch_amount_ exponentially. | |
97 prefetch_amount_ *= 2; | |
98 if (prefetch_amount_ > kMaxPrefetchAmount) | |
99 prefetch_amount_ = kMaxPrefetchAmount; | |
100 | |
101 return; | |
102 } | |
103 } else { | |
104 // Key argument supplied. We couldn't prefetch this. | |
105 ResetPrefetchCache(); | |
106 } | |
107 | |
108 dispatcher->RequestIDBCursorContinue(IndexedDBKeyBuilder::Build(key), | |
109 IndexedDBKeyBuilder::Build(primary_key), | |
110 callbacks.release(), | |
111 ipc_cursor_id_, | |
112 transaction_id_); | |
113 } | |
114 | |
115 void WebIDBCursorImpl::postSuccessHandlerCallback() { | |
116 pending_onsuccess_callbacks_--; | |
117 | |
118 // If the onsuccess callback called continue()/advance() on the cursor | |
119 // again, and that request was served by the prefetch cache, then | |
120 // pending_onsuccess_callbacks_ would be incremented. If not, it means the | |
121 // callback did something else, or nothing at all, in which case we need to | |
122 // reset the cache. | |
123 | |
124 if (pending_onsuccess_callbacks_ == 0) | |
125 ResetPrefetchCache(); | |
126 } | |
127 | |
128 void WebIDBCursorImpl::SetPrefetchData( | |
129 const std::vector<IndexedDBKey>& keys, | |
130 const std::vector<IndexedDBKey>& primary_keys, | |
131 const std::vector<WebIDBValue>& values) { | |
132 prefetch_keys_.assign(keys.begin(), keys.end()); | |
133 prefetch_primary_keys_.assign(primary_keys.begin(), primary_keys.end()); | |
134 prefetch_values_.assign(values.begin(), values.end()); | |
135 | |
136 used_prefetches_ = 0; | |
137 pending_onsuccess_callbacks_ = 0; | |
138 } | |
139 | |
140 void WebIDBCursorImpl::CachedAdvance(unsigned long count, | |
141 WebIDBCallbacks* callbacks) { | |
142 DCHECK_GE(prefetch_keys_.size(), count); | |
143 DCHECK_EQ(prefetch_primary_keys_.size(), prefetch_keys_.size()); | |
144 DCHECK_EQ(prefetch_values_.size(), prefetch_keys_.size()); | |
145 | |
146 while (count > 1) { | |
147 prefetch_keys_.pop_front(); | |
148 prefetch_primary_keys_.pop_front(); | |
149 prefetch_values_.pop_front(); | |
150 ++used_prefetches_; | |
151 --count; | |
152 } | |
153 | |
154 CachedContinue(callbacks); | |
155 } | |
156 | |
157 void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks* callbacks) { | |
158 DCHECK_GT(prefetch_keys_.size(), 0ul); | |
159 DCHECK_EQ(prefetch_primary_keys_.size(), prefetch_keys_.size()); | |
160 DCHECK_EQ(prefetch_values_.size(), prefetch_keys_.size()); | |
161 | |
162 IndexedDBKey key = prefetch_keys_.front(); | |
163 IndexedDBKey primary_key = prefetch_primary_keys_.front(); | |
164 WebIDBValue value = prefetch_values_.front(); | |
165 | |
166 prefetch_keys_.pop_front(); | |
167 prefetch_primary_keys_.pop_front(); | |
168 prefetch_values_.pop_front(); | |
169 ++used_prefetches_; | |
170 | |
171 ++pending_onsuccess_callbacks_; | |
172 | |
173 if (!continue_count_) { | |
174 // The cache was invalidated by a call to ResetPrefetchCache() | |
175 // after the RequestIDBCursorPrefetch() was made. Now that the | |
176 // initiating continue() call has been satisfied, discard | |
177 // the rest of the cache. | |
178 ResetPrefetchCache(); | |
179 } | |
180 | |
181 callbacks->onSuccess(WebIDBKeyBuilder::Build(key), | |
182 WebIDBKeyBuilder::Build(primary_key), value); | |
183 } | |
184 | |
185 void WebIDBCursorImpl::ResetPrefetchCache() { | |
186 continue_count_ = 0; | |
187 prefetch_amount_ = kMinPrefetchAmount; | |
188 | |
189 if (prefetch_keys_.empty()) { | |
190 // No prefetch cache, so no need to reset the cursor in the back-end. | |
191 return; | |
192 } | |
193 | |
194 // Ack any unused blobs. | |
195 std::vector<std::string> uuids; | |
196 for (const auto& value : prefetch_values_) { | |
197 for (size_t i = 0, size = value.webBlobInfo.size(); i < size; ++i) | |
198 uuids.push_back(value.webBlobInfo[i].uuid().latin1()); | |
199 } | |
200 if (!uuids.empty()) | |
201 thread_safe_sender_->Send(new IndexedDBHostMsg_AckReceivedBlobs(uuids)); | |
202 | |
203 // Reset the back-end cursor. | |
204 IndexedDBDispatcher* dispatcher = | |
205 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); | |
206 dispatcher->RequestIDBCursorPrefetchReset( | |
207 used_prefetches_, prefetch_keys_.size(), ipc_cursor_id_); | |
208 | |
209 // Reset the prefetch cache. | |
210 prefetch_keys_.clear(); | |
211 prefetch_primary_keys_.clear(); | |
212 prefetch_values_.clear(); | |
213 | |
214 pending_onsuccess_callbacks_ = 0; | |
215 } | |
216 | |
217 } // namespace content | |
OLD | NEW |