diff options
author | nhiroki <nhiroki@chromium.org> | 2014-11-09 19:05:53 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-10 03:06:21 +0000 |
commit | 75c6f18a7a3ed3a13b5a3572f35701d0e23e177a (patch) | |
tree | de2ebae7bf67c613f3674853c155fe5cef857769 | |
parent | 0e9bcc0770a48cdd8e3b6376c58dc5fbe4c6aea9 (diff) | |
download | chromium_src-75c6f18a7a3ed3a13b5a3572f35701d0e23e177a.zip chromium_src-75c6f18a7a3ed3a13b5a3572f35701d0e23e177a.tar.gz chromium_src-75c6f18a7a3ed3a13b5a3572f35701d0e23e177a.tar.bz2 |
Quota: Factor out ClientUsageTracker into its own file
From the point of view of readability, ClientUsageTracker seems too big to be
pushed into one file with UsageTracker. This CL moves ClientUsageTracker into
its own file.
BUG=n/a
TEST=compile
TBR=michaeln@chromium.org
Review URL: https://codereview.chromium.org/693713003
Cr-Commit-Position: refs/heads/master@{#303415}
-rw-r--r-- | storage/browser/BUILD.gn | 2 | ||||
-rw-r--r-- | storage/browser/quota/client_usage_tracker.cc | 483 | ||||
-rw-r--r-- | storage/browser/quota/client_usage_tracker.h | 139 | ||||
-rw-r--r-- | storage/browser/quota/quota_manager.cc | 1 | ||||
-rw-r--r-- | storage/browser/quota/usage_tracker.cc | 470 | ||||
-rw-r--r-- | storage/browser/quota/usage_tracker.h | 108 | ||||
-rw-r--r-- | storage/storage_browser.gyp | 2 |
7 files changed, 628 insertions, 577 deletions
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn index 7b0b461..3ca92d7 100644 --- a/storage/browser/BUILD.gn +++ b/storage/browser/BUILD.gn @@ -131,6 +131,8 @@ component("browser") { "fileapi/timed_task_helper.h", "fileapi/transient_file_util.cc", "fileapi/transient_file_util.h", + "quota/client_usage_tracker.cc", + "quota/client_usage_tracker.h", "quota/quota_callbacks.h", "quota/quota_client.h", "quota/quota_database.cc", diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc new file mode 100644 index 0000000..13ba61b --- /dev/null +++ b/storage/browser/quota/client_usage_tracker.cc @@ -0,0 +1,483 @@ +// 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 "storage/browser/quota/client_usage_tracker.h" + +#include "base/bind.h" +#include "base/stl_util.h" +#include "net/base/net_util.h" +#include "storage/browser/quota/storage_monitor.h" +#include "storage/browser/quota/storage_observer.h" + +namespace storage { + +namespace { + +typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator; +typedef ClientUsageTracker::OriginSetByHost OriginSetByHost; + +void DidGetOriginUsage(const OriginUsageAccumulator& accumulator, + const GURL& origin, + int64 usage) { + accumulator.Run(origin, usage); +} + +void DidGetHostUsage(const UsageCallback& callback, + int64 limited_usage, + int64 unlimited_usage) { + DCHECK_GE(limited_usage, 0); + DCHECK_GE(unlimited_usage, 0); + callback.Run(limited_usage + unlimited_usage); +} + +bool EraseOriginFromOriginSet(OriginSetByHost* origins_by_host, + const std::string& host, + const GURL& origin) { + OriginSetByHost::iterator found = origins_by_host->find(host); + if (found == origins_by_host->end()) + return false; + + if (!found->second.erase(origin)) + return false; + + if (found->second.empty()) + origins_by_host->erase(host); + return true; +} + +bool OriginSetContainsOrigin(const OriginSetByHost& origins, + const std::string& host, + const GURL& origin) { + OriginSetByHost::const_iterator itr = origins.find(host); + return itr != origins.end() && ContainsKey(itr->second, origin); +} + +void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback, + int64 total_global_usage, + int64 global_unlimited_usage) { + callback.Run(total_global_usage - global_unlimited_usage); +} + +} // namespace + +ClientUsageTracker::ClientUsageTracker( + UsageTracker* tracker, QuotaClient* client, StorageType type, + SpecialStoragePolicy* special_storage_policy, + StorageMonitor* storage_monitor) + : tracker_(tracker), + client_(client), + type_(type), + storage_monitor_(storage_monitor), + global_limited_usage_(0), + global_unlimited_usage_(0), + global_usage_retrieved_(false), + special_storage_policy_(special_storage_policy) { + DCHECK(tracker_); + DCHECK(client_); + if (special_storage_policy_.get()) + special_storage_policy_->AddObserver(this); +} + +ClientUsageTracker::~ClientUsageTracker() { + if (special_storage_policy_.get()) + special_storage_policy_->RemoveObserver(this); +} + +void ClientUsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) { + if (!global_usage_retrieved_) { + GetGlobalUsage(base::Bind(&DidGetGlobalUsageForLimitedGlobalUsage, + callback)); + return; + } + + if (non_cached_limited_origins_by_host_.empty()) { + callback.Run(global_limited_usage_); + return; + } + + AccumulateInfo* info = new AccumulateInfo; + info->pending_jobs = non_cached_limited_origins_by_host_.size() + 1; + UsageCallback accumulator = base::Bind( + &ClientUsageTracker::AccumulateLimitedOriginUsage, AsWeakPtr(), + base::Owned(info), callback); + + for (OriginSetByHost::iterator host_itr = + non_cached_limited_origins_by_host_.begin(); + host_itr != non_cached_limited_origins_by_host_.end(); ++host_itr) { + for (std::set<GURL>::iterator origin_itr = host_itr->second.begin(); + origin_itr != host_itr->second.end(); ++origin_itr) + client_->GetOriginUsage(*origin_itr, type_, accumulator); + } + + accumulator.Run(global_limited_usage_); +} + +void ClientUsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) { + if (global_usage_retrieved_ && + non_cached_limited_origins_by_host_.empty() && + non_cached_unlimited_origins_by_host_.empty()) { + callback.Run(global_limited_usage_ + global_unlimited_usage_, + global_unlimited_usage_); + return; + } + + client_->GetOriginsForType(type_, base::Bind( + &ClientUsageTracker::DidGetOriginsForGlobalUsage, AsWeakPtr(), + callback)); +} + +void ClientUsageTracker::GetHostUsage( + const std::string& host, const UsageCallback& callback) { + if (ContainsKey(cached_hosts_, host) && + !ContainsKey(non_cached_limited_origins_by_host_, host) && + !ContainsKey(non_cached_unlimited_origins_by_host_, host)) { + // TODO(kinuko): Drop host_usage_map_ cache periodically. + callback.Run(GetCachedHostUsage(host)); + return; + } + + if (!host_usage_accumulators_.Add( + host, base::Bind(&DidGetHostUsage, callback))) + return; + client_->GetOriginsForHost(type_, host, base::Bind( + &ClientUsageTracker::DidGetOriginsForHostUsage, AsWeakPtr(), host)); +} + +void ClientUsageTracker::UpdateUsageCache( + const GURL& origin, int64 delta) { + std::string host = net::GetHostOrSpecFromURL(origin); + if (cached_hosts_.find(host) != cached_hosts_.end()) { + if (!IsUsageCacheEnabledForOrigin(origin)) + return; + + cached_usage_by_host_[host][origin] += delta; + if (IsStorageUnlimited(origin)) + global_unlimited_usage_ += delta; + else + global_limited_usage_ += delta; + DCHECK_GE(cached_usage_by_host_[host][origin], 0); + DCHECK_GE(global_limited_usage_, 0); + + // Notify the usage monitor that usage has changed. The storage monitor may + // be NULL during tests. + if (storage_monitor_) { + StorageObserver::Filter filter(type_, origin); + storage_monitor_->NotifyUsageChange(filter, delta); + } + return; + } + + // We don't know about this host yet, so populate our cache for it. + GetHostUsage(host, base::Bind(&ClientUsageTracker::DidGetHostUsageAfterUpdate, + AsWeakPtr(), origin)); +} + +void ClientUsageTracker::GetCachedHostsUsage( + std::map<std::string, int64>* host_usage) const { + DCHECK(host_usage); + for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin(); + host_iter != cached_usage_by_host_.end(); host_iter++) { + const std::string& host = host_iter->first; + (*host_usage)[host] += GetCachedHostUsage(host); + } +} + +void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const { + DCHECK(origins); + for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin(); + host_iter != cached_usage_by_host_.end(); host_iter++) { + const UsageMap& origin_map = host_iter->second; + for (UsageMap::const_iterator origin_iter = origin_map.begin(); + origin_iter != origin_map.end(); origin_iter++) { + origins->insert(origin_iter->first); + } + } +} + +void ClientUsageTracker::SetUsageCacheEnabled(const GURL& origin, + bool enabled) { + std::string host = net::GetHostOrSpecFromURL(origin); + if (!enabled) { + // Erase |origin| from cache and subtract its usage. + HostUsageMap::iterator found_host = cached_usage_by_host_.find(host); + if (found_host != cached_usage_by_host_.end()) { + UsageMap& cached_usage_for_host = found_host->second; + + UsageMap::iterator found = cached_usage_for_host.find(origin); + if (found != cached_usage_for_host.end()) { + int64 usage = found->second; + UpdateUsageCache(origin, -usage); + cached_usage_for_host.erase(found); + if (cached_usage_for_host.empty()) { + cached_usage_by_host_.erase(found_host); + cached_hosts_.erase(host); + } + } + } + + if (IsStorageUnlimited(origin)) + non_cached_unlimited_origins_by_host_[host].insert(origin); + else + non_cached_limited_origins_by_host_[host].insert(origin); + } else { + // Erase |origin| from |non_cached_origins_| and invalidate the usage cache + // for the host. + if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_, + host, origin) || + EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_, + host, origin)) { + cached_hosts_.erase(host); + global_usage_retrieved_ = false; + } + } +} + +void ClientUsageTracker::AccumulateLimitedOriginUsage( + AccumulateInfo* info, + const UsageCallback& callback, + int64 usage) { + info->limited_usage += usage; + if (--info->pending_jobs) + return; + + callback.Run(info->limited_usage); +} + +void ClientUsageTracker::DidGetOriginsForGlobalUsage( + const GlobalUsageCallback& callback, + const std::set<GURL>& origins) { + OriginSetByHost origins_by_host; + for (std::set<GURL>::const_iterator itr = origins.begin(); + itr != origins.end(); ++itr) + origins_by_host[net::GetHostOrSpecFromURL(*itr)].insert(*itr); + + AccumulateInfo* info = new AccumulateInfo; + // Getting host usage may synchronously return the result if the usage is + // cached, which may in turn dispatch the completion callback before we finish + // looping over all hosts (because info->pending_jobs may reach 0 during the + // loop). To avoid this, we add one more pending host as a sentinel and + // fire the sentinel callback at the end. + info->pending_jobs = origins_by_host.size() + 1; + HostUsageAccumulator accumulator = + base::Bind(&ClientUsageTracker::AccumulateHostUsage, AsWeakPtr(), + base::Owned(info), callback); + + for (OriginSetByHost::iterator itr = origins_by_host.begin(); + itr != origins_by_host.end(); ++itr) { + if (host_usage_accumulators_.Add(itr->first, accumulator)) + GetUsageForOrigins(itr->first, itr->second); + } + + // Fire the sentinel as we've now called GetUsageForOrigins for all clients. + accumulator.Run(0, 0); +} + +void ClientUsageTracker::AccumulateHostUsage( + AccumulateInfo* info, + const GlobalUsageCallback& callback, + int64 limited_usage, + int64 unlimited_usage) { + info->limited_usage += limited_usage; + info->unlimited_usage += unlimited_usage; + if (--info->pending_jobs) + return; + + DCHECK_GE(info->limited_usage, 0); + DCHECK_GE(info->unlimited_usage, 0); + + global_usage_retrieved_ = true; + callback.Run(info->limited_usage + info->unlimited_usage, + info->unlimited_usage); +} + +void ClientUsageTracker::DidGetOriginsForHostUsage( + const std::string& host, + const std::set<GURL>& origins) { + GetUsageForOrigins(host, origins); +} + +void ClientUsageTracker::GetUsageForOrigins( + const std::string& host, + const std::set<GURL>& origins) { + AccumulateInfo* info = new AccumulateInfo; + // Getting origin usage may synchronously return the result if the usage is + // cached, which may in turn dispatch the completion callback before we finish + // looping over all origins (because info->pending_jobs may reach 0 during the + // loop). To avoid this, we add one more pending origin as a sentinel and + // fire the sentinel callback at the end. + info->pending_jobs = origins.size() + 1; + OriginUsageAccumulator accumulator = + base::Bind(&ClientUsageTracker::AccumulateOriginUsage, AsWeakPtr(), + base::Owned(info), host); + + for (std::set<GURL>::const_iterator itr = origins.begin(); + itr != origins.end(); ++itr) { + DCHECK_EQ(host, net::GetHostOrSpecFromURL(*itr)); + + int64 origin_usage = 0; + if (GetCachedOriginUsage(*itr, &origin_usage)) { + accumulator.Run(*itr, origin_usage); + } else { + client_->GetOriginUsage(*itr, type_, base::Bind( + &DidGetOriginUsage, accumulator, *itr)); + } + } + + // Fire the sentinel as we've now called GetOriginUsage for all clients. + accumulator.Run(GURL(), 0); +} + +void ClientUsageTracker::AccumulateOriginUsage(AccumulateInfo* info, + const std::string& host, + const GURL& origin, + int64 usage) { + if (!origin.is_empty()) { + if (usage < 0) + usage = 0; + + if (IsStorageUnlimited(origin)) + info->unlimited_usage += usage; + else + info->limited_usage += usage; + if (IsUsageCacheEnabledForOrigin(origin)) + AddCachedOrigin(origin, usage); + } + if (--info->pending_jobs) + return; + + AddCachedHost(host); + host_usage_accumulators_.Run( + host, MakeTuple(info->limited_usage, info->unlimited_usage)); +} + +void ClientUsageTracker::DidGetHostUsageAfterUpdate( + const GURL& origin, int64 usage) { + if (!storage_monitor_) + return; + + StorageObserver::Filter filter(type_, origin); + storage_monitor_->NotifyUsageChange(filter, 0); +} + +void ClientUsageTracker::AddCachedOrigin( + const GURL& origin, int64 new_usage) { + DCHECK(IsUsageCacheEnabledForOrigin(origin)); + + std::string host = net::GetHostOrSpecFromURL(origin); + int64* usage = &cached_usage_by_host_[host][origin]; + int64 delta = new_usage - *usage; + *usage = new_usage; + if (delta) { + if (IsStorageUnlimited(origin)) + global_unlimited_usage_ += delta; + else + global_limited_usage_ += delta; + } + DCHECK_GE(*usage, 0); + DCHECK_GE(global_limited_usage_, 0); +} + +void ClientUsageTracker::AddCachedHost(const std::string& host) { + cached_hosts_.insert(host); +} + +int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) const { + HostUsageMap::const_iterator found = cached_usage_by_host_.find(host); + if (found == cached_usage_by_host_.end()) + return 0; + + int64 usage = 0; + const UsageMap& map = found->second; + for (UsageMap::const_iterator iter = map.begin(); + iter != map.end(); ++iter) { + usage += iter->second; + } + return usage; +} + +bool ClientUsageTracker::GetCachedOriginUsage( + const GURL& origin, + int64* usage) const { + std::string host = net::GetHostOrSpecFromURL(origin); + HostUsageMap::const_iterator found_host = cached_usage_by_host_.find(host); + if (found_host == cached_usage_by_host_.end()) + return false; + + UsageMap::const_iterator found = found_host->second.find(origin); + if (found == found_host->second.end()) + return false; + + DCHECK(IsUsageCacheEnabledForOrigin(origin)); + *usage = found->second; + return true; +} + +bool ClientUsageTracker::IsUsageCacheEnabledForOrigin( + const GURL& origin) const { + std::string host = net::GetHostOrSpecFromURL(origin); + return !OriginSetContainsOrigin(non_cached_limited_origins_by_host_, + host, origin) && + !OriginSetContainsOrigin(non_cached_unlimited_origins_by_host_, + host, origin); +} + +void ClientUsageTracker::OnGranted(const GURL& origin, + int change_flags) { + DCHECK(CalledOnValidThread()); + if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { + int64 usage = 0; + if (GetCachedOriginUsage(origin, &usage)) { + global_unlimited_usage_ += usage; + global_limited_usage_ -= usage; + } + + std::string host = net::GetHostOrSpecFromURL(origin); + if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_, + host, origin)) + non_cached_unlimited_origins_by_host_[host].insert(origin); + } +} + +void ClientUsageTracker::OnRevoked(const GURL& origin, + int change_flags) { + DCHECK(CalledOnValidThread()); + if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { + int64 usage = 0; + if (GetCachedOriginUsage(origin, &usage)) { + global_unlimited_usage_ -= usage; + global_limited_usage_ += usage; + } + + std::string host = net::GetHostOrSpecFromURL(origin); + if (EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_, + host, origin)) + non_cached_limited_origins_by_host_[host].insert(origin); + } +} + +void ClientUsageTracker::OnCleared() { + DCHECK(CalledOnValidThread()); + global_limited_usage_ += global_unlimited_usage_; + global_unlimited_usage_ = 0; + + for (OriginSetByHost::const_iterator host_itr = + non_cached_unlimited_origins_by_host_.begin(); + host_itr != non_cached_unlimited_origins_by_host_.end(); + ++host_itr) { + for (std::set<GURL>::const_iterator origin_itr = host_itr->second.begin(); + origin_itr != host_itr->second.end(); + ++origin_itr) + non_cached_limited_origins_by_host_[host_itr->first].insert(*origin_itr); + } + non_cached_unlimited_origins_by_host_.clear(); +} + +bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const { + if (type_ == kStorageTypeSyncable) + return false; + return special_storage_policy_.get() && + special_storage_policy_->IsStorageUnlimited(origin); +} + +} // namespace storage diff --git a/storage/browser/quota/client_usage_tracker.h b/storage/browser/quota/client_usage_tracker.h new file mode 100644 index 0000000..dec4720 --- /dev/null +++ b/storage/browser/quota/client_usage_tracker.h @@ -0,0 +1,139 @@ +// 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. + +#ifndef STORAGE_BROWSER_QUOTA_CLIENT_USAGE_TRACKER_H_ +#define STORAGE_BROWSER_QUOTA_CLIENT_USAGE_TRACKER_H_ + +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/non_thread_safe.h" +#include "storage/browser/quota/quota_callbacks.h" +#include "storage/browser/quota/quota_client.h" +#include "storage/browser/quota/quota_task.h" +#include "storage/browser/quota/special_storage_policy.h" +#include "storage/browser/storage_browser_export.h" +#include "storage/common/quota/quota_types.h" +#include "url/gurl.h" + +namespace storage { + +class StorageMonitor; +class UsageTracker; + +// This class holds per-client usage tracking information and caches per-host +// usage data. An instance of this class is created per client. +class ClientUsageTracker : public SpecialStoragePolicy::Observer, + public base::NonThreadSafe, + public base::SupportsWeakPtr<ClientUsageTracker> { + public: + typedef base::Callback<void(int64 limited_usage, + int64 unlimited_usage)> HostUsageAccumulator; + typedef base::Callback<void(const GURL& origin, + int64 usage)> OriginUsageAccumulator; + typedef std::map<std::string, std::set<GURL> > OriginSetByHost; + + ClientUsageTracker(UsageTracker* tracker, + QuotaClient* client, + StorageType type, + SpecialStoragePolicy* special_storage_policy, + StorageMonitor* storage_monitor); + ~ClientUsageTracker() override; + + void GetGlobalLimitedUsage(const UsageCallback& callback); + void GetGlobalUsage(const GlobalUsageCallback& callback); + void GetHostUsage(const std::string& host, const UsageCallback& callback); + void UpdateUsageCache(const GURL& origin, int64 delta); + void GetCachedHostsUsage(std::map<std::string, int64>* host_usage) const; + void GetCachedOrigins(std::set<GURL>* origins) const; + int64 GetCachedOriginsUsage(const std::set<GURL>& origins, + std::vector<GURL>* origins_not_in_cache); + bool IsUsageCacheEnabledForOrigin(const GURL& origin) const; + void SetUsageCacheEnabled(const GURL& origin, bool enabled); + + private: + typedef CallbackQueueMap<HostUsageAccumulator, std::string, + Tuple2<int64, int64> > HostUsageAccumulatorMap; + + typedef std::set<std::string> HostSet; + typedef std::map<GURL, int64> UsageMap; + typedef std::map<std::string, UsageMap> HostUsageMap; + + struct AccumulateInfo { + int pending_jobs; + int64 limited_usage; + int64 unlimited_usage; + + AccumulateInfo() + : pending_jobs(0), limited_usage(0), unlimited_usage(0) {} + }; + + void AccumulateLimitedOriginUsage(AccumulateInfo* info, + const UsageCallback& callback, + int64 usage); + void DidGetOriginsForGlobalUsage(const GlobalUsageCallback& callback, + const std::set<GURL>& origins); + void AccumulateHostUsage(AccumulateInfo* info, + const GlobalUsageCallback& callback, + int64 limited_usage, + int64 unlimited_usage); + + void DidGetOriginsForHostUsage(const std::string& host, + const std::set<GURL>& origins); + + void GetUsageForOrigins(const std::string& host, + const std::set<GURL>& origins); + void AccumulateOriginUsage(AccumulateInfo* info, + const std::string& host, + const GURL& origin, + int64 usage); + + void DidGetHostUsageAfterUpdate(const GURL& origin, int64 usage); + + // Methods used by our GatherUsage tasks, as a task makes progress + // origins and hosts are added incrementally to the cache. + void AddCachedOrigin(const GURL& origin, int64 usage); + void AddCachedHost(const std::string& host); + + int64 GetCachedHostUsage(const std::string& host) const; + int64 GetCachedGlobalUnlimitedUsage(); + bool GetCachedOriginUsage(const GURL& origin, int64* usage) const; + + // SpecialStoragePolicy::Observer overrides + void OnGranted(const GURL& origin, int change_flags) override; + void OnRevoked(const GURL& origin, int change_flags) override; + void OnCleared() override; + + bool IsStorageUnlimited(const GURL& origin) const; + + UsageTracker* tracker_; + QuotaClient* client_; + const StorageType type_; + StorageMonitor* storage_monitor_; + + int64 global_limited_usage_; + int64 global_unlimited_usage_; + bool global_usage_retrieved_; + HostSet cached_hosts_; + HostUsageMap cached_usage_by_host_; + + OriginSetByHost non_cached_limited_origins_by_host_; + OriginSetByHost non_cached_unlimited_origins_by_host_; + + GlobalUsageCallbackQueue global_usage_callback_; + HostUsageAccumulatorMap host_usage_accumulators_; + + scoped_refptr<SpecialStoragePolicy> special_storage_policy_; + + DISALLOW_COPY_AND_ASSIGN(ClientUsageTracker); +}; + +} // namespace storage + +#endif // STORAGE_BROWSER_QUOTA_CLIENT_USAGE_TRACKER_H_ diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index e7b5f7b..a11ef08 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc @@ -23,6 +23,7 @@ #include "base/task_runner_util.h" #include "base/time/time.h" #include "net/base/net_util.h" +#include "storage/browser/quota/client_usage_tracker.h" #include "storage/browser/quota/quota_database.h" #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/browser/quota/quota_temporary_storage_evictor.h" diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc index 1c222bc..3840aee 100644 --- a/storage/browser/quota/usage_tracker.cc +++ b/storage/browser/quota/usage_tracker.cc @@ -5,61 +5,16 @@ #include "storage/browser/quota/usage_tracker.h" #include <algorithm> -#include <deque> -#include <set> -#include <string> -#include <vector> #include "base/bind.h" -#include "base/message_loop/message_loop_proxy.h" #include "base/stl_util.h" -#include "net/base/net_util.h" +#include "storage/browser/quota/client_usage_tracker.h" #include "storage/browser/quota/storage_monitor.h" -#include "storage/browser/quota/storage_observer.h" namespace storage { namespace { -typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator; -typedef ClientUsageTracker::OriginSetByHost OriginSetByHost; - -void DidGetOriginUsage(const OriginUsageAccumulator& accumulator, - const GURL& origin, - int64 usage) { - accumulator.Run(origin, usage); -} - -void DidGetHostUsage(const UsageCallback& callback, - int64 limited_usage, - int64 unlimited_usage) { - DCHECK_GE(limited_usage, 0); - DCHECK_GE(unlimited_usage, 0); - callback.Run(limited_usage + unlimited_usage); -} - -bool EraseOriginFromOriginSet(OriginSetByHost* origins_by_host, - const std::string& host, - const GURL& origin) { - OriginSetByHost::iterator found = origins_by_host->find(host); - if (found == origins_by_host->end()) - return false; - - if (!found->second.erase(origin)) - return false; - - if (found->second.empty()) - origins_by_host->erase(host); - return true; -} - -bool OriginSetContainsOrigin(const OriginSetByHost& origins, - const std::string& host, - const GURL& origin) { - OriginSetByHost::const_iterator itr = origins.find(host); - return itr != origins.end() && ContainsKey(itr->second, origin); -} - void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback, int64 total_global_usage, int64 global_unlimited_usage) { @@ -68,8 +23,6 @@ void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback, } // namespace -// UsageTracker ---------------------------------------------------------- - UsageTracker::UsageTracker(const QuotaClientList& clients, StorageType type, SpecialStoragePolicy* special_storage_policy, @@ -270,425 +223,4 @@ void UsageTracker::AccumulateClientHostUsage(AccumulateInfo* info, host_usage_callbacks_.Run(host, MakeTuple(info->usage)); } -// ClientUsageTracker ---------------------------------------------------- - -ClientUsageTracker::ClientUsageTracker( - UsageTracker* tracker, QuotaClient* client, StorageType type, - SpecialStoragePolicy* special_storage_policy, - StorageMonitor* storage_monitor) - : tracker_(tracker), - client_(client), - type_(type), - storage_monitor_(storage_monitor), - global_limited_usage_(0), - global_unlimited_usage_(0), - global_usage_retrieved_(false), - special_storage_policy_(special_storage_policy) { - DCHECK(tracker_); - DCHECK(client_); - if (special_storage_policy_.get()) - special_storage_policy_->AddObserver(this); -} - -ClientUsageTracker::~ClientUsageTracker() { - if (special_storage_policy_.get()) - special_storage_policy_->RemoveObserver(this); -} - -void ClientUsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) { - if (!global_usage_retrieved_) { - GetGlobalUsage(base::Bind(&DidGetGlobalUsageForLimitedGlobalUsage, - callback)); - return; - } - - if (non_cached_limited_origins_by_host_.empty()) { - callback.Run(global_limited_usage_); - return; - } - - AccumulateInfo* info = new AccumulateInfo; - info->pending_jobs = non_cached_limited_origins_by_host_.size() + 1; - UsageCallback accumulator = base::Bind( - &ClientUsageTracker::AccumulateLimitedOriginUsage, AsWeakPtr(), - base::Owned(info), callback); - - for (OriginSetByHost::iterator host_itr = - non_cached_limited_origins_by_host_.begin(); - host_itr != non_cached_limited_origins_by_host_.end(); ++host_itr) { - for (std::set<GURL>::iterator origin_itr = host_itr->second.begin(); - origin_itr != host_itr->second.end(); ++origin_itr) - client_->GetOriginUsage(*origin_itr, type_, accumulator); - } - - accumulator.Run(global_limited_usage_); -} - -void ClientUsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) { - if (global_usage_retrieved_ && - non_cached_limited_origins_by_host_.empty() && - non_cached_unlimited_origins_by_host_.empty()) { - callback.Run(global_limited_usage_ + global_unlimited_usage_, - global_unlimited_usage_); - return; - } - - client_->GetOriginsForType(type_, base::Bind( - &ClientUsageTracker::DidGetOriginsForGlobalUsage, AsWeakPtr(), - callback)); -} - -void ClientUsageTracker::GetHostUsage( - const std::string& host, const UsageCallback& callback) { - if (ContainsKey(cached_hosts_, host) && - !ContainsKey(non_cached_limited_origins_by_host_, host) && - !ContainsKey(non_cached_unlimited_origins_by_host_, host)) { - // TODO(kinuko): Drop host_usage_map_ cache periodically. - callback.Run(GetCachedHostUsage(host)); - return; - } - - if (!host_usage_accumulators_.Add( - host, base::Bind(&DidGetHostUsage, callback))) - return; - client_->GetOriginsForHost(type_, host, base::Bind( - &ClientUsageTracker::DidGetOriginsForHostUsage, AsWeakPtr(), host)); -} - -void ClientUsageTracker::UpdateUsageCache( - const GURL& origin, int64 delta) { - std::string host = net::GetHostOrSpecFromURL(origin); - if (cached_hosts_.find(host) != cached_hosts_.end()) { - if (!IsUsageCacheEnabledForOrigin(origin)) - return; - - cached_usage_by_host_[host][origin] += delta; - if (IsStorageUnlimited(origin)) - global_unlimited_usage_ += delta; - else - global_limited_usage_ += delta; - DCHECK_GE(cached_usage_by_host_[host][origin], 0); - DCHECK_GE(global_limited_usage_, 0); - - // Notify the usage monitor that usage has changed. The storage monitor may - // be NULL during tests. - if (storage_monitor_) { - StorageObserver::Filter filter(type_, origin); - storage_monitor_->NotifyUsageChange(filter, delta); - } - return; - } - - // We don't know about this host yet, so populate our cache for it. - GetHostUsage(host, base::Bind(&ClientUsageTracker::DidGetHostUsageAfterUpdate, - AsWeakPtr(), origin)); -} - -void ClientUsageTracker::GetCachedHostsUsage( - std::map<std::string, int64>* host_usage) const { - DCHECK(host_usage); - for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin(); - host_iter != cached_usage_by_host_.end(); host_iter++) { - const std::string& host = host_iter->first; - (*host_usage)[host] += GetCachedHostUsage(host); - } -} - -void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const { - DCHECK(origins); - for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin(); - host_iter != cached_usage_by_host_.end(); host_iter++) { - const UsageMap& origin_map = host_iter->second; - for (UsageMap::const_iterator origin_iter = origin_map.begin(); - origin_iter != origin_map.end(); origin_iter++) { - origins->insert(origin_iter->first); - } - } -} - -void ClientUsageTracker::SetUsageCacheEnabled(const GURL& origin, - bool enabled) { - std::string host = net::GetHostOrSpecFromURL(origin); - if (!enabled) { - // Erase |origin| from cache and subtract its usage. - HostUsageMap::iterator found_host = cached_usage_by_host_.find(host); - if (found_host != cached_usage_by_host_.end()) { - UsageMap& cached_usage_for_host = found_host->second; - - UsageMap::iterator found = cached_usage_for_host.find(origin); - if (found != cached_usage_for_host.end()) { - int64 usage = found->second; - UpdateUsageCache(origin, -usage); - cached_usage_for_host.erase(found); - if (cached_usage_for_host.empty()) { - cached_usage_by_host_.erase(found_host); - cached_hosts_.erase(host); - } - } - } - - if (IsStorageUnlimited(origin)) - non_cached_unlimited_origins_by_host_[host].insert(origin); - else - non_cached_limited_origins_by_host_[host].insert(origin); - } else { - // Erase |origin| from |non_cached_origins_| and invalidate the usage cache - // for the host. - if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_, - host, origin) || - EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_, - host, origin)) { - cached_hosts_.erase(host); - global_usage_retrieved_ = false; - } - } -} - -void ClientUsageTracker::AccumulateLimitedOriginUsage( - AccumulateInfo* info, - const UsageCallback& callback, - int64 usage) { - info->limited_usage += usage; - if (--info->pending_jobs) - return; - - callback.Run(info->limited_usage); -} - -void ClientUsageTracker::DidGetOriginsForGlobalUsage( - const GlobalUsageCallback& callback, - const std::set<GURL>& origins) { - OriginSetByHost origins_by_host; - for (std::set<GURL>::const_iterator itr = origins.begin(); - itr != origins.end(); ++itr) - origins_by_host[net::GetHostOrSpecFromURL(*itr)].insert(*itr); - - AccumulateInfo* info = new AccumulateInfo; - // Getting host usage may synchronously return the result if the usage is - // cached, which may in turn dispatch the completion callback before we finish - // looping over all hosts (because info->pending_jobs may reach 0 during the - // loop). To avoid this, we add one more pending host as a sentinel and - // fire the sentinel callback at the end. - info->pending_jobs = origins_by_host.size() + 1; - HostUsageAccumulator accumulator = - base::Bind(&ClientUsageTracker::AccumulateHostUsage, AsWeakPtr(), - base::Owned(info), callback); - - for (OriginSetByHost::iterator itr = origins_by_host.begin(); - itr != origins_by_host.end(); ++itr) { - if (host_usage_accumulators_.Add(itr->first, accumulator)) - GetUsageForOrigins(itr->first, itr->second); - } - - // Fire the sentinel as we've now called GetUsageForOrigins for all clients. - accumulator.Run(0, 0); -} - -void ClientUsageTracker::AccumulateHostUsage( - AccumulateInfo* info, - const GlobalUsageCallback& callback, - int64 limited_usage, - int64 unlimited_usage) { - info->limited_usage += limited_usage; - info->unlimited_usage += unlimited_usage; - if (--info->pending_jobs) - return; - - DCHECK_GE(info->limited_usage, 0); - DCHECK_GE(info->unlimited_usage, 0); - - global_usage_retrieved_ = true; - callback.Run(info->limited_usage + info->unlimited_usage, - info->unlimited_usage); -} - -void ClientUsageTracker::DidGetOriginsForHostUsage( - const std::string& host, - const std::set<GURL>& origins) { - GetUsageForOrigins(host, origins); -} - -void ClientUsageTracker::GetUsageForOrigins( - const std::string& host, - const std::set<GURL>& origins) { - AccumulateInfo* info = new AccumulateInfo; - // Getting origin usage may synchronously return the result if the usage is - // cached, which may in turn dispatch the completion callback before we finish - // looping over all origins (because info->pending_jobs may reach 0 during the - // loop). To avoid this, we add one more pending origin as a sentinel and - // fire the sentinel callback at the end. - info->pending_jobs = origins.size() + 1; - OriginUsageAccumulator accumulator = - base::Bind(&ClientUsageTracker::AccumulateOriginUsage, AsWeakPtr(), - base::Owned(info), host); - - for (std::set<GURL>::const_iterator itr = origins.begin(); - itr != origins.end(); ++itr) { - DCHECK_EQ(host, net::GetHostOrSpecFromURL(*itr)); - - int64 origin_usage = 0; - if (GetCachedOriginUsage(*itr, &origin_usage)) { - accumulator.Run(*itr, origin_usage); - } else { - client_->GetOriginUsage(*itr, type_, base::Bind( - &DidGetOriginUsage, accumulator, *itr)); - } - } - - // Fire the sentinel as we've now called GetOriginUsage for all clients. - accumulator.Run(GURL(), 0); -} - -void ClientUsageTracker::AccumulateOriginUsage(AccumulateInfo* info, - const std::string& host, - const GURL& origin, - int64 usage) { - if (!origin.is_empty()) { - if (usage < 0) - usage = 0; - - if (IsStorageUnlimited(origin)) - info->unlimited_usage += usage; - else - info->limited_usage += usage; - if (IsUsageCacheEnabledForOrigin(origin)) - AddCachedOrigin(origin, usage); - } - if (--info->pending_jobs) - return; - - AddCachedHost(host); - host_usage_accumulators_.Run( - host, MakeTuple(info->limited_usage, info->unlimited_usage)); -} - -void ClientUsageTracker::DidGetHostUsageAfterUpdate( - const GURL& origin, int64 usage) { - if (!storage_monitor_) - return; - - StorageObserver::Filter filter(type_, origin); - storage_monitor_->NotifyUsageChange(filter, 0); -} - -void ClientUsageTracker::AddCachedOrigin( - const GURL& origin, int64 new_usage) { - DCHECK(IsUsageCacheEnabledForOrigin(origin)); - - std::string host = net::GetHostOrSpecFromURL(origin); - int64* usage = &cached_usage_by_host_[host][origin]; - int64 delta = new_usage - *usage; - *usage = new_usage; - if (delta) { - if (IsStorageUnlimited(origin)) - global_unlimited_usage_ += delta; - else - global_limited_usage_ += delta; - } - DCHECK_GE(*usage, 0); - DCHECK_GE(global_limited_usage_, 0); -} - -void ClientUsageTracker::AddCachedHost(const std::string& host) { - cached_hosts_.insert(host); -} - -int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) const { - HostUsageMap::const_iterator found = cached_usage_by_host_.find(host); - if (found == cached_usage_by_host_.end()) - return 0; - - int64 usage = 0; - const UsageMap& map = found->second; - for (UsageMap::const_iterator iter = map.begin(); - iter != map.end(); ++iter) { - usage += iter->second; - } - return usage; -} - -bool ClientUsageTracker::GetCachedOriginUsage( - const GURL& origin, - int64* usage) const { - std::string host = net::GetHostOrSpecFromURL(origin); - HostUsageMap::const_iterator found_host = cached_usage_by_host_.find(host); - if (found_host == cached_usage_by_host_.end()) - return false; - - UsageMap::const_iterator found = found_host->second.find(origin); - if (found == found_host->second.end()) - return false; - - DCHECK(IsUsageCacheEnabledForOrigin(origin)); - *usage = found->second; - return true; -} - -bool ClientUsageTracker::IsUsageCacheEnabledForOrigin( - const GURL& origin) const { - std::string host = net::GetHostOrSpecFromURL(origin); - return !OriginSetContainsOrigin(non_cached_limited_origins_by_host_, - host, origin) && - !OriginSetContainsOrigin(non_cached_unlimited_origins_by_host_, - host, origin); -} - -void ClientUsageTracker::OnGranted(const GURL& origin, - int change_flags) { - DCHECK(CalledOnValidThread()); - if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { - int64 usage = 0; - if (GetCachedOriginUsage(origin, &usage)) { - global_unlimited_usage_ += usage; - global_limited_usage_ -= usage; - } - - std::string host = net::GetHostOrSpecFromURL(origin); - if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_, - host, origin)) - non_cached_unlimited_origins_by_host_[host].insert(origin); - } -} - -void ClientUsageTracker::OnRevoked(const GURL& origin, - int change_flags) { - DCHECK(CalledOnValidThread()); - if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { - int64 usage = 0; - if (GetCachedOriginUsage(origin, &usage)) { - global_unlimited_usage_ -= usage; - global_limited_usage_ += usage; - } - - std::string host = net::GetHostOrSpecFromURL(origin); - if (EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_, - host, origin)) - non_cached_limited_origins_by_host_[host].insert(origin); - } -} - -void ClientUsageTracker::OnCleared() { - DCHECK(CalledOnValidThread()); - global_limited_usage_ += global_unlimited_usage_; - global_unlimited_usage_ = 0; - - for (OriginSetByHost::const_iterator host_itr = - non_cached_unlimited_origins_by_host_.begin(); - host_itr != non_cached_unlimited_origins_by_host_.end(); - ++host_itr) { - for (std::set<GURL>::const_iterator origin_itr = host_itr->second.begin(); - origin_itr != host_itr->second.end(); - ++origin_itr) - non_cached_limited_origins_by_host_[host_itr->first].insert(*origin_itr); - } - non_cached_unlimited_origins_by_host_.clear(); -} - -bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const { - if (type_ == kStorageTypeSyncable) - return false; - return special_storage_policy_.get() && - special_storage_policy_->IsStorageUnlimited(origin); -} - } // namespace storage diff --git a/storage/browser/quota/usage_tracker.h b/storage/browser/quota/usage_tracker.h index b19aea1..b3f6d7b 100644 --- a/storage/browser/quota/usage_tracker.h +++ b/storage/browser/quota/usage_tracker.h @@ -5,7 +5,6 @@ #ifndef STORAGE_BROWSER_QUOTA_USAGE_TRACKER_H_ #define STORAGE_BROWSER_QUOTA_USAGE_TRACKER_H_ -#include <list> #include <map> #include <set> #include <string> @@ -90,113 +89,6 @@ class STORAGE_EXPORT UsageTracker : public QuotaTaskObserver { DISALLOW_COPY_AND_ASSIGN(UsageTracker); }; -// This class holds per-client usage tracking information and caches per-host -// usage data. An instance of this class is created per client. -class ClientUsageTracker : public SpecialStoragePolicy::Observer, - public base::NonThreadSafe, - public base::SupportsWeakPtr<ClientUsageTracker> { - public: - typedef base::Callback<void(int64 limited_usage, - int64 unlimited_usage)> HostUsageAccumulator; - typedef base::Callback<void(const GURL& origin, - int64 usage)> OriginUsageAccumulator; - typedef std::map<std::string, std::set<GURL> > OriginSetByHost; - - ClientUsageTracker(UsageTracker* tracker, - QuotaClient* client, - StorageType type, - SpecialStoragePolicy* special_storage_policy, - StorageMonitor* storage_monitor); - ~ClientUsageTracker() override; - - void GetGlobalLimitedUsage(const UsageCallback& callback); - void GetGlobalUsage(const GlobalUsageCallback& callback); - void GetHostUsage(const std::string& host, const UsageCallback& callback); - void UpdateUsageCache(const GURL& origin, int64 delta); - void GetCachedHostsUsage(std::map<std::string, int64>* host_usage) const; - void GetCachedOrigins(std::set<GURL>* origins) const; - int64 GetCachedOriginsUsage(const std::set<GURL>& origins, - std::vector<GURL>* origins_not_in_cache); - bool IsUsageCacheEnabledForOrigin(const GURL& origin) const; - void SetUsageCacheEnabled(const GURL& origin, bool enabled); - - private: - typedef CallbackQueueMap<HostUsageAccumulator, std::string, - Tuple2<int64, int64> > HostUsageAccumulatorMap; - - typedef std::set<std::string> HostSet; - typedef std::map<GURL, int64> UsageMap; - typedef std::map<std::string, UsageMap> HostUsageMap; - - struct AccumulateInfo { - int pending_jobs; - int64 limited_usage; - int64 unlimited_usage; - - AccumulateInfo() - : pending_jobs(0), limited_usage(0), unlimited_usage(0) {} - }; - - void AccumulateLimitedOriginUsage(AccumulateInfo* info, - const UsageCallback& callback, - int64 usage); - void DidGetOriginsForGlobalUsage(const GlobalUsageCallback& callback, - const std::set<GURL>& origins); - void AccumulateHostUsage(AccumulateInfo* info, - const GlobalUsageCallback& callback, - int64 limited_usage, - int64 unlimited_usage); - - void DidGetOriginsForHostUsage(const std::string& host, - const std::set<GURL>& origins); - - void GetUsageForOrigins(const std::string& host, - const std::set<GURL>& origins); - void AccumulateOriginUsage(AccumulateInfo* info, - const std::string& host, - const GURL& origin, - int64 usage); - - void DidGetHostUsageAfterUpdate(const GURL& origin, int64 usage); - - // Methods used by our GatherUsage tasks, as a task makes progress - // origins and hosts are added incrementally to the cache. - void AddCachedOrigin(const GURL& origin, int64 usage); - void AddCachedHost(const std::string& host); - - int64 GetCachedHostUsage(const std::string& host) const; - int64 GetCachedGlobalUnlimitedUsage(); - bool GetCachedOriginUsage(const GURL& origin, int64* usage) const; - - // SpecialStoragePolicy::Observer overrides - void OnGranted(const GURL& origin, int change_flags) override; - void OnRevoked(const GURL& origin, int change_flags) override; - void OnCleared() override; - - bool IsStorageUnlimited(const GURL& origin) const; - - UsageTracker* tracker_; - QuotaClient* client_; - const StorageType type_; - StorageMonitor* storage_monitor_; - - int64 global_limited_usage_; - int64 global_unlimited_usage_; - bool global_usage_retrieved_; - HostSet cached_hosts_; - HostUsageMap cached_usage_by_host_; - - OriginSetByHost non_cached_limited_origins_by_host_; - OriginSetByHost non_cached_unlimited_origins_by_host_; - - GlobalUsageCallbackQueue global_usage_callback_; - HostUsageAccumulatorMap host_usage_accumulators_; - - scoped_refptr<SpecialStoragePolicy> special_storage_policy_; - - DISALLOW_COPY_AND_ASSIGN(ClientUsageTracker); -}; - } // namespace storage #endif // STORAGE_BROWSER_QUOTA_USAGE_TRACKER_H_ diff --git a/storage/storage_browser.gyp b/storage/storage_browser.gyp index 272283c..2ec504f 100644 --- a/storage/storage_browser.gyp +++ b/storage/storage_browser.gyp @@ -149,6 +149,8 @@ 'browser/fileapi/timed_task_helper.h', 'browser/fileapi/transient_file_util.cc', 'browser/fileapi/transient_file_util.h', + 'browser/quota/client_usage_tracker.cc', + 'browser/quota/client_usage_tracker.h', 'browser/quota/quota_callbacks.h', 'browser/quota/quota_client.h', 'browser/quota/quota_database.cc', |