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