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 "storage/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 "storage/browser/quota/quota_manager.h" 12 #include "storage/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 380