| 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 if (host_quota > 0) { |
| 286 UMA_HISTOGRAM_PERCENTAGE("Quota.PercentUsedByOrigin", |
| 287 std::min(100, static_cast<int>((host_usage_ * 100) / host_quota))); |
| 288 } |
| 289 } |
| 290 DeleteSoon(); |
| 429 } | 291 } |
| 430 | 292 |
| 431 private: | 293 private: |
| 432 void DidGetHostUsage(int64_t usage) { | 294 QuotaManager* manager() const { |
| 433 if (status_ == kQuotaStatusUnknown) | 295 return static_cast<QuotaManager*>(observer()); |
| 434 status_ = kQuotaStatusOk; | 296 } |
| 435 usage_and_quota_.usage = usage; | 297 |
| 436 CheckCompleted(); | 298 void OnGotSettings(const base::Closure& barrier_closure, |
| 437 } | 299 const QuotaSettings& settings) { |
| 438 | 300 settings_ = settings; |
| 439 void DidGetGlobalLimitedUsage(int64_t limited_usage) { | 301 barrier_closure.Run(); |
| 440 if (status_ == kQuotaStatusUnknown) | 302 if (type_ == kStorageTypeTemporary && !is_unlimited_) { |
| 441 status_ = kQuotaStatusOk; | 303 SetDesiredHostQuota(barrier_closure, kQuotaStatusOk, |
| 442 usage_and_quota_.global_limited_usage = limited_usage; | 304 settings.per_host_quota); |
| 443 CheckCompleted(); | 305 } |
| 444 } | 306 } |
| 445 | 307 |
| 446 void DidGetQuota(QuotaStatusCode status, int64_t quota) { | 308 void OnGotCapacity(const base::Closure& barrier_closure, |
| 447 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) | 309 int64_t total_space, |
| 448 status_ = status; | 310 int64_t available_space) { |
| 449 usage_and_quota_.quota = quota; | 311 total_space_ = total_space; |
| 450 CheckCompleted(); | 312 available_space_ = available_space; |
| 451 } | 313 barrier_closure.Run(); |
| 452 | 314 } |
| 453 void DidGetAvailableSpace(QuotaStatusCode status, int64_t space) { | 315 |
| 454 // crbug.com/349708 | 316 void OnGotHostUsage(const base::Closure& barrier_closure, int64_t usage) { |
| 455 TRACE_EVENT0( | 317 host_usage_ = usage; |
| 456 "io", "UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace"); | 318 barrier_closure.Run(); |
| 457 | 319 } |
| 458 DCHECK_GE(space, 0); | 320 |
| 459 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) | 321 void SetDesiredHostQuota(const base::Closure& barrier_closure, |
| 460 status_ = status; | 322 QuotaStatusCode status, |
| 461 usage_and_quota_.available_disk_space = space; | 323 int64_t quota) { |
| 462 CheckCompleted(); | 324 desired_host_quota_ = quota; |
| 463 } | 325 barrier_closure.Run(); |
| 464 | 326 } |
| 327 |
| 328 void OnBarrierComplete() { CallCompleted(); } |
| 329 |
| 330 GURL origin_; |
| 331 QuotaManager::UsageAndQuotaCallback callback_; |
| 332 StorageType type_; |
| 333 bool is_unlimited_; |
| 334 bool is_incognito_; |
| 335 int64_t available_space_ = 0; |
| 336 int64_t total_space_ = 0; |
| 337 int64_t desired_host_quota_ = 0; |
| 338 int64_t host_usage_ = 0; |
| 339 QuotaSettings settings_; |
| 340 base::WeakPtrFactory<UsageAndQuotaHelper> weak_factory_; |
| 341 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaHelper); |
| 342 }; |
| 343 |
| 344 // Helper to asychronously gather information needed at the start of an |
| 345 // eviction round. |
| 346 class QuotaManager::EvictionRoundInfoHelper : public QuotaTask { |
| 347 public: |
| 348 EvictionRoundInfoHelper(QuotaManager* manager, |
| 349 const EvictionRoundInfoCallback& callback) |
| 350 : QuotaTask(manager), callback_(callback), weak_factory_(this) {} |
| 351 |
| 352 protected: |
| 465 void Run() override { | 353 void Run() override { |
| 466 // We initialize waiting_callbacks to 1 so that we won't run | 354 // Gather 2 pieces of info before deciding if we need to get GlobalUsage: |
| 467 // the completion callback until here even some of the callbacks | 355 // settings and device_storage_capacity. |
| 468 // are dispatched synchronously. | 356 base::Closure barrier = base::BarrierClosure( |
| 469 CheckCompleted(); | 357 2, base::Bind(&EvictionRoundInfoHelper::OnBarrierComplete, |
| 358 weak_factory_.GetWeakPtr())); |
| 359 |
| 360 manager()->GetQuotaSettings( |
| 361 base::Bind(&EvictionRoundInfoHelper::OnGotSettings, |
| 362 weak_factory_.GetWeakPtr(), barrier)); |
| 363 manager()->GetStorageCapacity( |
| 364 base::Bind(&EvictionRoundInfoHelper::OnGotCapacity, |
| 365 weak_factory_.GetWeakPtr(), barrier)); |
| 470 } | 366 } |
| 471 | 367 |
| 472 void Aborted() override { | 368 void Aborted() override { |
| 473 callback_.Run(kQuotaErrorAbort, UsageAndQuota()); | 369 weak_factory_.InvalidateWeakPtrs(); |
| 370 callback_.Run(kQuotaErrorAbort, QuotaSettings(), 0, 0, 0, false); |
| 474 DeleteSoon(); | 371 DeleteSoon(); |
| 475 } | 372 } |
| 476 | 373 |
| 477 void Completed() override { | 374 void Completed() override { |
| 478 // crbug.com/349708 | 375 weak_factory_.InvalidateWeakPtrs(); |
| 479 TRACE_EVENT0("io", "UsageAndQuotaCallbackDispatcher::Completed"); | 376 callback_.Run(kQuotaStatusOk, settings_, |
| 480 | 377 available_space_, total_space_, |
| 481 DCHECK(!has_usage_ || usage_and_quota_.usage >= 0); | 378 global_usage_, global_usage_is_complete_); |
| 482 DCHECK(!has_global_limited_usage_ || | 379 DeleteSoon(); |
| 483 usage_and_quota_.global_limited_usage >= 0); | 380 } |
| 484 DCHECK(!has_quota_ || usage_and_quota_.quota >= 0); | 381 |
| 485 DCHECK(!has_available_disk_space_ || | 382 private: |
| 486 usage_and_quota_.available_disk_space >= 0); | 383 QuotaManager* manager() const { |
| 487 | 384 return static_cast<QuotaManager*>(observer()); |
| 488 callback_.Run(status_, usage_and_quota_); | 385 } |
| 489 DeleteSoon(); | 386 |
| 490 } | 387 void OnGotSettings(const base::Closure& barrier_closure, |
| 491 | 388 const QuotaSettings& settings) { |
| 492 void CheckCompleted() { | 389 settings_ = settings; |
| 493 if (--waiting_callbacks_ <= 0) | 390 barrier_closure.Run(); |
| 391 } |
| 392 |
| 393 void OnGotCapacity(const base::Closure& barrier_closure, |
| 394 int64_t total_space, |
| 395 int64_t available_space) { |
| 396 total_space_ = total_space; |
| 397 available_space_ = available_space; |
| 398 barrier_closure.Run(); |
| 399 } |
| 400 |
| 401 void OnBarrierComplete() { |
| 402 // Avoid computing the full current_usage when there's no pressure. |
| 403 int64_t consumed_space = total_space_ - available_space_; |
| 404 if (consumed_space < settings_.pool_size && |
| 405 available_space_ > settings_.should_remain_available) { |
| 406 DCHECK(!global_usage_is_complete_); |
| 407 global_usage_ = |
| 408 manager()->GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage(); |
| 494 CallCompleted(); | 409 CallCompleted(); |
| 495 } | 410 return; |
| 496 | 411 } |
| 497 // For sanity checks, they're checked only when DCHECK is on. | 412 manager()->GetGlobalUsage( |
| 498 bool has_usage_; | 413 kStorageTypeTemporary, |
| 499 bool has_global_limited_usage_; | 414 base::Bind(&EvictionRoundInfoHelper::OnGotGlobalUsage, |
| 500 bool has_quota_; | 415 weak_factory_.GetWeakPtr())); |
| 501 bool has_available_disk_space_; | 416 } |
| 502 | 417 |
| 503 QuotaStatusCode status_; | 418 void OnGotGlobalUsage(int64_t usage, int64_t unlimited_usage) { |
| 504 UsageAndQuota usage_and_quota_; | 419 global_usage_ = std::max(INT64_C(0), usage - unlimited_usage); |
| 505 QuotaManager::UsageAndQuotaCallback callback_; | 420 global_usage_is_complete_ = true; |
| 506 int waiting_callbacks_; | 421 if (total_space_ > 0) { |
| 507 | 422 UMA_HISTOGRAM_PERCENTAGE("Quota.PercentUsedForTemporaryStorage", |
| 508 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher); | 423 std::min(100, |
| 424 static_cast<int>((global_usage_ * 100) / total_space_))); |
| 425 } |
| 426 CallCompleted(); |
| 427 } |
| 428 |
| 429 EvictionRoundInfoCallback callback_; |
| 430 QuotaSettings settings_; |
| 431 int64_t available_space_ = 0; |
| 432 int64_t total_space_ = 0; |
| 433 int64_t global_usage_ = 0; |
| 434 bool global_usage_is_complete_ = false; |
| 435 base::WeakPtrFactory<EvictionRoundInfoHelper> weak_factory_; |
| 436 DISALLOW_COPY_AND_ASSIGN(EvictionRoundInfoHelper); |
| 509 }; | 437 }; |
| 510 | 438 |
| 511 class QuotaManager::GetUsageInfoTask : public QuotaTask { | 439 class QuotaManager::GetUsageInfoTask : public QuotaTask { |
| 512 public: | 440 public: |
| 513 GetUsageInfoTask( | 441 GetUsageInfoTask( |
| 514 QuotaManager* manager, | 442 QuotaManager* manager, |
| 515 const GetUsageInfoCallback& callback) | 443 const GetUsageInfoCallback& callback) |
| 516 : QuotaTask(manager), | 444 : QuotaTask(manager), |
| 517 callback_(callback), | 445 callback_(callback), |
| 518 weak_factory_(this) { | 446 weak_factory_(this) { |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 860 OriginInfoTableEntries entries_; | 788 OriginInfoTableEntries entries_; |
| 861 }; | 789 }; |
| 862 | 790 |
| 863 // QuotaManager --------------------------------------------------------------- | 791 // QuotaManager --------------------------------------------------------------- |
| 864 | 792 |
| 865 QuotaManager::QuotaManager( | 793 QuotaManager::QuotaManager( |
| 866 bool is_incognito, | 794 bool is_incognito, |
| 867 const base::FilePath& profile_path, | 795 const base::FilePath& profile_path, |
| 868 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, | 796 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, |
| 869 const scoped_refptr<base::SequencedTaskRunner>& db_thread, | 797 const scoped_refptr<base::SequencedTaskRunner>& db_thread, |
| 870 const scoped_refptr<SpecialStoragePolicy>& special_storage_policy) | 798 const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, |
| 799 const GetQuotaSettingsFunc& get_settings_function) |
| 871 : is_incognito_(is_incognito), | 800 : is_incognito_(is_incognito), |
| 872 profile_path_(profile_path), | 801 profile_path_(profile_path), |
| 873 proxy_(new QuotaManagerProxy(this, io_thread)), | 802 proxy_(new QuotaManagerProxy(this, io_thread)), |
| 874 db_disabled_(false), | 803 db_disabled_(false), |
| 875 eviction_disabled_(false), | 804 eviction_disabled_(false), |
| 876 io_thread_(io_thread), | 805 io_thread_(io_thread), |
| 877 db_thread_(db_thread), | 806 db_thread_(db_thread), |
| 807 get_settings_function_(get_settings_function), |
| 878 is_getting_eviction_origin_(false), | 808 is_getting_eviction_origin_(false), |
| 879 temporary_quota_initialized_(false), | |
| 880 temporary_quota_override_(-1), | |
| 881 special_storage_policy_(special_storage_policy), | 809 special_storage_policy_(special_storage_policy), |
| 882 get_volume_info_fn_(&QuotaManager::GetVolumeInfo), | 810 get_volume_info_fn_(&QuotaManager::GetVolumeInfo), |
| 883 storage_monitor_(new StorageMonitor(this)), | 811 storage_monitor_(new StorageMonitor(this)), |
| 884 weak_factory_(this) {} | 812 weak_factory_(this) { |
| 813 DCHECK_EQ(settings_.refresh_interval, base::TimeDelta::Max()); |
| 814 if (!get_settings_function.is_null()) { |
| 815 // Reset the interval to ensure we use the get_settings_function |
| 816 // the first times settings_ is needed. |
| 817 settings_.refresh_interval = base::TimeDelta(); |
| 818 get_settings_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 819 } |
| 820 } |
| 821 |
| 822 void QuotaManager::SetQuotaSettings(const QuotaSettings& settings) { |
| 823 settings_ = settings; |
| 824 settings_timestamp_ = base::TimeTicks::Now(); |
| 825 } |
| 885 | 826 |
| 886 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) { | 827 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) { |
| 887 LazyInitialize(); | 828 LazyInitialize(); |
| 888 GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback); | 829 GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback); |
| 889 get_usage_info->Start(); | 830 get_usage_info->Start(); |
| 890 } | 831 } |
| 891 | 832 |
| 892 void QuotaManager::GetUsageAndQuotaForWebApps( | 833 void QuotaManager::GetUsageAndQuotaForWebApps( |
| 893 const GURL& origin, | 834 const GURL& origin, |
| 894 StorageType type, | 835 StorageType type, |
| 895 const GetUsageAndQuotaCallback& callback) { | 836 const UsageAndQuotaCallback& callback) { |
| 896 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed. | 837 DCHECK(origin == origin.GetOrigin()); |
| 897 tracked_objects::ScopedTracker tracking_profile( | 838 if (!IsSupportedType(type) || |
| 898 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 839 (is_incognito_ && !IsSupportedIncognitoType(type))) { |
| 899 "477117 QuotaManager::GetUsageAndQuotaForWebApps")); | |
| 900 if (type != kStorageTypeTemporary && | |
| 901 type != kStorageTypePersistent && | |
| 902 type != kStorageTypeSyncable) { | |
| 903 callback.Run(kQuotaErrorNotSupported, 0, 0); | 840 callback.Run(kQuotaErrorNotSupported, 0, 0); |
| 904 return; | 841 return; |
| 905 } | 842 } |
| 906 | |
| 907 DCHECK(origin == origin.GetOrigin()); | |
| 908 LazyInitialize(); | 843 LazyInitialize(); |
| 909 | 844 UsageAndQuotaHelper* helper = new UsageAndQuotaHelper( |
| 910 bool unlimited = IsStorageUnlimited(origin, type); | 845 this, origin, type, IsStorageUnlimited(origin, type), is_incognito_, |
| 911 bool can_query_disk_size = CanQueryDiskSize(origin); | 846 callback); |
| 912 | 847 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 } | 848 } |
| 943 | 849 |
| 944 void QuotaManager::GetUsageAndQuota( | 850 void QuotaManager::GetUsageAndQuota(const GURL& origin, |
| 945 const GURL& origin, StorageType type, | 851 StorageType type, |
| 946 const GetUsageAndQuotaCallback& callback) { | 852 const UsageAndQuotaCallback& callback) { |
| 947 DCHECK(origin == origin.GetOrigin()); | 853 DCHECK(origin == origin.GetOrigin()); |
| 948 | 854 |
| 949 if (IsStorageUnlimited(origin, type)) { | 855 if (IsStorageUnlimited(origin, type)) { |
| 856 // TODO(michaeln): This seems like a non-obvious odd behavior, probably for |
| 857 // apps/extensions, but it would be good to elimiate this special case. |
| 950 callback.Run(kQuotaStatusOk, 0, kNoLimit); | 858 callback.Run(kQuotaStatusOk, 0, kNoLimit); |
| 951 return; | 859 return; |
| 952 } | 860 } |
| 953 | 861 |
| 954 GetUsageAndQuotaForWebApps(origin, type, callback); | 862 GetUsageAndQuotaForWebApps(origin, type, callback); |
| 955 } | 863 } |
| 956 | 864 |
| 957 void QuotaManager::NotifyStorageAccessed( | 865 void QuotaManager::NotifyStorageAccessed( |
| 958 QuotaClient::ID client_id, | 866 QuotaClient::ID client_id, |
| 959 const GURL& origin, StorageType type) { | 867 const GURL& origin, StorageType type) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 985 | 893 |
| 986 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id, | 894 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id, |
| 987 const GURL& origin, | 895 const GURL& origin, |
| 988 StorageType type, | 896 StorageType type, |
| 989 bool enabled) { | 897 bool enabled) { |
| 990 LazyInitialize(); | 898 LazyInitialize(); |
| 991 DCHECK(GetUsageTracker(type)); | 899 DCHECK(GetUsageTracker(type)); |
| 992 GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled); | 900 GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled); |
| 993 } | 901 } |
| 994 | 902 |
| 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, | 903 void QuotaManager::DeleteOriginData(const GURL& origin, |
| 1001 StorageType type, | 904 StorageType type, |
| 1002 int quota_client_mask, | 905 int quota_client_mask, |
| 1003 const StatusCallback& callback) { | 906 const StatusCallback& callback) { |
| 1004 DeleteOriginDataInternal(origin, type, quota_client_mask, false, callback); | 907 DeleteOriginDataInternal(origin, type, quota_client_mask, false, callback); |
| 1005 } | 908 } |
| 1006 | 909 |
| 1007 void QuotaManager::DeleteHostData(const std::string& host, | 910 void QuotaManager::DeleteHostData(const std::string& host, |
| 1008 StorageType type, | 911 StorageType type, |
| 1009 int quota_client_mask, | 912 int quota_client_mask, |
| 1010 const StatusCallback& callback) { | 913 const StatusCallback& callback) { |
| 1011 LazyInitialize(); | 914 LazyInitialize(); |
| 1012 | |
| 1013 if (host.empty() || clients_.empty()) { | 915 if (host.empty() || clients_.empty()) { |
| 1014 callback.Run(kQuotaStatusOk); | 916 callback.Run(kQuotaStatusOk); |
| 1015 return; | 917 return; |
| 1016 } | 918 } |
| 1017 | 919 |
| 1018 HostDataDeleter* deleter = | 920 HostDataDeleter* deleter = |
| 1019 new HostDataDeleter(this, host, type, quota_client_mask, callback); | 921 new HostDataDeleter(this, host, type, quota_client_mask, callback); |
| 1020 deleter->Start(); | 922 deleter->Start(); |
| 1021 } | 923 } |
| 1022 | 924 |
| 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, | 925 void QuotaManager::GetPersistentHostQuota(const std::string& host, |
| 1090 const QuotaCallback& callback) { | 926 const QuotaCallback& callback) { |
| 1091 LazyInitialize(); | 927 LazyInitialize(); |
| 1092 if (host.empty()) { | 928 if (host.empty()) { |
| 1093 // This could happen if we are called on file:///. | 929 // This could happen if we are called on file:///. |
| 1094 // TODO(kinuko) We may want to respect --allow-file-access-from-files | 930 // TODO(kinuko) We may want to respect --allow-file-access-from-files |
| 1095 // command line switch. | 931 // command line switch. |
| 1096 callback.Run(kQuotaStatusOk, 0); | 932 callback.Run(kQuotaStatusOk, 0); |
| 1097 return; | 933 return; |
| 1098 } | 934 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1120 // This could happen if we are called on file:///. | 956 // This could happen if we are called on file:///. |
| 1121 callback.Run(kQuotaErrorNotSupported, 0); | 957 callback.Run(kQuotaErrorNotSupported, 0); |
| 1122 return; | 958 return; |
| 1123 } | 959 } |
| 1124 | 960 |
| 1125 if (new_quota < 0) { | 961 if (new_quota < 0) { |
| 1126 callback.Run(kQuotaErrorInvalidModification, -1); | 962 callback.Run(kQuotaErrorInvalidModification, -1); |
| 1127 return; | 963 return; |
| 1128 } | 964 } |
| 1129 | 965 |
| 1130 if (kPerHostPersistentQuotaLimit < new_quota) { | 966 // Cap the requested size at the per-host quota limit. |
| 1131 // Cap the requested size at the per-host quota limit. | 967 new_quota = std::min(new_quota, kPerHostPersistentQuotaLimit); |
| 1132 new_quota = kPerHostPersistentQuotaLimit; | |
| 1133 } | |
| 1134 | 968 |
| 1135 if (db_disabled_) { | 969 if (db_disabled_) { |
| 1136 callback.Run(kQuotaErrorInvalidAccess, -1); | 970 callback.Run(kQuotaErrorInvalidAccess, -1); |
| 1137 return; | 971 return; |
| 1138 } | 972 } |
| 1139 | 973 |
| 1140 int64_t* new_quota_ptr = new int64_t(new_quota); | 974 int64_t* new_quota_ptr = new int64_t(new_quota); |
| 1141 PostTaskAndReplyWithResultForDBThread( | 975 PostTaskAndReplyWithResultForDBThread( |
| 1142 FROM_HERE, | 976 FROM_HERE, |
| 1143 base::Bind(&SetPersistentHostQuotaOnDBThread, | 977 base::Bind(&SetPersistentHostQuotaOnDBThread, |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1283 QuotaManager::EvictionContext::EvictionContext() | 1117 QuotaManager::EvictionContext::EvictionContext() |
| 1284 : evicted_type(kStorageTypeUnknown) { | 1118 : evicted_type(kStorageTypeUnknown) { |
| 1285 } | 1119 } |
| 1286 | 1120 |
| 1287 QuotaManager::EvictionContext::~EvictionContext() { | 1121 QuotaManager::EvictionContext::~EvictionContext() { |
| 1288 } | 1122 } |
| 1289 | 1123 |
| 1290 void QuotaManager::LazyInitialize() { | 1124 void QuotaManager::LazyInitialize() { |
| 1291 DCHECK(io_thread_->BelongsToCurrentThread()); | 1125 DCHECK(io_thread_->BelongsToCurrentThread()); |
| 1292 if (database_) { | 1126 if (database_) { |
| 1293 // Initialization seems to be done already. | 1127 // Already initialized. |
| 1294 return; | 1128 return; |
| 1295 } | 1129 } |
| 1296 | 1130 |
| 1297 // Use an empty path to open an in-memory only databse for incognito. | 1131 // Use an empty path to open an in-memory only databse for incognito. |
| 1298 database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() : | 1132 database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() : |
| 1299 profile_path_.AppendASCII(kDatabaseName))); | 1133 profile_path_.AppendASCII(kDatabaseName))); |
| 1300 | 1134 |
| 1301 temporary_usage_tracker_.reset(new UsageTracker( | 1135 temporary_usage_tracker_.reset(new UsageTracker( |
| 1302 clients_, kStorageTypeTemporary, special_storage_policy_.get(), | 1136 clients_, kStorageTypeTemporary, special_storage_policy_.get(), |
| 1303 storage_monitor_.get())); | 1137 storage_monitor_.get())); |
| 1304 persistent_usage_tracker_.reset(new UsageTracker( | 1138 persistent_usage_tracker_.reset(new UsageTracker( |
| 1305 clients_, kStorageTypePersistent, special_storage_policy_.get(), | 1139 clients_, kStorageTypePersistent, special_storage_policy_.get(), |
| 1306 storage_monitor_.get())); | 1140 storage_monitor_.get())); |
| 1307 syncable_usage_tracker_.reset(new UsageTracker( | 1141 syncable_usage_tracker_.reset(new UsageTracker( |
| 1308 clients_, kStorageTypeSyncable, special_storage_policy_.get(), | 1142 clients_, kStorageTypeSyncable, special_storage_policy_.get(), |
| 1309 storage_monitor_.get())); | 1143 storage_monitor_.get())); |
| 1310 | 1144 |
| 1311 int64_t* temporary_quota_override = new int64_t(-1); | 1145 if (!is_incognito_) { |
| 1312 int64_t* desired_available_space = new int64_t(-1); | 1146 histogram_timer_.Start( |
| 1147 FROM_HERE, base::TimeDelta::FromMilliseconds(kReportHistogramInterval), |
| 1148 this, &QuotaManager::ReportHistogram); |
| 1149 } |
| 1150 |
| 1151 base::PostTaskAndReplyWithResult( |
| 1152 db_thread_.get(), FROM_HERE, |
| 1153 base::Bind(&QuotaDatabase::IsOriginDatabaseBootstrapped, |
| 1154 base::Unretained(database_.get())), |
| 1155 base::Bind(&QuotaManager::FinishLazyInitialize, |
| 1156 weak_factory_.GetWeakPtr())); |
| 1157 } |
| 1158 |
| 1159 void QuotaManager::FinishLazyInitialize(bool is_database_bootstrapped) { |
| 1160 is_database_bootstrapped_ = is_database_bootstrapped; |
| 1161 StartEviction(); |
| 1162 } |
| 1163 |
| 1164 void QuotaManager::BootstrapDatabaseForEviction( |
| 1165 const GetOriginCallback& did_get_origin_callback, |
| 1166 int64_t usage, |
| 1167 int64_t unlimited_usage) { |
| 1168 // The usage cache should be fully populated now so we can |
| 1169 // seed the database with origins we know about. |
| 1170 std::set<GURL>* origins = new std::set<GURL>; |
| 1171 temporary_usage_tracker_->GetCachedOrigins(origins); |
| 1313 PostTaskAndReplyWithResultForDBThread( | 1172 PostTaskAndReplyWithResultForDBThread( |
| 1314 FROM_HERE, | 1173 FROM_HERE, base::Bind(&BootstrapDatabaseOnDBThread, base::Owned(origins)), |
| 1315 base::Bind(&InitializeOnDBThread, | 1174 base::Bind(&QuotaManager::DidBootstrapDatabase, |
| 1316 base::Unretained(temporary_quota_override), | 1175 weak_factory_.GetWeakPtr(), did_get_origin_callback)); |
| 1317 base::Unretained(desired_available_space)), | 1176 } |
| 1318 base::Bind(&QuotaManager::DidInitialize, | 1177 |
| 1319 weak_factory_.GetWeakPtr(), | 1178 void QuotaManager::DidBootstrapDatabase( |
| 1320 base::Owned(temporary_quota_override), | 1179 const GetOriginCallback& did_get_origin_callback, |
| 1321 base::Owned(desired_available_space))); | 1180 bool success) { |
| 1181 is_database_bootstrapped_ = success; |
| 1182 DidDatabaseWork(success); |
| 1183 GetLRUOrigin(kStorageTypeTemporary, did_get_origin_callback); |
| 1322 } | 1184 } |
| 1323 | 1185 |
| 1324 void QuotaManager::RegisterClient(QuotaClient* client) { | 1186 void QuotaManager::RegisterClient(QuotaClient* client) { |
| 1325 DCHECK(!database_.get()); | 1187 DCHECK(!database_.get()); |
| 1326 clients_.push_back(client); | 1188 clients_.push_back(client); |
| 1327 } | 1189 } |
| 1328 | 1190 |
| 1329 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const { | 1191 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const { |
| 1330 switch (type) { | 1192 switch (type) { |
| 1331 case kStorageTypeTemporary: | 1193 case kStorageTypeTemporary: |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1406 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread, | 1268 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread, |
| 1407 base::Unretained(helper)), | 1269 base::Unretained(helper)), |
| 1408 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable, | 1270 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable, |
| 1409 base::Owned(helper), | 1271 base::Owned(helper), |
| 1410 weak_factory_.GetWeakPtr(), | 1272 weak_factory_.GetWeakPtr(), |
| 1411 callback)); | 1273 callback)); |
| 1412 } | 1274 } |
| 1413 | 1275 |
| 1414 void QuotaManager::StartEviction() { | 1276 void QuotaManager::StartEviction() { |
| 1415 DCHECK(!temporary_storage_evictor_.get()); | 1277 DCHECK(!temporary_storage_evictor_.get()); |
| 1278 if (eviction_disabled_) |
| 1279 return; |
| 1416 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor( | 1280 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor( |
| 1417 this, kEvictionIntervalInMilliSeconds)); | 1281 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(); | 1282 temporary_storage_evictor_->Start(); |
| 1422 } | 1283 } |
| 1423 | 1284 |
| 1424 void QuotaManager::DeleteOriginFromDatabase(const GURL& origin, | 1285 void QuotaManager::DeleteOriginFromDatabase(const GURL& origin, |
| 1425 StorageType type, | 1286 StorageType type, |
| 1426 bool is_eviction) { | 1287 bool is_eviction) { |
| 1427 LazyInitialize(); | 1288 LazyInitialize(); |
| 1428 if (db_disabled_) | 1289 if (db_disabled_) |
| 1429 return; | 1290 return; |
| 1430 | 1291 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 const GetOriginCallback& callback) { | 1457 const GetOriginCallback& callback) { |
| 1597 LazyInitialize(); | 1458 LazyInitialize(); |
| 1598 // This must not be called while there's an in-flight task. | 1459 // This must not be called while there's an in-flight task. |
| 1599 DCHECK(!is_getting_eviction_origin_); | 1460 DCHECK(!is_getting_eviction_origin_); |
| 1600 is_getting_eviction_origin_ = true; | 1461 is_getting_eviction_origin_ = true; |
| 1601 | 1462 |
| 1602 GetOriginCallback did_get_origin_callback = | 1463 GetOriginCallback did_get_origin_callback = |
| 1603 base::Bind(&QuotaManager::DidGetEvictionOrigin, | 1464 base::Bind(&QuotaManager::DidGetEvictionOrigin, |
| 1604 weak_factory_.GetWeakPtr(), callback); | 1465 weak_factory_.GetWeakPtr(), callback); |
| 1605 | 1466 |
| 1606 if (type == kStorageTypeTemporary && temporary_storage_eviction_policy_) { | 1467 if (!is_database_bootstrapped_ && !eviction_disabled_) { |
| 1607 std::map<GURL, int64_t> usage_map; | 1468 // Once bootstrapped, GetLRUOrigin will be called. |
| 1608 // The cached origins are populated by the prior call to | 1469 GetGlobalUsage( |
| 1609 // GetUsageAndQuotaForEviction(). | 1470 kStorageTypeTemporary, |
| 1610 GetUsageTracker(kStorageTypeTemporary)->GetCachedOriginsUsage(&usage_map); | 1471 base::Bind(&QuotaManager::BootstrapDatabaseForEviction, |
| 1611 | 1472 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; | 1473 return; |
| 1617 } | 1474 } |
| 1618 | 1475 |
| 1619 // TODO(calamity): convert LRU origin retrieval into a QuotaEvictionPolicy. | |
| 1620 GetLRUOrigin(type, did_get_origin_callback); | 1476 GetLRUOrigin(type, did_get_origin_callback); |
| 1621 } | 1477 } |
| 1622 | 1478 |
| 1623 void QuotaManager::EvictOriginData(const GURL& origin, | 1479 void QuotaManager::EvictOriginData(const GURL& origin, |
| 1624 StorageType type, | 1480 StorageType type, |
| 1625 const EvictOriginDataCallback& callback) { | 1481 const StatusCallback& callback) { |
| 1626 DCHECK(io_thread_->BelongsToCurrentThread()); | 1482 DCHECK(io_thread_->BelongsToCurrentThread()); |
| 1627 DCHECK_EQ(type, kStorageTypeTemporary); | 1483 DCHECK_EQ(type, kStorageTypeTemporary); |
| 1628 | 1484 |
| 1629 eviction_context_.evicted_origin = origin; | 1485 eviction_context_.evicted_origin = origin; |
| 1630 eviction_context_.evicted_type = type; | 1486 eviction_context_.evicted_type = type; |
| 1631 eviction_context_.evict_origin_data_callback = callback; | 1487 eviction_context_.evict_origin_data_callback = callback; |
| 1632 | 1488 |
| 1633 DeleteOriginDataInternal(origin, type, QuotaClient::kAllClientsMask, true, | 1489 DeleteOriginDataInternal(origin, type, QuotaClient::kAllClientsMask, true, |
| 1634 base::Bind(&QuotaManager::DidOriginDataEvicted, | 1490 base::Bind(&QuotaManager::DidOriginDataEvicted, |
| 1635 weak_factory_.GetWeakPtr())); | 1491 weak_factory_.GetWeakPtr())); |
| 1636 } | 1492 } |
| 1637 | 1493 |
| 1638 void QuotaManager::GetUsageAndQuotaForEviction( | 1494 void QuotaManager::GetEvictionRoundInfo( |
| 1639 const UsageAndQuotaCallback& callback) { | 1495 const EvictionRoundInfoCallback& callback) { |
| 1640 // crbug.com/349708 | |
| 1641 TRACE_EVENT0("io", "QuotaManager::GetUsageAndQuotaForEviction"); | |
| 1642 | |
| 1643 DCHECK(io_thread_->BelongsToCurrentThread()); | 1496 DCHECK(io_thread_->BelongsToCurrentThread()); |
| 1644 LazyInitialize(); | 1497 LazyInitialize(); |
| 1645 | 1498 EvictionRoundInfoHelper* helper = new EvictionRoundInfoHelper(this, callback); |
| 1646 UsageAndQuotaCallbackDispatcher* dispatcher = | 1499 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 } | 1500 } |
| 1680 | 1501 |
| 1681 void QuotaManager::GetLRUOrigin(StorageType type, | 1502 void QuotaManager::GetLRUOrigin(StorageType type, |
| 1682 const GetOriginCallback& callback) { | 1503 const GetOriginCallback& callback) { |
| 1683 LazyInitialize(); | 1504 LazyInitialize(); |
| 1684 // This must not be called while there's an in-flight task. | 1505 // This must not be called while there's an in-flight task. |
| 1685 DCHECK(lru_origin_callback_.is_null()); | 1506 DCHECK(lru_origin_callback_.is_null()); |
| 1686 lru_origin_callback_ = callback; | 1507 lru_origin_callback_ = callback; |
| 1687 if (db_disabled_) { | 1508 if (db_disabled_) { |
| 1688 lru_origin_callback_.Run(GURL()); | 1509 lru_origin_callback_.Run(GURL()); |
| 1689 lru_origin_callback_.Reset(); | 1510 lru_origin_callback_.Reset(); |
| 1690 return; | 1511 return; |
| 1691 } | 1512 } |
| 1692 | 1513 |
| 1693 GURL* url = new GURL; | 1514 GURL* url = new GURL; |
| 1694 PostTaskAndReplyWithResultForDBThread( | 1515 PostTaskAndReplyWithResultForDBThread( |
| 1695 FROM_HERE, base::Bind(&GetLRUOriginOnDBThread, type, | 1516 FROM_HERE, base::Bind(&GetLRUOriginOnDBThread, type, |
| 1696 GetEvictionOriginExceptions(std::set<GURL>()), | 1517 GetEvictionOriginExceptions(std::set<GURL>()), |
| 1697 base::RetainedRef(special_storage_policy_), | 1518 base::RetainedRef(special_storage_policy_), |
| 1698 base::Unretained(url)), | 1519 base::Unretained(url)), |
| 1699 base::Bind(&QuotaManager::DidGetLRUOrigin, weak_factory_.GetWeakPtr(), | 1520 base::Bind(&QuotaManager::DidGetLRUOrigin, weak_factory_.GetWeakPtr(), |
| 1700 base::Owned(url))); | 1521 base::Owned(url))); |
| 1701 } | 1522 } |
| 1702 | 1523 |
| 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, | 1524 void QuotaManager::DidGetPersistentHostQuota(const std::string& host, |
| 1721 const int64_t* quota, | 1525 const int64_t* quota, |
| 1722 bool success) { | 1526 bool success) { |
| 1723 DidDatabaseWork(success); | 1527 DidDatabaseWork(success); |
| 1724 persistent_host_quota_callbacks_.Run(host, kQuotaStatusOk, *quota); | 1528 persistent_host_quota_callbacks_.Run( |
| 1529 host, kQuotaStatusOk, std::min(*quota, kPerHostPersistentQuotaLimit)); |
| 1725 } | 1530 } |
| 1726 | 1531 |
| 1727 void QuotaManager::DidSetPersistentHostQuota(const std::string& host, | 1532 void QuotaManager::DidSetPersistentHostQuota(const std::string& host, |
| 1728 const QuotaCallback& callback, | 1533 const QuotaCallback& callback, |
| 1729 const int64_t* new_quota, | 1534 const int64_t* new_quota, |
| 1730 bool success) { | 1535 bool success) { |
| 1731 DidDatabaseWork(success); | 1536 DidDatabaseWork(success); |
| 1732 callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota); | 1537 callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota); |
| 1733 } | 1538 } |
| 1734 | 1539 |
| 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, | 1540 void QuotaManager::DidGetLRUOrigin(const GURL* origin, |
| 1757 bool success) { | 1541 bool success) { |
| 1758 DidDatabaseWork(success); | 1542 DidDatabaseWork(success); |
| 1759 | 1543 |
| 1760 lru_origin_callback_.Run(*origin); | 1544 lru_origin_callback_.Run(*origin); |
| 1761 lru_origin_callback_.Reset(); | 1545 lru_origin_callback_.Reset(); |
| 1762 } | 1546 } |
| 1763 | 1547 |
| 1764 void QuotaManager::DidGetInitialTemporaryGlobalQuota( | 1548 namespace { |
| 1765 base::TimeTicks start_ticks, | 1549 void DidGetSettingsThreadAdapter(base::TaskRunner* task_runner, |
| 1766 QuotaStatusCode status, | 1550 const OptionalQuotaSettingsCallback& callback, |
| 1767 int64_t quota_unused) { | 1551 base::Optional<QuotaSettings> settings) { |
| 1768 UMA_HISTOGRAM_LONG_TIMES( | 1552 task_runner->PostTask(FROM_HERE, base::Bind(callback, std::move(settings))); |
| 1769 "Quota.TimeToInitializeGlobalQuota", | 1553 } |
| 1770 base::TimeTicks::Now() - start_ticks); | 1554 } // namespace |
| 1771 | 1555 |
| 1772 if (eviction_disabled_) | 1556 void QuotaManager::GetQuotaSettings(const QuotaSettingsCallback& callback) { |
| 1557 if (base::TimeTicks::Now() - settings_timestamp_ < |
| 1558 settings_.refresh_interval) { |
| 1559 callback.Run(settings_); |
| 1560 return; |
| 1561 } |
| 1562 |
| 1563 if (!settings_callbacks_.Add(callback)) |
| 1773 return; | 1564 return; |
| 1774 | 1565 |
| 1775 std::set<GURL>* origins = new std::set<GURL>; | 1566 // We invoke our clients GetQuotaSettingsFunc on the |
| 1776 temporary_usage_tracker_->GetCachedOrigins(origins); | 1567 // UI thread and plumb the resulting value back to this thread. |
| 1777 // This will call the StartEviction() when initial origin registration | 1568 get_settings_task_runner_->PostTask( |
| 1778 // is completed. | |
| 1779 PostTaskAndReplyWithResultForDBThread( | |
| 1780 FROM_HERE, | 1569 FROM_HERE, |
| 1781 base::Bind(&InitializeTemporaryOriginsInfoOnDBThread, | 1570 base::Bind( |
| 1782 base::Owned(origins)), | 1571 get_settings_function_, |
| 1783 base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo, | 1572 base::Bind( |
| 1573 &DidGetSettingsThreadAdapter, |
| 1574 base::RetainedRef(base::ThreadTaskRunnerHandle::Get()), |
| 1575 base::Bind(&QuotaManager::DidGetSettings, |
| 1576 weak_factory_.GetWeakPtr(), base::TimeTicks::Now())))); |
| 1577 } |
| 1578 |
| 1579 void QuotaManager::DidGetSettings(base::TimeTicks start_ticks, |
| 1580 base::Optional<QuotaSettings> settings) { |
| 1581 if (!settings) { |
| 1582 settings = settings_; |
| 1583 settings->refresh_interval = base::TimeDelta::FromMinutes(1); |
| 1584 } |
| 1585 SetQuotaSettings(*settings); |
| 1586 settings_callbacks_.Run(*settings); |
| 1587 UMA_HISTOGRAM_MBYTES("Quota.GlobalTemporaryPoolSize", settings->pool_size); |
| 1588 UMA_HISTOGRAM_LONG_TIMES("Quota.TimeToGetSettings", |
| 1589 base::TimeTicks::Now() - start_ticks); |
| 1590 LOG_IF(WARNING, settings->pool_size == 0) |
| 1591 << "No storage quota provided in QuotaSettings."; |
| 1592 } |
| 1593 |
| 1594 void QuotaManager::GetStorageCapacity(const StorageCapacityCallback& callback) { |
| 1595 if (!storage_capacity_callbacks_.Add(callback)) |
| 1596 return; |
| 1597 if (is_incognito_) { |
| 1598 GetQuotaSettings( |
| 1599 base::Bind(&QuotaManager::ContinueIncognitoGetStorageCapacity, |
| 1600 weak_factory_.GetWeakPtr())); |
| 1601 return; |
| 1602 } |
| 1603 base::PostTaskAndReplyWithResult( |
| 1604 db_thread_.get(), FROM_HERE, |
| 1605 base::Bind(&QuotaManager::CallGetVolumeInfo, get_volume_info_fn_, |
| 1606 profile_path_), |
| 1607 base::Bind(&QuotaManager::DidGetStorageCapacity, |
| 1784 weak_factory_.GetWeakPtr())); | 1608 weak_factory_.GetWeakPtr())); |
| 1785 } | 1609 } |
| 1786 | 1610 |
| 1787 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) { | 1611 void QuotaManager::ContinueIncognitoGetStorageCapacity( |
| 1788 DidDatabaseWork(success); | 1612 const QuotaSettings& settings) { |
| 1789 if (success) | 1613 int64_t current_usage = |
| 1790 StartEviction(); | 1614 GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage(); |
| 1615 current_usage += GetUsageTracker(kStorageTypePersistent)->GetCachedUsage(); |
| 1616 int64_t available_space = |
| 1617 std::max(INT64_C(0), settings.pool_size - current_usage); |
| 1618 DidGetStorageCapacity(std::make_tuple(settings.pool_size, available_space)); |
| 1791 } | 1619 } |
| 1792 | 1620 |
| 1793 void QuotaManager::DidGetAvailableSpace(int64_t space) { | 1621 void QuotaManager::DidGetStorageCapacity( |
| 1794 // crbug.com/349708 | 1622 const std::tuple<int64_t, int64_t>& total_and_available) { |
| 1795 TRACE_EVENT1("io", "QuotaManager::DidGetAvailableSpace", | 1623 storage_capacity_callbacks_.Run(std::get<0>(total_and_available), |
| 1796 "n_callbacks", available_space_callbacks_.size()); | 1624 std::get<1>(total_and_available)); |
| 1797 | |
| 1798 available_space_callbacks_.Run(kQuotaStatusOk, space); | |
| 1799 } | 1625 } |
| 1800 | 1626 |
| 1801 void QuotaManager::DidDatabaseWork(bool success) { | 1627 void QuotaManager::DidDatabaseWork(bool success) { |
| 1802 db_disabled_ = !success; | 1628 db_disabled_ = !success; |
| 1803 } | 1629 } |
| 1804 | 1630 |
| 1805 void QuotaManager::DeleteOnCorrectThread() const { | 1631 void QuotaManager::DeleteOnCorrectThread() const { |
| 1806 if (!io_thread_->BelongsToCurrentThread() && | 1632 if (!io_thread_->BelongsToCurrentThread() && |
| 1807 io_thread_->DeleteSoon(FROM_HERE, this)) { | 1633 io_thread_->DeleteSoon(FROM_HERE, this)) { |
| 1808 return; | 1634 return; |
| 1809 } | 1635 } |
| 1810 delete this; | 1636 delete this; |
| 1811 } | 1637 } |
| 1812 | 1638 |
| 1813 void QuotaManager::PostTaskAndReplyWithResultForDBThread( | 1639 void QuotaManager::PostTaskAndReplyWithResultForDBThread( |
| 1814 const tracked_objects::Location& from_here, | 1640 const tracked_objects::Location& from_here, |
| 1815 const base::Callback<bool(QuotaDatabase*)>& task, | 1641 const base::Callback<bool(QuotaDatabase*)>& task, |
| 1816 const base::Callback<void(bool)>& reply) { | 1642 const base::Callback<void(bool)>& reply) { |
| 1817 // Deleting manager will post another task to DB thread to delete | 1643 // Deleting manager will post another task to DB thread to delete |
| 1818 // |database_|, therefore we can be sure that database_ is alive when this | 1644 // |database_|, therefore we can be sure that database_ is alive when this |
| 1819 // task runs. | 1645 // task runs. |
| 1820 base::PostTaskAndReplyWithResult( | 1646 base::PostTaskAndReplyWithResult( |
| 1821 db_thread_.get(), | 1647 db_thread_.get(), |
| 1822 from_here, | 1648 from_here, |
| 1823 base::Bind(task, base::Unretained(database_.get())), | 1649 base::Bind(task, base::Unretained(database_.get())), |
| 1824 reply); | 1650 reply); |
| 1825 } | 1651 } |
| 1826 | 1652 |
| 1827 // static | 1653 // static |
| 1828 int64_t QuotaManager::CallGetAmountOfFreeDiskSpace( | 1654 std::tuple<int64_t, int64_t> QuotaManager::CallGetVolumeInfo( |
| 1829 GetVolumeInfoFn get_volume_info_fn, | 1655 GetVolumeInfoFn get_volume_info_fn, |
| 1830 const base::FilePath& profile_path) { | 1656 const base::FilePath& path) { |
| 1831 // crbug.com/349708 | 1657 // crbug.com/349708 |
| 1832 TRACE_EVENT0("io", "CallSystemGetAmountOfFreeDiskSpace"); | 1658 TRACE_EVENT0("io", "CallGetVolumeInfo"); |
| 1833 if (!base::CreateDirectory(profile_path)) { | 1659 if (!base::CreateDirectory(path)) { |
| 1834 LOG(WARNING) << "Create directory failed for path" << profile_path.value(); | 1660 LOG(WARNING) << "Create directory failed for path" << path.value(); |
| 1835 return 0; | 1661 return std::make_tuple<int64_t, int64_t>(0, 0); |
| 1836 } | 1662 } |
| 1837 uint64_t available, total; | 1663 int64_t total; |
| 1838 if (!get_volume_info_fn(profile_path, &available, &total)) { | 1664 int64_t available; |
| 1839 return 0; | 1665 std::tie(total, available) = get_volume_info_fn(path); |
| 1666 if (total < 0 || available < 0) { |
| 1667 LOG(WARNING) << "Unable to get volume info: " << path.value(); |
| 1668 return std::make_tuple<int64_t, int64_t>(0, 0); |
| 1840 } | 1669 } |
| 1670 UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total); |
| 1841 UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", available); | 1671 UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", available); |
| 1842 UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total); | 1672 if (total > 0) { |
| 1843 return static_cast<int64_t>(available); | 1673 UMA_HISTOGRAM_PERCENTAGE("Quota.PercentDiskAvailable", |
| 1674 std::min(100, static_cast<int>((available * 100) / total))); |
| 1675 } |
| 1676 return std::make_tuple(total, available); |
| 1844 } | 1677 } |
| 1845 | 1678 |
| 1846 //static | 1679 // static |
| 1847 bool QuotaManager::GetVolumeInfo(const base::FilePath& path, | 1680 std::tuple<int64_t, int64_t> QuotaManager::GetVolumeInfo( |
| 1848 uint64_t* available_space, | 1681 const base::FilePath& path) { |
| 1849 uint64_t* total_size) { | 1682 return std::make_tuple(base::SysInfo::AmountOfTotalDiskSpace(path), |
| 1850 // Inspired by similar code in the base::SysInfo class. | 1683 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 } | 1684 } |
| 1864 | 1685 |
| 1865 } // namespace storage | 1686 } // namespace storage |
| OLD | NEW |