Include all dupe types (event when value is zero) in scan stats.
[chromium-blink-merge.git] / storage / browser / quota / storage_monitor.cc
blobf312bd3c455e9e1c4d70efdd50eac96efe54b538
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"
7 #include <algorithm>
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"
14 namespace storage {
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)
59 continue;
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);
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);
80 } else {
81 all_observers_notified = false;
82 base::TimeDelta delay = it->second.rate - delta;
83 if (delay < min_delay)
84 min_delay = 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(
95 FROM_HERE,
96 min_delay,
97 this,
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),
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) {
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)
133 return;
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;
143 // Ensure the observer receives the initial storage state once initialization
144 // is complete.
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) {
159 if (initialized_) {
160 cached_usage_ += delta;
161 DispatchEvent(filter, true);
162 return;
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.
174 if (initializing_) {
175 usage_deltas_during_init_ += delta;
176 return;
179 StartInitialization(filter);
182 void HostStorageObservers::StartInitialization(
183 const StorageObserver::Filter& filter) {
184 if (initialized_ || initializing_)
185 return;
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));
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;
205 initialized_ = true;
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));
216 if (is_update)
217 observers_.OnStorageChange(event);
218 else
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);
236 if (host.empty())
237 return;
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;
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()) {
256 delete it->second;
257 host_observers_map_.erase(it++);
258 } else {
259 ++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())
269 return;
271 it->second->RemoveObserver(observer);
272 if (!it->second->ContainsObservers()) {
273 delete it->second;
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())
282 return it->second;
284 return NULL;
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;
294 it->second->NotifyUsageChange(filter, delta);
298 // StorageMonitor:
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) {
310 DCHECK(observer);
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;
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;
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())
346 return;
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())
356 return it->second;
358 return NULL;
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;
371 StorageTypeObserversMap::iterator it =
372 storage_type_observers_map_.find(filter.storage_type);
373 if (it == storage_type_observers_map_.end())
374 return;
376 it->second->NotifyUsageChange(filter, delta);
379 } // namespace storage