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