Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(995)

Side by Side Diff: storage/browser/quota/quota_temporary_storage_evictor.cc

Issue 2592793002: Revert of Change how the quota system computes the total poolsize for temporary storage (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "storage/browser/quota/quota_temporary_storage_evictor.h" 5 #include "storage/browser/quota/quota_temporary_storage_evictor.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
11 #include "base/auto_reset.h"
12 #include "base/bind.h" 11 #include "base/bind.h"
13 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
14 #include "storage/browser/quota/quota_manager.h" 13 #include "storage/browser/quota/quota_manager.h"
15 #include "url/gurl.h" 14 #include "url/gurl.h"
16 15
17 #define UMA_HISTOGRAM_MBYTES(name, sample) \ 16 #define UMA_HISTOGRAM_MBYTES(name, sample) \
18 UMA_HISTOGRAM_CUSTOM_COUNTS( \ 17 UMA_HISTOGRAM_CUSTOM_COUNTS( \
19 (name), static_cast<int>((sample) / kMBytes), \ 18 (name), static_cast<int>((sample) / kMBytes), \
20 1, 10 * 1024 * 1024 /* 10TB */, 100) 19 1, 10 * 1024 * 1024 /* 10TB */, 100)
21 20
22 #define UMA_HISTOGRAM_MINUTES(name, sample) \ 21 #define UMA_HISTOGRAM_MINUTES(name, sample) \
23 UMA_HISTOGRAM_CUSTOM_TIMES( \ 22 UMA_HISTOGRAM_CUSTOM_TIMES( \
24 (name), (sample), \ 23 (name), (sample), \
25 base::TimeDelta::FromMinutes(1), \ 24 base::TimeDelta::FromMinutes(1), \
26 base::TimeDelta::FromDays(1), 50) 25 base::TimeDelta::FromDays(1), 50)
27 26
28 namespace { 27 namespace {
29 const int64_t kMBytes = 1024 * 1024; 28 const int64_t kMBytes = 1024 * 1024;
30 const double kUsageRatioToStartEviction = 0.7; 29 const double kUsageRatioToStartEviction = 0.7;
31 const int kThresholdOfErrorsToStopEviction = 5; 30 const int kThresholdOfErrorsToStopEviction = 5;
32 const int kHistogramReportIntervalMinutes = 60; 31 const int kHistogramReportIntervalMinutes = 60;
33 32 const double kMustRemainAvailableRatio = 0.1;
33 const int64_t kDefaultMustRemainAvailableSpace = 1024 * kMBytes;
34 const double kDiskSpaceShortageAllowanceRatio = 0.5; 34 const double kDiskSpaceShortageAllowanceRatio = 0.5;
35 } 35 }
36 36
37 namespace storage { 37 namespace storage {
38 38
39 const int QuotaTemporaryStorageEvictor::
40 kMinAvailableToStartEvictionNotSpecified = -1;
41
39 QuotaTemporaryStorageEvictor::EvictionRoundStatistics::EvictionRoundStatistics() 42 QuotaTemporaryStorageEvictor::EvictionRoundStatistics::EvictionRoundStatistics()
40 : in_round(false), 43 : in_round(false),
41 is_initialized(false), 44 is_initialized(false),
42 usage_overage_at_round(-1), 45 usage_overage_at_round(-1),
43 diskspace_shortage_at_round(-1), 46 diskspace_shortage_at_round(-1),
44 usage_on_beginning_of_round(-1), 47 usage_on_beginning_of_round(-1),
45 usage_on_end_of_round(-1), 48 usage_on_end_of_round(-1),
46 num_evicted_origins_in_round(0) { 49 num_evicted_origins_in_round(0) {
47 } 50 }
48 51
49 QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor( 52 QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor(
50 QuotaEvictionHandler* quota_eviction_handler, 53 QuotaEvictionHandler* quota_eviction_handler,
51 int64_t interval_ms) 54 int64_t interval_ms)
52 : quota_eviction_handler_(quota_eviction_handler), 55 : min_available_to_start_eviction_(
56 kMinAvailableToStartEvictionNotSpecified),
57 quota_eviction_handler_(quota_eviction_handler),
53 interval_ms_(interval_ms), 58 interval_ms_(interval_ms),
54 timer_disabled_for_testing_(false), 59 repeated_eviction_(true),
55 weak_factory_(this) { 60 weak_factory_(this) {
56 DCHECK(quota_eviction_handler); 61 DCHECK(quota_eviction_handler);
57 } 62 }
58 63
59 QuotaTemporaryStorageEvictor::~QuotaTemporaryStorageEvictor() { 64 QuotaTemporaryStorageEvictor::~QuotaTemporaryStorageEvictor() {
60 } 65 }
61 66
62 void QuotaTemporaryStorageEvictor::GetStatistics( 67 void QuotaTemporaryStorageEvictor::GetStatistics(
63 std::map<std::string, int64_t>* statistics) { 68 std::map<std::string, int64_t>* statistics) {
64 DCHECK(statistics); 69 DCHECK(statistics);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 time_of_end_of_last_nonskipped_round_ = base::Time::Now(); 135 time_of_end_of_last_nonskipped_round_ = base::Time::Now();
131 } else { 136 } else {
132 ++statistics_.num_skipped_eviction_rounds; 137 ++statistics_.num_skipped_eviction_rounds;
133 } 138 }
134 // Reset stats for next round. 139 // Reset stats for next round.
135 round_statistics_ = EvictionRoundStatistics(); 140 round_statistics_ = EvictionRoundStatistics();
136 } 141 }
137 142
138 void QuotaTemporaryStorageEvictor::Start() { 143 void QuotaTemporaryStorageEvictor::Start() {
139 DCHECK(CalledOnValidThread()); 144 DCHECK(CalledOnValidThread());
140
141 base::AutoReset<bool> auto_reset(&timer_disabled_for_testing_, false);
142 StartEvictionTimerWithDelay(0); 145 StartEvictionTimerWithDelay(0);
143 146
144 if (histogram_timer_.IsRunning()) 147 if (histogram_timer_.IsRunning())
145 return; 148 return;
146 149
147 histogram_timer_.Start( 150 histogram_timer_.Start(
148 FROM_HERE, base::TimeDelta::FromMinutes(kHistogramReportIntervalMinutes), 151 FROM_HERE, base::TimeDelta::FromMinutes(kHistogramReportIntervalMinutes),
149 this, &QuotaTemporaryStorageEvictor::ReportPerHourHistogram); 152 this, &QuotaTemporaryStorageEvictor::ReportPerHourHistogram);
150 } 153 }
151 154
152 void QuotaTemporaryStorageEvictor::StartEvictionTimerWithDelay(int delay_ms) { 155 void QuotaTemporaryStorageEvictor::StartEvictionTimerWithDelay(int delay_ms) {
153 if (eviction_timer_.IsRunning() || timer_disabled_for_testing_) 156 if (eviction_timer_.IsRunning())
154 return; 157 return;
155 eviction_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), 158 eviction_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms),
156 this, &QuotaTemporaryStorageEvictor::ConsiderEviction); 159 this, &QuotaTemporaryStorageEvictor::ConsiderEviction);
157 } 160 }
158 161
159 void QuotaTemporaryStorageEvictor::ConsiderEviction() { 162 void QuotaTemporaryStorageEvictor::ConsiderEviction() {
160 OnEvictionRoundStarted(); 163 OnEvictionRoundStarted();
161 quota_eviction_handler_->GetEvictionRoundInfo( 164
162 base::Bind(&QuotaTemporaryStorageEvictor::OnGotEvictionRoundInfo, 165 if (min_available_to_start_eviction_ ==
163 weak_factory_.GetWeakPtr())); 166 kMinAvailableToStartEvictionNotSpecified) {
167 quota_eviction_handler_->AsyncGetVolumeInfo(
168 base::Bind(&QuotaTemporaryStorageEvictor::OnGotVolumeInfo,
169 weak_factory_.GetWeakPtr()));
170 } else {
171 quota_eviction_handler_->GetUsageAndQuotaForEviction(
172 base::Bind(&QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction,
173 weak_factory_.GetWeakPtr(),
174 min_available_to_start_eviction_));
175 }
164 } 176 }
165 177
166 void QuotaTemporaryStorageEvictor::OnGotEvictionRoundInfo( 178 void QuotaTemporaryStorageEvictor::OnGotVolumeInfo(
179 bool success, uint64_t available_space, uint64_t total_size) {
180 // Compute how much to keep free as a function of total disk size.
181 int64_t must_remain_available_space = success ?
182 static_cast<int64_t>(total_size * kMustRemainAvailableRatio) :
183 kDefaultMustRemainAvailableSpace;
184
185 quota_eviction_handler_->GetUsageAndQuotaForEviction(
186 base::Bind(&QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction,
187 weak_factory_.GetWeakPtr(), must_remain_available_space));
188 }
189
190 void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction(
191 int64_t must_remain_available_space,
167 QuotaStatusCode status, 192 QuotaStatusCode status,
168 const QuotaSettings& settings, 193 const UsageAndQuota& qau) {
169 int64_t available_space, 194 DCHECK(CalledOnValidThread());
170 int64_t total_space,
171 int64_t current_usage,
172 bool current_usage_is_complete) {
173 DCHECK_GE(current_usage, 0);
174 195
175 // Note: if there is no storage pressure, |current_usage| 196 int64_t usage = qau.global_limited_usage;
176 // may not be fully calculated and may be 0. 197 DCHECK_GE(usage, 0);
177 198
178 if (status != kQuotaStatusOk) 199 if (status != kQuotaStatusOk)
179 ++statistics_.num_errors_on_getting_usage_and_quota; 200 ++statistics_.num_errors_on_getting_usage_and_quota;
180 201
181 int64_t usage_overage = std::max( 202 int64_t usage_overage = std::max(
182 static_cast<int64_t>(0), 203 static_cast<int64_t>(0),
183 current_usage - static_cast<int64_t>(settings.pool_size * 204 usage - static_cast<int64_t>(qau.quota * kUsageRatioToStartEviction));
184 kUsageRatioToStartEviction)); 205
185 int64_t diskspace_shortage = 206 int64_t diskspace_shortage = std::max(
186 std::max(static_cast<int64_t>(0), 207 static_cast<int64_t>(0),
187 settings.must_remain_available - available_space); 208 must_remain_available_space - qau.available_disk_space);
188 DCHECK(current_usage_is_complete || diskspace_shortage == 0);
189 209
190 // If we're using so little that freeing all of it wouldn't help, 210 // If we're using so little that freeing all of it wouldn't help,
191 // don't let the low space condition cause us to delete it all. 211 // don't let the low space condition cause us to delete it all.
192 if (current_usage < static_cast<int64_t>(diskspace_shortage * 212 if (usage < static_cast<int64_t>(diskspace_shortage *
193 kDiskSpaceShortageAllowanceRatio)) { 213 kDiskSpaceShortageAllowanceRatio)) {
194 diskspace_shortage = 0; 214 diskspace_shortage = 0;
195 } 215 }
196 216
197 if (!round_statistics_.is_initialized) { 217 if (!round_statistics_.is_initialized) {
198 round_statistics_.usage_overage_at_round = usage_overage; 218 round_statistics_.usage_overage_at_round = usage_overage;
199 round_statistics_.diskspace_shortage_at_round = diskspace_shortage; 219 round_statistics_.diskspace_shortage_at_round = diskspace_shortage;
200 round_statistics_.usage_on_beginning_of_round = current_usage; 220 round_statistics_.usage_on_beginning_of_round = usage;
201 round_statistics_.is_initialized = true; 221 round_statistics_.is_initialized = true;
202 } 222 }
203 round_statistics_.usage_on_end_of_round = current_usage; 223 round_statistics_.usage_on_end_of_round = usage;
204 224
205 int64_t amount_to_evict = std::max(usage_overage, diskspace_shortage); 225 int64_t amount_to_evict = std::max(usage_overage, diskspace_shortage);
206 if (status == kQuotaStatusOk && amount_to_evict > 0) { 226 if (status == kQuotaStatusOk && amount_to_evict > 0) {
207 // Space is getting tight. Get the least recently used origin and continue. 227 // Space is getting tight. Get the least recently used origin and continue.
208 // TODO(michaeln): if the reason for eviction is low physical disk space, 228 // TODO(michaeln): if the reason for eviction is low physical disk space,
209 // make 'unlimited' origins subject to eviction too. 229 // make 'unlimited' origins subject to eviction too.
210 quota_eviction_handler_->GetEvictionOrigin( 230 quota_eviction_handler_->GetEvictionOrigin(
211 kStorageTypeTemporary, in_progress_eviction_origins_, 231 kStorageTypeTemporary, in_progress_eviction_origins_, qau.quota,
212 settings.pool_size,
213 base::Bind(&QuotaTemporaryStorageEvictor::OnGotEvictionOrigin, 232 base::Bind(&QuotaTemporaryStorageEvictor::OnGotEvictionOrigin,
214 weak_factory_.GetWeakPtr())); 233 weak_factory_.GetWeakPtr()));
215 return; 234 } else {
235 if (repeated_eviction_) {
236 // No action required, sleep for a while and check again later.
237 if (statistics_.num_errors_on_getting_usage_and_quota <
238 kThresholdOfErrorsToStopEviction) {
239 StartEvictionTimerWithDelay(interval_ms_);
240 } else {
241 // TODO(dmikurube): Try restarting eviction after a while.
242 LOG(WARNING) << "Stopped eviction of temporary storage due to errors "
243 "in GetUsageAndQuotaForEviction.";
244 }
245 }
246 OnEvictionRoundFinished();
216 } 247 }
217 248
218 // No action required, sleep for a while and check again later. 249 // TODO(dmikurube): Add error handling for the case status != kQuotaStatusOk.
219 if (statistics_.num_errors_on_getting_usage_and_quota <
220 kThresholdOfErrorsToStopEviction) {
221 StartEvictionTimerWithDelay(interval_ms_);
222 } else {
223 // TODO(dmikurube): Add error handling for the case status is not OK.
224 // TODO(dmikurube): Try restarting eviction after a while.
225 LOG(WARNING) << "Stopped eviction of temporary storage due to errors";
226 }
227
228 OnEvictionRoundFinished();
229 } 250 }
230 251
231 void QuotaTemporaryStorageEvictor::OnGotEvictionOrigin(const GURL& origin) { 252 void QuotaTemporaryStorageEvictor::OnGotEvictionOrigin(const GURL& origin) {
232 DCHECK(CalledOnValidThread()); 253 DCHECK(CalledOnValidThread());
233 254
234 if (origin.is_empty()) { 255 if (origin.is_empty()) {
235 StartEvictionTimerWithDelay(interval_ms_); 256 if (repeated_eviction_)
257 StartEvictionTimerWithDelay(interval_ms_);
236 OnEvictionRoundFinished(); 258 OnEvictionRoundFinished();
237 return; 259 return;
238 } 260 }
239 261
240 in_progress_eviction_origins_.insert(origin); 262 in_progress_eviction_origins_.insert(origin);
241 263
242 quota_eviction_handler_->EvictOriginData(origin, kStorageTypeTemporary, 264 quota_eviction_handler_->EvictOriginData(origin, kStorageTypeTemporary,
243 base::Bind( 265 base::Bind(
244 &QuotaTemporaryStorageEvictor::OnEvictionComplete, 266 &QuotaTemporaryStorageEvictor::OnEvictionComplete,
245 weak_factory_.GetWeakPtr())); 267 weak_factory_.GetWeakPtr()));
246 } 268 }
247 269
248 void QuotaTemporaryStorageEvictor::OnEvictionComplete( 270 void QuotaTemporaryStorageEvictor::OnEvictionComplete(
249 QuotaStatusCode status) { 271 QuotaStatusCode status) {
250 DCHECK(CalledOnValidThread()); 272 DCHECK(CalledOnValidThread());
251 273
252 // Just calling ConsiderEviction() or StartEvictionTimerWithDelay() here is 274 // Just calling ConsiderEviction() or StartEvictionTimerWithDelay() here is
253 // ok. No need to deal with the case that all of the Delete operations fail 275 // ok. No need to deal with the case that all of the Delete operations fail
254 // for a certain origin. It doesn't result in trying to evict the same 276 // for a certain origin. It doesn't result in trying to evict the same
255 // origin permanently. The evictor skips origins which had deletion errors 277 // origin permanently. The evictor skips origins which had deletion errors
256 // a few times. 278 // a few times.
257 279
258 if (status == kQuotaStatusOk) { 280 if (status == kQuotaStatusOk) {
259 ++statistics_.num_evicted_origins; 281 ++statistics_.num_evicted_origins;
260 ++round_statistics_.num_evicted_origins_in_round; 282 ++round_statistics_.num_evicted_origins_in_round;
261 // We many need to get rid of more space so reconsider immediately. 283 // We many need to get rid of more space so reconsider immediately.
262 ConsiderEviction(); 284 ConsiderEviction();
263 } else { 285 } else {
264 ++statistics_.num_errors_on_evicting_origin; 286 ++statistics_.num_errors_on_evicting_origin;
265 // Sleep for a while and retry again until we see too many errors. 287 if (repeated_eviction_) {
266 StartEvictionTimerWithDelay(interval_ms_); 288 // Sleep for a while and retry again until we see too many errors.
289 StartEvictionTimerWithDelay(interval_ms_);
290 }
267 OnEvictionRoundFinished(); 291 OnEvictionRoundFinished();
268 } 292 }
269 } 293 }
270 294
271 } // namespace storage 295 } // namespace storage
OLDNEW
« no previous file with comments | « storage/browser/quota/quota_temporary_storage_evictor.h ('k') | storage/browser/quota/special_storage_policy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698