OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "webkit/browser/quota/storage_monitor.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/stl_util.h" | |
10 #include "net/base/net_util.h" | |
11 #include "webkit/browser/quota/quota_manager.h" | |
12 #include "webkit/common/quota/quota_status_code.h" | |
13 | |
14 namespace quota { | |
15 | |
16 namespace { | |
17 | |
18 // The minimum rate between event notifications. | |
19 const int kMinimumRateMSec = 50; | |
20 | |
21 } // namespace | |
22 | |
23 // StorageObserverList: | |
24 | |
25 StorageObserverList::ObserverState::ObserverState() | |
26 : requires_update(false) { | |
27 } | |
28 | |
29 StorageObserverList::StorageObserverList() {} | |
30 | |
31 StorageObserverList::~StorageObserverList() {} | |
32 | |
33 void StorageObserverList::AddObserver( | |
34 StorageObserver* observer, const StorageObserver::MonitorParams& params) { | |
35 ObserverState& observer_state = observers_[observer]; | |
36 observer_state.origin = params.filter.origin; | |
37 observer_state.rate = | |
38 params.rate > 0 ? base::TimeDelta::FromSeconds(params.rate) | |
39 : base::TimeDelta::FromMilliseconds(kMinimumRateMSec); | |
40 } | |
41 | |
42 void StorageObserverList::RemoveObserver(StorageObserver* observer) { | |
43 StorageObserverStateMap::iterator it = observers_.find(observer); | |
tzik
2014/03/31 06:54:16
just observers_.erase(observer); works.
| |
44 if (it != observers_.end()) | |
45 observers_.erase(it); | |
46 } | |
47 | |
48 int StorageObserverList::ObserverCount() const { | |
49 return observers_.size(); | |
50 } | |
51 | |
52 void StorageObserverList::OnStorageChange(const StorageObserver::Event& event) { | |
53 for (StorageObserverStateMap::iterator it = observers_.begin(); | |
54 it != observers_.end(); ++it) { | |
55 it->second.requires_update = true; | |
56 } | |
57 | |
58 MaybeDispatchEvent(event); | |
59 } | |
60 | |
61 const StorageObserver::Event* StorageObserverList::GetPendingEvent() const { | |
62 return notification_timer_.IsRunning() ? &pending_event_ | |
63 : NULL; | |
64 } | |
65 | |
66 int StorageObserverList::GetRequiredUpdatesCount() const { | |
67 int count = 0; | |
68 for (StorageObserverStateMap::const_iterator it = observers_.begin(); | |
69 it != observers_.end(); ++it) { | |
70 if (it->second.requires_update) | |
71 ++count; | |
72 } | |
73 | |
74 return count; | |
75 } | |
76 | |
77 void StorageObserverList::MaybeDispatchEvent( | |
78 const StorageObserver::Event& event) { | |
79 notification_timer_.Stop(); | |
80 base::TimeDelta min_delay = base::TimeDelta::Max(); | |
81 bool all_observers_notified = true; | |
82 | |
83 for (StorageObserverStateMap::iterator it = observers_.begin(); | |
84 it != observers_.end(); ++it) { | |
85 if (!it->second.requires_update) | |
86 continue; | |
87 | |
88 base::Time current_time = base::Time::Now(); | |
89 base::TimeDelta delta = current_time - it->second.last_notification_time; | |
90 if (delta >= it->second.rate) { | |
91 it->second.requires_update = false; | |
92 it->second.last_notification_time = current_time; | |
93 | |
94 if (it->second.origin == event.filter.origin) { | |
95 it->first->OnStorageEvent(event); | |
96 } else { | |
97 // When the quota and usage of an origin is requested, QuotaManager | |
98 // returns the quota and usage of the host. Multiple origins can map to | |
99 // to the same host, so ensure the |origin| field in the dispatched | |
100 // event matches the |origin| specified by the observer when it was | |
101 // registered. | |
102 StorageObserver::Event dispatch_event(event); | |
103 dispatch_event.filter.origin = it->second.origin; | |
104 it->first->OnStorageEvent(dispatch_event); | |
105 } | |
106 } else { | |
107 all_observers_notified = false; | |
108 base::TimeDelta delay = it->second.rate - delta; | |
109 if (delay < min_delay) | |
110 min_delay = delay; | |
111 } | |
112 } | |
113 | |
114 // We need to respect the notification rate specified by observers. So if it | |
115 // is too soon to dispatch an event to an observer, save the event and | |
116 // dispatch it after a delay. If we simply drop the event, another one may | |
117 // not arrive anytime soon and the observer will miss the most recent event. | |
118 if (!all_observers_notified) { | |
119 pending_event_ = event; | |
120 notification_timer_.Start( | |
121 FROM_HERE, | |
122 min_delay, | |
123 this, | |
124 &StorageObserverList::DispatchPendingEvent); | |
125 } | |
126 } | |
127 | |
128 void StorageObserverList::ScheduleUpdateForObserver(StorageObserver* observer) { | |
129 DCHECK(observers_.find(observer) != observers_.end()); | |
tzik
2014/03/31 07:45:48
I think
DCHECK(ContainsKey(observers_, observer));
| |
130 observers_[observer].requires_update = true; | |
131 } | |
132 | |
133 void StorageObserverList::DispatchPendingEvent() { | |
134 MaybeDispatchEvent(pending_event_); | |
135 } | |
136 | |
137 | |
138 // HostStorageObservers: | |
139 | |
140 HostStorageObservers::HostStorageObservers(QuotaManager* quota_manager) | |
141 : quota_manager_(quota_manager), | |
142 weak_factory_(this), | |
143 initialized_(false), | |
144 initializing_(false), | |
145 event_occurred_before_init_(false), | |
146 cached_usage_(0), | |
147 cached_quota_(0) { | |
148 } | |
149 | |
150 HostStorageObservers::~HostStorageObservers() {} | |
151 | |
152 void HostStorageObservers::AddObserver( | |
153 StorageObserver* observer, | |
154 const StorageObserver::MonitorParams& params) { | |
155 StorageObserverList::AddObserver(observer, params); | |
156 | |
157 if (!params.dispatch_initial_state) | |
158 return; | |
159 | |
160 if (initialized_) { | |
161 StorageObserver::Event event(params.filter, | |
162 std::max<int64>(cached_usage_, 0), | |
163 std::max<int64>(cached_quota_, 0)); | |
164 observer->OnStorageEvent(event); | |
165 return; | |
166 } | |
167 | |
168 // Ensure the observer receives the initial storage state once initialization | |
169 // is complete. | |
170 ScheduleUpdateForObserver(observer); | |
171 StartInitialization(params.filter); | |
172 } | |
173 | |
174 void HostStorageObservers::NotifyUsageChange( | |
175 const StorageObserver::Filter& filter, int64 delta) { | |
176 if (initialized_) { | |
177 cached_usage_ += delta; | |
178 DispatchEvent(filter, true); | |
179 return; | |
180 } | |
181 | |
182 // If a storage change occurs before initialization, ensure all observers will | |
183 // receive an event once initialization is complete. | |
184 event_occurred_before_init_ = true; | |
185 StartInitialization(filter); | |
186 } | |
187 | |
188 void HostStorageObservers::StartInitialization( | |
189 const StorageObserver::Filter& filter) { | |
190 if (initialized_ || initializing_) | |
191 return; | |
192 | |
193 initializing_ = true; | |
194 quota_manager_->GetUsageAndQuotaForWebApps( | |
195 filter.origin, | |
196 filter.storage_type, | |
197 base::Bind(&HostStorageObservers::GotHostUsageAndQuota, | |
198 weak_factory_.GetWeakPtr(), | |
199 filter)); | |
200 } | |
201 | |
202 void HostStorageObservers::GotHostUsageAndQuota( | |
203 const StorageObserver::Filter& filter, | |
204 QuotaStatusCode status, | |
205 int64 usage, | |
206 int64 quota) { | |
207 initializing_ = false; | |
208 if (status != kQuotaStatusOk) | |
209 return; | |
210 | |
211 initialized_ = true; | |
212 cached_quota_ = quota; | |
213 cached_usage_ = usage; | |
214 DispatchEvent(filter, event_occurred_before_init_); | |
215 } | |
216 | |
217 void HostStorageObservers::DispatchEvent( | |
218 const StorageObserver::Filter& filter, bool is_update) { | |
219 StorageObserver::Event event(filter, | |
220 std::max<int64>(cached_usage_, 0), | |
221 std::max<int64>(cached_quota_, 0)); | |
222 if (is_update) | |
223 OnStorageChange(event); | |
224 else | |
225 MaybeDispatchEvent(event); | |
226 } | |
227 | |
228 | |
229 // StorageTypeObservers: | |
230 | |
231 StorageTypeObservers::StorageTypeObservers(QuotaManager* quota_manager) | |
232 : quota_manager_(quota_manager) { | |
233 } | |
234 | |
235 StorageTypeObservers::~StorageTypeObservers() { | |
236 STLDeleteValues(&host_observers_map_); | |
237 } | |
238 | |
239 void StorageTypeObservers::AddObserver( | |
240 StorageObserver* observer, const StorageObserver::MonitorParams& params) { | |
241 std::string host = net::GetHostOrSpecFromURL(params.filter.origin); | |
242 if (host.empty()) | |
243 return; | |
244 | |
245 HostStorageObservers* host_observers = NULL; | |
246 HostObserversMap::iterator it = host_observers_map_.find(host); | |
247 if (it == host_observers_map_.end()) { | |
248 host_observers = new HostStorageObservers(quota_manager_); | |
249 host_observers_map_[host] = host_observers; | |
250 } else { | |
251 host_observers = it->second; | |
252 } | |
253 | |
254 host_observers->AddObserver(observer, params); | |
255 } | |
256 | |
257 void StorageTypeObservers::RemoveObserver(StorageObserver* observer) { | |
258 for (HostObserversMap::iterator it = host_observers_map_.begin(); | |
259 it != host_observers_map_.end(); ) { | |
260 it->second->RemoveObserver(observer); | |
261 if (it->second->ObserverCount() == 0) { | |
262 delete it->second; | |
263 host_observers_map_.erase(it++); | |
264 } else { | |
265 ++it; | |
266 } | |
267 } | |
268 } | |
269 | |
270 void StorageTypeObservers::RemoveObserverForFilter( | |
271 StorageObserver* observer, const StorageObserver::Filter& filter) { | |
272 std::string host = net::GetHostOrSpecFromURL(filter.origin); | |
273 HostObserversMap::iterator it = host_observers_map_.find(host); | |
274 if (it == host_observers_map_.end()) | |
275 return; | |
276 | |
277 it->second->RemoveObserver(observer); | |
278 if (it->second->ObserverCount() == 0) { | |
279 delete it->second; | |
280 host_observers_map_.erase(it); | |
281 } | |
282 } | |
283 | |
284 const HostStorageObservers* StorageTypeObservers::GetHostObservers( | |
285 const std::string& host) const { | |
286 HostObserversMap::const_iterator it = host_observers_map_.find(host); | |
287 if (it != host_observers_map_.end()) | |
288 return it->second; | |
289 | |
290 return NULL; | |
291 } | |
292 | |
293 void StorageTypeObservers::NotifyUsageChange( | |
294 const StorageObserver::Filter& filter, int64 delta) { | |
295 std::string host = net::GetHostOrSpecFromURL(filter.origin); | |
296 HostObserversMap::iterator it = host_observers_map_.find(host); | |
297 if (it == host_observers_map_.end()) | |
298 return; | |
299 | |
300 it->second->NotifyUsageChange(filter, delta); | |
301 } | |
302 | |
303 | |
304 // StorageMonitor: | |
305 | |
306 StorageMonitor::StorageMonitor(QuotaManager* quota_manager) | |
307 : quota_manager_(quota_manager) { | |
308 } | |
309 | |
310 StorageMonitor::~StorageMonitor() { | |
311 STLDeleteValues(&storage_type_observers_map_); | |
312 } | |
313 | |
314 void StorageMonitor::AddObserver( | |
315 StorageObserver* observer, const StorageObserver::MonitorParams& params) { | |
316 DCHECK(observer); | |
317 | |
318 // Check preconditions. | |
319 if (params.filter.storage_type == kStorageTypeUnknown || | |
320 params.filter.storage_type == kStorageTypeQuotaNotManaged || | |
321 params.filter.origin.is_empty()) { | |
322 NOTREACHED(); | |
323 return; | |
324 } | |
325 | |
326 StorageTypeObservers* type_observers = NULL; | |
327 StorageTypeObserversMap::iterator it = | |
328 storage_type_observers_map_.find(params.filter.storage_type); | |
329 if (it == storage_type_observers_map_.end()) { | |
330 type_observers = new StorageTypeObservers(quota_manager_); | |
331 storage_type_observers_map_[params.filter.storage_type] = type_observers; | |
332 } else { | |
333 type_observers = it->second; | |
334 } | |
335 | |
336 type_observers->AddObserver(observer, params); | |
337 } | |
338 | |
339 void StorageMonitor::RemoveObserver(StorageObserver* observer) { | |
340 for (StorageTypeObserversMap::iterator it = | |
341 storage_type_observers_map_.begin(); | |
342 it != storage_type_observers_map_.end(); ++it) { | |
343 it->second->RemoveObserver(observer); | |
344 } | |
345 } | |
346 | |
347 void StorageMonitor::RemoveObserverForFilter( | |
348 StorageObserver* observer, const StorageObserver::Filter& filter) { | |
349 StorageTypeObserversMap::iterator it = | |
350 storage_type_observers_map_.find(filter.storage_type); | |
351 if (it == storage_type_observers_map_.end()) | |
352 return; | |
353 | |
354 it->second->RemoveObserverForFilter(observer, filter); | |
355 } | |
356 | |
357 const StorageTypeObservers* StorageMonitor::GetStorageTypeObservers( | |
358 StorageType storage_type) const { | |
359 StorageTypeObserversMap::const_iterator it = | |
360 storage_type_observers_map_.find(storage_type); | |
361 if (it != storage_type_observers_map_.end()) | |
362 return it->second; | |
363 | |
364 return NULL; | |
365 } | |
366 | |
367 void StorageMonitor::NotifyUsageChange( | |
368 const StorageObserver::Filter& filter, int64 delta) { | |
369 // Check preconditions. | |
370 if (filter.storage_type == kStorageTypeUnknown || | |
371 filter.storage_type == kStorageTypeQuotaNotManaged || | |
372 filter.origin.is_empty()) { | |
373 NOTREACHED(); | |
374 return; | |
375 } | |
376 | |
377 StorageTypeObserversMap::iterator it = | |
378 storage_type_observers_map_.find(filter.storage_type); | |
379 if (it == storage_type_observers_map_.end()) | |
380 return; | |
381 | |
382 it->second->NotifyUsageChange(filter, delta); | |
383 } | |
384 | |
385 } // namespace quota | |
OLD | NEW |