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

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

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