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