Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: content/renderer/dom_storage/dom_storage_dispatcher.cc

Issue 10383123: Switch to using the async DomStorage IPC messages and add a caching layer … (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/dom_storage/dom_storage_dispatcher.h" 5 #include "content/renderer/dom_storage/dom_storage_dispatcher.h"
6 6
7 #include <list>
8 #include <map>
9
10 #include "base/string_number_conversions.h"
11 #include "base/synchronization/lock.h"
7 #include "content/common/dom_storage_messages.h" 12 #include "content/common/dom_storage_messages.h"
8 #include "content/renderer/dom_storage/webstoragearea_impl.h" 13 #include "content/renderer/dom_storage/webstoragearea_impl.h"
9 #include "content/renderer/dom_storage/webstoragenamespace_impl.h" 14 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
10 #include "content/renderer/render_thread_impl.h" 15 #include "content/renderer/render_thread_impl.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatfo rmSupport.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageEventDispat cher.h" 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageEventDispat cher.h"
19 #include "webkit/dom_storage/dom_storage_cached_area.h"
20 #include "webkit/dom_storage/dom_storage_proxy.h"
21 #include "webkit/dom_storage/dom_storage_types.h"
22
23 using dom_storage::DomStorageCachedArea;
24 using dom_storage::DomStorageProxy;
25 using dom_storage::ValuesMap;
26
27 namespace {
28 // MessageThrottlingFilter -------------------------------------------
29 // Used to limit the number of ipc messages pending completion so we
30 // don't overwhelm the main browser process. When the limit is reached,
31 // a synchronous message is sent to flush all pending messages thru.
32 // We expect to receive an 'ack' for each message sent. This object
33 // observes receipt of the acks on the IPC thread to decrement a counter.
34 class MessageThrottlingFilter : public IPC::ChannelProxy::MessageFilter {
35 public:
36 explicit MessageThrottlingFilter(RenderThreadImpl* sender)
37 : pending_count_(0), sender_(sender) {}
38
39 void SendThrottled(IPC::Message* message);
40
41 private:
42 virtual ~MessageThrottlingFilter() {}
43
44 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
45
46 int GetPendingCount() { return IncrementPendingCountN(0); }
47 int IncrementPendingCount() { return IncrementPendingCountN(1); }
48 int DecrementPendingCount() { return IncrementPendingCountN(-1); }
49 int IncrementPendingCountN(int increment) {
50 base::AutoLock locker(lock_);
51 pending_count_ += increment;
52 return pending_count_;
53 }
54
55 base::Lock lock_;
56 int pending_count_;
57 RenderThreadImpl* sender_;
58 };
59
60 void MessageThrottlingFilter::SendThrottled(IPC::Message* message) {
61 // Should only be used for sending of messages which will be acknowledged
62 // with a separate DOMStorageMsg_AsyncOperationComplete message.
63 DCHECK(message->type() == DOMStorageHostMsg_LoadStorageArea::ID ||
64 message->type() == DOMStorageHostMsg_SetItem::ID ||
65 message->type() == DOMStorageHostMsg_RemoveItem::ID ||
66 message->type() == DOMStorageHostMsg_Clear::ID);
67 const int kMaxPendingMessages = 1000;
68 bool need_to_flush = IncrementPendingCount() > kMaxPendingMessages;
69 sender_->Send(message);
70 if (need_to_flush && !message->is_sync()) {
71 sender_->Send(new DOMStorageHostMsg_FlushMessages);
72 DCHECK_EQ(0, GetPendingCount());
73 } else {
74 DCHECK_LE(0, GetPendingCount());
75 }
76 }
77
78 bool MessageThrottlingFilter::OnMessageReceived(const IPC::Message& message) {
79 if (message.type() == DOMStorageMsg_AsyncOperationComplete::ID) {
80 DecrementPendingCount();
81 DCHECK_LE(0, GetPendingCount());
82 }
83 return false;
84 }
85 } // namespace
86
87 // ProxyImpl -----------------------------------------------------
88 // An implementation of the DomStorageProxy interface in terms of IPC.
89 // This class also manages the collection of cached areas and pending
90 // operations awaiting completion callbacks.
91 class DomStorageDispatcher::ProxyImpl : public DomStorageProxy {
92 public:
93 explicit ProxyImpl(RenderThreadImpl* sender);
94
95 // Methods for use by DomStorageDispatcher directly.
96 DomStorageCachedArea* OpenCachedArea(
97 int64 namespace_id, const GURL& origin);
98 void CloseCachedArea(DomStorageCachedArea* area);
99 DomStorageCachedArea* LookupCachedArea(
100 int64 namespace_id, const GURL& origin);
101 void CompleteOnePendingCallback(bool success);
102 void Shutdown();
103
104 // DomStorageProxy interface for use by DomStorageCachedArea.
105 virtual void LoadArea(int connection_id, ValuesMap* values,
106 const CompletionCallback& callback) OVERRIDE;
107 virtual void SetItem(int connection_id, const string16& key,
108 const string16& value, const GURL& page_url,
109 const CompletionCallback& callback) OVERRIDE;
110 virtual void RemoveItem(int connection_id, const string16& key,
111 const GURL& page_url,
112 const CompletionCallback& callback) OVERRIDE;
113 virtual void ClearArea(int connection_id,
114 const GURL& page_url,
115 const CompletionCallback& callback) OVERRIDE;
116
117 private:
118 // Struct to hold references to our contained areas and
119 // to keep track of how many tabs have a given area open.
120 struct CachedAreaHolder {
121 scoped_refptr<DomStorageCachedArea> area_;
122 int open_count_;
123 CachedAreaHolder() : open_count_(0) {}
124 CachedAreaHolder(DomStorageCachedArea* area, int count)
125 : area_(area), open_count_(count) {}
126 };
127 typedef std::map<std::string, CachedAreaHolder> CachedAreaMap;
128 typedef std::list<CompletionCallback> CallbackList;
129
130 virtual ~ProxyImpl() {
131 }
132
133 // Sudden termination is disabled when there are callbacks pending
134 // to more reliably commit changes during shutdown.
135 void PushPendingCallback(const CompletionCallback& callback) {
136 if (pending_callbacks_.empty())
137 WebKit::webKitPlatformSupport()->suddenTerminationChanged(false);
138 pending_callbacks_.push_back(callback);
139 }
140
141 CompletionCallback PopPendingCallback() {
142 CompletionCallback callback = pending_callbacks_.front();
143 pending_callbacks_.pop_front();
144 if (pending_callbacks_.empty())
145 WebKit::webKitPlatformSupport()->suddenTerminationChanged(true);
146 return callback;
147 }
148
149 std::string GetCachedAreaKey(int64 namespace_id, const GURL& origin) {
150 return base::Int64ToString(namespace_id) + origin.spec();
151 }
152
153 CachedAreaHolder* GetAreaHolder(const std::string& key) {
154 CachedAreaMap::iterator found = cached_areas_.find(key);
155 if (found == cached_areas_.end())
156 return NULL;
157 return &(found->second);
158 }
159
160
161 RenderThreadImpl* sender_;
162 CachedAreaMap cached_areas_;
163 CallbackList pending_callbacks_;
164 scoped_refptr<MessageThrottlingFilter> throttling_filter_;
165 };
166
167 DomStorageDispatcher::ProxyImpl::ProxyImpl(RenderThreadImpl* sender)
168 : sender_(sender),
169 throttling_filter_(new MessageThrottlingFilter(sender)) {
170 sender_->AddFilter(throttling_filter_);
171 }
172
173 DomStorageCachedArea* DomStorageDispatcher::ProxyImpl::OpenCachedArea(
174 int64 namespace_id, const GURL& origin) {
175 std::string key = GetCachedAreaKey(namespace_id, origin);
176 if (CachedAreaHolder* holder = GetAreaHolder(key)) {
177 ++(holder->open_count_);
178 return holder->area_;
179 }
180 scoped_refptr<DomStorageCachedArea> area =
181 new DomStorageCachedArea(namespace_id, origin, this);
182 cached_areas_[key] = CachedAreaHolder(area, 1);
183 return area.get();
184 }
185
186 void DomStorageDispatcher::ProxyImpl::CloseCachedArea(
187 DomStorageCachedArea* area) {
188 std::string key = GetCachedAreaKey(area->namespace_id(), area->origin());
189 CachedAreaHolder* holder = GetAreaHolder(key);
190 DCHECK(holder);
191 DCHECK_EQ(holder->area_.get(), area);
192 DCHECK_GT(holder->open_count_, 0);
193 if (--(holder->open_count_) == 0) {
194 cached_areas_.erase(key);
195 }
196 }
197
198 DomStorageCachedArea* DomStorageDispatcher::ProxyImpl::LookupCachedArea(
199 int64 namespace_id, const GURL& origin) {
200 std::string key = GetCachedAreaKey(namespace_id, origin);
201 CachedAreaHolder* holder = GetAreaHolder(key);
202 if (!holder)
203 return NULL;
204 return holder->area_.get();
205 }
206
207 void DomStorageDispatcher::ProxyImpl::CompleteOnePendingCallback(bool success) {
208 PopPendingCallback().Run(success);
209 }
210
211 void DomStorageDispatcher::ProxyImpl::Shutdown() {
212 sender_->RemoveFilter(throttling_filter_);
213 sender_ = NULL;
214 cached_areas_.clear();
215 pending_callbacks_.clear();
216 }
217
218 void DomStorageDispatcher::ProxyImpl::LoadArea(
219 int connection_id, ValuesMap* values,
220 const CompletionCallback& callback) {
221 PushPendingCallback(callback);
222 throttling_filter_->SendThrottled(new DOMStorageHostMsg_LoadStorageArea(
223 connection_id, values));
224 }
225
226 void DomStorageDispatcher::ProxyImpl::SetItem(
227 int connection_id, const string16& key,
228 const string16& value, const GURL& page_url,
229 const CompletionCallback& callback) {
230 PushPendingCallback(callback);
231 throttling_filter_->SendThrottled(new DOMStorageHostMsg_SetItem(
232 connection_id, key, value, page_url));
233 }
234
235 void DomStorageDispatcher::ProxyImpl::RemoveItem(
236 int connection_id, const string16& key, const GURL& page_url,
237 const CompletionCallback& callback) {
238 PushPendingCallback(callback);
239 throttling_filter_->SendThrottled(new DOMStorageHostMsg_RemoveItem(
240 connection_id, key, page_url));
241 }
242
243 void DomStorageDispatcher::ProxyImpl::ClearArea(int connection_id,
244 const GURL& page_url,
245 const CompletionCallback& callback) {
246 PushPendingCallback(callback);
247 throttling_filter_->SendThrottled(new DOMStorageHostMsg_Clear(
248 connection_id, page_url));
249 }
250
251 // DomStorageDispatcher ------------------------------------------------
252
253 DomStorageDispatcher::DomStorageDispatcher()
254 : proxy_(new ProxyImpl(RenderThreadImpl::current())) {
255 }
256
257 DomStorageDispatcher::~DomStorageDispatcher() {
258 proxy_->Shutdown();
259 }
260
261 scoped_refptr<DomStorageCachedArea> DomStorageDispatcher::OpenCachedArea(
262 int connection_id, int64 namespace_id, const GURL& origin) {
263 RenderThreadImpl::current()->Send(
264 new DOMStorageHostMsg_OpenStorageArea(
265 connection_id, namespace_id, origin));
266 return proxy_->OpenCachedArea(namespace_id, origin);
267 }
268
269 void DomStorageDispatcher::CloseCachedArea(
270 int connection_id, DomStorageCachedArea* area) {
271 RenderThreadImpl::current()->Send(
272 new DOMStorageHostMsg_CloseStorageArea(connection_id));
273 proxy_->CloseCachedArea(area);
274 }
12 275
13 bool DomStorageDispatcher::OnMessageReceived(const IPC::Message& msg) { 276 bool DomStorageDispatcher::OnMessageReceived(const IPC::Message& msg) {
14 bool handled = true; 277 bool handled = true;
15 IPC_BEGIN_MESSAGE_MAP(DomStorageDispatcher, msg) 278 IPC_BEGIN_MESSAGE_MAP(DomStorageDispatcher, msg)
16 IPC_MESSAGE_HANDLER(DOMStorageMsg_Event, OnStorageEvent) 279 IPC_MESSAGE_HANDLER(DOMStorageMsg_Event, OnStorageEvent)
280 IPC_MESSAGE_HANDLER(DOMStorageMsg_AsyncOperationComplete,
281 OnAsyncOperationComplete)
17 IPC_MESSAGE_UNHANDLED(handled = false) 282 IPC_MESSAGE_UNHANDLED(handled = false)
18 IPC_END_MESSAGE_MAP() 283 IPC_END_MESSAGE_MAP()
19 return handled; 284 return handled;
20 } 285 }
21 286
22 void DomStorageDispatcher::OnStorageEvent( 287 void DomStorageDispatcher::OnStorageEvent(
23 const DOMStorageMsg_Event_Params& params) { 288 const DOMStorageMsg_Event_Params& params) {
24 RenderThreadImpl::current()->EnsureWebKitInitialized(); 289 RenderThreadImpl::current()->EnsureWebKitInitialized();
25 290
26 bool originated_in_process = params.connection_id != 0; 291 bool originated_in_process = params.connection_id != 0;
27 WebStorageAreaImpl* originating_area = NULL; 292 WebStorageAreaImpl* originating_area = NULL;
28 if (originated_in_process) { 293 if (originated_in_process) {
29 originating_area = WebStorageAreaImpl::FromConnectionId( 294 originating_area = WebStorageAreaImpl::FromConnectionId(
30 params.connection_id); 295 params.connection_id);
296 } else {
297 DomStorageCachedArea* cached_area = proxy_->LookupCachedArea(
298 params.namespace_id, params.origin);
299 if (cached_area)
300 cached_area->ApplyMutation(params.key, params.new_value);
31 } 301 }
32 302
33 if (params.namespace_id == dom_storage::kLocalStorageNamespaceId) { 303 if (params.namespace_id == dom_storage::kLocalStorageNamespaceId) {
34 WebKit::WebStorageEventDispatcher::dispatchLocalStorageEvent( 304 WebKit::WebStorageEventDispatcher::dispatchLocalStorageEvent(
35 params.key, 305 params.key,
36 params.old_value, 306 params.old_value,
37 params.new_value, 307 params.new_value,
38 params.origin, 308 params.origin,
39 params.page_url, 309 params.page_url,
40 originating_area, 310 originating_area,
41 originated_in_process); 311 originated_in_process);
42 } else if (originated_in_process) { 312 } else {
43 // TODO(michaeln): For now, we only raise session storage events into the
44 // process which caused the event to occur. However there are cases where
45 // sessions can span process boundaries, so there are correctness issues.
46 WebStorageNamespaceImpl 313 WebStorageNamespaceImpl
47 session_namespace_for_event_dispatch(params.namespace_id); 314 session_namespace_for_event_dispatch(params.namespace_id);
48 WebKit::WebStorageEventDispatcher::dispatchSessionStorageEvent( 315 WebKit::WebStorageEventDispatcher::dispatchSessionStorageEvent(
49 params.key, 316 params.key,
50 params.old_value, 317 params.old_value,
51 params.new_value, 318 params.new_value,
52 params.origin, 319 params.origin,
53 params.page_url, 320 params.page_url,
54 session_namespace_for_event_dispatch, 321 session_namespace_for_event_dispatch,
55 originating_area, 322 originating_area,
56 originated_in_process); 323 originated_in_process);
57 } 324 }
58 } 325 }
326
327 void DomStorageDispatcher::OnAsyncOperationComplete(bool success) {
328 proxy_->CompleteOnePendingCallback(success);
329 }
OLDNEW
« no previous file with comments | « content/renderer/dom_storage/dom_storage_dispatcher.h ('k') | content/renderer/dom_storage/webstoragearea_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698