// Copyright 2013 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/usage_tracker.h" #include #include "base/bind.h" #include "base/stl_util.h" #include "storage/browser/quota/client_usage_tracker.h" #include "storage/browser/quota/storage_monitor.h" namespace storage { namespace { void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback, int64 total_global_usage, int64 global_unlimited_usage) { callback.Run(total_global_usage - global_unlimited_usage); } } // namespace UsageTracker::UsageTracker(const QuotaClientList& clients, StorageType type, SpecialStoragePolicy* special_storage_policy, StorageMonitor* storage_monitor) : type_(type), storage_monitor_(storage_monitor), weak_factory_(this) { for (const auto& client : clients) { if (client->DoesSupport(type)) { client_tracker_map_[client->id()] = new ClientUsageTracker(this, client, type, special_storage_policy, storage_monitor_); } } } UsageTracker::~UsageTracker() { STLDeleteValues(&client_tracker_map_); } ClientUsageTracker* UsageTracker::GetClientTracker(QuotaClient::ID client_id) { ClientTrackerMap::iterator found = client_tracker_map_.find(client_id); if (found != client_tracker_map_.end()) return found->second; return nullptr; } void UsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) { if (global_usage_callbacks_.HasCallbacks()) { global_usage_callbacks_.Add(base::Bind( &DidGetGlobalUsageForLimitedGlobalUsage, callback)); return; } if (!global_limited_usage_callbacks_.Add(callback)) return; AccumulateInfo* info = new AccumulateInfo; // Calling GetGlobalLimitedUsage(accumulator) may synchronously // return if the usage is cached, which may in turn dispatch // the completion callback before we finish looping over // all clients (because info->pending_clients may reach 0 // during the loop). // To avoid this, we add one more pending client as a sentinel // and fire the sentinel callback at the end. info->pending_clients = client_tracker_map_.size() + 1; UsageCallback accumulator = base::Bind( &UsageTracker::AccumulateClientGlobalLimitedUsage, weak_factory_.GetWeakPtr(), base::Owned(info)); for (const auto& client_id_and_tracker : client_tracker_map_) client_id_and_tracker.second->GetGlobalLimitedUsage(accumulator); // Fire the sentinel as we've now called GetGlobalUsage for all clients. accumulator.Run(0); } void UsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) { if (!global_usage_callbacks_.Add(callback)) return; AccumulateInfo* info = new AccumulateInfo; // Calling GetGlobalUsage(accumulator) may synchronously // return if the usage is cached, which may in turn dispatch // the completion callback before we finish looping over // all clients (because info->pending_clients may reach 0 // during the loop). // To avoid this, we add one more pending client as a sentinel // and fire the sentinel callback at the end. info->pending_clients = client_tracker_map_.size() + 1; GlobalUsageCallback accumulator = base::Bind( &UsageTracker::AccumulateClientGlobalUsage, weak_factory_.GetWeakPtr(), base::Owned(info)); for (const auto& client_id_and_tracker : client_tracker_map_) client_id_and_tracker.second->GetGlobalUsage(accumulator); // Fire the sentinel as we've now called GetGlobalUsage for all clients. accumulator.Run(0, 0); } void UsageTracker::GetHostUsage(const std::string& host, const UsageCallback& callback) { if (!host_usage_callbacks_.Add(host, callback)) return; AccumulateInfo* info = new AccumulateInfo; // Calling GetHostUsage(accumulator) may synchronously // return if the usage is cached, which may in turn dispatch // the completion callback before we finish looping over // all clients (because info->pending_clients may reach 0 // during the loop). // To avoid this, we add one more pending client as a sentinel // and fire the sentinel callback at the end. info->pending_clients = client_tracker_map_.size() + 1; UsageCallback accumulator = base::Bind( &UsageTracker::AccumulateClientHostUsage, weak_factory_.GetWeakPtr(), base::Owned(info), host); for (const auto& client_id_and_tracker : client_tracker_map_) client_id_and_tracker.second->GetHostUsage(host, accumulator); // Fire the sentinel as we've now called GetHostUsage for all clients. accumulator.Run(0); } void UsageTracker::UpdateUsageCache( QuotaClient::ID client_id, const GURL& origin, int64 delta) { ClientUsageTracker* client_tracker = GetClientTracker(client_id); DCHECK(client_tracker); client_tracker->UpdateUsageCache(origin, delta); } void UsageTracker::GetCachedHostsUsage( std::map* host_usage) const { DCHECK(host_usage); host_usage->clear(); for (const auto& client_id_and_tracker : client_tracker_map_) client_id_and_tracker.second->GetCachedHostsUsage(host_usage); } void UsageTracker::GetCachedOrigins(std::set* origins) const { DCHECK(origins); origins->clear(); for (const auto& client_id_and_tracker : client_tracker_map_) client_id_and_tracker.second->GetCachedOrigins(origins); } void UsageTracker::SetUsageCacheEnabled(QuotaClient::ID client_id, const GURL& origin, bool enabled) { ClientUsageTracker* client_tracker = GetClientTracker(client_id); DCHECK(client_tracker); client_tracker->SetUsageCacheEnabled(origin, enabled); } void UsageTracker::AccumulateClientGlobalLimitedUsage(AccumulateInfo* info, int64 limited_usage) { info->usage += limited_usage; if (--info->pending_clients) return; // All the clients have returned their usage data. Dispatch the // pending callbacks. global_limited_usage_callbacks_.Run(info->usage); } void UsageTracker::AccumulateClientGlobalUsage(AccumulateInfo* info, int64 usage, int64 unlimited_usage) { info->usage += usage; info->unlimited_usage += unlimited_usage; if (--info->pending_clients) return; // Defend against confusing inputs from clients. if (info->usage < 0) info->usage = 0; // TODO(michaeln): The unlimited number is not trustworthy, it // can get out of whack when apps are installed or uninstalled. if (info->unlimited_usage > info->usage) info->unlimited_usage = info->usage; else if (info->unlimited_usage < 0) info->unlimited_usage = 0; // All the clients have returned their usage data. Dispatch the // pending callbacks. global_usage_callbacks_.Run(info->usage, info->unlimited_usage); } void UsageTracker::AccumulateClientHostUsage(AccumulateInfo* info, const std::string& host, int64 usage) { info->usage += usage; if (--info->pending_clients) return; // Defend against confusing inputs from clients. if (info->usage < 0) info->usage = 0; // All the clients have returned their usage data. Dispatch the // pending callbacks. host_usage_callbacks_.Run(host, info->usage); } } // namespace storage