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 // 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 cached_usage_(0), |
| 120 cached_quota_(0), |
| 121 weak_factory_(this) { |
| 122 } |
| 123 |
| 124 HostStorageObservers::~HostStorageObservers() {} |
| 125 |
| 126 void HostStorageObservers::AddObserver( |
| 127 StorageObserver* observer, |
| 128 const StorageObserver::MonitorParams& params) { |
| 129 observers_.AddObserver(observer, params); |
| 130 |
| 131 if (!params.dispatch_initial_state) |
| 132 return; |
| 133 |
| 134 if (initialized_) { |
| 135 StorageObserver::Event event(params.filter, |
| 136 std::max<int64>(cached_usage_, 0), |
| 137 std::max<int64>(cached_quota_, 0)); |
| 138 observer->OnStorageEvent(event); |
| 139 return; |
| 140 } |
| 141 |
| 142 // Ensure the observer receives the initial storage state once initialization |
| 143 // is complete. |
| 144 observers_.ScheduleUpdateForObserver(observer); |
| 145 StartInitialization(params.filter); |
| 146 } |
| 147 |
| 148 void HostStorageObservers::RemoveObserver(StorageObserver* observer) { |
| 149 observers_.RemoveObserver(observer); |
| 150 } |
| 151 |
| 152 bool HostStorageObservers::ContainsObservers() const { |
| 153 return observers_.ObserverCount() > 0; |
| 154 } |
| 155 |
| 156 void HostStorageObservers::NotifyUsageChange( |
| 157 const StorageObserver::Filter& filter, int64 delta) { |
| 158 if (initialized_) { |
| 159 cached_usage_ += delta; |
| 160 DispatchEvent(filter, true); |
| 161 return; |
| 162 } |
| 163 |
| 164 // If a storage change occurs before initialization, ensure all observers will |
| 165 // receive an event once initialization is complete. |
| 166 event_occurred_before_init_ = true; |
| 167 StartInitialization(filter); |
| 168 } |
| 169 |
| 170 void HostStorageObservers::StartInitialization( |
| 171 const StorageObserver::Filter& filter) { |
| 172 if (initialized_ || initializing_) |
| 173 return; |
| 174 |
| 175 initializing_ = true; |
| 176 quota_manager_->GetUsageAndQuotaForWebApps( |
| 177 filter.origin, |
| 178 filter.storage_type, |
| 179 base::Bind(&HostStorageObservers::GotHostUsageAndQuota, |
| 180 weak_factory_.GetWeakPtr(), |
| 181 filter)); |
| 182 } |
| 183 |
| 184 void HostStorageObservers::GotHostUsageAndQuota( |
| 185 const StorageObserver::Filter& filter, |
| 186 QuotaStatusCode status, |
| 187 int64 usage, |
| 188 int64 quota) { |
| 189 initializing_ = false; |
| 190 if (status != kQuotaStatusOk) |
| 191 return; |
| 192 |
| 193 initialized_ = true; |
| 194 cached_quota_ = quota; |
| 195 cached_usage_ = usage; |
| 196 DispatchEvent(filter, event_occurred_before_init_); |
| 197 } |
| 198 |
| 199 void HostStorageObservers::DispatchEvent( |
| 200 const StorageObserver::Filter& filter, bool is_update) { |
| 201 StorageObserver::Event event(filter, |
| 202 std::max<int64>(cached_usage_, 0), |
| 203 std::max<int64>(cached_quota_, 0)); |
| 204 if (is_update) |
| 205 observers_.OnStorageChange(event); |
| 206 else |
| 207 observers_.MaybeDispatchEvent(event); |
| 208 } |
| 209 |
| 210 |
| 211 // StorageTypeObservers: |
| 212 |
| 213 StorageTypeObservers::StorageTypeObservers(QuotaManager* quota_manager) |
| 214 : quota_manager_(quota_manager) { |
| 215 } |
| 216 |
| 217 StorageTypeObservers::~StorageTypeObservers() { |
| 218 STLDeleteValues(&host_observers_map_); |
| 219 } |
| 220 |
| 221 void StorageTypeObservers::AddObserver( |
| 222 StorageObserver* observer, const StorageObserver::MonitorParams& params) { |
| 223 std::string host = net::GetHostOrSpecFromURL(params.filter.origin); |
| 224 if (host.empty()) |
| 225 return; |
| 226 |
| 227 HostStorageObservers* host_observers = NULL; |
| 228 HostObserversMap::iterator it = host_observers_map_.find(host); |
| 229 if (it == host_observers_map_.end()) { |
| 230 host_observers = new HostStorageObservers(quota_manager_); |
| 231 host_observers_map_[host] = host_observers; |
| 232 } else { |
| 233 host_observers = it->second; |
| 234 } |
| 235 |
| 236 host_observers->AddObserver(observer, params); |
| 237 } |
| 238 |
| 239 void StorageTypeObservers::RemoveObserver(StorageObserver* observer) { |
| 240 for (HostObserversMap::iterator it = host_observers_map_.begin(); |
| 241 it != host_observers_map_.end(); ) { |
| 242 it->second->RemoveObserver(observer); |
| 243 if (!it->second->ContainsObservers()) { |
| 244 delete it->second; |
| 245 host_observers_map_.erase(it++); |
| 246 } else { |
| 247 ++it; |
| 248 } |
| 249 } |
| 250 } |
| 251 |
| 252 void StorageTypeObservers::RemoveObserverForFilter( |
| 253 StorageObserver* observer, const StorageObserver::Filter& filter) { |
| 254 std::string host = net::GetHostOrSpecFromURL(filter.origin); |
| 255 HostObserversMap::iterator it = host_observers_map_.find(host); |
| 256 if (it == host_observers_map_.end()) |
| 257 return; |
| 258 |
| 259 it->second->RemoveObserver(observer); |
| 260 if (!it->second->ContainsObservers()) { |
| 261 delete it->second; |
| 262 host_observers_map_.erase(it); |
| 263 } |
| 264 } |
| 265 |
| 266 const HostStorageObservers* StorageTypeObservers::GetHostObservers( |
| 267 const std::string& host) const { |
| 268 HostObserversMap::const_iterator it = host_observers_map_.find(host); |
| 269 if (it != host_observers_map_.end()) |
| 270 return it->second; |
| 271 |
| 272 return NULL; |
| 273 } |
| 274 |
| 275 void StorageTypeObservers::NotifyUsageChange( |
| 276 const StorageObserver::Filter& filter, int64 delta) { |
| 277 std::string host = net::GetHostOrSpecFromURL(filter.origin); |
| 278 HostObserversMap::iterator it = host_observers_map_.find(host); |
| 279 if (it == host_observers_map_.end()) |
| 280 return; |
| 281 |
| 282 it->second->NotifyUsageChange(filter, delta); |
| 283 } |
| 284 |
| 285 |
| 286 // StorageMonitor: |
| 287 |
| 288 StorageMonitor::StorageMonitor(QuotaManager* quota_manager) |
| 289 : quota_manager_(quota_manager) { |
| 290 } |
| 291 |
| 292 StorageMonitor::~StorageMonitor() { |
| 293 STLDeleteValues(&storage_type_observers_map_); |
| 294 } |
| 295 |
| 296 void StorageMonitor::AddObserver( |
| 297 StorageObserver* observer, const StorageObserver::MonitorParams& params) { |
| 298 DCHECK(observer); |
| 299 |
| 300 // Check preconditions. |
| 301 if (params.filter.storage_type == kStorageTypeUnknown || |
| 302 params.filter.storage_type == kStorageTypeQuotaNotManaged || |
| 303 params.filter.origin.is_empty()) { |
| 304 NOTREACHED(); |
| 305 return; |
| 306 } |
| 307 |
| 308 StorageTypeObservers* type_observers = NULL; |
| 309 StorageTypeObserversMap::iterator it = |
| 310 storage_type_observers_map_.find(params.filter.storage_type); |
| 311 if (it == storage_type_observers_map_.end()) { |
| 312 type_observers = new StorageTypeObservers(quota_manager_); |
| 313 storage_type_observers_map_[params.filter.storage_type] = type_observers; |
| 314 } else { |
| 315 type_observers = it->second; |
| 316 } |
| 317 |
| 318 type_observers->AddObserver(observer, params); |
| 319 } |
| 320 |
| 321 void StorageMonitor::RemoveObserver(StorageObserver* observer) { |
| 322 for (StorageTypeObserversMap::iterator it = |
| 323 storage_type_observers_map_.begin(); |
| 324 it != storage_type_observers_map_.end(); ++it) { |
| 325 it->second->RemoveObserver(observer); |
| 326 } |
| 327 } |
| 328 |
| 329 void StorageMonitor::RemoveObserverForFilter( |
| 330 StorageObserver* observer, const StorageObserver::Filter& filter) { |
| 331 StorageTypeObserversMap::iterator it = |
| 332 storage_type_observers_map_.find(filter.storage_type); |
| 333 if (it == storage_type_observers_map_.end()) |
| 334 return; |
| 335 |
| 336 it->second->RemoveObserverForFilter(observer, filter); |
| 337 } |
| 338 |
| 339 const StorageTypeObservers* StorageMonitor::GetStorageTypeObservers( |
| 340 StorageType storage_type) const { |
| 341 StorageTypeObserversMap::const_iterator it = |
| 342 storage_type_observers_map_.find(storage_type); |
| 343 if (it != storage_type_observers_map_.end()) |
| 344 return it->second; |
| 345 |
| 346 return NULL; |
| 347 } |
| 348 |
| 349 void StorageMonitor::NotifyUsageChange( |
| 350 const StorageObserver::Filter& filter, int64 delta) { |
| 351 // Check preconditions. |
| 352 if (filter.storage_type == kStorageTypeUnknown || |
| 353 filter.storage_type == kStorageTypeQuotaNotManaged || |
| 354 filter.origin.is_empty()) { |
| 355 NOTREACHED(); |
| 356 return; |
| 357 } |
| 358 |
| 359 StorageTypeObserversMap::iterator it = |
| 360 storage_type_observers_map_.find(filter.storage_type); |
| 361 if (it == storage_type_observers_map_.end()) |
| 362 return; |
| 363 |
| 364 it->second->NotifyUsageChange(filter, delta); |
| 365 } |
| 366 |
| 367 } // namespace quota |
OLD | NEW |