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

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

Powered by Google App Engine
This is Rietveld 408576698