• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // StorageObserverList:
17 
ObserverState()18 StorageObserverList::ObserverState::ObserverState()
19     : requires_update(false) {
20 }
21 
StorageObserverList()22 StorageObserverList::StorageObserverList() {}
23 
~StorageObserverList()24 StorageObserverList::~StorageObserverList() {}
25 
AddObserver(StorageObserver * observer,const StorageObserver::MonitorParams & params)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 
RemoveObserver(StorageObserver * observer)33 void StorageObserverList::RemoveObserver(StorageObserver* observer) {
34   observers_.erase(observer);
35 }
36 
ObserverCount() const37 int StorageObserverList::ObserverCount() const {
38   return observers_.size();
39 }
40 
OnStorageChange(const StorageObserver::Event & event)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 
MaybeDispatchEvent(const StorageObserver::Event & event)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 
ScheduleUpdateForObserver(StorageObserver * observer)102 void StorageObserverList::ScheduleUpdateForObserver(StorageObserver* observer) {
103   DCHECK(ContainsKey(observers_, observer));
104   observers_[observer].requires_update = true;
105 }
106 
DispatchPendingEvent()107 void StorageObserverList::DispatchPendingEvent() {
108   MaybeDispatchEvent(pending_event_);
109 }
110 
111 
112 // HostStorageObservers:
113 
HostStorageObservers(QuotaManager * quota_manager)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 
~HostStorageObservers()125 HostStorageObservers::~HostStorageObservers() {}
126 
AddObserver(StorageObserver * observer,const StorageObserver::MonitorParams & params)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 
RemoveObserver(StorageObserver * observer)149 void HostStorageObservers::RemoveObserver(StorageObserver* observer) {
150   observers_.RemoveObserver(observer);
151 }
152 
ContainsObservers() const153 bool HostStorageObservers::ContainsObservers() const {
154   return observers_.ObserverCount() > 0;
155 }
156 
NotifyUsageChange(const StorageObserver::Filter & filter,int64 delta)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 
StartInitialization(const StorageObserver::Filter & filter)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 
GotHostUsageAndQuota(const StorageObserver::Filter & filter,QuotaStatusCode status,int64 usage,int64 quota)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 
DispatchEvent(const StorageObserver::Filter & filter,bool is_update)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 
StorageTypeObservers(QuotaManager * quota_manager)225 StorageTypeObservers::StorageTypeObservers(QuotaManager* quota_manager)
226     : quota_manager_(quota_manager) {
227 }
228 
~StorageTypeObservers()229 StorageTypeObservers::~StorageTypeObservers() {
230   STLDeleteValues(&host_observers_map_);
231 }
232 
AddObserver(StorageObserver * observer,const StorageObserver::MonitorParams & params)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 
RemoveObserver(StorageObserver * observer)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 
RemoveObserverForFilter(StorageObserver * observer,const StorageObserver::Filter & filter)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 
GetHostObservers(const std::string & host) const278 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 
NotifyUsageChange(const StorageObserver::Filter & filter,int64 delta)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 
StorageMonitor(QuotaManager * quota_manager)300 StorageMonitor::StorageMonitor(QuotaManager* quota_manager)
301     : quota_manager_(quota_manager) {
302 }
303 
~StorageMonitor()304 StorageMonitor::~StorageMonitor() {
305   STLDeleteValues(&storage_type_observers_map_);
306 }
307 
AddObserver(StorageObserver * observer,const StorageObserver::MonitorParams & params)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 
RemoveObserver(StorageObserver * observer)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 
RemoveObserverForFilter(StorageObserver * observer,const StorageObserver::Filter & filter)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 
GetStorageTypeObservers(StorageType storage_type) const351 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 
NotifyUsageChange(const StorageObserver::Filter & filter,int64 delta)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 quota
380