diff options
author | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-31 13:36:25 +0000 |
---|---|---|
committer | dmikurube@chromium.org <dmikurube@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-31 13:36:25 +0000 |
commit | 4576fb4ad01115b612efd9c96df9c90d2d042e0c (patch) | |
tree | 83c7f7cc87e6342cc42c9d758b066ca07d44ad7e /webkit/quota | |
parent | 45267a9d51bd55c66f60c0662aec66a7a4f1db6a (diff) | |
download | chromium_src-4576fb4ad01115b612efd9c96df9c90d2d042e0c.zip chromium_src-4576fb4ad01115b612efd9c96df9c90d2d042e0c.tar.gz chromium_src-4576fb4ad01115b612efd9c96df9c90d2d042e0c.tar.bz2 |
Add eviction statistics.
BUG=61676
TEST=QuotaTemporaryStorageEvictorTest.*
Review URL: http://codereview.chromium.org/7065022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@87300 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/quota')
-rw-r--r-- | webkit/quota/quota_manager.cc | 14 | ||||
-rw-r--r-- | webkit/quota/quota_manager.h | 2 | ||||
-rw-r--r-- | webkit/quota/quota_temporary_storage_evictor.cc | 75 | ||||
-rw-r--r-- | webkit/quota/quota_temporary_storage_evictor.h | 28 | ||||
-rw-r--r-- | webkit/quota/quota_temporary_storage_evictor_unittest.cc | 139 |
5 files changed, 243 insertions, 15 deletions
diff --git a/webkit/quota/quota_manager.cc b/webkit/quota/quota_manager.cc index dc530eb..2d89d5a 100644 --- a/webkit/quota/quota_manager.cc +++ b/webkit/quota/quota_manager.cc @@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/message_loop_proxy.h" #include "base/stl_util-inl.h" +#include "base/string_number_conversions.h" #include "base/sys_info.h" #include "net/base/net_util.h" #include "webkit/quota/quota_database.h" @@ -937,6 +938,19 @@ void QuotaManager::GetHostUsage(const std::string& host, StorageType type, GetUsageTracker(type)->GetHostUsage(host, callback); } +void QuotaManager::GetStatistics( + std::map<std::string, std::string>* statistics) { + DCHECK(statistics); + if (temporary_storage_evictor_.get()) { + std::map<std::string, int64> stats; + temporary_storage_evictor_->GetStatistics(&stats); + for (std::map<std::string, int64>::iterator p = stats.begin(); + p != stats.end(); + ++p) + (*statistics)[p->first] = base::Int64ToString(p->second); + } +} + void QuotaManager::LazyInitialize() { DCHECK(io_thread_->BelongsToCurrentThread()); if (database_.get()) { diff --git a/webkit/quota/quota_manager.h b/webkit/quota/quota_manager.h index 706bec8..923cad7 100644 --- a/webkit/quota/quota_manager.h +++ b/webkit/quota/quota_manager.h @@ -134,6 +134,8 @@ class QuotaManager : public QuotaTaskObserver, void GetHostUsage(const std::string& host, StorageType type, HostUsageCallback* callback); + void GetStatistics(std::map<std::string, std::string>* statistics); + bool IsStorageUnlimited(const GURL& origin) const { return special_storage_policy_.get() && special_storage_policy_->IsStorageUnlimited(origin); diff --git a/webkit/quota/quota_temporary_storage_evictor.cc b/webkit/quota/quota_temporary_storage_evictor.cc index 16e88bc..e5240a8 100644 --- a/webkit/quota/quota_temporary_storage_evictor.cc +++ b/webkit/quota/quota_temporary_storage_evictor.cc @@ -9,9 +9,26 @@ namespace quota { +const char QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin[] = + "errors-on-evicting-origin"; +const char QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota[] = + "errors-on-getting-usage-and-quota"; +const char QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins[] = + "evicted-origins"; +const char QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds[] = + "eviction-rounds"; +const char QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds[] = + "skipped-eviction-rounds"; + const double QuotaTemporaryStorageEvictor::kUsageRatioToStartEviction = 0.7; const int64 QuotaTemporaryStorageEvictor:: kDefaultMinAvailableDiskSpaceToStartEviction = 1000 * 1000 * 500; +const int QuotaTemporaryStorageEvictor::kThresholdOfErrorsToStopEviction = 5; QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor( QuotaEvictionHandler* quota_eviction_handler, @@ -28,6 +45,22 @@ QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor( QuotaTemporaryStorageEvictor::~QuotaTemporaryStorageEvictor() { } +void QuotaTemporaryStorageEvictor::GetStatistics( + std::map<std::string, int64>* statistics) { + DCHECK(statistics); + + (*statistics)[std::string(kStatsLabelNumberOfErrorsOnEvictingOrigin)] = + statistics_.num_errors_on_evicting_origin; + (*statistics)[std::string(kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)] = + statistics_.num_errors_on_getting_usage_and_quota; + (*statistics)[std::string(kStatsLabelNumberOfEvictedOrigins)] = + statistics_.num_evicted_origins; + (*statistics)[std::string(kStatsLabelNumberOfEvictionRounds)] = + statistics_.num_eviction_rounds; + (*statistics)[std::string(kStatsLabelNumberOfSkippedEvictionRounds)] = + statistics_.num_skipped_eviction_rounds; +} + void QuotaTemporaryStorageEvictor::Start() { DCHECK(CalledOnValidThread()); StartEvictionTimerWithDelay(0); @@ -36,6 +69,8 @@ void QuotaTemporaryStorageEvictor::Start() { void QuotaTemporaryStorageEvictor::StartEvictionTimerWithDelay(int delay_ms) { if (timer_.IsRunning()) return; + num_evicted_origins_in_round_ = 0; + ++statistics_.num_eviction_rounds; timer_.Start(base::TimeDelta::FromMilliseconds(delay_ms), this, &QuotaTemporaryStorageEvictor::ConsiderEviction); } @@ -58,6 +93,9 @@ void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction( usage -= unlimited_usage; + if (status != kQuotaStatusOk) + ++statistics_.num_errors_on_getting_usage_and_quota; + if (status == kQuotaStatusOk && (usage > quota * kUsageRatioToStartEviction || min_available_disk_space_to_start_eviction_ > available_disk_space)) { @@ -69,11 +107,17 @@ void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction( &QuotaTemporaryStorageEvictor::OnGotLRUOrigin)); } else if (repeated_eviction_) { // No action required, sleep for a while and check again later. - // TODO(dmikurube): Stop repeating if error happens frequently. - StartEvictionTimerWithDelay(interval_ms_); + if (num_evicted_origins_in_round_ == 0) + ++statistics_.num_skipped_eviction_rounds; + if (statistics_.num_errors_on_getting_usage_and_quota < + kThresholdOfErrorsToStopEviction) + StartEvictionTimerWithDelay(interval_ms_); + else + // TODO(dmikurube): Try restarting eviction after a while. + LOG(WARNING) << "Stopped eviction of temporary storage due to errors " + "in GetUsageAndQuotaForEviction."; } - // TODO(dmikurube): Add stats on # of {error, eviction, skipped}. // TODO(dmikurube): Add error handling for the case status != kQuotaStatusOk. } @@ -95,13 +139,24 @@ void QuotaTemporaryStorageEvictor::OnEvictionComplete( QuotaStatusCode status) { DCHECK(CalledOnValidThread()); - // Just calling ConsiderEviction() here is ok. No need to deal with the - // case that all of the Delete operations fail for a certain origin. It - // doesn't result in trying to evict the same origin permanently. The - // evictor skips origins which had deletion errors a few times. - - // We many need to get rid of more space so reconsider immediately. - ConsiderEviction(); + // Just calling ConsiderEviction() or StartEvictionTimerWithDelay() here is + // ok. No need to deal with the case that all of the Delete operations fail + // for a certain origin. It doesn't result in trying to evict the same + // origin permanently. The evictor skips origins which had deletion errors + // a few times. + + if (status == kQuotaStatusOk) { + ++statistics_.num_evicted_origins; + ++num_evicted_origins_in_round_; + // We many need to get rid of more space so reconsider immediately. + ConsiderEviction(); + } else { + ++statistics_.num_errors_on_evicting_origin; + if (repeated_eviction_) { + // Sleep for a while and retry again until we see too many errors. + StartEvictionTimerWithDelay(interval_ms_); + } + } } } // namespace quota diff --git a/webkit/quota/quota_temporary_storage_evictor.h b/webkit/quota/quota_temporary_storage_evictor.h index 7bb1899..5c0e964 100644 --- a/webkit/quota/quota_temporary_storage_evictor.h +++ b/webkit/quota/quota_temporary_storage_evictor.h @@ -6,6 +6,9 @@ #define WEBKIT_QUOTA_QUOTA_TEMPORARY_STORAGE_EVICTOR_H_ #pragma once +#include <map> +#include <string> + #include "base/memory/scoped_callback_factory.h" #include "base/threading/non_thread_safe.h" #include "base/timer.h" @@ -23,13 +26,34 @@ class QuotaEvictionHandler; class QuotaTemporaryStorageEvictor : public base::NonThreadSafe { public: + struct Statistics { + Statistics() + : num_errors_on_evicting_origin(0), + num_errors_on_getting_usage_and_quota(0), + num_evicted_origins(0), + num_eviction_rounds(0), + num_skipped_eviction_rounds(0) {} + int64 num_errors_on_evicting_origin; + int64 num_errors_on_getting_usage_and_quota; + int64 num_evicted_origins; + int64 num_eviction_rounds; + int64 num_skipped_eviction_rounds; + }; + QuotaTemporaryStorageEvictor( QuotaEvictionHandler* quota_eviction_handler, int64 interval_ms); virtual ~QuotaTemporaryStorageEvictor(); + void GetStatistics(std::map<std::string, int64>* statistics); void Start(); + static const char kStatsLabelNumberOfErrorsOnEvictingOrigin[]; + static const char kStatsLabelNumberOfErrorsOnGettingUsageAndQuota[]; + static const char kStatsLabelNumberOfEvictedOrigins[]; + static const char kStatsLabelNumberOfEvictionRounds[]; + static const char kStatsLabelNumberOfSkippedEvictionRounds[]; + private: friend class QuotaTemporaryStorageEvictorTest; @@ -51,14 +75,18 @@ class QuotaTemporaryStorageEvictor : public base::NonThreadSafe { static const double kUsageRatioToStartEviction; static const int64 kDefaultMinAvailableDiskSpaceToStartEviction; + static const int kThresholdOfErrorsToStopEviction; const int64 min_available_disk_space_to_start_eviction_; // Not owned; quota_eviction_handler owns us. QuotaEvictionHandler* quota_eviction_handler_; + Statistics statistics_; + int64 interval_ms_; bool repeated_eviction_; + int num_evicted_origins_in_round_; base::OneShotTimer<QuotaTemporaryStorageEvictor> timer_; diff --git a/webkit/quota/quota_temporary_storage_evictor_unittest.cc b/webkit/quota/quota_temporary_storage_evictor_unittest.cc index 59933e0..3786c34 100644 --- a/webkit/quota/quota_temporary_storage_evictor_unittest.cc +++ b/webkit/quota/quota_temporary_storage_evictor_unittest.cc @@ -27,12 +27,19 @@ class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler { : quota_(0), unlimited_usage_(0), available_space_(0), + error_on_evict_origin_data_(false), + error_on_get_usage_and_quota_(false), test_(test) {} virtual void EvictOriginData( const GURL& origin, StorageType type, EvictOriginDataCallback* callback) OVERRIDE { + if (error_on_evict_origin_data_) { + callback->Run(quota::kQuotaErrorInvalidModification); + delete callback; + return; + } int64 origin_usage = EnsureOriginRemoved(origin); if (origin_usage >= 0) available_space_ += origin_usage; @@ -42,6 +49,11 @@ class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler { virtual void GetUsageAndQuotaForEviction( GetUsageAndQuotaForEvictionCallback* callback) OVERRIDE { + if (error_on_get_usage_and_quota_) { + callback->Run(quota::kQuotaErrorInvalidAccess, 0, 0, 0, 0); + delete callback; + return; + } if (task_for_get_usage_and_quota_.get()) task_for_get_usage_and_quota_->Run(); callback->Run(quota::kQuotaStatusOk, GetUsage(), unlimited_usage_, @@ -80,6 +92,12 @@ class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler { void set_task_for_get_usage_and_quota(CancelableTask* task) { task_for_get_usage_and_quota_.reset(task); } + void set_error_on_evict_origin_data(bool error_on_evict_origin_data) { + error_on_evict_origin_data_ = error_on_evict_origin_data; + } + void set_error_on_get_usage_and_quota(bool error_on_get_usage_and_quota) { + error_on_get_usage_and_quota_ = error_on_get_usage_and_quota; + } // Simulates an access to |origin|. It reorders the internal LRU list. // It internally uses AddOrigin(). @@ -116,6 +134,8 @@ class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler { int64 available_space_; std::list<GURL> origin_order_; std::map<GURL, int64> origins_; + bool error_on_evict_origin_data_; + bool error_on_get_usage_and_quota_; QuotaTemporaryStorageEvictorTest *test_; scoped_ptr<CancelableTask> task_for_get_usage_and_quota_; @@ -148,16 +168,18 @@ class QuotaTemporaryStorageEvictorTest : public testing::Test { const GURL& origin_to_be_accessed, int expected_usage_after_first, int expected_usage_after_second) { + EXPECT_GE(4, num_get_usage_and_quota_for_eviction_); switch (num_get_usage_and_quota_for_eviction_) { - case 1: + case 2: EXPECT_EQ(expected_usage_after_first, quota_eviction_handler()->GetUsage()); - quota_eviction_handler()->AddOrigin(origin_to_be_added.first, - origin_to_be_added.second); + if (!origin_to_be_added.first.is_empty()) + quota_eviction_handler()->AddOrigin(origin_to_be_added.first, + origin_to_be_added.second); if (!origin_to_be_accessed.is_empty()) quota_eviction_handler()->AccessOrigin(origin_to_be_accessed); break; - case 2: + case 3: EXPECT_EQ(expected_usage_after_second, quota_eviction_handler()->GetUsage()); temporary_storage_evictor()->set_repeated_eviction(false); @@ -211,6 +233,19 @@ TEST_F(QuotaTemporaryStorageEvictorTest, SimpleEvictionTest) { temporary_storage_evictor()->Start(); MessageLoop::current()->RunAllPending(); EXPECT_EQ(200 + 500, quota_eviction_handler()->GetUsage()); + + std::map<std::string, int64> stats; + temporary_storage_evictor()->GetStatistics(&stats); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)]); + EXPECT_EQ(1, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins)]); + EXPECT_EQ(1, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds)]); } TEST_F(QuotaTemporaryStorageEvictorTest, MultipleEvictionTest) { @@ -225,6 +260,19 @@ TEST_F(QuotaTemporaryStorageEvictorTest, MultipleEvictionTest) { temporary_storage_evictor()->Start(); MessageLoop::current()->RunAllPending(); EXPECT_EQ(450 + 400, quota_eviction_handler()->GetUsage()); + + std::map<std::string, int64> stats; + temporary_storage_evictor()->GetStatistics(&stats); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)]); + EXPECT_EQ(2, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins)]); + EXPECT_EQ(1, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds)]); } TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionTest) { @@ -253,7 +301,62 @@ TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionTest) { MessageLoop::current()->RunAllPending(); EXPECT_EQ(initial_total_size - d_size + e_size - c_size - b_size, quota_eviction_handler()->GetUsage()); + EXPECT_EQ(5, num_get_usage_and_quota_for_eviction()); + + std::map<std::string, int64> stats; + temporary_storage_evictor()->GetStatistics(&stats); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)]); + EXPECT_EQ(3, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins)]); + EXPECT_EQ(2, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds)]); +} + +TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionSkippedTest) { + const int64 a_size = 400; + const int64 b_size = 150; + const int64 c_size = 120; + const int64 d_size = 292; + const int64 initial_total_size = a_size + b_size + c_size + d_size; + + quota_eviction_handler()->AddOrigin(GURL("http://www.d.com"), d_size); + quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); + quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); + quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); + quota_eviction_handler()->set_quota(1000); + quota_eviction_handler()->set_available_space(1000000000); + quota_eviction_handler()->set_task_for_get_usage_and_quota( + runnable_factory_.NewRunnableMethod( + &QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, + std::make_pair(GURL(), 0), + GURL(), + initial_total_size - d_size, + initial_total_size - d_size)); + EXPECT_EQ(initial_total_size, quota_eviction_handler()->GetUsage()); + set_repeated_eviction(true); + temporary_storage_evictor()->Start(); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(initial_total_size - d_size, + quota_eviction_handler()->GetUsage()); EXPECT_EQ(4, num_get_usage_and_quota_for_eviction()); + + std::map<std::string, int64> stats; + temporary_storage_evictor()->GetStatistics(&stats); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)]); + EXPECT_EQ(1, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins)]); + EXPECT_EQ(3, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds)]); + EXPECT_EQ(1, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds)]); } TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionWithAccessOriginTest) { @@ -282,7 +385,20 @@ TEST_F(QuotaTemporaryStorageEvictorTest, RepeatedEvictionWithAccessOriginTest) { MessageLoop::current()->RunAllPending(); EXPECT_EQ(initial_total_size - d_size + e_size - b_size - a_size, quota_eviction_handler()->GetUsage()); - EXPECT_EQ(4, num_get_usage_and_quota_for_eviction()); + EXPECT_EQ(5, num_get_usage_and_quota_for_eviction()); + + std::map<std::string, int64> stats; + temporary_storage_evictor()->GetStatistics(&stats); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)]); + EXPECT_EQ(3, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins)]); + EXPECT_EQ(2, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds)]); } TEST_F(QuotaTemporaryStorageEvictorTest, DiskSpaceEvictionTest) { @@ -298,6 +414,19 @@ TEST_F(QuotaTemporaryStorageEvictorTest, DiskSpaceEvictionTest) { temporary_storage_evictor()->Start(); MessageLoop::current()->RunAllPending(); EXPECT_EQ(150 + 300, quota_eviction_handler()->GetUsage()); + + std::map<std::string, int64> stats; + temporary_storage_evictor()->GetStatistics(&stats); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnEvictingOrigin)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfErrorsOnGettingUsageAndQuota)]); + EXPECT_EQ(2, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictedOrigins)]); + EXPECT_EQ(1, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfEvictionRounds)]); + EXPECT_EQ(0, stats[std::string(QuotaTemporaryStorageEvictor:: + kStatsLabelNumberOfSkippedEvictionRounds)]); } TEST_F(QuotaTemporaryStorageEvictorTest, UnlimitedExclusionEvictionTest) { |