Home | History | Annotate | Download | only in quota
      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       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 quota
    380