| 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 |