root/webkit/browser/quota/storage_monitor.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AddObserver
  2. RemoveObserver
  3. ObserverCount
  4. OnStorageChange
  5. MaybeDispatchEvent
  6. ScheduleUpdateForObserver
  7. DispatchPendingEvent
  8. weak_factory_
  9. AddObserver
  10. RemoveObserver
  11. ContainsObservers
  12. NotifyUsageChange
  13. StartInitialization
  14. GotHostUsageAndQuota
  15. DispatchEvent
  16. AddObserver
  17. RemoveObserver
  18. RemoveObserverForFilter
  19. GetHostObservers
  20. NotifyUsageChange
  21. AddObserver
  22. RemoveObserver
  23. RemoveObserverForFilter
  24. GetStorageTypeObservers
  25. NotifyUsageChange

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/browser/quota/storage_monitor.h"

#include <algorithm>

#include "base/stl_util.h"
#include "net/base/net_util.h"
#include "webkit/browser/quota/quota_manager.h"
#include "webkit/common/quota/quota_status_code.h"

namespace quota {

// StorageObserverList:

StorageObserverList::ObserverState::ObserverState()
    : requires_update(false) {
}

StorageObserverList::StorageObserverList() {}

StorageObserverList::~StorageObserverList() {}

void StorageObserverList::AddObserver(
    StorageObserver* observer, const StorageObserver::MonitorParams& params) {
  ObserverState& observer_state = observers_[observer];
  observer_state.origin = params.filter.origin;
  observer_state.rate = params.rate;
}

void StorageObserverList::RemoveObserver(StorageObserver* observer) {
  observers_.erase(observer);
}

int StorageObserverList::ObserverCount() const {
  return observers_.size();
}

void StorageObserverList::OnStorageChange(const StorageObserver::Event& event) {
  for (StorageObserverStateMap::iterator it = observers_.begin();
       it != observers_.end(); ++it) {
    it->second.requires_update = true;
  }

  MaybeDispatchEvent(event);
}

void StorageObserverList::MaybeDispatchEvent(
    const StorageObserver::Event& event) {
  notification_timer_.Stop();
  base::TimeDelta min_delay = base::TimeDelta::Max();
  bool all_observers_notified = true;

  for (StorageObserverStateMap::iterator it = observers_.begin();
       it != observers_.end(); ++it) {
    if (!it->second.requires_update)
      continue;

    base::TimeTicks current_time = base::TimeTicks::Now();
    base::TimeDelta delta = current_time - it->second.last_notification_time;
    if (it->second.last_notification_time.is_null() ||
        delta >= it->second.rate) {
      it->second.requires_update = false;
      it->second.last_notification_time = current_time;

      if (it->second.origin == event.filter.origin) {
        it->first->OnStorageEvent(event);
      } else {
        // When the quota and usage of an origin is requested, QuotaManager
        // returns the quota and usage of the host. Multiple origins can map to
        // to the same host, so ensure the |origin| field in the dispatched
        // event matches the |origin| specified by the observer when it was
        // registered.
        StorageObserver::Event dispatch_event(event);
        dispatch_event.filter.origin = it->second.origin;
        it->first->OnStorageEvent(dispatch_event);
      }
    } else {
      all_observers_notified = false;
      base::TimeDelta delay = it->second.rate - delta;
      if (delay < min_delay)
        min_delay = delay;
    }
  }

  // We need to respect the notification rate specified by observers. So if it
  // is too soon to dispatch an event to an observer, save the event and
  // dispatch it after a delay. If we simply drop the event, another one may
  // not arrive anytime soon and the observer will miss the most recent event.
  if (!all_observers_notified) {
    pending_event_ = event;
    notification_timer_.Start(
        FROM_HERE,
        min_delay,
        this,
        &StorageObserverList::DispatchPendingEvent);
  }
}

void StorageObserverList::ScheduleUpdateForObserver(StorageObserver* observer) {
  DCHECK(ContainsKey(observers_, observer));
  observers_[observer].requires_update = true;
}

void StorageObserverList::DispatchPendingEvent() {
  MaybeDispatchEvent(pending_event_);
}


// HostStorageObservers:

HostStorageObservers::HostStorageObservers(QuotaManager* quota_manager)
    : quota_manager_(quota_manager),
      initialized_(false),
      initializing_(false),
      event_occurred_before_init_(false),
      cached_usage_(0),
      cached_quota_(0),
      weak_factory_(this) {
}

HostStorageObservers::~HostStorageObservers() {}

void HostStorageObservers::AddObserver(
    StorageObserver* observer,
    const StorageObserver::MonitorParams& params) {
  observers_.AddObserver(observer, params);

  if (!params.dispatch_initial_state)
    return;

  if (initialized_) {
    StorageObserver::Event event(params.filter,
                                 std::max<int64>(cached_usage_, 0),
                                 std::max<int64>(cached_quota_, 0));
    observer->OnStorageEvent(event);
    return;
  }

  // Ensure the observer receives the initial storage state once initialization
  // is complete.
  observers_.ScheduleUpdateForObserver(observer);
  StartInitialization(params.filter);
}

void HostStorageObservers::RemoveObserver(StorageObserver* observer) {
  observers_.RemoveObserver(observer);
}

bool HostStorageObservers::ContainsObservers() const {
  return observers_.ObserverCount() > 0;
}

void HostStorageObservers::NotifyUsageChange(
    const StorageObserver::Filter& filter, int64 delta) {
  if (initialized_) {
    cached_usage_ += delta;
    DispatchEvent(filter, true);
    return;
  }

  // If a storage change occurs before initialization, ensure all observers will
  // receive an event once initialization is complete.
  event_occurred_before_init_ = true;
  StartInitialization(filter);
}

void HostStorageObservers::StartInitialization(
    const StorageObserver::Filter& filter) {
  if (initialized_ || initializing_)
    return;

  initializing_ = true;
  quota_manager_->GetUsageAndQuotaForWebApps(
      filter.origin,
      filter.storage_type,
      base::Bind(&HostStorageObservers::GotHostUsageAndQuota,
                 weak_factory_.GetWeakPtr(),
                 filter));
}

void HostStorageObservers::GotHostUsageAndQuota(
    const StorageObserver::Filter& filter,
    QuotaStatusCode status,
    int64 usage,
    int64 quota) {
  initializing_ = false;
  if (status != kQuotaStatusOk)
    return;

  initialized_ = true;
  cached_quota_ = quota;
  cached_usage_ = usage;
  DispatchEvent(filter, event_occurred_before_init_);
}

void HostStorageObservers::DispatchEvent(
    const StorageObserver::Filter& filter, bool is_update) {
  StorageObserver::Event event(filter,
                               std::max<int64>(cached_usage_, 0),
                               std::max<int64>(cached_quota_, 0));
  if (is_update)
    observers_.OnStorageChange(event);
  else
    observers_.MaybeDispatchEvent(event);
}


// StorageTypeObservers:

StorageTypeObservers::StorageTypeObservers(QuotaManager* quota_manager)
    : quota_manager_(quota_manager) {
}

StorageTypeObservers::~StorageTypeObservers() {
  STLDeleteValues(&host_observers_map_);
}

void StorageTypeObservers::AddObserver(
    StorageObserver* observer, const StorageObserver::MonitorParams& params) {
  std::string host = net::GetHostOrSpecFromURL(params.filter.origin);
  if (host.empty())
    return;

  HostStorageObservers* host_observers = NULL;
  HostObserversMap::iterator it = host_observers_map_.find(host);
  if (it == host_observers_map_.end()) {
    host_observers = new HostStorageObservers(quota_manager_);
    host_observers_map_[host] = host_observers;
  } else {
    host_observers = it->second;
  }

  host_observers->AddObserver(observer, params);
}

void StorageTypeObservers::RemoveObserver(StorageObserver* observer) {
  for (HostObserversMap::iterator it = host_observers_map_.begin();
       it != host_observers_map_.end(); ) {
    it->second->RemoveObserver(observer);
    if (!it->second->ContainsObservers()) {
      delete it->second;
      host_observers_map_.erase(it++);
    } else {
      ++it;
    }
  }
}

void StorageTypeObservers::RemoveObserverForFilter(
    StorageObserver* observer, const StorageObserver::Filter& filter) {
  std::string host = net::GetHostOrSpecFromURL(filter.origin);
  HostObserversMap::iterator it = host_observers_map_.find(host);
  if (it == host_observers_map_.end())
    return;

  it->second->RemoveObserver(observer);
  if (!it->second->ContainsObservers()) {
    delete it->second;
    host_observers_map_.erase(it);
  }
}

const HostStorageObservers* StorageTypeObservers::GetHostObservers(
    const std::string& host) const {
  HostObserversMap::const_iterator it = host_observers_map_.find(host);
  if (it != host_observers_map_.end())
    return it->second;

  return NULL;
}

void StorageTypeObservers::NotifyUsageChange(
    const StorageObserver::Filter& filter, int64 delta) {
  std::string host = net::GetHostOrSpecFromURL(filter.origin);
  HostObserversMap::iterator it = host_observers_map_.find(host);
  if (it == host_observers_map_.end())
    return;

  it->second->NotifyUsageChange(filter, delta);
}


// StorageMonitor:

StorageMonitor::StorageMonitor(QuotaManager* quota_manager)
    : quota_manager_(quota_manager) {
}

StorageMonitor::~StorageMonitor() {
  STLDeleteValues(&storage_type_observers_map_);
}

void StorageMonitor::AddObserver(
    StorageObserver* observer, const StorageObserver::MonitorParams& params) {
  DCHECK(observer);

  // Check preconditions.
  if (params.filter.storage_type == kStorageTypeUnknown ||
      params.filter.storage_type == kStorageTypeQuotaNotManaged ||
      params.filter.origin.is_empty()) {
    NOTREACHED();
    return;
  }

  StorageTypeObservers* type_observers = NULL;
  StorageTypeObserversMap::iterator it =
      storage_type_observers_map_.find(params.filter.storage_type);
  if (it == storage_type_observers_map_.end()) {
    type_observers = new StorageTypeObservers(quota_manager_);
    storage_type_observers_map_[params.filter.storage_type] = type_observers;
  } else {
    type_observers = it->second;
  }

  type_observers->AddObserver(observer, params);
}

void StorageMonitor::RemoveObserver(StorageObserver* observer) {
  for (StorageTypeObserversMap::iterator it =
           storage_type_observers_map_.begin();
       it != storage_type_observers_map_.end(); ++it) {
    it->second->RemoveObserver(observer);
  }
}

void StorageMonitor::RemoveObserverForFilter(
    StorageObserver* observer, const StorageObserver::Filter& filter) {
  StorageTypeObserversMap::iterator it =
      storage_type_observers_map_.find(filter.storage_type);
  if (it == storage_type_observers_map_.end())
    return;

  it->second->RemoveObserverForFilter(observer, filter);
}

const StorageTypeObservers* StorageMonitor::GetStorageTypeObservers(
    StorageType storage_type) const {
  StorageTypeObserversMap::const_iterator it =
      storage_type_observers_map_.find(storage_type);
  if (it != storage_type_observers_map_.end())
    return it->second;

  return NULL;
}

void StorageMonitor::NotifyUsageChange(
    const StorageObserver::Filter& filter, int64 delta) {
  // Check preconditions.
  if (filter.storage_type == kStorageTypeUnknown ||
      filter.storage_type == kStorageTypeQuotaNotManaged ||
      filter.origin.is_empty()) {
    NOTREACHED();
    return;
  }

  StorageTypeObserversMap::iterator it =
      storage_type_observers_map_.find(filter.storage_type);
  if (it == storage_type_observers_map_.end())
    return;

  it->second->NotifyUsageChange(filter, delta);
}

}  // namespace quota

/* [<][>][^][v][top][bottom][index][help] */