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 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 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 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 61 void WebIDBCursorImpl::continueFunction(const WebIDBKey& key, 62 WebIDBCallbacks* callbacks_ptr) { 63 continueFunction(key, WebIDBKey::createNull(), callbacks_ptr); 64 } 65 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 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 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 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 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 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