From 9c79f8034ba1029a359be35be1ef0f95bcf72647 Mon Sep 17 00:00:00 2001 From: calamity Date: Mon, 19 Oct 2015 17:24:42 -0700 Subject: Add Quota.TimeSinceOriginEvicted UMA histogram. This CL adds a UMA histogram that tracks the amount of time since an origin last had its temporary storage evicted. The last eviction time data is stored by adding a table to the QuotaManager database which tracks the last eviction time for an origin. BUG=542075 Review URL: https://codereview.chromium.org/1403673002 Cr-Commit-Position: refs/heads/master@{#354932} --- storage/browser/quota/quota_database.cc | 115 ++++++++++++++++++++++++++++---- storage/browser/quota/quota_database.h | 8 +++ storage/browser/quota/quota_manager.cc | 92 +++++++++++++++++-------- storage/browser/quota/quota_manager.h | 12 +++- 4 files changed, 183 insertions(+), 44 deletions(-) (limited to 'storage') diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc index aff5602..f1fefb6 100644 --- a/storage/browser/quota/quota_database.cc +++ b/storage/browser/quota/quota_database.cc @@ -21,11 +21,12 @@ namespace { // Definitions for database schema. -const int kCurrentVersion = 4; +const int kCurrentVersion = 5; const int kCompatibleVersion = 2; const char kHostQuotaTable[] = "HostQuotaTable"; const char kOriginInfoTable[] = "OriginInfoTable"; +const char kEvictionInfoTable[] = "EvictionInfoTable"; const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped"; bool VerifyValidQuotaConfig(const char* key) { @@ -62,19 +63,23 @@ const char QuotaDatabase::kTemporaryQuotaOverrideKey[] = "TemporaryQuotaOverride"; const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = { - { kHostQuotaTable, - "(host TEXT NOT NULL," - " type INTEGER NOT NULL," - " quota INTEGER DEFAULT 0," - " UNIQUE(host, type))" }, - { kOriginInfoTable, - "(origin TEXT NOT NULL," - " type INTEGER NOT NULL," - " used_count INTEGER DEFAULT 0," - " last_access_time INTEGER DEFAULT 0," - " last_modified_time INTEGER DEFAULT 0," - " UNIQUE(origin, type))" }, -}; + {kHostQuotaTable, + "(host TEXT NOT NULL," + " type INTEGER NOT NULL," + " quota INTEGER DEFAULT 0," + " UNIQUE(host, type))"}, + {kOriginInfoTable, + "(origin TEXT NOT NULL," + " type INTEGER NOT NULL," + " used_count INTEGER DEFAULT 0," + " last_access_time INTEGER DEFAULT 0," + " last_modified_time INTEGER DEFAULT 0," + " UNIQUE(origin, type))"}, + {kEvictionInfoTable, + "(origin TEXT NOT NULL," + " type INTEGER NOT NULL," + " last_eviction_time INTEGER DEFAULT 0," + " UNIQUE(origin, type))"}}; // static const QuotaDatabase::IndexSchema QuotaDatabase::kIndexes[] = { @@ -264,6 +269,71 @@ bool QuotaDatabase::SetOriginLastModifiedTime( return true; } +bool QuotaDatabase::GetOriginLastEvictionTime(const GURL& origin, + StorageType type, + base::Time* last_modified_time) { + DCHECK(last_modified_time); + if (!LazyOpen(false)) + return false; + + const char kSql[] = + "SELECT last_eviction_time" + " FROM EvictionInfoTable" + " WHERE origin = ? AND type = ?"; + + sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); + statement.BindString(0, origin.spec()); + statement.BindInt(1, static_cast(type)); + + if (!statement.Step()) + return statement.Succeeded(); + + *last_modified_time = base::Time::FromInternalValue(statement.ColumnInt64(0)); + return true; +} + +bool QuotaDatabase::SetOriginLastEvictionTime(const GURL& origin, + StorageType type, + base::Time last_modified_time) { + if (!LazyOpen(true)) + return false; + + const char kSql[] = + "INSERT OR REPLACE INTO EvictionInfoTable" + " (last_eviction_time, origin, type)" + " VALUES (?, ?, ?)"; + sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); + statement.BindInt64(0, last_modified_time.ToInternalValue()); + statement.BindString(1, origin.spec()); + statement.BindInt(2, static_cast(type)); + + if (!statement.Run()) + return false; + + ScheduleCommit(); + return true; +} + +bool QuotaDatabase::DeleteOriginLastEvictionTime(const GURL& origin, + StorageType type) { + if (!LazyOpen(false)) + return false; + + const char kSql[] = + "DELETE FROM EvictionInfoTable" + " WHERE origin = ? AND type = ?"; + + sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql)); + statement.BindString(0, origin.spec()); + statement.BindInt(1, static_cast(type)); + + if (!statement.Run()) + return false; + + ScheduleCommit(); + return true; +} + bool QuotaDatabase::RegisterInitialOriginInfo( const std::set& origins, StorageType type) { if (!LazyOpen(true)) @@ -617,6 +687,23 @@ bool QuotaDatabase::UpgradeSchema(int current_version) { return false; } Commit(); + + return true; + } else if (current_version < 5) { + const QuotaDatabase::TableSchema& eviction_table_schema = kTables[2]; + DCHECK_EQ(strcmp(kEvictionInfoTable, eviction_table_schema.table_name), 0); + + std::string sql("CREATE TABLE "); + sql += eviction_table_schema.table_name; + sql += eviction_table_schema.columns; + if (!db_->Execute(sql.c_str())) { + VLOG(1) << "Failed to execute " << sql; + return false; + } + + meta_table_->SetVersionNumber(5); + Commit(); + return true; } return false; diff --git a/storage/browser/quota/quota_database.h b/storage/browser/quota/quota_database.h index 02a76fc..09e90b3 100644 --- a/storage/browser/quota/quota_database.h +++ b/storage/browser/quota/quota_database.h @@ -58,6 +58,14 @@ class STORAGE_EXPORT_PRIVATE QuotaDatabase { StorageType type, base::Time last_modified_time); + bool GetOriginLastEvictionTime(const GURL& origin, + StorageType type, + base::Time* last_eviction_time); + bool SetOriginLastEvictionTime(const GURL& origin, + StorageType type, + base::Time last_eviction_time); + bool DeleteOriginLastEvictionTime(const GURL& origin, StorageType type); + // Register initial |origins| info |type| to the database. // This method is assumed to be called only after the installation or // the database schema reset. diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index c2ccb26..3187621 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc @@ -74,6 +74,9 @@ int64 QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes; const int QuotaManager::kEvictionIntervalInMilliSeconds = 30 * kMinutesInMilliSeconds; +const char QuotaManager::kTimeBetweenRepeatedOriginEvictionsHistogram[] = + "Quota.TimeBetweenRepeatedOriginEvictions"; + // Heuristics: assuming average cloud server allows a few Gigs storage // on the server side and the storage needs to be shared for user data // and by multiple apps. @@ -153,9 +156,29 @@ bool GetLRUOriginOnDBThread(StorageType type, bool DeleteOriginInfoOnDBThread(const GURL& origin, StorageType type, + bool is_eviction, QuotaDatabase* database) { DCHECK(database); - return database->DeleteOriginInfo(origin, type); + if (!database->DeleteOriginInfo(origin, type)) + return false; + + // If the deletion is not due to an eviction, delete the entry in the eviction + // table as well due to privacy concerns. + if (!is_eviction) + return database->DeleteOriginLastEvictionTime(origin, type); + + base::Time last_eviction_time; + if (!database->GetOriginLastEvictionTime(origin, type, &last_eviction_time)) + return false; + + base::Time now = base::Time::Now(); + if (last_eviction_time != base::Time()) { + UMA_HISTOGRAM_LONG_TIMES( + QuotaManager::kTimeBetweenRepeatedOriginEvictionsHistogram, + now - last_eviction_time); + } + + return database->SetOriginLastEvictionTime(origin, type, now); } bool InitializeTemporaryOriginsInfoOnDBThread(const std::set* origins, @@ -551,6 +574,7 @@ class QuotaManager::OriginDataDeleter : public QuotaTask { const GURL& origin, StorageType type, int quota_client_mask, + bool is_eviction, const StatusCallback& callback) : QuotaTask(manager), origin_(origin), @@ -559,6 +583,7 @@ class QuotaManager::OriginDataDeleter : public QuotaTask { error_count_(0), remaining_clients_(-1), skipped_clients_(0), + is_eviction_(is_eviction), callback_(callback), weak_factory_(this) {} @@ -588,7 +613,7 @@ class QuotaManager::OriginDataDeleter : public QuotaTask { // Only remove the entire origin if we didn't skip any client types. if (skipped_clients_ == 0) - manager()->DeleteOriginFromDatabase(origin_, type_); + manager()->DeleteOriginFromDatabase(origin_, type_, is_eviction_); callback_.Run(kQuotaStatusOk); } else { // crbug.com/349708 @@ -625,6 +650,7 @@ class QuotaManager::OriginDataDeleter : public QuotaTask { int error_count_; int remaining_clients_; int skipped_clients_; + bool is_eviction_; StatusCallback callback_; base::WeakPtrFactory weak_factory_; @@ -700,11 +726,10 @@ class QuotaManager::HostDataDeleter : public QuotaTask { for (std::set::const_iterator p = origins_.begin(); p != origins_.end(); ++p) { - OriginDataDeleter* deleter = - new OriginDataDeleter( - manager(), *p, type_, quota_client_mask_, - base::Bind(&HostDataDeleter::DidDeleteOriginData, - weak_factory_.GetWeakPtr())); + OriginDataDeleter* deleter = new OriginDataDeleter( + manager(), *p, type_, quota_client_mask_, false, + base::Bind(&HostDataDeleter::DidDeleteOriginData, + weak_factory_.GetWeakPtr())); deleter->Start(); } } @@ -959,20 +984,11 @@ void QuotaManager::SetTemporaryStorageEvictionPolicy( temporary_storage_eviction_policy_ = policy.Pass(); } -void QuotaManager::DeleteOriginData( - const GURL& origin, StorageType type, int quota_client_mask, - const StatusCallback& callback) { - LazyInitialize(); - - if (origin.is_empty() || clients_.empty()) { - callback.Run(kQuotaStatusOk); - return; - } - - DCHECK(origin == origin.GetOrigin()); - OriginDataDeleter* deleter = - new OriginDataDeleter(this, origin, type, quota_client_mask, callback); - deleter->Start(); +void QuotaManager::DeleteOriginData(const GURL& origin, + StorageType type, + int quota_client_mask, + const StatusCallback& callback) { + DeleteOriginDataInternal(origin, type, quota_client_mask, false, callback); } void QuotaManager::DeleteHostData(const std::string& host, @@ -1390,17 +1406,17 @@ void QuotaManager::StartEviction() { temporary_storage_evictor_->Start(); } -void QuotaManager::DeleteOriginFromDatabase( - const GURL& origin, StorageType type) { +void QuotaManager::DeleteOriginFromDatabase(const GURL& origin, + StorageType type, + bool is_eviction) { LazyInitialize(); if (db_disabled_) return; PostTaskAndReplyWithResultForDBThread( FROM_HERE, - base::Bind(&DeleteOriginInfoOnDBThread, origin, type), - base::Bind(&QuotaManager::DidDatabaseWork, - weak_factory_.GetWeakPtr())); + base::Bind(&DeleteOriginInfoOnDBThread, origin, type, is_eviction), + base::Bind(&QuotaManager::DidDatabaseWork, weak_factory_.GetWeakPtr())); } void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status) { @@ -1417,6 +1433,24 @@ void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status) { eviction_context_.evict_origin_data_callback.Reset(); } +void QuotaManager::DeleteOriginDataInternal(const GURL& origin, + StorageType type, + int quota_client_mask, + bool is_eviction, + const StatusCallback& callback) { + LazyInitialize(); + + if (origin.is_empty() || clients_.empty()) { + callback.Run(kQuotaStatusOk); + return; + } + + DCHECK(origin == origin.GetOrigin()); + OriginDataDeleter* deleter = new OriginDataDeleter( + this, origin, type, quota_client_mask, is_eviction, callback); + deleter->Start(); +} + void QuotaManager::ReportHistogram() { GetGlobalUsage(kStorageTypeTemporary, base::Bind( @@ -1521,9 +1555,9 @@ void QuotaManager::EvictOriginData(const GURL& origin, eviction_context_.evicted_type = type; eviction_context_.evict_origin_data_callback = callback; - DeleteOriginData(origin, type, QuotaClient::kAllClientsMask, - base::Bind(&QuotaManager::DidOriginDataEvicted, - weak_factory_.GetWeakPtr())); + DeleteOriginDataInternal(origin, type, QuotaClient::kAllClientsMask, true, + base::Bind(&QuotaManager::DidOriginDataEvicted, + weak_factory_.GetWeakPtr())); } void QuotaManager::GetUsageAndQuotaForEviction( diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h index 0e4884b..5780cbb 100644 --- a/storage/browser/quota/quota_manager.h +++ b/storage/browser/quota/quota_manager.h @@ -275,6 +275,8 @@ class STORAGE_EXPORT QuotaManager static const int kEvictionIntervalInMilliSeconds; + static const char kTimeBetweenRepeatedOriginEvictionsHistogram[]; + // These are kept non-const so that test code can change the value. // TODO(kinuko): Make this a real const value and add a proper way to set // the quota for syncable storage. (http://crbug.com/155488) @@ -371,9 +373,17 @@ class STORAGE_EXPORT QuotaManager void DumpQuotaTable(const DumpQuotaTableCallback& callback); void DumpOriginInfoTable(const DumpOriginInfoTableCallback& callback); + void DeleteOriginDataInternal(const GURL& origin, + StorageType type, + int quota_client_mask, + bool is_eviction, + const StatusCallback& callback); + // Methods for eviction logic. void StartEviction(); - void DeleteOriginFromDatabase(const GURL& origin, StorageType type); + void DeleteOriginFromDatabase(const GURL& origin, + StorageType type, + bool is_eviction); void DidOriginDataEvicted(QuotaStatusCode status); -- cgit v1.1