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

Side by Side Diff: storage/browser/quota/quota_manager.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_manager.h" 5 #include "storage/browser/quota/quota_manager.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <functional> 11 #include <functional>
12 #include <limits> 12 #include <limits>
13 #include <memory> 13 #include <memory>
14 #include <utility> 14 #include <utility>
15 15
16 #include "base/barrier_closure.h"
16 #include "base/bind.h" 17 #include "base/bind.h"
17 #include "base/bind_helpers.h" 18 #include "base/bind_helpers.h"
18 #include "base/command_line.h" 19 #include "base/command_line.h"
19 #include "base/files/file_util.h" 20 #include "base/files/file_util.h"
20 #include "base/macros.h" 21 #include "base/macros.h"
21 #include "base/metrics/histogram_macros.h" 22 #include "base/metrics/histogram_macros.h"
22 #include "base/numerics/safe_conversions.h" 23 #include "base/numerics/safe_conversions.h"
23 #include "base/profiler/scoped_tracker.h" 24 #include "base/profiler/scoped_tracker.h"
24 #include "base/sequenced_task_runner.h" 25 #include "base/sequenced_task_runner.h"
25 #include "base/single_thread_task_runner.h" 26 #include "base/single_thread_task_runner.h"
26 #include "base/strings/string_number_conversions.h" 27 #include "base/strings/string_number_conversions.h"
27 #include "base/sys_info.h" 28 #include "base/sys_info.h"
28 #include "base/task_runner_util.h" 29 #include "base/task_runner_util.h"
30 #include "base/threading/thread_task_runner_handle.h"
29 #include "base/time/time.h" 31 #include "base/time/time.h"
30 #include "base/trace_event/trace_event.h" 32 #include "base/trace_event/trace_event.h"
31 #include "net/base/url_util.h" 33 #include "net/base/url_util.h"
32 #include "storage/browser/quota/client_usage_tracker.h" 34 #include "storage/browser/quota/client_usage_tracker.h"
33 #include "storage/browser/quota/quota_manager_proxy.h" 35 #include "storage/browser/quota/quota_manager_proxy.h"
34 #include "storage/browser/quota/quota_temporary_storage_evictor.h" 36 #include "storage/browser/quota/quota_temporary_storage_evictor.h"
35 #include "storage/browser/quota/storage_monitor.h" 37 #include "storage/browser/quota/storage_monitor.h"
36 #include "storage/browser/quota/usage_tracker.h" 38 #include "storage/browser/quota/usage_tracker.h"
37 #include "storage/common/quota/quota_types.h" 39 #include "storage/common/quota/quota_types.h"
38 40
39 #define UMA_HISTOGRAM_MBYTES(name, sample) \
40 UMA_HISTOGRAM_CUSTOM_COUNTS( \
41 (name), static_cast<int>((sample) / kMBytes), \
42 1, 10 * 1024 * 1024 /* 10TB */, 100)
43
44 namespace storage { 41 namespace storage {
45 42
46 namespace { 43 namespace {
47 44
48 const int64_t kMBytes = 1024 * 1024; 45 const int64_t kMBytes = 1024 * 1024;
49 const int kMinutesInMilliSeconds = 60 * 1000; 46 const int kMinutesInMilliSeconds = 60 * 1000;
47 const int64_t kReportHistogramInterval = 60 * 60 * 1000; // 1 hour
50 48
51 const int64_t kReportHistogramInterval = 60 * 60 * 1000; // 1 hour 49 #define UMA_HISTOGRAM_MBYTES(name, sample) \
52 const double kTemporaryQuotaRatioToAvail = 1.0 / 3.0; // 33% 50 UMA_HISTOGRAM_CUSTOM_COUNTS( \
51 (name), static_cast<int>((sample) / kMBytes), \
52 1, 10 * 1024 * 1024 /* 10TB */, 100)
53 53
54 } // namespace 54 } // namespace
55 55
56 // Arbitrary for now, but must be reasonably small so that
57 // in-memory databases can fit.
58 // TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this.
59 const int64_t QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
60
61 const int64_t QuotaManager::kNoLimit = INT64_MAX; 56 const int64_t QuotaManager::kNoLimit = INT64_MAX;
62 57
63 const int QuotaManager::kPerHostTemporaryPortion = 5; // 20%
64
65 // Cap size for per-host persistent quota determined by the histogram. 58 // Cap size for per-host persistent quota determined by the histogram.
66 // This is a bit lax value because the histogram says nothing about per-host 59 // This is a bit lax value because the histogram says nothing about per-host
67 // persistent storage usage and we determined by global persistent storage 60 // persistent storage usage and we determined by global persistent storage
68 // usage that is less than 10GB for almost all users. 61 // usage that is less than 10GB for almost all users.
69 const int64_t QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes; 62 const int64_t QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes;
70 63
64 // Heuristics: assuming average cloud server allows a few Gigs storage
65 // on the server side and the storage needs to be shared for user data
66 // and by multiple apps.
67 int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
68
71 const char QuotaManager::kDatabaseName[] = "QuotaManager"; 69 const char QuotaManager::kDatabaseName[] = "QuotaManager";
72 70
73 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3; 71 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3;
74
75 // Preserve kMinimumPreserveForSystem disk space for system book-keeping
76 // when returning the quota to unlimited apps/extensions.
77 // TODO(kinuko): This should be like 10% of the actual disk space.
78 // For now we simply use a constant as getting the disk size needs
79 // platform-dependent code. (http://crbug.com/178976)
80 int64_t QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
81
82 const int QuotaManager::kEvictionIntervalInMilliSeconds = 72 const int QuotaManager::kEvictionIntervalInMilliSeconds =
83 30 * kMinutesInMilliSeconds; 73 30 * kMinutesInMilliSeconds;
84 74
85 const char QuotaManager::kTimeBetweenRepeatedOriginEvictionsHistogram[] = 75 const char QuotaManager::kTimeBetweenRepeatedOriginEvictionsHistogram[] =
86 "Quota.TimeBetweenRepeatedOriginEvictions"; 76 "Quota.TimeBetweenRepeatedOriginEvictions";
87 const char QuotaManager::kEvictedOriginAccessedCountHistogram[] = 77 const char QuotaManager::kEvictedOriginAccessedCountHistogram[] =
88 "Quota.EvictedOriginAccessCount"; 78 "Quota.EvictedOriginAccessCount";
89 const char QuotaManager::kEvictedOriginTimeSinceAccessHistogram[] = 79 const char QuotaManager::kEvictedOriginTimeSinceAccessHistogram[] =
90 "Quota.EvictedOriginTimeSinceAccess"; 80 "Quota.EvictedOriginTimeSinceAccess";
91 81
92 // Heuristics: assuming average cloud server allows a few Gigs storage
93 // on the server side and the storage needs to be shared for user data
94 // and by multiple apps.
95 int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
96
97 namespace { 82 namespace {
98 83
99 void CountOriginType(const std::set<GURL>& origins, 84 void CountOriginType(const std::set<GURL>& origins,
100 SpecialStoragePolicy* policy, 85 SpecialStoragePolicy* policy,
101 size_t* protected_origins, 86 size_t* protected_origins,
102 size_t* unlimited_origins) { 87 size_t* unlimited_origins) {
103 DCHECK(protected_origins); 88 DCHECK(protected_origins);
104 DCHECK(unlimited_origins); 89 DCHECK(unlimited_origins);
105 *protected_origins = 0; 90 *protected_origins = 0;
106 *unlimited_origins = 0; 91 *unlimited_origins = 0;
107 if (!policy) 92 if (!policy)
108 return; 93 return;
109 for (std::set<GURL>::const_iterator itr = origins.begin(); 94 for (std::set<GURL>::const_iterator itr = origins.begin();
110 itr != origins.end(); 95 itr != origins.end();
111 ++itr) { 96 ++itr) {
112 if (policy->IsStorageProtected(*itr)) 97 if (policy->IsStorageProtected(*itr))
113 ++*protected_origins; 98 ++*protected_origins;
114 if (policy->IsStorageUnlimited(*itr)) 99 if (policy->IsStorageUnlimited(*itr))
115 ++*unlimited_origins; 100 ++*unlimited_origins;
116 } 101 }
117 } 102 }
118 103
119 bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64_t* new_quota,
120 QuotaDatabase* database) {
121 DCHECK(database);
122 if (!database->SetQuotaConfigValue(
123 QuotaDatabase::kTemporaryQuotaOverrideKey, *new_quota)) {
124 *new_quota = -1;
125 return false;
126 }
127 return true;
128 }
129
130 bool GetPersistentHostQuotaOnDBThread(const std::string& host, 104 bool GetPersistentHostQuotaOnDBThread(const std::string& host,
131 int64_t* quota, 105 int64_t* quota,
132 QuotaDatabase* database) { 106 QuotaDatabase* database) {
133 DCHECK(database); 107 DCHECK(database);
134 database->GetHostQuota(host, kStorageTypePersistent, quota); 108 database->GetHostQuota(host, kStorageTypePersistent, quota);
135 return true; 109 return true;
136 } 110 }
137 111
138 bool SetPersistentHostQuotaOnDBThread(const std::string& host, 112 bool SetPersistentHostQuotaOnDBThread(const std::string& host,
139 int64_t* new_quota, 113 int64_t* new_quota,
140 QuotaDatabase* database) { 114 QuotaDatabase* database) {
141 DCHECK(database); 115 DCHECK(database);
142 if (database->SetHostQuota(host, kStorageTypePersistent, *new_quota)) 116 if (database->SetHostQuota(host, kStorageTypePersistent, *new_quota))
143 return true; 117 return true;
144 *new_quota = 0; 118 *new_quota = 0;
145 return false; 119 return false;
146 } 120 }
147 121
148 bool InitializeOnDBThread(int64_t* temporary_quota_override,
149 int64_t* desired_available_space,
150 QuotaDatabase* database) {
151 DCHECK(database);
152 database->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey,
153 temporary_quota_override);
154 database->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey,
155 desired_available_space);
156 return true;
157 }
158
159 bool GetLRUOriginOnDBThread(StorageType type, 122 bool GetLRUOriginOnDBThread(StorageType type,
160 const std::set<GURL>& exceptions, 123 const std::set<GURL>& exceptions,
161 SpecialStoragePolicy* policy, 124 SpecialStoragePolicy* policy,
162 GURL* url, 125 GURL* url,
163 QuotaDatabase* database) { 126 QuotaDatabase* database) {
164 DCHECK(database); 127 DCHECK(database);
165 database->GetLRUOrigin(type, exceptions, policy, url); 128 database->GetLRUOrigin(type, exceptions, policy, url);
166 return true; 129 return true;
167 } 130 }
168 131
(...skipping 28 matching lines...) Expand all
197 160
198 if (last_eviction_time != base::Time()) { 161 if (last_eviction_time != base::Time()) {
199 UMA_HISTOGRAM_LONG_TIMES( 162 UMA_HISTOGRAM_LONG_TIMES(
200 QuotaManager::kTimeBetweenRepeatedOriginEvictionsHistogram, 163 QuotaManager::kTimeBetweenRepeatedOriginEvictionsHistogram,
201 now - last_eviction_time); 164 now - last_eviction_time);
202 } 165 }
203 166
204 return database->SetOriginLastEvictionTime(origin, type, now); 167 return database->SetOriginLastEvictionTime(origin, type, now);
205 } 168 }
206 169
207 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set<GURL>* origins, 170 bool BootstrapDatabaseOnDBThread(const std::set<GURL>* origins,
208 QuotaDatabase* database) { 171 QuotaDatabase* database) {
209 DCHECK(database); 172 DCHECK(database);
210 if (database->IsOriginDatabaseBootstrapped()) 173 if (database->IsOriginDatabaseBootstrapped())
211 return true; 174 return true;
212 175
213 // Register existing origins with 0 last time access. 176 // Register existing origins with 0 last time access.
214 if (database->RegisterInitialOriginInfo(*origins, kStorageTypeTemporary)) { 177 if (database->RegisterInitialOriginInfo(*origins, kStorageTypeTemporary)) {
215 database->SetOriginDatabaseBootstrapped(true); 178 database->SetOriginDatabaseBootstrapped(true);
216 return true; 179 return true;
217 } 180 }
218 return false; 181 return false;
219 } 182 }
220 183
221 bool UpdateAccessTimeOnDBThread(const GURL& origin, 184 bool UpdateAccessTimeOnDBThread(const GURL& origin,
222 StorageType type, 185 StorageType type,
223 base::Time accessed_time, 186 base::Time accessed_time,
224 QuotaDatabase* database) { 187 QuotaDatabase* database) {
225 DCHECK(database); 188 DCHECK(database);
226 return database->SetOriginLastAccessTime(origin, type, accessed_time); 189 return database->SetOriginLastAccessTime(origin, type, accessed_time);
227 } 190 }
228 191
229 bool UpdateModifiedTimeOnDBThread(const GURL& origin, 192 bool UpdateModifiedTimeOnDBThread(const GURL& origin,
230 StorageType type, 193 StorageType type,
231 base::Time modified_time, 194 base::Time modified_time,
232 QuotaDatabase* database) { 195 QuotaDatabase* database) {
233 DCHECK(database); 196 DCHECK(database);
234 return database->SetOriginLastModifiedTime(origin, type, modified_time); 197 return database->SetOriginLastModifiedTime(origin, type, modified_time);
235 } 198 }
236 199
237 int64_t CalculateTemporaryGlobalQuota(int64_t global_limited_usage,
238 int64_t available_space) {
239 DCHECK_GE(global_limited_usage, 0);
240 int64_t avail_space = available_space;
241 if (avail_space <
242 std::numeric_limits<int64_t>::max() - global_limited_usage) {
243 // We basically calculate the temporary quota by
244 // [available_space + space_used_for_temp] * kTempQuotaRatio,
245 // but make sure we'll have no overflow.
246 avail_space += global_limited_usage;
247 }
248 int64_t pool_size = avail_space * kTemporaryQuotaRatioToAvail;
249 UMA_HISTOGRAM_MBYTES("Quota.GlobalTemporaryPoolSize", pool_size);
250 return pool_size;
251 }
252
253 void DispatchTemporaryGlobalQuotaCallback(
254 const QuotaCallback& callback,
255 QuotaStatusCode status,
256 const UsageAndQuota& usage_and_quota) {
257 if (status != kQuotaStatusOk) {
258 callback.Run(status, 0);
259 return;
260 }
261
262 callback.Run(status, CalculateTemporaryGlobalQuota(
263 usage_and_quota.global_limited_usage,
264 usage_and_quota.available_disk_space));
265 }
266
267 int64_t CalculateQuotaWithDiskSpace(int64_t available_disk_space,
268 int64_t usage,
269 int64_t quota) {
270 if (available_disk_space < QuotaManager::kMinimumPreserveForSystem) {
271 LOG(WARNING)
272 << "Running out of disk space for profile."
273 << " QuotaManager starts forbidding further quota consumption.";
274 return usage;
275 }
276
277 if (quota < usage) {
278 // No more space; cap the quota to the current usage.
279 return usage;
280 }
281
282 available_disk_space -= QuotaManager::kMinimumPreserveForSystem;
283 if (available_disk_space < quota - usage)
284 return available_disk_space + usage;
285
286 return quota;
287 }
288
289 int64_t CalculateTemporaryHostQuota(int64_t host_usage,
290 int64_t global_quota,
291 int64_t global_limited_usage) {
292 DCHECK_GE(global_limited_usage, 0);
293 int64_t host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion;
294 if (global_limited_usage > global_quota)
295 host_quota = std::min(host_quota, host_usage);
296 return host_quota;
297 }
298
299 void DispatchUsageAndQuotaForWebApps(
300 StorageType type,
301 bool is_incognito,
302 bool is_unlimited,
303 bool can_query_disk_size,
304 const QuotaManager::GetUsageAndQuotaCallback& callback,
305 QuotaStatusCode status,
306 const UsageAndQuota& usage_and_quota) {
307 if (status != kQuotaStatusOk) {
308 callback.Run(status, 0, 0);
309 return;
310 }
311
312 int64_t usage = usage_and_quota.usage;
313 int64_t quota = usage_and_quota.quota;
314
315 if (type == kStorageTypeTemporary && !is_unlimited) {
316 quota = CalculateTemporaryHostQuota(
317 usage, quota, usage_and_quota.global_limited_usage);
318 }
319
320 if (is_incognito) {
321 quota = std::min(quota, QuotaManager::kIncognitoDefaultQuotaLimit);
322 callback.Run(status, usage, quota);
323 return;
324 }
325
326 // For apps with unlimited permission or can_query_disk_size is true (and not
327 // in incognito mode).
328 // We assume we can expose the actual disk size for them and cap the quota by
329 // the available disk space.
330 if (is_unlimited || can_query_disk_size) {
331 quota = CalculateQuotaWithDiskSpace(
332 usage_and_quota.available_disk_space,
333 usage, quota);
334 }
335
336 callback.Run(status, usage, quota);
337
338 if (type == kStorageTypeTemporary && !is_unlimited)
339 UMA_HISTOGRAM_MBYTES("Quota.QuotaForOrigin", quota);
340 }
341
342 } // namespace 200 } // namespace
343 201
344 UsageAndQuota::UsageAndQuota() 202 class QuotaManager::UsageAndQuotaHelper : public QuotaTask {
345 : usage(0),
346 global_limited_usage(0),
347 quota(0),
348 available_disk_space(0) {
349 }
350
351 UsageAndQuota::UsageAndQuota(int64_t usage,
352 int64_t global_limited_usage,
353 int64_t quota,
354 int64_t available_disk_space)
355 : usage(usage),
356 global_limited_usage(global_limited_usage),
357 quota(quota),
358 available_disk_space(available_disk_space) {}
359
360 class UsageAndQuotaCallbackDispatcher
361 : public QuotaTask,
362 public base::SupportsWeakPtr<UsageAndQuotaCallbackDispatcher> {
363 public: 203 public:
364 explicit UsageAndQuotaCallbackDispatcher(QuotaManager* manager) 204 UsageAndQuotaHelper(QuotaManager* manager,
205 const GURL& origin,
206 StorageType type,
207 bool is_unlimited,
208 bool is_incognito,
209 const UsageAndQuotaCallback& callback)
365 : QuotaTask(manager), 210 : QuotaTask(manager),
366 has_usage_(false), 211 origin_(origin),
367 has_global_limited_usage_(false), 212 callback_(callback),
368 has_quota_(false), 213 type_(type),
369 has_available_disk_space_(false), 214 is_unlimited_(is_unlimited),
370 status_(kQuotaStatusUnknown), 215 is_incognito_(is_incognito),
371 usage_and_quota_(-1, -1, -1, -1), 216 weak_factory_(this) {}
372 waiting_callbacks_(1) {} 217
373 218 protected:
374 ~UsageAndQuotaCallbackDispatcher() override {} 219 void Run() override {
375 220 // Start the async process of gathering the info we need.
376 void WaitForResults(const QuotaManager::UsageAndQuotaCallback& callback) { 221 // Gather 4 pieces of info before computing an answer:
377 callback_ = callback; 222 // settings, device_storage_capacity, host_usage, and host_quota.
378 Start(); 223 base::Closure barrier = base::BarrierClosure(
379 } 224 4, base::Bind(&UsageAndQuotaHelper::OnBarrierComplete,
380 225 weak_factory_.GetWeakPtr()));
381 void set_usage(int64_t usage) { 226
382 usage_and_quota_.usage = usage; 227 std::string host = net::GetHostOrSpecFromURL(origin_);
383 has_usage_ = true; 228
384 } 229 manager()->GetQuotaSettings(base::Bind(&UsageAndQuotaHelper::OnGotSettings,
385 230 weak_factory_.GetWeakPtr(),
386 void set_global_limited_usage(int64_t global_limited_usage) { 231 barrier));
387 usage_and_quota_.global_limited_usage = global_limited_usage; 232 manager()->GetStorageCapacity(
388 has_global_limited_usage_ = true; 233 base::Bind(&UsageAndQuotaHelper::OnGotCapacity,
389 } 234 weak_factory_.GetWeakPtr(), barrier));
390 235 manager()->GetHostUsage(host, type_,
391 void set_quota(int64_t quota) { 236 base::Bind(&UsageAndQuotaHelper::OnGotHostUsage,
392 usage_and_quota_.quota = quota; 237 weak_factory_.GetWeakPtr(), barrier));
393 has_quota_ = true; 238
394 } 239 // Determine host_quota differently depending on type.
395 240 if (is_unlimited_) {
396 void set_available_disk_space(int64_t available_disk_space) { 241 SetDesiredHostQuota(barrier, kQuotaStatusOk, kNoLimit);
397 usage_and_quota_.available_disk_space = available_disk_space; 242 } else if (type_ == kStorageTypeSyncable) {
398 has_available_disk_space_ = true; 243 SetDesiredHostQuota(barrier, kQuotaStatusOk,
399 } 244 kSyncableStorageDefaultHostQuota);
400 245 } else if (type_ == kStorageTypePersistent) {
401 UsageCallback GetHostUsageCallback() { 246 manager()->GetPersistentHostQuota(
402 ++waiting_callbacks_; 247 host, base::Bind(&UsageAndQuotaHelper::SetDesiredHostQuota,
403 has_usage_ = true; 248 weak_factory_.GetWeakPtr(), barrier));
404 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage, 249 } else {
405 AsWeakPtr()); 250 DCHECK_EQ(kStorageTypeTemporary, type_);
406 } 251 // For temporary storge, OnGotSettings will set the host quota.
407 252 }
408 UsageCallback GetGlobalLimitedUsageCallback() { 253 }
409 ++waiting_callbacks_; 254
410 has_global_limited_usage_ = true; 255 void Aborted() override {
411 return base::Bind( 256 weak_factory_.InvalidateWeakPtrs();
412 &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage, 257 callback_.Run(kQuotaErrorAbort, 0, 0);
413 AsWeakPtr()); 258 DeleteSoon();
414 } 259 }
415 260
416 QuotaCallback GetQuotaCallback() { 261 void Completed() override {
417 ++waiting_callbacks_; 262 weak_factory_.InvalidateWeakPtrs();
418 has_quota_ = true; 263
419 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota, 264 // Constrain the desired |host_quota| to something that fits.
420 AsWeakPtr()); 265 // If available space is too low, cap usage at current levels.
421 } 266 // If it's close to being too low, cap growth to avoid it getting too low.
422 267 int64_t host_quota =
423 QuotaCallback GetAvailableSpaceCallback() { 268 std::min(desired_host_quota_,
424 ++waiting_callbacks_; 269 host_usage_ +
425 has_available_disk_space_ = true; 270 std::max(INT64_C(0), available_space_ -
426 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace, 271 settings_.must_remain_available));
427 AsWeakPtr()); 272 callback_.Run(kQuotaStatusOk, host_usage_, host_quota);
273 if (type_ == kStorageTypeTemporary && !is_incognito_ && !is_unlimited_)
274 UMA_HISTOGRAM_MBYTES("Quota.QuotaForOrigin", host_quota);
275 DeleteSoon();
428 } 276 }
429 277
430 private: 278 private:
431 void DidGetHostUsage(int64_t usage) { 279 QuotaManager* manager() const {
432 if (status_ == kQuotaStatusUnknown) 280 return static_cast<QuotaManager*>(observer());
433 status_ = kQuotaStatusOk; 281 }
434 usage_and_quota_.usage = usage; 282
435 CheckCompleted(); 283 void OnGotSettings(const base::Closure& barrier_closure,
436 } 284 const QuotaSettings& settings) {
437 285 settings_ = settings;
438 void DidGetGlobalLimitedUsage(int64_t limited_usage) { 286 barrier_closure.Run();
439 if (status_ == kQuotaStatusUnknown) 287 if (type_ == kStorageTypeTemporary && !is_unlimited_) {
440 status_ = kQuotaStatusOk; 288 SetDesiredHostQuota(barrier_closure, kQuotaStatusOk,
441 usage_and_quota_.global_limited_usage = limited_usage; 289 settings.per_host_quota);
442 CheckCompleted(); 290 }
443 } 291 }
444 292
445 void DidGetQuota(QuotaStatusCode status, int64_t quota) { 293 void OnGotCapacity(const base::Closure& barrier_closure,
446 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) 294 int64_t total_space,
447 status_ = status; 295 int64_t available_space) {
448 usage_and_quota_.quota = quota; 296 total_space_ = total_space;
449 CheckCompleted(); 297 available_space_ = available_space;
450 } 298 barrier_closure.Run();
451 299 }
452 void DidGetAvailableSpace(QuotaStatusCode status, int64_t space) { 300
453 // crbug.com/349708 301 void OnGotHostUsage(const base::Closure& barrier_closure, int64_t usage) {
454 TRACE_EVENT0( 302 host_usage_ = usage;
455 "io", "UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace"); 303 barrier_closure.Run();
456 304 }
457 DCHECK_GE(space, 0); 305
458 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) 306 void SetDesiredHostQuota(const base::Closure& barrier_closure,
459 status_ = status; 307 QuotaStatusCode status,
460 usage_and_quota_.available_disk_space = space; 308 int64_t quota) {
461 CheckCompleted(); 309 desired_host_quota_ = quota;
462 } 310 barrier_closure.Run();
463 311 }
312
313 void OnBarrierComplete() { CallCompleted(); }
314
315 GURL origin_;
316 QuotaManager::UsageAndQuotaCallback callback_;
317 StorageType type_;
318 bool is_unlimited_;
319 bool is_incognito_;
320 int64_t available_space_ = 0;
321 int64_t total_space_ = 0;
322 int64_t desired_host_quota_ = 0;
323 int64_t host_usage_ = 0;
324 QuotaSettings settings_;
325 base::WeakPtrFactory<UsageAndQuotaHelper> weak_factory_;
326 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaHelper);
327 };
328
329 // Helper to asychronously gather information needed at the start of an
330 // eviction round.
331 class QuotaManager::EvictionRoundInfoHelper : public QuotaTask {
332 public:
333 EvictionRoundInfoHelper(QuotaManager* manager,
334 const EvictionRoundInfoCallback& callback)
335 : QuotaTask(manager), callback_(callback), weak_factory_(this) {}
336
337 protected:
464 void Run() override { 338 void Run() override {
465 // We initialize waiting_callbacks to 1 so that we won't run 339 // Gather 2 pieces of info before deciding if we need to get GlobalUsage:
466 // the completion callback until here even some of the callbacks 340 // settings and device_storage_capacity.
467 // are dispatched synchronously. 341 base::Closure barrier = base::BarrierClosure(
468 CheckCompleted(); 342 2, base::Bind(&EvictionRoundInfoHelper::OnBarrierComplete,
343 weak_factory_.GetWeakPtr()));
344
345 manager()->GetQuotaSettings(
346 base::Bind(&EvictionRoundInfoHelper::OnGotSettings,
347 weak_factory_.GetWeakPtr(), barrier));
348 manager()->GetStorageCapacity(
349 base::Bind(&EvictionRoundInfoHelper::OnGotCapacity,
350 weak_factory_.GetWeakPtr(), barrier));
469 } 351 }
470 352
471 void Aborted() override { 353 void Aborted() override {
472 callback_.Run(kQuotaErrorAbort, UsageAndQuota()); 354 weak_factory_.InvalidateWeakPtrs();
355 callback_.Run(kQuotaErrorAbort, QuotaSettings(), 0, 0, 0, false);
473 DeleteSoon(); 356 DeleteSoon();
474 } 357 }
475 358
476 void Completed() override { 359 void Completed() override {
477 // crbug.com/349708 360 weak_factory_.InvalidateWeakPtrs();
478 TRACE_EVENT0("io", "UsageAndQuotaCallbackDispatcher::Completed"); 361 callback_.Run(kQuotaStatusOk, settings_, available_space_, total_space_,
479 362 global_usage_, global_usage_is_complete_);
480 DCHECK(!has_usage_ || usage_and_quota_.usage >= 0); 363 DeleteSoon();
481 DCHECK(!has_global_limited_usage_ || 364 }
482 usage_and_quota_.global_limited_usage >= 0); 365
483 DCHECK(!has_quota_ || usage_and_quota_.quota >= 0); 366 private:
484 DCHECK(!has_available_disk_space_ || 367 QuotaManager* manager() const {
485 usage_and_quota_.available_disk_space >= 0); 368 return static_cast<QuotaManager*>(observer());
486 369 }
487 callback_.Run(status_, usage_and_quota_); 370
488 DeleteSoon(); 371 void OnGotSettings(const base::Closure& barrier_closure,
489 } 372 const QuotaSettings& settings) {
490 373 settings_ = settings;
491 void CheckCompleted() { 374 barrier_closure.Run();
492 if (--waiting_callbacks_ <= 0) 375 }
376
377 void OnGotCapacity(const base::Closure& barrier_closure,
378 int64_t total_space,
379 int64_t available_space) {
380 total_space_ = total_space;
381 available_space_ = available_space;
382 barrier_closure.Run();
383 }
384
385 void OnBarrierComplete() {
386 // Avoid computing the full current_usage when there's no pressure.
jsbell 2016/11/09 00:12:04 Nice.
387 int64_t consumed_space = total_space_ - available_space_;
388 if (consumed_space < settings_.pool_size &&
389 available_space_ > settings_.must_remain_available) {
390 DCHECK(!global_usage_is_complete_);
391 global_usage_ =
392 manager()->GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage();
493 CallCompleted(); 393 CallCompleted();
494 } 394 return;
495 395 }
496 // For sanity checks, they're checked only when DCHECK is on. 396 manager()->GetGlobalUsage(
497 bool has_usage_; 397 kStorageTypeTemporary,
498 bool has_global_limited_usage_; 398 base::Bind(&EvictionRoundInfoHelper::OnGotGlobalUsage,
499 bool has_quota_; 399 weak_factory_.GetWeakPtr()));
500 bool has_available_disk_space_; 400 }
501 401
502 QuotaStatusCode status_; 402 void OnGotGlobalUsage(int64_t usage, int64_t unlimited_usage) {
503 UsageAndQuota usage_and_quota_; 403 global_usage_ = std::max(INT64_C(0), usage - unlimited_usage);
504 QuotaManager::UsageAndQuotaCallback callback_; 404 global_usage_is_complete_ = true;
505 int waiting_callbacks_; 405 CallCompleted();
506 406 }
507 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher); 407
408 EvictionRoundInfoCallback callback_;
409 QuotaSettings settings_;
410 int64_t available_space_ = 0;
411 int64_t total_space_ = 0;
412 int64_t global_usage_ = 0;
413 bool global_usage_is_complete_ = false;
414 base::WeakPtrFactory<EvictionRoundInfoHelper> weak_factory_;
415 DISALLOW_COPY_AND_ASSIGN(EvictionRoundInfoHelper);
508 }; 416 };
509 417
510 class QuotaManager::GetUsageInfoTask : public QuotaTask { 418 class QuotaManager::GetUsageInfoTask : public QuotaTask {
511 public: 419 public:
512 GetUsageInfoTask( 420 GetUsageInfoTask(
513 QuotaManager* manager, 421 QuotaManager* manager,
514 const GetUsageInfoCallback& callback) 422 const GetUsageInfoCallback& callback)
515 : QuotaTask(manager), 423 : QuotaTask(manager),
516 callback_(callback), 424 callback_(callback),
517 weak_factory_(this) { 425 weak_factory_(this) {
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 OriginInfoTableEntries entries_; 767 OriginInfoTableEntries entries_;
860 }; 768 };
861 769
862 // QuotaManager --------------------------------------------------------------- 770 // QuotaManager ---------------------------------------------------------------
863 771
864 QuotaManager::QuotaManager( 772 QuotaManager::QuotaManager(
865 bool is_incognito, 773 bool is_incognito,
866 const base::FilePath& profile_path, 774 const base::FilePath& profile_path,
867 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, 775 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread,
868 const scoped_refptr<base::SequencedTaskRunner>& db_thread, 776 const scoped_refptr<base::SequencedTaskRunner>& db_thread,
869 const scoped_refptr<SpecialStoragePolicy>& special_storage_policy) 777 const scoped_refptr<SpecialStoragePolicy>& special_storage_policy,
778 const GetQuotaSettingsFunc& get_settings_function)
870 : is_incognito_(is_incognito), 779 : is_incognito_(is_incognito),
871 profile_path_(profile_path), 780 profile_path_(profile_path),
872 proxy_(new QuotaManagerProxy(this, io_thread)), 781 proxy_(new QuotaManagerProxy(this, io_thread)),
873 db_disabled_(false), 782 db_disabled_(false),
874 eviction_disabled_(false), 783 eviction_disabled_(false),
875 io_thread_(io_thread), 784 io_thread_(io_thread),
876 db_thread_(db_thread), 785 db_thread_(db_thread),
786 get_settings_function_(get_settings_function),
877 is_getting_eviction_origin_(false), 787 is_getting_eviction_origin_(false),
878 temporary_quota_initialized_(false),
879 temporary_quota_override_(-1),
880 special_storage_policy_(special_storage_policy), 788 special_storage_policy_(special_storage_policy),
881 get_volume_info_fn_(&QuotaManager::GetVolumeInfo), 789 get_volume_info_fn_(&QuotaManager::GetVolumeInfo),
882 storage_monitor_(new StorageMonitor(this)), 790 storage_monitor_(new StorageMonitor(this)),
883 weak_factory_(this) {} 791 weak_factory_(this) {
792 DCHECK_EQ(settings_.refresh_interval, base::TimeDelta::Max());
793 if (!get_settings_function.is_null()) {
794 // Reset the interval to ensure we use the get_settings_function
795 // the first times settings_ is needed.
796 settings_.refresh_interval = base::TimeDelta();
797 get_settings_task_runner_ = base::ThreadTaskRunnerHandle::Get();
798 }
799 }
800
801 void QuotaManager::SetQuotaSettings(const QuotaSettings& settings) {
802 settings_ = settings;
803 settings_timestamp_ = base::TimeTicks::Now();
804 }
884 805
885 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) { 806 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) {
886 LazyInitialize(); 807 LazyInitialize();
887 GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback); 808 GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback);
888 get_usage_info->Start(); 809 get_usage_info->Start();
889 } 810 }
890 811
812 namespace {
813 bool IsSupportedType(StorageType type) {
814 return type != kStorageTypeTemporary || type != kStorageTypePersistent ||
815 type != kStorageTypeSyncable;
816 }
817
818 bool IsSupportedIncognitoType(StorageType type) {
819 return type != kStorageTypeTemporary || type != kStorageTypePersistent;
820 }
821 } // anon
822
891 void QuotaManager::GetUsageAndQuotaForWebApps( 823 void QuotaManager::GetUsageAndQuotaForWebApps(
892 const GURL& origin, 824 const GURL& origin,
893 StorageType type, 825 StorageType type,
894 const GetUsageAndQuotaCallback& callback) { 826 const UsageAndQuotaCallback& callback) {
895 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed. 827 DCHECK(origin == origin.GetOrigin());
896 tracked_objects::ScopedTracker tracking_profile( 828 if (!IsSupportedType(type) ||
897 FROM_HERE_WITH_EXPLICIT_FUNCTION( 829 (is_incognito_ && !IsSupportedIncognitoType(type))) {
898 "477117 QuotaManager::GetUsageAndQuotaForWebApps"));
899 if (type != kStorageTypeTemporary &&
900 type != kStorageTypePersistent &&
901 type != kStorageTypeSyncable) {
902 callback.Run(kQuotaErrorNotSupported, 0, 0); 830 callback.Run(kQuotaErrorNotSupported, 0, 0);
903 return; 831 return;
904 } 832 }
905
906 DCHECK(origin == origin.GetOrigin());
907 LazyInitialize(); 833 LazyInitialize();
908 834 UsageAndQuotaHelper* helper = new UsageAndQuotaHelper(
909 bool unlimited = IsStorageUnlimited(origin, type); 835 this, origin, type, IsStorageUnlimited(origin, type), is_incognito_,
910 bool can_query_disk_size = CanQueryDiskSize(origin); 836 callback);
911 837 helper->Start();
912 UsageAndQuotaCallbackDispatcher* dispatcher =
913 new UsageAndQuotaCallbackDispatcher(this);
914
915 if (unlimited) {
916 dispatcher->set_quota(kNoLimit);
917 } else {
918 if (type == kStorageTypeTemporary) {
919 GetUsageTracker(type)->GetGlobalLimitedUsage(
920 dispatcher->GetGlobalLimitedUsageCallback());
921 GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
922 } else if (type == kStorageTypePersistent) {
923 GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin),
924 dispatcher->GetQuotaCallback());
925 } else {
926 dispatcher->set_quota(kSyncableStorageDefaultHostQuota);
927 }
928 }
929
930 DCHECK(GetUsageTracker(type));
931 GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin),
932 dispatcher->GetHostUsageCallback());
933
934 if (!is_incognito_ && (unlimited || can_query_disk_size))
935 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
936
937 dispatcher->WaitForResults(base::Bind(
938 &DispatchUsageAndQuotaForWebApps,
939 type, is_incognito_, unlimited, can_query_disk_size,
940 callback));
941 } 838 }
942 839
943 void QuotaManager::GetUsageAndQuota( 840 void QuotaManager::GetUsageAndQuota(const GURL& origin,
944 const GURL& origin, StorageType type, 841 StorageType type,
945 const GetUsageAndQuotaCallback& callback) { 842 const UsageAndQuotaCallback& callback) {
946 DCHECK(origin == origin.GetOrigin()); 843 DCHECK(origin == origin.GetOrigin());
947 844
948 if (IsStorageUnlimited(origin, type)) { 845 if (IsStorageUnlimited(origin, type)) {
846 // TODO: This seems like a non-obvious odd behavior.
jsbell 2016/11/09 00:12:04 That it doesn't give useful numbers? (i.e. actual
949 callback.Run(kQuotaStatusOk, 0, kNoLimit); 847 callback.Run(kQuotaStatusOk, 0, kNoLimit);
950 return; 848 return;
951 } 849 }
952 850
953 GetUsageAndQuotaForWebApps(origin, type, callback); 851 GetUsageAndQuotaForWebApps(origin, type, callback);
954 } 852 }
955 853
956 void QuotaManager::NotifyStorageAccessed( 854 void QuotaManager::NotifyStorageAccessed(
957 QuotaClient::ID client_id, 855 QuotaClient::ID client_id,
958 const GURL& origin, StorageType type) { 856 const GURL& origin, StorageType type) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1001 int quota_client_mask, 899 int quota_client_mask,
1002 const StatusCallback& callback) { 900 const StatusCallback& callback) {
1003 DeleteOriginDataInternal(origin, type, quota_client_mask, false, callback); 901 DeleteOriginDataInternal(origin, type, quota_client_mask, false, callback);
1004 } 902 }
1005 903
1006 void QuotaManager::DeleteHostData(const std::string& host, 904 void QuotaManager::DeleteHostData(const std::string& host,
1007 StorageType type, 905 StorageType type,
1008 int quota_client_mask, 906 int quota_client_mask,
1009 const StatusCallback& callback) { 907 const StatusCallback& callback) {
1010 LazyInitialize(); 908 LazyInitialize();
1011
1012 if (host.empty() || clients_.empty()) { 909 if (host.empty() || clients_.empty()) {
1013 callback.Run(kQuotaStatusOk); 910 callback.Run(kQuotaStatusOk);
1014 return; 911 return;
1015 } 912 }
1016 913
1017 HostDataDeleter* deleter = 914 HostDataDeleter* deleter =
1018 new HostDataDeleter(this, host, type, quota_client_mask, callback); 915 new HostDataDeleter(this, host, type, quota_client_mask, callback);
1019 deleter->Start(); 916 deleter->Start();
1020 } 917 }
1021 918
1022 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback& callback) {
1023 if (!available_space_callbacks_.Add(callback))
1024 return;
1025 // crbug.com/349708
1026 TRACE_EVENT0("io", "QuotaManager::GetAvailableSpace");
1027
1028 PostTaskAndReplyWithResult(
1029 db_thread_.get(),
1030 FROM_HERE,
1031 base::Bind(&QuotaManager::CallGetAmountOfFreeDiskSpace,
1032 get_volume_info_fn_, profile_path_),
1033 base::Bind(&QuotaManager::DidGetAvailableSpace,
1034 weak_factory_.GetWeakPtr()));
1035 }
1036
1037 void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback& callback) {
1038 LazyInitialize();
1039 if (!temporary_quota_initialized_) {
1040 db_initialization_callbacks_.Add(base::Bind(
1041 &QuotaManager::GetTemporaryGlobalQuota,
1042 weak_factory_.GetWeakPtr(), callback));
1043 return;
1044 }
1045
1046 if (temporary_quota_override_ > 0) {
1047 callback.Run(kQuotaStatusOk, temporary_quota_override_);
1048 return;
1049 }
1050
1051 UsageAndQuotaCallbackDispatcher* dispatcher =
1052 new UsageAndQuotaCallbackDispatcher(this);
1053 GetUsageTracker(kStorageTypeTemporary)->
1054 GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
1055 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
1056 dispatcher->WaitForResults(
1057 base::Bind(&DispatchTemporaryGlobalQuotaCallback, callback));
1058 }
1059
1060 void QuotaManager::SetTemporaryGlobalOverrideQuota(
1061 int64_t new_quota,
1062 const QuotaCallback& callback) {
1063 LazyInitialize();
1064
1065 if (new_quota < 0) {
1066 if (!callback.is_null())
1067 callback.Run(kQuotaErrorInvalidModification, -1);
1068 return;
1069 }
1070
1071 if (db_disabled_) {
1072 if (!callback.is_null())
1073 callback.Run(kQuotaErrorInvalidAccess, -1);
1074 return;
1075 }
1076
1077 int64_t* new_quota_ptr = new int64_t(new_quota);
1078 PostTaskAndReplyWithResultForDBThread(
1079 FROM_HERE,
1080 base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread,
1081 base::Unretained(new_quota_ptr)),
1082 base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota,
1083 weak_factory_.GetWeakPtr(),
1084 callback,
1085 base::Owned(new_quota_ptr)));
1086 }
1087
1088 void QuotaManager::GetPersistentHostQuota(const std::string& host, 919 void QuotaManager::GetPersistentHostQuota(const std::string& host,
1089 const QuotaCallback& callback) { 920 const QuotaCallback& callback) {
1090 LazyInitialize(); 921 LazyInitialize();
1091 if (host.empty()) { 922 if (host.empty()) {
1092 // This could happen if we are called on file:///. 923 // This could happen if we are called on file:///.
1093 // TODO(kinuko) We may want to respect --allow-file-access-from-files 924 // TODO(kinuko) We may want to respect --allow-file-access-from-files
1094 // command line switch. 925 // command line switch.
1095 callback.Run(kQuotaStatusOk, 0); 926 callback.Run(kQuotaStatusOk, 0);
1096 return; 927 return;
1097 } 928 }
(...skipping 21 matching lines...) Expand all
1119 // This could happen if we are called on file:///. 950 // This could happen if we are called on file:///.
1120 callback.Run(kQuotaErrorNotSupported, 0); 951 callback.Run(kQuotaErrorNotSupported, 0);
1121 return; 952 return;
1122 } 953 }
1123 954
1124 if (new_quota < 0) { 955 if (new_quota < 0) {
1125 callback.Run(kQuotaErrorInvalidModification, -1); 956 callback.Run(kQuotaErrorInvalidModification, -1);
1126 return; 957 return;
1127 } 958 }
1128 959
1129 if (kPerHostPersistentQuotaLimit < new_quota) { 960 // Cap the requested size at the per-host quota limit.
1130 // Cap the requested size at the per-host quota limit. 961 new_quota = std::min(new_quota, kPerHostPersistentQuotaLimit);
1131 new_quota = kPerHostPersistentQuotaLimit;
1132 }
1133 962
1134 if (db_disabled_) { 963 if (db_disabled_) {
1135 callback.Run(kQuotaErrorInvalidAccess, -1); 964 callback.Run(kQuotaErrorInvalidAccess, -1);
1136 return; 965 return;
1137 } 966 }
1138 967
1139 int64_t* new_quota_ptr = new int64_t(new_quota); 968 int64_t* new_quota_ptr = new int64_t(new_quota);
1140 PostTaskAndReplyWithResultForDBThread( 969 PostTaskAndReplyWithResultForDBThread(
1141 FROM_HERE, 970 FROM_HERE,
1142 base::Bind(&SetPersistentHostQuotaOnDBThread, 971 base::Bind(&SetPersistentHostQuotaOnDBThread,
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
1282 QuotaManager::EvictionContext::EvictionContext() 1111 QuotaManager::EvictionContext::EvictionContext()
1283 : evicted_type(kStorageTypeUnknown) { 1112 : evicted_type(kStorageTypeUnknown) {
1284 } 1113 }
1285 1114
1286 QuotaManager::EvictionContext::~EvictionContext() { 1115 QuotaManager::EvictionContext::~EvictionContext() {
1287 } 1116 }
1288 1117
1289 void QuotaManager::LazyInitialize() { 1118 void QuotaManager::LazyInitialize() {
1290 DCHECK(io_thread_->BelongsToCurrentThread()); 1119 DCHECK(io_thread_->BelongsToCurrentThread());
1291 if (database_) { 1120 if (database_) {
1292 // Initialization seems to be done already. 1121 // Already initialized.
1293 return; 1122 return;
1294 } 1123 }
1295 1124
1296 // Use an empty path to open an in-memory only databse for incognito. 1125 // Use an empty path to open an in-memory only databse for incognito.
1297 database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() : 1126 database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() :
1298 profile_path_.AppendASCII(kDatabaseName))); 1127 profile_path_.AppendASCII(kDatabaseName)));
1299 1128
1300 temporary_usage_tracker_.reset(new UsageTracker( 1129 temporary_usage_tracker_.reset(new UsageTracker(
1301 clients_, kStorageTypeTemporary, special_storage_policy_.get(), 1130 clients_, kStorageTypeTemporary, special_storage_policy_.get(),
1302 storage_monitor_.get())); 1131 storage_monitor_.get()));
1303 persistent_usage_tracker_.reset(new UsageTracker( 1132 persistent_usage_tracker_.reset(new UsageTracker(
1304 clients_, kStorageTypePersistent, special_storage_policy_.get(), 1133 clients_, kStorageTypePersistent, special_storage_policy_.get(),
1305 storage_monitor_.get())); 1134 storage_monitor_.get()));
1306 syncable_usage_tracker_.reset(new UsageTracker( 1135 syncable_usage_tracker_.reset(new UsageTracker(
1307 clients_, kStorageTypeSyncable, special_storage_policy_.get(), 1136 clients_, kStorageTypeSyncable, special_storage_policy_.get(),
1308 storage_monitor_.get())); 1137 storage_monitor_.get()));
1309 1138
1310 int64_t* temporary_quota_override = new int64_t(-1); 1139 if (!is_incognito_) {
1311 int64_t* desired_available_space = new int64_t(-1); 1140 histogram_timer_.Start(
1141 FROM_HERE, base::TimeDelta::FromMilliseconds(kReportHistogramInterval),
1142 this, &QuotaManager::ReportHistogram);
1143 }
1144
1145 base::PostTaskAndReplyWithResult(
1146 db_thread_.get(), FROM_HERE,
1147 base::Bind(&QuotaDatabase::IsOriginDatabaseBootstrapped,
1148 base::Unretained(database_.get())),
1149 base::Bind(&QuotaManager::FinishLazyInitialize,
1150 weak_factory_.GetWeakPtr()));
1151 }
1152
1153 void QuotaManager::FinishLazyInitialize(bool is_database_bootstrapped) {
1154 is_database_bootstrapped_ = is_database_bootstrapped;
1155 StartEviction();
1156 }
1157
1158 void QuotaManager::BootstrapDatabaseForEviction(
1159 const GetOriginCallback& did_get_origin_callback,
1160 int64_t usage,
1161 int64_t unlimited_usage) {
1162 // The usage cache should be fully populated now so we can
1163 // seed the database with origins we know about.
1164 std::set<GURL>* origins = new std::set<GURL>;
1165 temporary_usage_tracker_->GetCachedOrigins(origins);
1312 PostTaskAndReplyWithResultForDBThread( 1166 PostTaskAndReplyWithResultForDBThread(
1313 FROM_HERE, 1167 FROM_HERE, base::Bind(&BootstrapDatabaseOnDBThread, base::Owned(origins)),
1314 base::Bind(&InitializeOnDBThread, 1168 base::Bind(&QuotaManager::DidBootstrapDatabase,
1315 base::Unretained(temporary_quota_override), 1169 weak_factory_.GetWeakPtr(), did_get_origin_callback));
1316 base::Unretained(desired_available_space)), 1170 }
1317 base::Bind(&QuotaManager::DidInitialize, 1171
1318 weak_factory_.GetWeakPtr(), 1172 void QuotaManager::DidBootstrapDatabase(
1319 base::Owned(temporary_quota_override), 1173 const GetOriginCallback& did_get_origin_callback,
1320 base::Owned(desired_available_space))); 1174 bool success) {
1175 is_database_bootstrapped_ = success;
1176 DidDatabaseWork(success);
1177 GetLRUOrigin(kStorageTypeTemporary, did_get_origin_callback);
1321 } 1178 }
1322 1179
1323 void QuotaManager::RegisterClient(QuotaClient* client) { 1180 void QuotaManager::RegisterClient(QuotaClient* client) {
1324 DCHECK(!database_.get()); 1181 DCHECK(!database_.get());
1325 clients_.push_back(client); 1182 clients_.push_back(client);
1326 } 1183 }
1327 1184
1328 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const { 1185 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const {
1329 switch (type) { 1186 switch (type) {
1330 case kStorageTypeTemporary: 1187 case kStorageTypeTemporary:
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1405 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread, 1262 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread,
1406 base::Unretained(helper)), 1263 base::Unretained(helper)),
1407 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable, 1264 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable,
1408 base::Owned(helper), 1265 base::Owned(helper),
1409 weak_factory_.GetWeakPtr(), 1266 weak_factory_.GetWeakPtr(),
1410 callback)); 1267 callback));
1411 } 1268 }
1412 1269
1413 void QuotaManager::StartEviction() { 1270 void QuotaManager::StartEviction() {
1414 DCHECK(!temporary_storage_evictor_.get()); 1271 DCHECK(!temporary_storage_evictor_.get());
1272 if (eviction_disabled_)
1273 return;
1415 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor( 1274 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(
1416 this, kEvictionIntervalInMilliSeconds)); 1275 this, kEvictionIntervalInMilliSeconds));
1417 if (desired_available_space_ >= 0)
1418 temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction(
1419 desired_available_space_);
1420 temporary_storage_evictor_->Start(); 1276 temporary_storage_evictor_->Start();
1421 } 1277 }
1422 1278
1423 void QuotaManager::DeleteOriginFromDatabase(const GURL& origin, 1279 void QuotaManager::DeleteOriginFromDatabase(const GURL& origin,
1424 StorageType type, 1280 StorageType type,
1425 bool is_eviction) { 1281 bool is_eviction) {
1426 LazyInitialize(); 1282 LazyInitialize();
1427 if (db_disabled_) 1283 if (db_disabled_)
1428 return; 1284 return;
1429 1285
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
1595 const GetOriginCallback& callback) { 1451 const GetOriginCallback& callback) {
1596 LazyInitialize(); 1452 LazyInitialize();
1597 // This must not be called while there's an in-flight task. 1453 // This must not be called while there's an in-flight task.
1598 DCHECK(!is_getting_eviction_origin_); 1454 DCHECK(!is_getting_eviction_origin_);
1599 is_getting_eviction_origin_ = true; 1455 is_getting_eviction_origin_ = true;
1600 1456
1601 GetOriginCallback did_get_origin_callback = 1457 GetOriginCallback did_get_origin_callback =
1602 base::Bind(&QuotaManager::DidGetEvictionOrigin, 1458 base::Bind(&QuotaManager::DidGetEvictionOrigin,
1603 weak_factory_.GetWeakPtr(), callback); 1459 weak_factory_.GetWeakPtr(), callback);
1604 1460
1461 // TODO(michaeln): remove support for this for now?
1605 if (type == kStorageTypeTemporary && temporary_storage_eviction_policy_) { 1462 if (type == kStorageTypeTemporary && temporary_storage_eviction_policy_) {
1606 std::map<GURL, int64_t> usage_map; 1463 std::map<GURL, int64_t> usage_map;
1607 // The cached origins are populated by the prior call to 1464 // The cached origins are populated by the prior call to
1608 // GetUsageAndQuotaForEviction(). 1465 // GetUsageAndQuotaForEviction().
1609 GetUsageTracker(kStorageTypeTemporary)->GetCachedOriginsUsage(&usage_map); 1466 GetUsageTracker(kStorageTypeTemporary)->GetCachedOriginsUsage(&usage_map);
1610 1467
1611 temporary_storage_eviction_policy_->GetEvictionOrigin( 1468 temporary_storage_eviction_policy_->GetEvictionOrigin(
1612 special_storage_policy_, GetEvictionOriginExceptions(extra_exceptions), 1469 special_storage_policy_, GetEvictionOriginExceptions(extra_exceptions),
1613 usage_map, global_quota, did_get_origin_callback); 1470 usage_map, global_quota, did_get_origin_callback);
1614 1471
1615 return; 1472 return;
1616 } 1473 }
1617 1474
1618 // TODO(calamity): convert LRU origin retrieval into a QuotaEvictionPolicy. 1475 if (!is_database_bootstrapped_ && !eviction_disabled_) {
1476 // Once bootstrapped, GetLRUOrigin will be called.
1477 GetGlobalUsage(
1478 kStorageTypeTemporary,
1479 base::Bind(&QuotaManager::BootstrapDatabaseForEviction,
1480 weak_factory_.GetWeakPtr(), did_get_origin_callback));
1481 return;
1482 }
1483
1619 GetLRUOrigin(type, did_get_origin_callback); 1484 GetLRUOrigin(type, did_get_origin_callback);
1620 } 1485 }
1621 1486
1622 void QuotaManager::EvictOriginData(const GURL& origin, 1487 void QuotaManager::EvictOriginData(const GURL& origin,
1623 StorageType type, 1488 StorageType type,
1624 const EvictOriginDataCallback& callback) { 1489 const StatusCallback& callback) {
1625 DCHECK(io_thread_->BelongsToCurrentThread()); 1490 DCHECK(io_thread_->BelongsToCurrentThread());
1626 DCHECK_EQ(type, kStorageTypeTemporary); 1491 DCHECK_EQ(type, kStorageTypeTemporary);
1627 1492
1628 eviction_context_.evicted_origin = origin; 1493 eviction_context_.evicted_origin = origin;
1629 eviction_context_.evicted_type = type; 1494 eviction_context_.evicted_type = type;
1630 eviction_context_.evict_origin_data_callback = callback; 1495 eviction_context_.evict_origin_data_callback = callback;
1631 1496
1632 DeleteOriginDataInternal(origin, type, QuotaClient::kAllClientsMask, true, 1497 DeleteOriginDataInternal(origin, type, QuotaClient::kAllClientsMask, true,
1633 base::Bind(&QuotaManager::DidOriginDataEvicted, 1498 base::Bind(&QuotaManager::DidOriginDataEvicted,
1634 weak_factory_.GetWeakPtr())); 1499 weak_factory_.GetWeakPtr()));
1635 } 1500 }
1636 1501
1637 void QuotaManager::GetUsageAndQuotaForEviction( 1502 void QuotaManager::GetEvictionRoundInfo(
1638 const UsageAndQuotaCallback& callback) { 1503 const EvictionRoundInfoCallback& callback) {
1639 // crbug.com/349708
1640 TRACE_EVENT0("io", "QuotaManager::GetUsageAndQuotaForEviction");
1641
1642 DCHECK(io_thread_->BelongsToCurrentThread()); 1504 DCHECK(io_thread_->BelongsToCurrentThread());
1643 LazyInitialize(); 1505 LazyInitialize();
1644 1506 EvictionRoundInfoHelper* helper = new EvictionRoundInfoHelper(this, callback);
1645 UsageAndQuotaCallbackDispatcher* dispatcher = 1507 helper->Start();
1646 new UsageAndQuotaCallbackDispatcher(this);
1647 GetUsageTracker(kStorageTypeTemporary)
1648 ->GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
1649 GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
1650 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
1651 dispatcher->WaitForResults(callback);
1652 }
1653
1654 void QuotaManager::AsyncGetVolumeInfo(
1655 const VolumeInfoCallback& callback) {
1656 DCHECK(io_thread_->BelongsToCurrentThread());
1657 uint64_t* available_space = new uint64_t(0);
1658 uint64_t* total_space = new uint64_t(0);
1659 PostTaskAndReplyWithResult(
1660 db_thread_.get(),
1661 FROM_HERE,
1662 base::Bind(get_volume_info_fn_,
1663 profile_path_,
1664 base::Unretained(available_space),
1665 base::Unretained(total_space)),
1666 base::Bind(&QuotaManager::DidGetVolumeInfo,
1667 weak_factory_.GetWeakPtr(),
1668 callback,
1669 base::Owned(available_space),
1670 base::Owned(total_space)));
1671 }
1672
1673 void QuotaManager::DidGetVolumeInfo(
1674 const VolumeInfoCallback& callback,
1675 uint64_t* available_space, uint64_t* total_space, bool success) {
1676 DCHECK(io_thread_->BelongsToCurrentThread());
1677 callback.Run(success, *available_space, *total_space);
1678 } 1508 }
1679 1509
1680 void QuotaManager::GetLRUOrigin(StorageType type, 1510 void QuotaManager::GetLRUOrigin(StorageType type,
1681 const GetOriginCallback& callback) { 1511 const GetOriginCallback& callback) {
1682 LazyInitialize(); 1512 LazyInitialize();
1683 // This must not be called while there's an in-flight task. 1513 // This must not be called while there's an in-flight task.
1684 DCHECK(lru_origin_callback_.is_null()); 1514 DCHECK(lru_origin_callback_.is_null());
1685 lru_origin_callback_ = callback; 1515 lru_origin_callback_ = callback;
1686 if (db_disabled_) { 1516 if (db_disabled_) {
1687 lru_origin_callback_.Run(GURL()); 1517 lru_origin_callback_.Run(GURL());
1688 lru_origin_callback_.Reset(); 1518 lru_origin_callback_.Reset();
1689 return; 1519 return;
1690 } 1520 }
1691 1521
1692 GURL* url = new GURL; 1522 GURL* url = new GURL;
1693 PostTaskAndReplyWithResultForDBThread( 1523 PostTaskAndReplyWithResultForDBThread(
1694 FROM_HERE, base::Bind(&GetLRUOriginOnDBThread, type, 1524 FROM_HERE, base::Bind(&GetLRUOriginOnDBThread, type,
1695 GetEvictionOriginExceptions(std::set<GURL>()), 1525 GetEvictionOriginExceptions(std::set<GURL>()),
1696 base::RetainedRef(special_storage_policy_), 1526 base::RetainedRef(special_storage_policy_),
1697 base::Unretained(url)), 1527 base::Unretained(url)),
1698 base::Bind(&QuotaManager::DidGetLRUOrigin, weak_factory_.GetWeakPtr(), 1528 base::Bind(&QuotaManager::DidGetLRUOrigin, weak_factory_.GetWeakPtr(),
1699 base::Owned(url))); 1529 base::Owned(url)));
1700 } 1530 }
1701 1531
1702 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
1703 const QuotaCallback& callback,
1704 const int64_t* new_quota,
1705 bool success) {
1706 QuotaStatusCode status = kQuotaErrorInvalidAccess;
1707 DidDatabaseWork(success);
1708 if (success) {
1709 temporary_quota_override_ = *new_quota;
1710 status = kQuotaStatusOk;
1711 }
1712
1713 if (callback.is_null())
1714 return;
1715
1716 callback.Run(status, *new_quota);
1717 }
1718
1719 void QuotaManager::DidGetPersistentHostQuota(const std::string& host, 1532 void QuotaManager::DidGetPersistentHostQuota(const std::string& host,
1720 const int64_t* quota, 1533 const int64_t* quota,
1721 bool success) { 1534 bool success) {
1722 DidDatabaseWork(success); 1535 DidDatabaseWork(success);
1723 persistent_host_quota_callbacks_.Run(host, kQuotaStatusOk, *quota); 1536 persistent_host_quota_callbacks_.Run(
1537 host, kQuotaStatusOk, std::min(*quota, kPerHostPersistentQuotaLimit));
1724 } 1538 }
1725 1539
1726 void QuotaManager::DidSetPersistentHostQuota(const std::string& host, 1540 void QuotaManager::DidSetPersistentHostQuota(const std::string& host,
1727 const QuotaCallback& callback, 1541 const QuotaCallback& callback,
1728 const int64_t* new_quota, 1542 const int64_t* new_quota,
1729 bool success) { 1543 bool success) {
1730 DidDatabaseWork(success); 1544 DidDatabaseWork(success);
1731 callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota); 1545 callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota);
1732 } 1546 }
1733 1547
1734 void QuotaManager::DidInitialize(int64_t* temporary_quota_override,
1735 int64_t* desired_available_space,
1736 bool success) {
1737 temporary_quota_override_ = *temporary_quota_override;
1738 desired_available_space_ = *desired_available_space;
1739 temporary_quota_initialized_ = true;
1740 DidDatabaseWork(success);
1741
1742 if (!is_incognito_) {
1743 histogram_timer_.Start(FROM_HERE,
1744 base::TimeDelta::FromMilliseconds(
1745 kReportHistogramInterval),
1746 this, &QuotaManager::ReportHistogram);
1747 }
1748
1749 db_initialization_callbacks_.Run();
1750 GetTemporaryGlobalQuota(
1751 base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota,
1752 weak_factory_.GetWeakPtr(), base::TimeTicks::Now()));
1753 }
1754
1755 void QuotaManager::DidGetLRUOrigin(const GURL* origin, 1548 void QuotaManager::DidGetLRUOrigin(const GURL* origin,
1756 bool success) { 1549 bool success) {
1757 DidDatabaseWork(success); 1550 DidDatabaseWork(success);
1758 1551
1759 lru_origin_callback_.Run(*origin); 1552 lru_origin_callback_.Run(*origin);
1760 lru_origin_callback_.Reset(); 1553 lru_origin_callback_.Reset();
1761 } 1554 }
1762 1555
1763 void QuotaManager::DidGetInitialTemporaryGlobalQuota( 1556 namespace {
1764 base::TimeTicks start_ticks, 1557 void DidGetSettingsThreadAdapter(base::TaskRunner* task_runner,
1765 QuotaStatusCode status, 1558 const OptionalQuotaSettingsCallback& callback,
1766 int64_t quota_unused) { 1559 base::Optional<QuotaSettings> settings) {
1767 UMA_HISTOGRAM_LONG_TIMES( 1560 task_runner->PostTask(FROM_HERE, base::Bind(callback, std::move(settings)));
1768 "Quota.TimeToInitializeGlobalQuota", 1561 }
1769 base::TimeTicks::Now() - start_ticks); 1562 } // namespace
1770 1563
1771 if (eviction_disabled_) 1564 void QuotaManager::GetQuotaSettings(const QuotaSettingsCallback& callback) {
1565 if (base::TimeTicks::Now() - settings_timestamp_ <
1566 settings_.refresh_interval) {
1567 callback.Run(settings_);
1568 return;
1569 }
1570
1571 if (!settings_callbacks_.Add(callback))
1772 return; 1572 return;
1773 1573
1774 std::set<GURL>* origins = new std::set<GURL>; 1574 // We invoke our clients GetQuotaSettingsFunc on the
1775 temporary_usage_tracker_->GetCachedOrigins(origins); 1575 // UI thread and plumb the resulting value back to this thread.
1776 // This will call the StartEviction() when initial origin registration 1576 get_settings_task_runner_->PostTask(
1777 // is completed.
1778 PostTaskAndReplyWithResultForDBThread(
1779 FROM_HERE, 1577 FROM_HERE,
1780 base::Bind(&InitializeTemporaryOriginsInfoOnDBThread, 1578 base::Bind(
1781 base::Owned(origins)), 1579 get_settings_function_, profile_path_, is_incognito_,
1782 base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo, 1580 base::Bind(&DidGetSettingsThreadAdapter,
1581 base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
1582 base::Bind(&QuotaManager::DidGetSettings,
1583 weak_factory_.GetWeakPtr(),
1584 base::TimeTicks::Now()))));
1585 }
1586
1587 void QuotaManager::DidGetSettings(base::TimeTicks start_ticks,
1588 base::Optional<QuotaSettings> settings) {
1589 if (!settings) {
1590 settings = settings_;
1591 settings->refresh_interval = base::TimeDelta::FromMinutes(1);
1592 }
1593 SetQuotaSettings(*settings);
1594 settings_callbacks_.Run(*settings);
1595 UMA_HISTOGRAM_MBYTES("Quota.GlobalTemporaryPoolSize", settings->pool_size);
1596 UMA_HISTOGRAM_LONG_TIMES("Quota.TimeToGetSettings",
1597 base::TimeTicks::Now() - start_ticks);
1598 }
1599
1600 void QuotaManager::GetStorageCapacity(const StorageCapacityCallback& callback) {
1601 if (!storage_capacity_callbacks_.Add(callback))
1602 return;
1603 if (is_incognito_) {
1604 GetQuotaSettings(
1605 base::Bind(&QuotaManager::ContinueIncognitoGetStorageCapacity,
1606 weak_factory_.GetWeakPtr()));
1607 return;
1608 }
1609 base::PostTaskAndReplyWithResult(
1610 db_thread_.get(), FROM_HERE,
1611 base::Bind(&QuotaManager::CallGetVolumeInfo, get_volume_info_fn_,
1612 profile_path_),
1613 base::Bind(&QuotaManager::DidGetStorageCapacity,
1783 weak_factory_.GetWeakPtr())); 1614 weak_factory_.GetWeakPtr()));
1784 } 1615 }
1785 1616
1786 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) { 1617 void QuotaManager::ContinueIncognitoGetStorageCapacity(
1787 DidDatabaseWork(success); 1618 const QuotaSettings& settings) {
1788 if (success) 1619 int64_t current_usage =
1789 StartEviction(); 1620 GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage();
1621 current_usage += GetUsageTracker(kStorageTypePersistent)->GetCachedUsage();
1622 int64_t available_space =
1623 std::max(INT64_C(0), settings.pool_size - current_usage);
1624 DidGetStorageCapacity(std::make_pair(settings.pool_size, available_space));
1790 } 1625 }
1791 1626
1792 void QuotaManager::DidGetAvailableSpace(int64_t space) { 1627 void QuotaManager::DidGetStorageCapacity(
1793 // crbug.com/349708 1628 const std::pair<int64_t, int64_t>& total_and_available) {
1794 TRACE_EVENT1("io", "QuotaManager::DidGetAvailableSpace", 1629 storage_capacity_callbacks_.Run(total_and_available.first,
1795 "n_callbacks", available_space_callbacks_.size()); 1630 total_and_available.second);
1796
1797 available_space_callbacks_.Run(kQuotaStatusOk, space);
1798 } 1631 }
1799 1632
1800 void QuotaManager::DidDatabaseWork(bool success) { 1633 void QuotaManager::DidDatabaseWork(bool success) {
1801 db_disabled_ = !success; 1634 db_disabled_ = !success;
1802 } 1635 }
1803 1636
1804 void QuotaManager::DeleteOnCorrectThread() const { 1637 void QuotaManager::DeleteOnCorrectThread() const {
1805 if (!io_thread_->BelongsToCurrentThread() && 1638 if (!io_thread_->BelongsToCurrentThread() &&
1806 io_thread_->DeleteSoon(FROM_HERE, this)) { 1639 io_thread_->DeleteSoon(FROM_HERE, this)) {
1807 return; 1640 return;
1808 } 1641 }
1809 delete this; 1642 delete this;
1810 } 1643 }
1811 1644
1812 void QuotaManager::PostTaskAndReplyWithResultForDBThread( 1645 void QuotaManager::PostTaskAndReplyWithResultForDBThread(
1813 const tracked_objects::Location& from_here, 1646 const tracked_objects::Location& from_here,
1814 const base::Callback<bool(QuotaDatabase*)>& task, 1647 const base::Callback<bool(QuotaDatabase*)>& task,
1815 const base::Callback<void(bool)>& reply) { 1648 const base::Callback<void(bool)>& reply) {
1816 // Deleting manager will post another task to DB thread to delete 1649 // Deleting manager will post another task to DB thread to delete
1817 // |database_|, therefore we can be sure that database_ is alive when this 1650 // |database_|, therefore we can be sure that database_ is alive when this
1818 // task runs. 1651 // task runs.
1819 base::PostTaskAndReplyWithResult( 1652 base::PostTaskAndReplyWithResult(
1820 db_thread_.get(), 1653 db_thread_.get(),
1821 from_here, 1654 from_here,
1822 base::Bind(task, base::Unretained(database_.get())), 1655 base::Bind(task, base::Unretained(database_.get())),
1823 reply); 1656 reply);
1824 } 1657 }
1825 1658
1826 // static 1659 // static
1827 int64_t QuotaManager::CallGetAmountOfFreeDiskSpace( 1660 std::pair<int64_t, int64_t> QuotaManager::CallGetVolumeInfo(
1828 GetVolumeInfoFn get_volume_info_fn, 1661 GetVolumeInfoFn get_volume_info_fn,
1829 const base::FilePath& profile_path) { 1662 const base::FilePath& path) {
1830 // crbug.com/349708 1663 // crbug.com/349708
1831 TRACE_EVENT0("io", "CallSystemGetAmountOfFreeDiskSpace"); 1664 TRACE_EVENT0("io", "CallGetVolumeInfo");
1832 if (!base::CreateDirectory(profile_path)) { 1665 if (!base::CreateDirectory(path)) {
1833 LOG(WARNING) << "Create directory failed for path" << profile_path.value(); 1666 LOG(WARNING) << "Create directory failed for path" << path.value();
1834 return 0; 1667 return std::make_pair<int64_t, int64_t>(0, 0);
1835 } 1668 }
1836 uint64_t available, total; 1669 std::pair<int64_t, int64_t> total_and_available = get_volume_info_fn(path);
1837 if (!get_volume_info_fn(profile_path, &available, &total)) { 1670 if (total_and_available.first < 0 || total_and_available.second < 0) {
1838 return 0; 1671 LOG(WARNING) << "Unable to get volume info: " << path.value();
1672 return std::make_pair<int64_t, int64_t>(0, 0);
1839 } 1673 }
1840 UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", available); 1674 UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total_and_available.first);
1841 UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total); 1675 UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", total_and_available.second);
1842 return static_cast<int64_t>(available); 1676 return total_and_available;
1843 } 1677 }
1844 1678
1845 //static 1679 // static
1846 bool QuotaManager::GetVolumeInfo(const base::FilePath& path, 1680 std::pair<int64_t, int64_t> QuotaManager::GetVolumeInfo(
1847 uint64_t* available_space, 1681 const base::FilePath& path) {
1848 uint64_t* total_size) { 1682 return std::make_pair(base::SysInfo::AmountOfTotalDiskSpace(path),
1849 // Inspired by similar code in the base::SysInfo class. 1683 base::SysInfo::AmountOfFreeDiskSpace(path));
1850 base::ThreadRestrictions::AssertIOAllowed();
1851
1852 int64_t available = base::SysInfo::AmountOfFreeDiskSpace(path);
1853 if (available < 0)
1854 return false;
1855 int64_t total = base::SysInfo::AmountOfTotalDiskSpace(path);
1856 if (total < 0)
1857 return false;
1858
1859 *available_space = static_cast<uint64_t>(available);
1860 *total_size = static_cast<uint64_t>(total);
1861 return true;
1862 } 1684 }
1863 1685
1864 } // namespace storage 1686 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698