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

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

Powered by Google App Engine
This is Rietveld 408576698