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

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

Powered by Google App Engine
This is Rietveld 408576698