Home | History | Annotate | Download | only in indexed_db
      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