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 ThreadSafeSender* thread_safe_sender) 22 : ipc_cursor_id_(ipc_cursor_id), 23 continue_count_(0), 24 used_prefetches_(0), 25 pending_onsuccess_callbacks_(0), 26 prefetch_amount_(kMinPrefetchAmount), 27 thread_safe_sender_(thread_safe_sender) {} 28 29 WebIDBCursorImpl::~WebIDBCursorImpl() { 30 // It's not possible for there to be pending callbacks that address this 31 // object since inside WebKit, they hold a reference to the object which owns 32 // this object. But, if that ever changed, then we'd need to invalidate 33 // any such pointers. 34 35 if (ipc_cursor_id_ != kInvalidCursorId) { 36 // Invalid ID used in tests to avoid really sending this message. 37 thread_safe_sender_->Send( 38 new IndexedDBHostMsg_CursorDestroyed(ipc_cursor_id_)); 39 } 40 IndexedDBDispatcher* dispatcher = 41 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); 42 dispatcher->CursorDestroyed(ipc_cursor_id_); 43 } 44 45 void WebIDBCursorImpl::advance(unsigned long count, 46 WebIDBCallbacks* callbacks_ptr) { 47 IndexedDBDispatcher* dispatcher = 48 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); 49 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 50 ResetPrefetchCache(); 51 dispatcher->RequestIDBCursorAdvance( 52 count, callbacks.release(), ipc_cursor_id_); 53 } 54 55 void WebIDBCursorImpl::continueFunction(const WebIDBKey& key, 56 WebIDBCallbacks* callbacks_ptr) { 57 continueFunction(key, WebIDBKey::createNull(), callbacks_ptr); 58 } 59 60 void WebIDBCursorImpl::continueFunction(const WebIDBKey& key, 61 const WebIDBKey& primary_key, 62 WebIDBCallbacks* callbacks_ptr) { 63 IndexedDBDispatcher* dispatcher = 64 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); 65 scoped_ptr<WebIDBCallbacks> callbacks(callbacks_ptr); 66 67 if (key.keyType() == blink::WebIDBKeyTypeNull && 68 primary_key.keyType() == blink::WebIDBKeyTypeNull) { 69 // No key(s), so this would qualify for a prefetch. 70 ++continue_count_; 71 72 if (!prefetch_keys_.empty()) { 73 // We have a prefetch cache, so serve the result from that. 74 CachedContinue(callbacks.get()); 75 return; 76 } 77 78 if (continue_count_ > kPrefetchContinueThreshold) { 79 // Request pre-fetch. 80 ++pending_onsuccess_callbacks_; 81 dispatcher->RequestIDBCursorPrefetch( 82 prefetch_amount_, callbacks.release(), ipc_cursor_id_); 83 84 // Increase prefetch_amount_ exponentially. 85 prefetch_amount_ *= 2; 86 if (prefetch_amount_ > kMaxPrefetchAmount) 87 prefetch_amount_ = kMaxPrefetchAmount; 88 89 return; 90 } 91 } else { 92 // Key argument supplied. We couldn't prefetch this. 93 ResetPrefetchCache(); 94 } 95 96 dispatcher->RequestIDBCursorContinue(IndexedDBKeyBuilder::Build(key), 97 IndexedDBKeyBuilder::Build(primary_key), 98 callbacks.release(), 99 ipc_cursor_id_); 100 } 101 102 void WebIDBCursorImpl::postSuccessHandlerCallback() { 103 pending_onsuccess_callbacks_--; 104 105 // If the onsuccess callback called continue() on the cursor again, 106 // and that continue was served by the prefetch cache, then 107 // pending_onsuccess_callbacks_ would be incremented. 108 // If not, it means the callback did something else, or nothing at all, 109 // in which case we need to reset the cache. 110 111 if (pending_onsuccess_callbacks_ == 0) 112 ResetPrefetchCache(); 113 } 114 115 void WebIDBCursorImpl::SetPrefetchData( 116 const std::vector<IndexedDBKey>& keys, 117 const std::vector<IndexedDBKey>& primary_keys, 118 const std::vector<WebData>& values) { 119 prefetch_keys_.assign(keys.begin(), keys.end()); 120 prefetch_primary_keys_.assign(primary_keys.begin(), primary_keys.end()); 121 prefetch_values_.assign(values.begin(), values.end()); 122 123 used_prefetches_ = 0; 124 pending_onsuccess_callbacks_ = 0; 125 } 126 127 void WebIDBCursorImpl::CachedContinue(WebIDBCallbacks* callbacks) { 128 DCHECK_GT(prefetch_keys_.size(), 0ul); 129 DCHECK(prefetch_primary_keys_.size() == prefetch_keys_.size()); 130 DCHECK(prefetch_values_.size() == prefetch_keys_.size()); 131 132 IndexedDBKey key = prefetch_keys_.front(); 133 IndexedDBKey primary_key = prefetch_primary_keys_.front(); 134 // this could be a real problem.. we need 2 CachedContinues 135 WebData value = prefetch_values_.front(); 136 137 prefetch_keys_.pop_front(); 138 prefetch_primary_keys_.pop_front(); 139 prefetch_values_.pop_front(); 140 used_prefetches_++; 141 142 pending_onsuccess_callbacks_++; 143 144 callbacks->onSuccess(WebIDBKeyBuilder::Build(key), 145 WebIDBKeyBuilder::Build(primary_key), 146 value); 147 } 148 149 void WebIDBCursorImpl::ResetPrefetchCache() { 150 continue_count_ = 0; 151 prefetch_amount_ = kMinPrefetchAmount; 152 153 if (!prefetch_keys_.size()) { 154 // No prefetch cache, so no need to reset the cursor in the back-end. 155 return; 156 } 157 158 IndexedDBDispatcher* dispatcher = 159 IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get()); 160 dispatcher->RequestIDBCursorPrefetchReset( 161 used_prefetches_, prefetch_keys_.size(), ipc_cursor_id_); 162 prefetch_keys_.clear(); 163 prefetch_primary_keys_.clear(); 164 prefetch_values_.clear(); 165 166 pending_onsuccess_callbacks_ = 0; 167 } 168 169 } // namespace content 170