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