Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/quota/quota_temporary_storage_evictor.h" | 5 #include "webkit/quota/quota_temporary_storage_evictor.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "googleurl/src/gurl.h" | 8 #include "googleurl/src/gurl.h" |
| 9 #include "webkit/quota/quota_manager.h" | 9 #include "webkit/quota/quota_manager.h" |
| 10 | 10 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 (*statistics)["errors-on-getting-usage-and-quota"] = | 57 (*statistics)["errors-on-getting-usage-and-quota"] = |
| 58 statistics_.num_errors_on_getting_usage_and_quota; | 58 statistics_.num_errors_on_getting_usage_and_quota; |
| 59 (*statistics)["evicted-origins"] = | 59 (*statistics)["evicted-origins"] = |
| 60 statistics_.num_evicted_origins; | 60 statistics_.num_evicted_origins; |
| 61 (*statistics)["eviction-rounds"] = | 61 (*statistics)["eviction-rounds"] = |
| 62 statistics_.num_eviction_rounds; | 62 statistics_.num_eviction_rounds; |
| 63 (*statistics)["skipped-eviction-rounds"] = | 63 (*statistics)["skipped-eviction-rounds"] = |
| 64 statistics_.num_skipped_eviction_rounds; | 64 statistics_.num_skipped_eviction_rounds; |
| 65 } | 65 } |
| 66 | 66 |
| 67 void QuotaTemporaryStorageEvictor::ReportHistogram() { | 67 void QuotaTemporaryStorageEvictor::ReportPerRoundHistogram() { |
| 68 UMA_HISTOGRAM_COUNTS("Quota.ErrorsOnEvictingOrigin", | 68 DCHECK(round_statistics_.in_round); |
| 69 statistics_.num_errors_on_evicting_origin); | 69 DCHECK(round_statistics_.is_initialized); |
| 70 UMA_HISTOGRAM_COUNTS("Quota.ErrorsOnGettingUsageAndQuota", | |
| 71 statistics_.num_errors_on_getting_usage_and_quota); | |
| 72 UMA_HISTOGRAM_COUNTS("Quota.EvictedOrigins", | |
| 73 statistics_.num_evicted_origins); | |
| 74 UMA_HISTOGRAM_COUNTS("Quota.EvictionRounds", | |
| 75 statistics_.num_eviction_rounds); | |
| 76 UMA_HISTOGRAM_COUNTS("Quota.SkippedEvictionRounds", | |
| 77 statistics_.num_skipped_eviction_rounds); | |
| 78 | 70 |
| 79 statistics_ = Statistics(); | 71 base::Time now = base::Time::Now(); |
| 72 UMA_HISTOGRAM_TIMES("Quota.TimeSpentToAEvictionRound", | |
| 73 now - round_statistics_.start_time); | |
| 74 if (!time_of_end_of_last_round_.is_null()) | |
| 75 UMA_HISTOGRAM_MINUTES("Quota.TimeDeltaOfEvictionRounds", | |
| 76 now - time_of_end_of_last_round_); | |
| 77 UMA_HISTOGRAM_MBYTES("Quota.UsageOverageOfTemporaryGlobalStorage", | |
| 78 round_statistics_.usage_overage_at_round); | |
| 79 UMA_HISTOGRAM_MBYTES("Quota.DiskspaceShortage", | |
| 80 round_statistics_.diskspace_shortage_at_round); | |
| 81 UMA_HISTOGRAM_MBYTES("Quota.EvictedBytesPerRound", | |
| 82 round_statistics_.usage_on_beginning_of_round - | |
| 83 round_statistics_.usage_on_end_of_round); | |
| 84 UMA_HISTOGRAM_COUNTS("Quota.NumberOfEvictedOriginsPerRound", | |
| 85 round_statistics_.num_evicted_origins_in_round); | |
| 86 } | |
| 87 | |
| 88 void QuotaTemporaryStorageEvictor::ReportPerHourHistogram() { | |
| 89 Statistics stats(statistics_); | |
|
Dai Mikurube (NOT FULLTIME)
2011/08/12 07:32:39
Can we have more appropriate name for this variabl
tzik
2011/08/16 04:31:54
Done.
| |
| 90 stats.subtract_assign(previous_statistics_); | |
| 91 previous_statistics_ = statistics_; | |
| 92 | |
| 93 UMA_HISTOGRAM_COUNTS("Quota.ErrorsOnEvictingOriginPerHour", | |
| 94 stats.num_errors_on_evicting_origin); | |
| 95 UMA_HISTOGRAM_COUNTS("Quota.ErrorsOnGettingUsageAndQuotaPerHour", | |
| 96 stats.num_errors_on_getting_usage_and_quota); | |
| 97 UMA_HISTOGRAM_COUNTS("Quota.EvictedOriginsPerHour", | |
| 98 stats.num_evicted_origins); | |
| 99 UMA_HISTOGRAM_COUNTS("Quota.EvictionRoundsPerHour", | |
| 100 stats.num_eviction_rounds); | |
| 101 UMA_HISTOGRAM_COUNTS("Quota.SkippedEvictionRoundsPerHour", | |
| 102 stats.num_skipped_eviction_rounds); | |
| 103 } | |
| 104 | |
| 105 void QuotaTemporaryStorageEvictor::OnEvictionRoundStarted() { | |
| 106 if (round_statistics_.in_round) | |
| 107 return; | |
| 108 round_statistics_.in_round = true; | |
| 109 round_statistics_.start_time = base::Time::Now(); | |
| 110 ++statistics_.num_eviction_rounds; | |
| 111 } | |
| 112 | |
| 113 void QuotaTemporaryStorageEvictor::OnEvictionRoundFinished() { | |
| 114 // Check if skipped round | |
| 115 if (round_statistics_.num_evicted_origins_in_round) { | |
| 116 ReportPerRoundHistogram(); | |
| 117 time_of_end_of_last_nonskipped_round_ = base::Time::Now(); | |
| 118 } else { | |
| 119 ++statistics_.num_skipped_eviction_rounds; | |
| 120 } | |
| 121 // Reset stats for next round. | |
| 122 round_statistics_ = EvictionRoundStatistics(); | |
| 80 } | 123 } |
| 81 | 124 |
| 82 void QuotaTemporaryStorageEvictor::Start() { | 125 void QuotaTemporaryStorageEvictor::Start() { |
| 83 DCHECK(CalledOnValidThread()); | 126 DCHECK(CalledOnValidThread()); |
| 84 StartEvictionTimerWithDelay(0); | 127 StartEvictionTimerWithDelay(0); |
| 85 | 128 |
| 86 if (histogram_timer_.IsRunning()) | 129 if (histogram_timer_.IsRunning()) |
| 87 return; | 130 return; |
| 88 histogram_timer_.Start(kHistogramReportInterval, this, | 131 histogram_timer_.Start(kHistogramReportInterval, this, |
| 89 &QuotaTemporaryStorageEvictor::ReportHistogram); | 132 &QuotaTemporaryStorageEvictor::ReportPerHourHistogram); |
| 90 } | 133 } |
| 91 | 134 |
| 92 void QuotaTemporaryStorageEvictor::StartEvictionTimerWithDelay(int delay_ms) { | 135 void QuotaTemporaryStorageEvictor::StartEvictionTimerWithDelay(int delay_ms) { |
| 93 if (eviction_timer_.IsRunning()) | 136 if (eviction_timer_.IsRunning()) |
| 94 return; | 137 return; |
| 95 num_evicted_origins_in_round_ = 0; | |
| 96 usage_on_beginning_of_round_ = -1; | |
| 97 time_of_beginning_of_round_ = base::Time::Now(); | |
| 98 ++statistics_.num_eviction_rounds; | |
| 99 eviction_timer_.Start(base::TimeDelta::FromMilliseconds(delay_ms), this, | 138 eviction_timer_.Start(base::TimeDelta::FromMilliseconds(delay_ms), this, |
| 100 &QuotaTemporaryStorageEvictor::ConsiderEviction); | 139 &QuotaTemporaryStorageEvictor::ConsiderEviction); |
| 101 } | 140 } |
| 102 | 141 |
| 103 void QuotaTemporaryStorageEvictor::ConsiderEviction() { | 142 void QuotaTemporaryStorageEvictor::ConsiderEviction() { |
| 143 OnEvictionRoundStarted(); | |
| 144 | |
| 104 // Get usage and disk space, then continue. | 145 // Get usage and disk space, then continue. |
| 105 quota_eviction_handler_->GetUsageAndQuotaForEviction(callback_factory_. | 146 quota_eviction_handler_->GetUsageAndQuotaForEviction(callback_factory_. |
| 106 NewCallback( | 147 NewCallback( |
| 107 &QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction)); | 148 &QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction)); |
| 108 } | 149 } |
| 109 | 150 |
| 110 void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction( | 151 void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction( |
| 111 QuotaStatusCode status, | 152 QuotaStatusCode status, |
| 112 int64 usage, | 153 int64 usage, |
| 113 int64 unlimited_usage, | 154 int64 unlimited_usage, |
| 114 int64 quota, | 155 int64 quota, |
| 115 int64 available_disk_space) { | 156 int64 available_disk_space) { |
| 116 DCHECK(CalledOnValidThread()); | 157 DCHECK(CalledOnValidThread()); |
| 117 DCHECK_GE(usage, unlimited_usage); // unlimited_usage is a subset of usage | 158 DCHECK_GE(usage, unlimited_usage); // unlimited_usage is a subset of usage |
| 118 | 159 |
| 119 usage -= unlimited_usage; | 160 usage -= unlimited_usage; |
| 120 | 161 |
| 121 if (status != kQuotaStatusOk) | 162 if (status != kQuotaStatusOk) |
| 122 ++statistics_.num_errors_on_getting_usage_and_quota; | 163 ++statistics_.num_errors_on_getting_usage_and_quota; |
| 123 | 164 |
| 124 int64 amount_to_evict = std::max( | 165 int64 usage_overage = std::max( |
| 125 usage - static_cast<int64>(quota * kUsageRatioToStartEviction), | 166 static_cast<int64>(0), |
| 167 usage - static_cast<int64>(quota * kUsageRatioToStartEviction)); | |
| 168 | |
| 169 int64 diskspace_shortage = std::max( | |
| 170 static_cast<int64>(0), | |
| 126 min_available_disk_space_to_start_eviction_ - available_disk_space); | 171 min_available_disk_space_to_start_eviction_ - available_disk_space); |
| 172 | |
| 173 if (!round_statistics_.is_initialized) { | |
| 174 round_statistics_.usage_overage_at_round = usage_overage; | |
| 175 round_statistics_.diskspace_shortage_at_round = diskspace_shortage; | |
| 176 round_statistics_.usage_on_beginning_of_round = usage; | |
| 177 round_statistics_.is_initialized = true; | |
| 178 } | |
| 179 round_statistics_.usage_on_end_of_round = usage; | |
| 180 | |
| 181 int64 amount_to_evict = std::max(usage_overage, diskspace_shortage); | |
| 127 if (status == kQuotaStatusOk && amount_to_evict > 0) { | 182 if (status == kQuotaStatusOk && amount_to_evict > 0) { |
| 128 // Space is getting tight. Get the least recently used origin and continue. | 183 // Space is getting tight. Get the least recently used origin and continue. |
| 129 // TODO(michaeln): if the reason for eviction is low physical disk space, | 184 // TODO(michaeln): if the reason for eviction is low physical disk space, |
| 130 // make 'unlimited' origins subject to eviction too. | 185 // make 'unlimited' origins subject to eviction too. |
| 131 | |
| 132 if (usage_on_beginning_of_round_ < 0) { | |
| 133 usage_on_beginning_of_round_ = usage; | |
| 134 UMA_HISTOGRAM_MBYTES("Quota.TemporaryStorageSizeToEvict", | |
| 135 amount_to_evict); | |
| 136 } | |
| 137 | |
| 138 quota_eviction_handler_->GetLRUOrigin(kStorageTypeTemporary, | 186 quota_eviction_handler_->GetLRUOrigin(kStorageTypeTemporary, |
| 139 callback_factory_.NewCallback( | 187 callback_factory_.NewCallback( |
| 140 &QuotaTemporaryStorageEvictor::OnGotLRUOrigin)); | 188 &QuotaTemporaryStorageEvictor::OnGotLRUOrigin)); |
| 141 } else if (repeated_eviction_) { | 189 } else { |
| 142 // No action required, sleep for a while and check again later. | 190 if (repeated_eviction_) { |
| 143 if (num_evicted_origins_in_round_ == 0) { | 191 // No action required, sleep for a while and check again later. |
| 144 ++statistics_.num_skipped_eviction_rounds; | 192 if (statistics_.num_errors_on_getting_usage_and_quota < |
| 145 } else if (usage_on_beginning_of_round_ >= 0) { | 193 kThresholdOfErrorsToStopEviction) { |
| 146 int64 evicted_bytes = usage_on_beginning_of_round_ - usage; | 194 StartEvictionTimerWithDelay(interval_ms_); |
| 147 base::Time now = base::Time::Now(); | 195 } else { |
| 148 UMA_HISTOGRAM_MBYTES("Quota.EvictedBytesPerRound", evicted_bytes); | 196 // TODO(dmikurube): Try restarting eviction after a while. |
| 149 UMA_HISTOGRAM_COUNTS("Quota.NumberOfEvictedOriginsPerRound", | 197 LOG(WARNING) << "Stopped eviction of temporary storage due to errors " |
| 150 num_evicted_origins_in_round_); | 198 "in GetUsageAndQuotaForEviction."; |
| 151 UMA_HISTOGRAM_TIMES("Quota.TimeSpentToAEvictionRound", | |
| 152 now - time_of_beginning_of_round_); | |
| 153 if (!time_of_end_of_last_round_.is_null()) { | |
| 154 UMA_HISTOGRAM_MINUTES("Quota.TimeDeltaOfEvictionRounds", | |
| 155 now - time_of_end_of_last_round_); | |
| 156 } | 199 } |
| 157 time_of_end_of_last_round_ = now; | |
| 158 } | 200 } |
| 159 if (statistics_.num_errors_on_getting_usage_and_quota < | 201 OnEvictionRoundFinished(); |
| 160 kThresholdOfErrorsToStopEviction) { | |
| 161 StartEvictionTimerWithDelay(interval_ms_); | |
| 162 } else { | |
| 163 // TODO(dmikurube): Try restarting eviction after a while. | |
| 164 LOG(WARNING) << "Stopped eviction of temporary storage due to errors " | |
| 165 "in GetUsageAndQuotaForEviction."; | |
| 166 } | |
| 167 } | 202 } |
| 168 | 203 |
| 169 // TODO(dmikurube): Add error handling for the case status != kQuotaStatusOk. | 204 // TODO(dmikurube): Add error handling for the case status != kQuotaStatusOk. |
| 170 } | 205 } |
| 171 | 206 |
| 172 void QuotaTemporaryStorageEvictor::OnGotLRUOrigin(const GURL& origin) { | 207 void QuotaTemporaryStorageEvictor::OnGotLRUOrigin(const GURL& origin) { |
| 173 DCHECK(CalledOnValidThread()); | 208 DCHECK(CalledOnValidThread()); |
| 174 | 209 |
| 175 if (origin.is_empty()) { | 210 if (origin.is_empty()) { |
| 176 if (repeated_eviction_) | 211 if (repeated_eviction_) |
| 177 StartEvictionTimerWithDelay(interval_ms_); | 212 StartEvictionTimerWithDelay(interval_ms_); |
| 213 OnEvictionRoundFinished(); | |
| 178 return; | 214 return; |
| 179 } | 215 } |
| 180 | 216 |
| 181 quota_eviction_handler_->EvictOriginData(origin, kStorageTypeTemporary, | 217 quota_eviction_handler_->EvictOriginData(origin, kStorageTypeTemporary, |
| 182 callback_factory_.NewCallback( | 218 callback_factory_.NewCallback( |
| 183 &QuotaTemporaryStorageEvictor::OnEvictionComplete)); | 219 &QuotaTemporaryStorageEvictor::OnEvictionComplete)); |
| 184 } | 220 } |
| 185 | 221 |
| 186 void QuotaTemporaryStorageEvictor::OnEvictionComplete( | 222 void QuotaTemporaryStorageEvictor::OnEvictionComplete( |
| 187 QuotaStatusCode status) { | 223 QuotaStatusCode status) { |
| 188 DCHECK(CalledOnValidThread()); | 224 DCHECK(CalledOnValidThread()); |
| 189 | 225 |
| 190 // Just calling ConsiderEviction() or StartEvictionTimerWithDelay() here is | 226 // Just calling ConsiderEviction() or StartEvictionTimerWithDelay() here is |
| 191 // ok. No need to deal with the case that all of the Delete operations fail | 227 // ok. No need to deal with the case that all of the Delete operations fail |
| 192 // for a certain origin. It doesn't result in trying to evict the same | 228 // for a certain origin. It doesn't result in trying to evict the same |
| 193 // origin permanently. The evictor skips origins which had deletion errors | 229 // origin permanently. The evictor skips origins which had deletion errors |
| 194 // a few times. | 230 // a few times. |
| 195 | 231 |
| 196 if (status == kQuotaStatusOk) { | 232 if (status == kQuotaStatusOk) { |
| 197 ++statistics_.num_evicted_origins; | 233 ++statistics_.num_evicted_origins; |
| 198 ++num_evicted_origins_in_round_; | 234 ++round_statistics_.num_evicted_origins_in_round; |
| 199 // We many need to get rid of more space so reconsider immediately. | 235 // We many need to get rid of more space so reconsider immediately. |
| 200 ConsiderEviction(); | 236 ConsiderEviction(); |
| 201 } else { | 237 } else { |
| 202 ++statistics_.num_errors_on_evicting_origin; | 238 ++statistics_.num_errors_on_evicting_origin; |
| 203 if (repeated_eviction_) { | 239 if (repeated_eviction_) { |
| 204 // Sleep for a while and retry again until we see too many errors. | 240 // Sleep for a while and retry again until we see too many errors. |
| 205 StartEvictionTimerWithDelay(interval_ms_); | 241 StartEvictionTimerWithDelay(interval_ms_); |
| 206 } | 242 } |
| 243 OnEvictionRoundFinished(); | |
| 207 } | 244 } |
| 208 } | 245 } |
| 209 | 246 |
| 210 } // namespace quota | 247 } // namespace quota |
| OLD | NEW |