OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |