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.
5 #include "storage/browser/quota/storage_monitor.h"
9 #include "base/stl_util.h"
10 #include "net/base/net_util.h"
11 #include "storage/browser/quota/quota_manager.h"
12 #include "storage/common/quota/quota_status_code.h"
16 // StorageObserverList:
18 StorageObserverList::ObserverState::ObserverState()
19 : requires_update(false) {
22 StorageObserverList::StorageObserverList() {}
24 StorageObserverList::~StorageObserverList() {}
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
;
33 void StorageObserverList::RemoveObserver(StorageObserver
* observer
) {
34 observers_
.erase(observer
);
37 int StorageObserverList::ObserverCount() const {
38 return observers_
.size();
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;
47 MaybeDispatchEvent(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;
56 for (StorageObserverStateMap::iterator it
= observers_
.begin();
57 it
!= observers_
.end(); ++it
) {
58 if (!it
->second
.requires_update
)
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
;
68 if (it
->second
.origin
== event
.filter
.origin
) {
69 it
->first
->OnStorageEvent(event
);
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
76 StorageObserver::Event
dispatch_event(event
);
77 dispatch_event
.filter
.origin
= it
->second
.origin
;
78 it
->first
->OnStorageEvent(dispatch_event
);
81 all_observers_notified
= false;
82 base::TimeDelta delay
= it
->second
.rate
- delta
;
83 if (delay
< min_delay
)
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(
98 &StorageObserverList::DispatchPendingEvent
);
102 void StorageObserverList::ScheduleUpdateForObserver(StorageObserver
* observer
) {
103 DCHECK(ContainsKey(observers_
, observer
));
104 observers_
[observer
].requires_update
= true;
107 void StorageObserverList::DispatchPendingEvent() {
108 MaybeDispatchEvent(pending_event_
);
112 // HostStorageObservers:
114 HostStorageObservers::HostStorageObservers(QuotaManager
* quota_manager
)
115 : quota_manager_(quota_manager
),
117 initializing_(false),
118 event_occurred_before_init_(false),
119 usage_deltas_during_init_(0),
122 weak_factory_(this) {
125 HostStorageObservers::~HostStorageObservers() {}
127 void HostStorageObservers::AddObserver(
128 StorageObserver
* observer
,
129 const StorageObserver::MonitorParams
& params
) {
130 observers_
.AddObserver(observer
, params
);
132 if (!params
.dispatch_initial_state
)
136 StorageObserver::Event
event(params
.filter
,
137 std::max
<int64
>(cached_usage_
, 0),
138 std::max
<int64
>(cached_quota_
, 0));
139 observer
->OnStorageEvent(event
);
143 // Ensure the observer receives the initial storage state once initialization
145 observers_
.ScheduleUpdateForObserver(observer
);
146 StartInitialization(params
.filter
);
149 void HostStorageObservers::RemoveObserver(StorageObserver
* observer
) {
150 observers_
.RemoveObserver(observer
);
153 bool HostStorageObservers::ContainsObservers() const {
154 return observers_
.ObserverCount() > 0;
157 void HostStorageObservers::NotifyUsageChange(
158 const StorageObserver::Filter
& filter
, int64 delta
) {
160 cached_usage_
+= delta
;
161 DispatchEvent(filter
, true);
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;
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.
175 usage_deltas_during_init_
+= delta
;
179 StartInitialization(filter
);
182 void HostStorageObservers::StartInitialization(
183 const StorageObserver::Filter
& filter
) {
184 if (initialized_
|| initializing_
)
187 initializing_
= true;
188 quota_manager_
->GetUsageAndQuotaForWebApps(
191 base::Bind(&HostStorageObservers::GotHostUsageAndQuota
,
192 weak_factory_
.GetWeakPtr(),
196 void HostStorageObservers::GotHostUsageAndQuota(
197 const StorageObserver::Filter
& filter
,
198 QuotaStatusCode status
,
201 initializing_
= false;
202 if (status
!= kQuotaStatusOk
)
206 cached_quota_
= quota
;
207 cached_usage_
= usage
+ usage_deltas_during_init_
;
208 DispatchEvent(filter
, event_occurred_before_init_
);
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));
217 observers_
.OnStorageChange(event
);
219 observers_
.MaybeDispatchEvent(event
);
223 // StorageTypeObservers:
225 StorageTypeObservers::StorageTypeObservers(QuotaManager
* quota_manager
)
226 : quota_manager_(quota_manager
) {
229 StorageTypeObservers::~StorageTypeObservers() {
230 STLDeleteValues(&host_observers_map_
);
233 void StorageTypeObservers::AddObserver(
234 StorageObserver
* observer
, const StorageObserver::MonitorParams
& params
) {
235 std::string host
= net::GetHostOrSpecFromURL(params
.filter
.origin
);
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
;
245 host_observers
= it
->second
;
248 host_observers
->AddObserver(observer
, params
);
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()) {
257 host_observers_map_
.erase(it
++);
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())
271 it
->second
->RemoveObserver(observer
);
272 if (!it
->second
->ContainsObservers()) {
274 host_observers_map_
.erase(it
);
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())
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())
294 it
->second
->NotifyUsageChange(filter
, delta
);
300 StorageMonitor::StorageMonitor(QuotaManager
* quota_manager
)
301 : quota_manager_(quota_manager
) {
304 StorageMonitor::~StorageMonitor() {
305 STLDeleteValues(&storage_type_observers_map_
);
308 void StorageMonitor::AddObserver(
309 StorageObserver
* observer
, const StorageObserver::MonitorParams
& params
) {
312 // Check preconditions.
313 if (params
.filter
.storage_type
== kStorageTypeUnknown
||
314 params
.filter
.storage_type
== kStorageTypeQuotaNotManaged
||
315 params
.filter
.origin
.is_empty()) {
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
;
327 type_observers
= it
->second
;
330 type_observers
->AddObserver(observer
, params
);
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
);
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())
348 it
->second
->RemoveObserverForFilter(observer
, filter
);
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())
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()) {
371 StorageTypeObserversMap::iterator it
=
372 storage_type_observers_map_
.find(filter
.storage_type
);
373 if (it
== storage_type_observers_map_
.end())
376 it
->second
->NotifyUsageChange(filter
, delta
);
379 } // namespace storage