[go: nahoru, domu]

blob: b8e4dd06b2098da3407c602a3aaf03a0f36492c9 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// 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 <stdint.h>
#include <algorithm>
#include <memory>
#include "base/barrier_closure.h"
#include "base/functional/bind.h"
#include "components/services/storage/public/cpp/buckets/constants.h"
#include "storage/browser/quota/client_usage_tracker.h"
#include "storage/browser/quota/quota_client_type.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
namespace storage {
struct UsageTracker::AccumulateInfo {
int64_t usage = 0;
int64_t unlimited_usage = 0;
blink::mojom::UsageBreakdownPtr usage_breakdown =
blink::mojom::UsageBreakdown::New();
};
UsageTracker::UsageTracker(
QuotaManagerImpl* quota_manager_impl,
const base::flat_map<mojom::QuotaClient*, QuotaClientType>& client_types,
blink::mojom::StorageType type,
scoped_refptr<SpecialStoragePolicy> special_storage_policy)
: quota_manager_impl_(quota_manager_impl), type_(type) {
DCHECK(quota_manager_impl_);
for (const auto& client_and_type : client_types) {
mojom::QuotaClient* client = client_and_type.first;
QuotaClientType client_type = client_and_type.second;
auto [it, inserted] = client_tracker_map_.insert(std::make_pair(
client_type, std::make_unique<ClientUsageTracker>(
this, client, type, special_storage_policy)));
CHECK(inserted);
}
}
UsageTracker::~UsageTracker() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void UsageTracker::GetGlobalUsage(UsageCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
global_usage_callbacks_.emplace_back(std::move(callback));
if (global_usage_callbacks_.size() > 1)
return;
quota_manager_impl_->GetBucketsForType(
type_, base::BindOnce(&UsageTracker::DidGetBucketsForType,
weak_factory_.GetWeakPtr()));
}
void UsageTracker::GetStorageKeyUsageWithBreakdown(
const blink::StorageKey& storage_key,
UsageWithBreakdownCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<UsageWithBreakdownCallback>& storage_key_callbacks =
storage_key_usage_callbacks_[storage_key];
storage_key_callbacks.emplace_back(std::move(callback));
if (storage_key_callbacks.size() > 1)
return;
quota_manager_impl_->GetBucketsForStorageKey(
storage_key, type_,
base::BindOnce(&UsageTracker::DidGetBucketsForStorageKey,
weak_factory_.GetWeakPtr(), storage_key));
}
void UsageTracker::GetBucketUsageWithBreakdown(
const BucketLocator& bucket,
UsageWithBreakdownCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(bucket.id);
std::vector<UsageWithBreakdownCallback>& bucket_callbacks =
bucket_usage_callbacks_[bucket];
bucket_callbacks.emplace_back(std::move(callback));
if (bucket_callbacks.size() > 1)
return;
auto info = std::make_unique<AccumulateInfo>();
auto* info_ptr = info.get();
base::RepeatingClosure barrier = base::BarrierClosure(
client_tracker_map_.size(),
base::BindOnce(&UsageTracker::FinallySendBucketUsageWithBreakdown,
weak_factory_.GetWeakPtr(), std::move(info), bucket));
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
client_tracker->GetBucketsUsage(
{bucket},
// base::Unretained usage is safe here because BarrierClosure holds
// the std::unque_ptr that keeps AccumulateInfo alive, and the
// BarrierClosure will outlive all the AccumulateClientGlobalUsage
// closures.
base::BindOnce(&UsageTracker::AccumulateClientUsageWithBreakdown,
weak_factory_.GetWeakPtr(), barrier,
base::Unretained(info_ptr), client_type));
}
}
void UsageTracker::UpdateBucketUsageCache(QuotaClientType client_type,
const BucketLocator& bucket,
absl::optional<int64_t> delta) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
GetClient(client_type).UpdateBucketUsageCache(bucket, delta);
}
void UsageTracker::DeleteBucketCache(QuotaClientType client_type,
const BucketLocator& bucket) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(bucket.type, type_);
GetClient(client_type).DeleteBucketCache(bucket);
}
int64_t UsageTracker::GetCachedUsage() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
int64_t usage = 0;
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
usage += client_tracker->GetCachedUsage();
}
return usage;
}
std::map<std::string, int64_t> UsageTracker::GetCachedHostsUsage() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::map<std::string, int64_t> host_usage;
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
const ClientUsageTracker::BucketUsageMap& usage_map =
client_tracker->GetCachedBucketsUsage();
for (const auto& [bucket, usage] : usage_map) {
host_usage[bucket.storage_key.origin().host()] += usage;
}
}
return host_usage;
}
std::map<blink::StorageKey, int64_t> UsageTracker::GetCachedStorageKeysUsage()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::map<blink::StorageKey, int64_t> storage_key_usage;
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
const ClientUsageTracker::BucketUsageMap& usage_map =
client_tracker->GetCachedBucketsUsage();
for (const auto& [bucket, usage] : usage_map) {
storage_key_usage[bucket.storage_key] += usage;
}
}
return storage_key_usage;
}
std::map<BucketLocator, int64_t> UsageTracker::GetCachedBucketsUsage() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::map<BucketLocator, int64_t> aggregated_usage;
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
const ClientUsageTracker::BucketUsageMap& usage_map =
client_tracker->GetCachedBucketsUsage();
for (const auto& [bucket, usage] : usage_map) {
aggregated_usage[bucket] += usage;
}
}
return aggregated_usage;
}
void UsageTracker::SetUsageCacheEnabled(QuotaClientType client_type,
const blink::StorageKey& storage_key,
bool enabled) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
GetClient(client_type).SetUsageCacheEnabled(storage_key, enabled);
}
void UsageTracker::DidGetBucketsForType(
QuotaErrorOr<std::set<BucketInfo>> result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto info = std::make_unique<AccumulateInfo>();
if (!result.has_value()) {
// Return with invalid values on error.
info->usage = -1;
info->unlimited_usage = -1;
FinallySendGlobalUsage(std::move(info));
return;
}
const std::set<BucketInfo>& buckets = result.value();
if (buckets.empty()) {
FinallySendGlobalUsage(std::move(info));
return;
}
std::set<BucketLocator> bucket_locators =
BucketInfosToBucketLocators(buckets);
auto* info_ptr = info.get();
base::RepeatingClosure barrier = base::BarrierClosure(
client_tracker_map_.size(),
base::BindOnce(&UsageTracker::FinallySendGlobalUsage,
weak_factory_.GetWeakPtr(), std::move(info)));
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
client_tracker->GetBucketsUsage(
bucket_locators,
// base::Unretained usage is safe here because BarrierClosure holds
// the std::unque_ptr that keeps AccumulateInfo alive, and the
// BarrierClosure will outlive all the AccumulateClientGlobalUsage
// closures.
base::BindOnce(&UsageTracker::AccumulateClientGlobalUsage,
weak_factory_.GetWeakPtr(), barrier,
base::Unretained(info_ptr)));
}
}
void UsageTracker::DidGetBucketsForStorageKey(
const blink::StorageKey& storage_key,
QuotaErrorOr<std::set<BucketInfo>> result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto info = std::make_unique<AccumulateInfo>();
if (!result.has_value()) {
// Return with invalid values on error.
info->usage = -1;
info->unlimited_usage = -1;
FinallySendStorageKeyUsageWithBreakdown(std::move(info), storage_key);
return;
}
const std::set<BucketInfo>& buckets = result.value();
if (buckets.empty()) {
FinallySendStorageKeyUsageWithBreakdown(std::move(info), storage_key);
return;
}
std::set<BucketLocator> bucket_locators =
BucketInfosToBucketLocators(buckets);
auto* info_ptr = info.get();
base::RepeatingClosure barrier = base::BarrierClosure(
client_tracker_map_.size(),
base::BindOnce(&UsageTracker::FinallySendStorageKeyUsageWithBreakdown,
weak_factory_.GetWeakPtr(), std::move(info), storage_key));
for (const auto& [client_type, client_tracker] : client_tracker_map_) {
client_tracker->GetBucketsUsage(
bucket_locators,
// base::Unretained usage is safe here because BarrierClosure holds
// the std::unque_ptr that keeps AccumulateInfo alive, and the
// BarrierClosure will outlive all the AccumulateClientGlobalUsage
// closures.
base::BindOnce(&UsageTracker::AccumulateClientUsageWithBreakdown,
weak_factory_.GetWeakPtr(), barrier,
base::Unretained(info_ptr), client_type));
}
}
void UsageTracker::AccumulateClientGlobalUsage(
base::OnceClosure barrier_callback,
AccumulateInfo* info,
int64_t total_usage,
int64_t unlimited_usage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GE(unlimited_usage, 0);
DCHECK_GE(total_usage, unlimited_usage);
info->usage += total_usage;
info->unlimited_usage += unlimited_usage;
std::move(barrier_callback).Run();
}
void UsageTracker::AccumulateClientUsageWithBreakdown(
base::OnceClosure barrier_callback,
AccumulateInfo* info,
QuotaClientType client,
int64_t total_usage,
int64_t unlimited_usage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GE(unlimited_usage, 0);
DCHECK_GE(total_usage, unlimited_usage);
info->usage += total_usage;
switch (client) {
case QuotaClientType::kFileSystem:
info->usage_breakdown->fileSystem += total_usage;
break;
case QuotaClientType::kDatabase:
info->usage_breakdown->webSql += total_usage;
break;
case QuotaClientType::kIndexedDatabase:
info->usage_breakdown->indexedDatabase += total_usage;
break;
case QuotaClientType::kServiceWorkerCache:
info->usage_breakdown->serviceWorkerCache += total_usage;
break;
case QuotaClientType::kServiceWorker:
info->usage_breakdown->serviceWorker += total_usage;
break;
case QuotaClientType::kBackgroundFetch:
info->usage_breakdown->backgroundFetch += total_usage;
break;
case QuotaClientType::kMediaLicense:
// Media license data does not count against quota and should always
// report 0 usage.
// TODO(crbug.com/1305441): Consider counting media license data against
// quota.
DCHECK_EQ(total_usage, 0);
break;
}
std::move(barrier_callback).Run();
}
void UsageTracker::FinallySendGlobalUsage(
std::unique_ptr<AccumulateInfo> info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GE(info->unlimited_usage, -1);
DCHECK_GE(info->usage, info->unlimited_usage);
// Moving callbacks out of the original vector early handles the case where a
// callback makes a new quota call.
std::vector<UsageCallback> pending_callbacks;
pending_callbacks.swap(global_usage_callbacks_);
for (auto& callback : pending_callbacks)
std::move(callback).Run(info->usage, info->unlimited_usage);
}
void UsageTracker::FinallySendStorageKeyUsageWithBreakdown(
std::unique_ptr<AccumulateInfo> info,
const blink::StorageKey& storage_key) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = storage_key_usage_callbacks_.find(storage_key);
if (it == storage_key_usage_callbacks_.end())
return;
std::vector<UsageWithBreakdownCallback> pending_callbacks;
pending_callbacks.swap(it->second);
DCHECK(pending_callbacks.size() > 0) << "storage_key_usage_callbacks_ should "
"only have non-empty callback lists";
storage_key_usage_callbacks_.erase(it);
for (auto& callback : pending_callbacks)
std::move(callback).Run(info->usage, info->usage_breakdown->Clone());
}
void UsageTracker::FinallySendBucketUsageWithBreakdown(
std::unique_ptr<AccumulateInfo> info,
const BucketLocator& bucket) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = bucket_usage_callbacks_.find(bucket);
if (it == bucket_usage_callbacks_.end())
return;
std::vector<UsageWithBreakdownCallback> pending_callbacks;
pending_callbacks.swap(it->second);
DCHECK(pending_callbacks.size() > 0)
<< "bucket_usage_callbacks_ should only have non-empty callback lists";
bucket_usage_callbacks_.erase(it);
for (auto& callback : pending_callbacks)
std::move(callback).Run(info->usage, info->usage_breakdown->Clone());
}
ClientUsageTracker& UsageTracker::GetClient(QuotaClientType type) {
auto iter = client_tracker_map_.find(type);
CHECK(iter != client_tracker_map_.end());
return *iter->second;
}
} // namespace storage