net cleanup: Remove unnecessary namespace prefixes.
[chromium-blink-merge.git] / storage / browser / quota / quota_manager.cc
blob55f00a03a1c7e52faa2d3796782cace9555abcaa
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
3 // found in the LICENSE file.
5 #include "storage/browser/quota/quota_manager.h"
7 #include <algorithm>
8 #include <deque>
9 #include <functional>
10 #include <set>
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/metrics/histogram.h"
19 #include "base/profiler/scoped_tracker.h"
20 #include "base/sequenced_task_runner.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/sys_info.h"
24 #include "base/task_runner_util.h"
25 #include "base/time/time.h"
26 #include "net/base/net_util.h"
27 #include "storage/browser/quota/client_usage_tracker.h"
28 #include "storage/browser/quota/quota_database.h"
29 #include "storage/browser/quota/quota_manager_proxy.h"
30 #include "storage/browser/quota/quota_temporary_storage_evictor.h"
31 #include "storage/browser/quota/storage_monitor.h"
32 #include "storage/browser/quota/usage_tracker.h"
33 #include "storage/common/quota/quota_types.h"
35 #define UMA_HISTOGRAM_MBYTES(name, sample) \
36 UMA_HISTOGRAM_CUSTOM_COUNTS( \
37 (name), static_cast<int>((sample) / kMBytes), \
38 1, 10 * 1024 * 1024 /* 10TB */, 100)
40 namespace storage {
42 namespace {
44 const int64 kMBytes = 1024 * 1024;
45 const int kMinutesInMilliSeconds = 60 * 1000;
47 const int64 kReportHistogramInterval = 60 * 60 * 1000; // 1 hour
48 const double kTemporaryQuotaRatioToAvail = 1.0 / 3.0; // 33%
50 } // namespace
52 // Arbitrary for now, but must be reasonably small so that
53 // in-memory databases can fit.
54 // TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this.
55 const int64 QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
57 const int64 QuotaManager::kNoLimit = kint64max;
59 const int QuotaManager::kPerHostTemporaryPortion = 5; // 20%
61 // Cap size for per-host persistent quota determined by the histogram.
62 // This is a bit lax value because the histogram says nothing about per-host
63 // persistent storage usage and we determined by global persistent storage
64 // usage that is less than 10GB for almost all users.
65 const int64 QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes;
67 const char QuotaManager::kDatabaseName[] = "QuotaManager";
69 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3;
71 // Preserve kMinimumPreserveForSystem disk space for system book-keeping
72 // when returning the quota to unlimited apps/extensions.
73 // TODO(kinuko): This should be like 10% of the actual disk space.
74 // For now we simply use a constant as getting the disk size needs
75 // platform-dependent code. (http://crbug.com/178976)
76 int64 QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
78 const int QuotaManager::kEvictionIntervalInMilliSeconds =
79 30 * kMinutesInMilliSeconds;
81 // Heuristics: assuming average cloud server allows a few Gigs storage
82 // on the server side and the storage needs to be shared for user data
83 // and by multiple apps.
84 int64 QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
86 namespace {
88 void CountOriginType(const std::set<GURL>& origins,
89 SpecialStoragePolicy* policy,
90 size_t* protected_origins,
91 size_t* unlimited_origins) {
92 DCHECK(protected_origins);
93 DCHECK(unlimited_origins);
94 *protected_origins = 0;
95 *unlimited_origins = 0;
96 if (!policy)
97 return;
98 for (std::set<GURL>::const_iterator itr = origins.begin();
99 itr != origins.end();
100 ++itr) {
101 if (policy->IsStorageProtected(*itr))
102 ++*protected_origins;
103 if (policy->IsStorageUnlimited(*itr))
104 ++*unlimited_origins;
108 bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64* new_quota,
109 QuotaDatabase* database) {
110 DCHECK(database);
111 if (!database->SetQuotaConfigValue(
112 QuotaDatabase::kTemporaryQuotaOverrideKey, *new_quota)) {
113 *new_quota = -1;
114 return false;
116 return true;
119 bool GetPersistentHostQuotaOnDBThread(const std::string& host,
120 int64* quota,
121 QuotaDatabase* database) {
122 DCHECK(database);
123 database->GetHostQuota(host, kStorageTypePersistent, quota);
124 return true;
127 bool SetPersistentHostQuotaOnDBThread(const std::string& host,
128 int64* new_quota,
129 QuotaDatabase* database) {
130 DCHECK(database);
131 if (database->SetHostQuota(host, kStorageTypePersistent, *new_quota))
132 return true;
133 *new_quota = 0;
134 return false;
137 bool InitializeOnDBThread(int64* temporary_quota_override,
138 int64* desired_available_space,
139 QuotaDatabase* database) {
140 DCHECK(database);
141 database->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey,
142 temporary_quota_override);
143 database->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey,
144 desired_available_space);
145 return true;
148 bool GetLRUOriginOnDBThread(StorageType type,
149 std::set<GURL>* exceptions,
150 SpecialStoragePolicy* policy,
151 GURL* url,
152 QuotaDatabase* database) {
153 DCHECK(database);
154 database->GetLRUOrigin(type, *exceptions, policy, url);
155 return true;
158 bool DeleteOriginInfoOnDBThread(const GURL& origin,
159 StorageType type,
160 QuotaDatabase* database) {
161 DCHECK(database);
162 return database->DeleteOriginInfo(origin, type);
165 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set<GURL>* origins,
166 QuotaDatabase* database) {
167 DCHECK(database);
168 if (database->IsOriginDatabaseBootstrapped())
169 return true;
171 // Register existing origins with 0 last time access.
172 if (database->RegisterInitialOriginInfo(*origins, kStorageTypeTemporary)) {
173 database->SetOriginDatabaseBootstrapped(true);
174 return true;
176 return false;
179 bool UpdateAccessTimeOnDBThread(const GURL& origin,
180 StorageType type,
181 base::Time accessed_time,
182 QuotaDatabase* database) {
183 DCHECK(database);
184 return database->SetOriginLastAccessTime(origin, type, accessed_time);
187 bool UpdateModifiedTimeOnDBThread(const GURL& origin,
188 StorageType type,
189 base::Time modified_time,
190 QuotaDatabase* database) {
191 DCHECK(database);
192 return database->SetOriginLastModifiedTime(origin, type, modified_time);
195 int64 CallSystemGetAmountOfFreeDiskSpace(const base::FilePath& profile_path) {
196 // Ensure the profile path exists.
197 if (!base::CreateDirectory(profile_path)) {
198 LOG(WARNING) << "Create directory failed for path" << profile_path.value();
199 return 0;
201 return base::SysInfo::AmountOfFreeDiskSpace(profile_path);
204 int64 CalculateTemporaryGlobalQuota(int64 global_limited_usage,
205 int64 available_space) {
206 DCHECK_GE(global_limited_usage, 0);
207 int64 avail_space = available_space;
208 if (avail_space < kint64max - global_limited_usage) {
209 // We basically calculate the temporary quota by
210 // [available_space + space_used_for_temp] * kTempQuotaRatio,
211 // but make sure we'll have no overflow.
212 avail_space += global_limited_usage;
214 return avail_space * kTemporaryQuotaRatioToAvail;
217 void DispatchTemporaryGlobalQuotaCallback(
218 const QuotaCallback& callback,
219 QuotaStatusCode status,
220 const UsageAndQuota& usage_and_quota) {
221 if (status != kQuotaStatusOk) {
222 callback.Run(status, 0);
223 return;
226 callback.Run(status, CalculateTemporaryGlobalQuota(
227 usage_and_quota.global_limited_usage,
228 usage_and_quota.available_disk_space));
231 int64 CalculateQuotaWithDiskSpace(
232 int64 available_disk_space, int64 usage, int64 quota) {
233 if (available_disk_space < QuotaManager::kMinimumPreserveForSystem) {
234 LOG(WARNING)
235 << "Running out of disk space for profile."
236 << " QuotaManager starts forbidding further quota consumption.";
237 return usage;
240 if (quota < usage) {
241 // No more space; cap the quota to the current usage.
242 return usage;
245 available_disk_space -= QuotaManager::kMinimumPreserveForSystem;
246 if (available_disk_space < quota - usage)
247 return available_disk_space + usage;
249 return quota;
252 int64 CalculateTemporaryHostQuota(int64 host_usage,
253 int64 global_quota,
254 int64 global_limited_usage) {
255 DCHECK_GE(global_limited_usage, 0);
256 int64 host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion;
257 if (global_limited_usage > global_quota)
258 host_quota = std::min(host_quota, host_usage);
259 return host_quota;
262 void DispatchUsageAndQuotaForWebApps(
263 StorageType type,
264 bool is_incognito,
265 bool is_unlimited,
266 bool can_query_disk_size,
267 const QuotaManager::GetUsageAndQuotaCallback& callback,
268 QuotaStatusCode status,
269 const UsageAndQuota& usage_and_quota) {
270 if (status != kQuotaStatusOk) {
271 callback.Run(status, 0, 0);
272 return;
275 int64 usage = usage_and_quota.usage;
276 int64 quota = usage_and_quota.quota;
278 if (type == kStorageTypeTemporary && !is_unlimited) {
279 quota = CalculateTemporaryHostQuota(
280 usage, quota, usage_and_quota.global_limited_usage);
283 if (is_incognito) {
284 quota = std::min(quota, QuotaManager::kIncognitoDefaultQuotaLimit);
285 callback.Run(status, usage, quota);
286 return;
289 // For apps with unlimited permission or can_query_disk_size is true (and not
290 // in incognito mode).
291 // We assume we can expose the actual disk size for them and cap the quota by
292 // the available disk space.
293 if (is_unlimited || can_query_disk_size) {
294 callback.Run(
295 status, usage,
296 CalculateQuotaWithDiskSpace(
297 usage_and_quota.available_disk_space,
298 usage, quota));
299 return;
302 callback.Run(status, usage, quota);
305 } // namespace
307 UsageAndQuota::UsageAndQuota()
308 : usage(0),
309 global_limited_usage(0),
310 quota(0),
311 available_disk_space(0) {
314 UsageAndQuota::UsageAndQuota(
315 int64 usage,
316 int64 global_limited_usage,
317 int64 quota,
318 int64 available_disk_space)
319 : usage(usage),
320 global_limited_usage(global_limited_usage),
321 quota(quota),
322 available_disk_space(available_disk_space) {
325 class UsageAndQuotaCallbackDispatcher
326 : public QuotaTask,
327 public base::SupportsWeakPtr<UsageAndQuotaCallbackDispatcher> {
328 public:
329 explicit UsageAndQuotaCallbackDispatcher(QuotaManager* manager)
330 : QuotaTask(manager),
331 has_usage_(false),
332 has_global_limited_usage_(false),
333 has_quota_(false),
334 has_available_disk_space_(false),
335 status_(kQuotaStatusUnknown),
336 usage_and_quota_(-1, -1, -1, -1),
337 waiting_callbacks_(1) {}
339 ~UsageAndQuotaCallbackDispatcher() override {}
341 void WaitForResults(const QuotaManager::UsageAndQuotaCallback& callback) {
342 callback_ = callback;
343 Start();
346 void set_usage(int64 usage) {
347 usage_and_quota_.usage = usage;
348 has_usage_ = true;
351 void set_global_limited_usage(int64 global_limited_usage) {
352 usage_and_quota_.global_limited_usage = global_limited_usage;
353 has_global_limited_usage_ = true;
356 void set_quota(int64 quota) {
357 usage_and_quota_.quota = quota;
358 has_quota_ = true;
361 void set_available_disk_space(int64 available_disk_space) {
362 usage_and_quota_.available_disk_space = available_disk_space;
363 has_available_disk_space_ = true;
366 UsageCallback GetHostUsageCallback() {
367 ++waiting_callbacks_;
368 has_usage_ = true;
369 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage,
370 AsWeakPtr());
373 UsageCallback GetGlobalLimitedUsageCallback() {
374 ++waiting_callbacks_;
375 has_global_limited_usage_ = true;
376 return base::Bind(
377 &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage,
378 AsWeakPtr());
381 QuotaCallback GetQuotaCallback() {
382 ++waiting_callbacks_;
383 has_quota_ = true;
384 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota,
385 AsWeakPtr());
388 QuotaCallback GetAvailableSpaceCallback() {
389 ++waiting_callbacks_;
390 has_available_disk_space_ = true;
391 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace,
392 AsWeakPtr());
395 private:
396 void DidGetHostUsage(int64 usage) {
397 if (status_ == kQuotaStatusUnknown)
398 status_ = kQuotaStatusOk;
399 usage_and_quota_.usage = usage;
400 CheckCompleted();
403 void DidGetGlobalLimitedUsage(int64 limited_usage) {
404 if (status_ == kQuotaStatusUnknown)
405 status_ = kQuotaStatusOk;
406 usage_and_quota_.global_limited_usage = limited_usage;
407 CheckCompleted();
410 void DidGetQuota(QuotaStatusCode status, int64 quota) {
411 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
412 status_ = status;
413 usage_and_quota_.quota = quota;
414 CheckCompleted();
417 void DidGetAvailableSpace(QuotaStatusCode status, int64 space) {
418 DCHECK_GE(space, 0);
419 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
420 status_ = status;
421 usage_and_quota_.available_disk_space = space;
422 CheckCompleted();
425 void Run() override {
426 // We initialize waiting_callbacks to 1 so that we won't run
427 // the completion callback until here even some of the callbacks
428 // are dispatched synchronously.
429 CheckCompleted();
432 void Aborted() override {
433 callback_.Run(kQuotaErrorAbort, UsageAndQuota());
434 DeleteSoon();
437 void Completed() override {
438 DCHECK(!has_usage_ || usage_and_quota_.usage >= 0);
439 DCHECK(!has_global_limited_usage_ ||
440 usage_and_quota_.global_limited_usage >= 0);
441 DCHECK(!has_quota_ || usage_and_quota_.quota >= 0);
442 DCHECK(!has_available_disk_space_ ||
443 usage_and_quota_.available_disk_space >= 0);
445 callback_.Run(status_, usage_and_quota_);
446 DeleteSoon();
449 void CheckCompleted() {
450 if (--waiting_callbacks_ <= 0)
451 CallCompleted();
454 // For sanity checks, they're checked only when DCHECK is on.
455 bool has_usage_;
456 bool has_global_limited_usage_;
457 bool has_quota_;
458 bool has_available_disk_space_;
460 QuotaStatusCode status_;
461 UsageAndQuota usage_and_quota_;
462 QuotaManager::UsageAndQuotaCallback callback_;
463 int waiting_callbacks_;
465 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher);
468 class QuotaManager::GetUsageInfoTask : public QuotaTask {
469 public:
470 GetUsageInfoTask(
471 QuotaManager* manager,
472 const GetUsageInfoCallback& callback)
473 : QuotaTask(manager),
474 callback_(callback),
475 weak_factory_(this) {
478 protected:
479 void Run() override {
480 remaining_trackers_ = 3;
481 // This will populate cached hosts and usage info.
482 manager()->GetUsageTracker(kStorageTypeTemporary)->GetGlobalUsage(
483 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
484 weak_factory_.GetWeakPtr(),
485 kStorageTypeTemporary));
486 manager()->GetUsageTracker(kStorageTypePersistent)->GetGlobalUsage(
487 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
488 weak_factory_.GetWeakPtr(),
489 kStorageTypePersistent));
490 manager()->GetUsageTracker(kStorageTypeSyncable)->GetGlobalUsage(
491 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
492 weak_factory_.GetWeakPtr(),
493 kStorageTypeSyncable));
496 void Completed() override {
497 callback_.Run(entries_);
498 DeleteSoon();
501 void Aborted() override {
502 callback_.Run(UsageInfoEntries());
503 DeleteSoon();
506 private:
507 void AddEntries(StorageType type, UsageTracker* tracker) {
508 std::map<std::string, int64> host_usage;
509 tracker->GetCachedHostsUsage(&host_usage);
510 for (std::map<std::string, int64>::const_iterator iter = host_usage.begin();
511 iter != host_usage.end();
512 ++iter) {
513 entries_.push_back(UsageInfo(iter->first, type, iter->second));
515 if (--remaining_trackers_ == 0)
516 CallCompleted();
519 void DidGetGlobalUsage(StorageType type, int64, int64) {
520 DCHECK(manager()->GetUsageTracker(type));
521 AddEntries(type, manager()->GetUsageTracker(type));
524 QuotaManager* manager() const {
525 return static_cast<QuotaManager*>(observer());
528 GetUsageInfoCallback callback_;
529 UsageInfoEntries entries_;
530 int remaining_trackers_;
531 base::WeakPtrFactory<GetUsageInfoTask> weak_factory_;
533 DISALLOW_COPY_AND_ASSIGN(GetUsageInfoTask);
536 class QuotaManager::OriginDataDeleter : public QuotaTask {
537 public:
538 OriginDataDeleter(QuotaManager* manager,
539 const GURL& origin,
540 StorageType type,
541 int quota_client_mask,
542 const StatusCallback& callback)
543 : QuotaTask(manager),
544 origin_(origin),
545 type_(type),
546 quota_client_mask_(quota_client_mask),
547 error_count_(0),
548 remaining_clients_(-1),
549 skipped_clients_(0),
550 callback_(callback),
551 weak_factory_(this) {}
553 protected:
554 void Run() override {
555 error_count_ = 0;
556 remaining_clients_ = manager()->clients_.size();
557 for (QuotaClientList::iterator iter = manager()->clients_.begin();
558 iter != manager()->clients_.end(); ++iter) {
559 if (quota_client_mask_ & (*iter)->id()) {
560 (*iter)->DeleteOriginData(
561 origin_, type_,
562 base::Bind(&OriginDataDeleter::DidDeleteOriginData,
563 weak_factory_.GetWeakPtr()));
564 } else {
565 ++skipped_clients_;
566 if (--remaining_clients_ == 0)
567 CallCompleted();
572 void Completed() override {
573 if (error_count_ == 0) {
574 // Only remove the entire origin if we didn't skip any client types.
575 if (skipped_clients_ == 0)
576 manager()->DeleteOriginFromDatabase(origin_, type_);
577 callback_.Run(kQuotaStatusOk);
578 } else {
579 callback_.Run(kQuotaErrorInvalidModification);
581 DeleteSoon();
584 void Aborted() override {
585 callback_.Run(kQuotaErrorAbort);
586 DeleteSoon();
589 private:
590 void DidDeleteOriginData(QuotaStatusCode status) {
591 DCHECK_GT(remaining_clients_, 0);
593 if (status != kQuotaStatusOk)
594 ++error_count_;
596 if (--remaining_clients_ == 0)
597 CallCompleted();
600 QuotaManager* manager() const {
601 return static_cast<QuotaManager*>(observer());
604 GURL origin_;
605 StorageType type_;
606 int quota_client_mask_;
607 int error_count_;
608 int remaining_clients_;
609 int skipped_clients_;
610 StatusCallback callback_;
612 base::WeakPtrFactory<OriginDataDeleter> weak_factory_;
613 DISALLOW_COPY_AND_ASSIGN(OriginDataDeleter);
616 class QuotaManager::HostDataDeleter : public QuotaTask {
617 public:
618 HostDataDeleter(QuotaManager* manager,
619 const std::string& host,
620 StorageType type,
621 int quota_client_mask,
622 const StatusCallback& callback)
623 : QuotaTask(manager),
624 host_(host),
625 type_(type),
626 quota_client_mask_(quota_client_mask),
627 error_count_(0),
628 remaining_clients_(-1),
629 remaining_deleters_(-1),
630 callback_(callback),
631 weak_factory_(this) {}
633 protected:
634 void Run() override {
635 error_count_ = 0;
636 remaining_clients_ = manager()->clients_.size();
637 for (QuotaClientList::iterator iter = manager()->clients_.begin();
638 iter != manager()->clients_.end(); ++iter) {
639 (*iter)->GetOriginsForHost(
640 type_, host_,
641 base::Bind(&HostDataDeleter::DidGetOriginsForHost,
642 weak_factory_.GetWeakPtr()));
646 void Completed() override {
647 if (error_count_ == 0) {
648 callback_.Run(kQuotaStatusOk);
649 } else {
650 callback_.Run(kQuotaErrorInvalidModification);
652 DeleteSoon();
655 void Aborted() override {
656 callback_.Run(kQuotaErrorAbort);
657 DeleteSoon();
660 private:
661 void DidGetOriginsForHost(const std::set<GURL>& origins) {
662 DCHECK_GT(remaining_clients_, 0);
664 origins_.insert(origins.begin(), origins.end());
666 if (--remaining_clients_ == 0) {
667 if (!origins_.empty())
668 ScheduleOriginsDeletion();
669 else
670 CallCompleted();
674 void ScheduleOriginsDeletion() {
675 remaining_deleters_ = origins_.size();
676 for (std::set<GURL>::const_iterator p = origins_.begin();
677 p != origins_.end();
678 ++p) {
679 OriginDataDeleter* deleter =
680 new OriginDataDeleter(
681 manager(), *p, type_, quota_client_mask_,
682 base::Bind(&HostDataDeleter::DidDeleteOriginData,
683 weak_factory_.GetWeakPtr()));
684 deleter->Start();
688 void DidDeleteOriginData(QuotaStatusCode status) {
689 DCHECK_GT(remaining_deleters_, 0);
691 if (status != kQuotaStatusOk)
692 ++error_count_;
694 if (--remaining_deleters_ == 0)
695 CallCompleted();
698 QuotaManager* manager() const {
699 return static_cast<QuotaManager*>(observer());
702 std::string host_;
703 StorageType type_;
704 int quota_client_mask_;
705 std::set<GURL> origins_;
706 int error_count_;
707 int remaining_clients_;
708 int remaining_deleters_;
709 StatusCallback callback_;
711 base::WeakPtrFactory<HostDataDeleter> weak_factory_;
712 DISALLOW_COPY_AND_ASSIGN(HostDataDeleter);
715 class QuotaManager::GetModifiedSinceHelper {
716 public:
717 bool GetModifiedSinceOnDBThread(StorageType type,
718 base::Time modified_since,
719 QuotaDatabase* database) {
720 DCHECK(database);
721 return database->GetOriginsModifiedSince(type, &origins_, modified_since);
724 void DidGetModifiedSince(const base::WeakPtr<QuotaManager>& manager,
725 const GetOriginsCallback& callback,
726 StorageType type,
727 bool success) {
728 if (!manager) {
729 // The operation was aborted.
730 callback.Run(std::set<GURL>(), type);
731 return;
733 manager->DidDatabaseWork(success);
734 callback.Run(origins_, type);
737 private:
738 std::set<GURL> origins_;
741 class QuotaManager::DumpQuotaTableHelper {
742 public:
743 bool DumpQuotaTableOnDBThread(QuotaDatabase* database) {
744 DCHECK(database);
745 return database->DumpQuotaTable(
746 base::Bind(&DumpQuotaTableHelper::AppendEntry, base::Unretained(this)));
749 void DidDumpQuotaTable(const base::WeakPtr<QuotaManager>& manager,
750 const DumpQuotaTableCallback& callback,
751 bool success) {
752 if (!manager) {
753 // The operation was aborted.
754 callback.Run(QuotaTableEntries());
755 return;
757 manager->DidDatabaseWork(success);
758 callback.Run(entries_);
761 private:
762 bool AppendEntry(const QuotaTableEntry& entry) {
763 entries_.push_back(entry);
764 return true;
767 QuotaTableEntries entries_;
770 class QuotaManager::DumpOriginInfoTableHelper {
771 public:
772 bool DumpOriginInfoTableOnDBThread(QuotaDatabase* database) {
773 DCHECK(database);
774 return database->DumpOriginInfoTable(
775 base::Bind(&DumpOriginInfoTableHelper::AppendEntry,
776 base::Unretained(this)));
779 void DidDumpOriginInfoTable(const base::WeakPtr<QuotaManager>& manager,
780 const DumpOriginInfoTableCallback& callback,
781 bool success) {
782 if (!manager) {
783 // The operation was aborted.
784 callback.Run(OriginInfoTableEntries());
785 return;
787 manager->DidDatabaseWork(success);
788 callback.Run(entries_);
791 private:
792 bool AppendEntry(const OriginInfoTableEntry& entry) {
793 entries_.push_back(entry);
794 return true;
797 OriginInfoTableEntries entries_;
800 // QuotaManager ---------------------------------------------------------------
802 QuotaManager::QuotaManager(
803 bool is_incognito,
804 const base::FilePath& profile_path,
805 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread,
806 const scoped_refptr<base::SequencedTaskRunner>& db_thread,
807 const scoped_refptr<SpecialStoragePolicy>& special_storage_policy)
808 : is_incognito_(is_incognito),
809 profile_path_(profile_path),
810 proxy_(new QuotaManagerProxy(this, io_thread)),
811 db_disabled_(false),
812 eviction_disabled_(false),
813 io_thread_(io_thread),
814 db_thread_(db_thread),
815 temporary_quota_initialized_(false),
816 temporary_quota_override_(-1),
817 desired_available_space_(-1),
818 special_storage_policy_(special_storage_policy),
819 get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace),
820 storage_monitor_(new StorageMonitor(this)),
821 weak_factory_(this) {
824 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) {
825 LazyInitialize();
826 GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback);
827 get_usage_info->Start();
830 void QuotaManager::GetUsageAndQuotaForWebApps(
831 const GURL& origin,
832 StorageType type,
833 const GetUsageAndQuotaCallback& callback) {
834 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
835 tracked_objects::ScopedTracker tracking_profile(
836 FROM_HERE_WITH_EXPLICIT_FUNCTION(
837 "477117 QuotaManager::GetUsageAndQuotaForWebApps"));
838 if (type != kStorageTypeTemporary &&
839 type != kStorageTypePersistent &&
840 type != kStorageTypeSyncable) {
841 callback.Run(kQuotaErrorNotSupported, 0, 0);
842 return;
845 DCHECK(origin == origin.GetOrigin());
846 LazyInitialize();
848 bool unlimited = IsStorageUnlimited(origin, type);
849 bool can_query_disk_size = CanQueryDiskSize(origin);
851 UsageAndQuotaCallbackDispatcher* dispatcher =
852 new UsageAndQuotaCallbackDispatcher(this);
854 UsageAndQuota usage_and_quota;
855 if (unlimited) {
856 dispatcher->set_quota(kNoLimit);
857 } else {
858 if (type == kStorageTypeTemporary) {
859 GetUsageTracker(type)->GetGlobalLimitedUsage(
860 dispatcher->GetGlobalLimitedUsageCallback());
861 GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
862 } else if (type == kStorageTypePersistent) {
863 GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin),
864 dispatcher->GetQuotaCallback());
865 } else {
866 dispatcher->set_quota(kSyncableStorageDefaultHostQuota);
870 DCHECK(GetUsageTracker(type));
871 GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin),
872 dispatcher->GetHostUsageCallback());
874 if (!is_incognito_ && (unlimited || can_query_disk_size))
875 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
877 dispatcher->WaitForResults(base::Bind(
878 &DispatchUsageAndQuotaForWebApps,
879 type, is_incognito_, unlimited, can_query_disk_size,
880 callback));
883 void QuotaManager::GetUsageAndQuota(
884 const GURL& origin, StorageType type,
885 const GetUsageAndQuotaCallback& callback) {
886 DCHECK(origin == origin.GetOrigin());
888 if (IsStorageUnlimited(origin, type)) {
889 callback.Run(kQuotaStatusOk, 0, kNoLimit);
890 return;
893 GetUsageAndQuotaForWebApps(origin, type, callback);
896 void QuotaManager::NotifyStorageAccessed(
897 QuotaClient::ID client_id,
898 const GURL& origin, StorageType type) {
899 DCHECK(origin == origin.GetOrigin());
900 NotifyStorageAccessedInternal(client_id, origin, type, base::Time::Now());
903 void QuotaManager::NotifyStorageModified(
904 QuotaClient::ID client_id,
905 const GURL& origin, StorageType type, int64 delta) {
906 DCHECK(origin == origin.GetOrigin());
907 NotifyStorageModifiedInternal(client_id, origin, type, delta,
908 base::Time::Now());
911 void QuotaManager::NotifyOriginInUse(const GURL& origin) {
912 DCHECK(io_thread_->BelongsToCurrentThread());
913 origins_in_use_[origin]++;
916 void QuotaManager::NotifyOriginNoLongerInUse(const GURL& origin) {
917 DCHECK(io_thread_->BelongsToCurrentThread());
918 DCHECK(IsOriginInUse(origin));
919 int& count = origins_in_use_[origin];
920 if (--count == 0)
921 origins_in_use_.erase(origin);
924 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id,
925 const GURL& origin,
926 StorageType type,
927 bool enabled) {
928 LazyInitialize();
929 DCHECK(GetUsageTracker(type));
930 GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled);
933 void QuotaManager::DeleteOriginData(
934 const GURL& origin, StorageType type, int quota_client_mask,
935 const StatusCallback& callback) {
936 LazyInitialize();
938 if (origin.is_empty() || clients_.empty()) {
939 callback.Run(kQuotaStatusOk);
940 return;
943 DCHECK(origin == origin.GetOrigin());
944 OriginDataDeleter* deleter =
945 new OriginDataDeleter(this, origin, type, quota_client_mask, callback);
946 deleter->Start();
949 void QuotaManager::DeleteHostData(const std::string& host,
950 StorageType type,
951 int quota_client_mask,
952 const StatusCallback& callback) {
953 LazyInitialize();
955 if (host.empty() || clients_.empty()) {
956 callback.Run(kQuotaStatusOk);
957 return;
960 HostDataDeleter* deleter =
961 new HostDataDeleter(this, host, type, quota_client_mask, callback);
962 deleter->Start();
965 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback& callback) {
966 if (!available_space_callbacks_.Add(callback))
967 return;
969 PostTaskAndReplyWithResult(db_thread_.get(),
970 FROM_HERE,
971 base::Bind(get_disk_space_fn_, profile_path_),
972 base::Bind(&QuotaManager::DidGetAvailableSpace,
973 weak_factory_.GetWeakPtr()));
976 void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback& callback) {
977 LazyInitialize();
978 if (!temporary_quota_initialized_) {
979 db_initialization_callbacks_.Add(base::Bind(
980 &QuotaManager::GetTemporaryGlobalQuota,
981 weak_factory_.GetWeakPtr(), callback));
982 return;
985 if (temporary_quota_override_ > 0) {
986 callback.Run(kQuotaStatusOk, temporary_quota_override_);
987 return;
990 UsageAndQuotaCallbackDispatcher* dispatcher =
991 new UsageAndQuotaCallbackDispatcher(this);
992 GetUsageTracker(kStorageTypeTemporary)->
993 GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
994 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
995 dispatcher->WaitForResults(
996 base::Bind(&DispatchTemporaryGlobalQuotaCallback, callback));
999 void QuotaManager::SetTemporaryGlobalOverrideQuota(
1000 int64 new_quota, const QuotaCallback& callback) {
1001 LazyInitialize();
1003 if (new_quota < 0) {
1004 if (!callback.is_null())
1005 callback.Run(kQuotaErrorInvalidModification, -1);
1006 return;
1009 if (db_disabled_) {
1010 if (!callback.is_null())
1011 callback.Run(kQuotaErrorInvalidAccess, -1);
1012 return;
1015 int64* new_quota_ptr = new int64(new_quota);
1016 PostTaskAndReplyWithResultForDBThread(
1017 FROM_HERE,
1018 base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread,
1019 base::Unretained(new_quota_ptr)),
1020 base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota,
1021 weak_factory_.GetWeakPtr(),
1022 callback,
1023 base::Owned(new_quota_ptr)));
1026 void QuotaManager::GetPersistentHostQuota(const std::string& host,
1027 const QuotaCallback& callback) {
1028 LazyInitialize();
1029 if (host.empty()) {
1030 // This could happen if we are called on file:///.
1031 // TODO(kinuko) We may want to respect --allow-file-access-from-files
1032 // command line switch.
1033 callback.Run(kQuotaStatusOk, 0);
1034 return;
1037 if (!persistent_host_quota_callbacks_.Add(host, callback))
1038 return;
1040 int64* quota_ptr = new int64(0);
1041 PostTaskAndReplyWithResultForDBThread(
1042 FROM_HERE,
1043 base::Bind(&GetPersistentHostQuotaOnDBThread,
1044 host,
1045 base::Unretained(quota_ptr)),
1046 base::Bind(&QuotaManager::DidGetPersistentHostQuota,
1047 weak_factory_.GetWeakPtr(),
1048 host,
1049 base::Owned(quota_ptr)));
1052 void QuotaManager::SetPersistentHostQuota(const std::string& host,
1053 int64 new_quota,
1054 const QuotaCallback& callback) {
1055 LazyInitialize();
1056 if (host.empty()) {
1057 // This could happen if we are called on file:///.
1058 callback.Run(kQuotaErrorNotSupported, 0);
1059 return;
1062 if (new_quota < 0) {
1063 callback.Run(kQuotaErrorInvalidModification, -1);
1064 return;
1067 if (kPerHostPersistentQuotaLimit < new_quota) {
1068 // Cap the requested size at the per-host quota limit.
1069 new_quota = kPerHostPersistentQuotaLimit;
1072 if (db_disabled_) {
1073 callback.Run(kQuotaErrorInvalidAccess, -1);
1074 return;
1077 int64* new_quota_ptr = new int64(new_quota);
1078 PostTaskAndReplyWithResultForDBThread(
1079 FROM_HERE,
1080 base::Bind(&SetPersistentHostQuotaOnDBThread,
1081 host,
1082 base::Unretained(new_quota_ptr)),
1083 base::Bind(&QuotaManager::DidSetPersistentHostQuota,
1084 weak_factory_.GetWeakPtr(),
1085 host,
1086 callback,
1087 base::Owned(new_quota_ptr)));
1090 void QuotaManager::GetGlobalUsage(StorageType type,
1091 const GlobalUsageCallback& callback) {
1092 LazyInitialize();
1093 DCHECK(GetUsageTracker(type));
1094 GetUsageTracker(type)->GetGlobalUsage(callback);
1097 void QuotaManager::GetHostUsage(const std::string& host,
1098 StorageType type,
1099 const UsageCallback& callback) {
1100 LazyInitialize();
1101 DCHECK(GetUsageTracker(type));
1102 GetUsageTracker(type)->GetHostUsage(host, callback);
1105 void QuotaManager::GetHostUsage(const std::string& host,
1106 StorageType type,
1107 QuotaClient::ID client_id,
1108 const UsageCallback& callback) {
1109 LazyInitialize();
1110 DCHECK(GetUsageTracker(type));
1111 ClientUsageTracker* tracker =
1112 GetUsageTracker(type)->GetClientTracker(client_id);
1113 if (!tracker) {
1114 callback.Run(0);
1115 return;
1117 tracker->GetHostUsage(host, callback);
1120 bool QuotaManager::IsTrackingHostUsage(StorageType type,
1121 QuotaClient::ID client_id) const {
1122 UsageTracker* tracker = GetUsageTracker(type);
1123 return tracker && tracker->GetClientTracker(client_id);
1126 void QuotaManager::GetStatistics(
1127 std::map<std::string, std::string>* statistics) {
1128 DCHECK(statistics);
1129 if (temporary_storage_evictor_) {
1130 std::map<std::string, int64> stats;
1131 temporary_storage_evictor_->GetStatistics(&stats);
1132 for (std::map<std::string, int64>::iterator p = stats.begin();
1133 p != stats.end();
1134 ++p)
1135 (*statistics)[p->first] = base::Int64ToString(p->second);
1139 bool QuotaManager::IsStorageUnlimited(const GURL& origin,
1140 StorageType type) const {
1141 // For syncable storage we should always enforce quota (since the
1142 // quota must be capped by the server limit).
1143 if (type == kStorageTypeSyncable)
1144 return false;
1145 if (type == kStorageTypeQuotaNotManaged)
1146 return true;
1147 return special_storage_policy_.get() &&
1148 special_storage_policy_->IsStorageUnlimited(origin);
1151 void QuotaManager::GetOriginsModifiedSince(StorageType type,
1152 base::Time modified_since,
1153 const GetOriginsCallback& callback) {
1154 LazyInitialize();
1155 GetModifiedSinceHelper* helper = new GetModifiedSinceHelper;
1156 PostTaskAndReplyWithResultForDBThread(
1157 FROM_HERE,
1158 base::Bind(&GetModifiedSinceHelper::GetModifiedSinceOnDBThread,
1159 base::Unretained(helper),
1160 type,
1161 modified_since),
1162 base::Bind(&GetModifiedSinceHelper::DidGetModifiedSince,
1163 base::Owned(helper),
1164 weak_factory_.GetWeakPtr(),
1165 callback,
1166 type));
1169 bool QuotaManager::ResetUsageTracker(StorageType type) {
1170 DCHECK(GetUsageTracker(type));
1171 if (GetUsageTracker(type)->IsWorking())
1172 return false;
1173 switch (type) {
1174 case kStorageTypeTemporary:
1175 temporary_usage_tracker_.reset(new UsageTracker(
1176 clients_, kStorageTypeTemporary, special_storage_policy_.get(),
1177 storage_monitor_.get()));
1178 return true;
1179 case kStorageTypePersistent:
1180 persistent_usage_tracker_.reset(new UsageTracker(
1181 clients_, kStorageTypePersistent, special_storage_policy_.get(),
1182 storage_monitor_.get()));
1183 return true;
1184 case kStorageTypeSyncable:
1185 syncable_usage_tracker_.reset(new UsageTracker(
1186 clients_, kStorageTypeSyncable, special_storage_policy_.get(),
1187 storage_monitor_.get()));
1188 return true;
1189 default:
1190 NOTREACHED();
1192 return true;
1195 void QuotaManager::AddStorageObserver(
1196 StorageObserver* observer, const StorageObserver::MonitorParams& params) {
1197 DCHECK(observer);
1198 storage_monitor_->AddObserver(observer, params);
1201 void QuotaManager::RemoveStorageObserver(StorageObserver* observer) {
1202 DCHECK(observer);
1203 storage_monitor_->RemoveObserver(observer);
1206 void QuotaManager::RemoveStorageObserverForFilter(
1207 StorageObserver* observer, const StorageObserver::Filter& filter) {
1208 DCHECK(observer);
1209 storage_monitor_->RemoveObserverForFilter(observer, filter);
1212 QuotaManager::~QuotaManager() {
1213 proxy_->manager_ = NULL;
1214 std::for_each(clients_.begin(), clients_.end(),
1215 std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed));
1216 if (database_)
1217 db_thread_->DeleteSoon(FROM_HERE, database_.release());
1220 QuotaManager::EvictionContext::EvictionContext()
1221 : evicted_type(kStorageTypeUnknown) {
1224 QuotaManager::EvictionContext::~EvictionContext() {
1227 void QuotaManager::LazyInitialize() {
1228 DCHECK(io_thread_->BelongsToCurrentThread());
1229 if (database_) {
1230 // Initialization seems to be done already.
1231 return;
1234 // Use an empty path to open an in-memory only databse for incognito.
1235 database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() :
1236 profile_path_.AppendASCII(kDatabaseName)));
1238 temporary_usage_tracker_.reset(new UsageTracker(
1239 clients_, kStorageTypeTemporary, special_storage_policy_.get(),
1240 storage_monitor_.get()));
1241 persistent_usage_tracker_.reset(new UsageTracker(
1242 clients_, kStorageTypePersistent, special_storage_policy_.get(),
1243 storage_monitor_.get()));
1244 syncable_usage_tracker_.reset(new UsageTracker(
1245 clients_, kStorageTypeSyncable, special_storage_policy_.get(),
1246 storage_monitor_.get()));
1248 int64* temporary_quota_override = new int64(-1);
1249 int64* desired_available_space = new int64(-1);
1250 PostTaskAndReplyWithResultForDBThread(
1251 FROM_HERE,
1252 base::Bind(&InitializeOnDBThread,
1253 base::Unretained(temporary_quota_override),
1254 base::Unretained(desired_available_space)),
1255 base::Bind(&QuotaManager::DidInitialize,
1256 weak_factory_.GetWeakPtr(),
1257 base::Owned(temporary_quota_override),
1258 base::Owned(desired_available_space)));
1261 void QuotaManager::RegisterClient(QuotaClient* client) {
1262 DCHECK(!database_.get());
1263 clients_.push_back(client);
1266 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const {
1267 switch (type) {
1268 case kStorageTypeTemporary:
1269 return temporary_usage_tracker_.get();
1270 case kStorageTypePersistent:
1271 return persistent_usage_tracker_.get();
1272 case kStorageTypeSyncable:
1273 return syncable_usage_tracker_.get();
1274 case kStorageTypeQuotaNotManaged:
1275 return NULL;
1276 case kStorageTypeUnknown:
1277 NOTREACHED();
1279 return NULL;
1282 void QuotaManager::GetCachedOrigins(
1283 StorageType type, std::set<GURL>* origins) {
1284 DCHECK(origins);
1285 LazyInitialize();
1286 DCHECK(GetUsageTracker(type));
1287 GetUsageTracker(type)->GetCachedOrigins(origins);
1290 void QuotaManager::NotifyStorageAccessedInternal(
1291 QuotaClient::ID client_id,
1292 const GURL& origin, StorageType type,
1293 base::Time accessed_time) {
1294 LazyInitialize();
1295 if (type == kStorageTypeTemporary && !lru_origin_callback_.is_null()) {
1296 // Record the accessed origins while GetLRUOrigin task is runing
1297 // to filter out them from eviction.
1298 access_notified_origins_.insert(origin);
1301 if (db_disabled_)
1302 return;
1303 PostTaskAndReplyWithResultForDBThread(
1304 FROM_HERE,
1305 base::Bind(&UpdateAccessTimeOnDBThread, origin, type, accessed_time),
1306 base::Bind(&QuotaManager::DidDatabaseWork,
1307 weak_factory_.GetWeakPtr()));
1310 void QuotaManager::NotifyStorageModifiedInternal(
1311 QuotaClient::ID client_id,
1312 const GURL& origin,
1313 StorageType type,
1314 int64 delta,
1315 base::Time modified_time) {
1316 LazyInitialize();
1317 DCHECK(GetUsageTracker(type));
1318 GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta);
1320 PostTaskAndReplyWithResultForDBThread(
1321 FROM_HERE,
1322 base::Bind(&UpdateModifiedTimeOnDBThread, origin, type, modified_time),
1323 base::Bind(&QuotaManager::DidDatabaseWork,
1324 weak_factory_.GetWeakPtr()));
1327 void QuotaManager::DumpQuotaTable(const DumpQuotaTableCallback& callback) {
1328 DumpQuotaTableHelper* helper = new DumpQuotaTableHelper;
1329 PostTaskAndReplyWithResultForDBThread(
1330 FROM_HERE,
1331 base::Bind(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread,
1332 base::Unretained(helper)),
1333 base::Bind(&DumpQuotaTableHelper::DidDumpQuotaTable,
1334 base::Owned(helper),
1335 weak_factory_.GetWeakPtr(),
1336 callback));
1339 void QuotaManager::DumpOriginInfoTable(
1340 const DumpOriginInfoTableCallback& callback) {
1341 DumpOriginInfoTableHelper* helper = new DumpOriginInfoTableHelper;
1342 PostTaskAndReplyWithResultForDBThread(
1343 FROM_HERE,
1344 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread,
1345 base::Unretained(helper)),
1346 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable,
1347 base::Owned(helper),
1348 weak_factory_.GetWeakPtr(),
1349 callback));
1352 void QuotaManager::StartEviction() {
1353 DCHECK(!temporary_storage_evictor_.get());
1354 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(
1355 this, kEvictionIntervalInMilliSeconds));
1356 if (desired_available_space_ >= 0)
1357 temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction(
1358 desired_available_space_);
1359 temporary_storage_evictor_->Start();
1362 void QuotaManager::DeleteOriginFromDatabase(
1363 const GURL& origin, StorageType type) {
1364 LazyInitialize();
1365 if (db_disabled_)
1366 return;
1368 PostTaskAndReplyWithResultForDBThread(
1369 FROM_HERE,
1370 base::Bind(&DeleteOriginInfoOnDBThread, origin, type),
1371 base::Bind(&QuotaManager::DidDatabaseWork,
1372 weak_factory_.GetWeakPtr()));
1375 void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status) {
1376 DCHECK(io_thread_->BelongsToCurrentThread());
1378 // We only try evict origins that are not in use, so basically
1379 // deletion attempt for eviction should not fail. Let's record
1380 // the origin if we get error and exclude it from future eviction
1381 // if the error happens consistently (> kThresholdOfErrorsToBeBlacklisted).
1382 if (status != kQuotaStatusOk)
1383 origins_in_error_[eviction_context_.evicted_origin]++;
1385 eviction_context_.evict_origin_data_callback.Run(status);
1386 eviction_context_.evict_origin_data_callback.Reset();
1389 void QuotaManager::ReportHistogram() {
1390 GetGlobalUsage(kStorageTypeTemporary,
1391 base::Bind(
1392 &QuotaManager::DidGetTemporaryGlobalUsageForHistogram,
1393 weak_factory_.GetWeakPtr()));
1394 GetGlobalUsage(kStorageTypePersistent,
1395 base::Bind(
1396 &QuotaManager::DidGetPersistentGlobalUsageForHistogram,
1397 weak_factory_.GetWeakPtr()));
1400 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
1401 int64 usage,
1402 int64 unlimited_usage) {
1403 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfTemporaryStorage", usage);
1405 std::set<GURL> origins;
1406 GetCachedOrigins(kStorageTypeTemporary, &origins);
1408 size_t num_origins = origins.size();
1409 size_t protected_origins = 0;
1410 size_t unlimited_origins = 0;
1411 CountOriginType(origins,
1412 special_storage_policy_.get(),
1413 &protected_origins,
1414 &unlimited_origins);
1416 UMA_HISTOGRAM_COUNTS("Quota.NumberOfTemporaryStorageOrigins",
1417 num_origins);
1418 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedTemporaryStorageOrigins",
1419 protected_origins);
1420 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedTemporaryStorageOrigins",
1421 unlimited_origins);
1424 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
1425 int64 usage,
1426 int64 unlimited_usage) {
1427 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage);
1429 std::set<GURL> origins;
1430 GetCachedOrigins(kStorageTypePersistent, &origins);
1432 size_t num_origins = origins.size();
1433 size_t protected_origins = 0;
1434 size_t unlimited_origins = 0;
1435 CountOriginType(origins,
1436 special_storage_policy_.get(),
1437 &protected_origins,
1438 &unlimited_origins);
1440 UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
1441 num_origins);
1442 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
1443 protected_origins);
1444 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
1445 unlimited_origins);
1448 void QuotaManager::GetLRUOrigin(
1449 StorageType type,
1450 const GetLRUOriginCallback& callback) {
1451 LazyInitialize();
1452 // This must not be called while there's an in-flight task.
1453 DCHECK(lru_origin_callback_.is_null());
1454 lru_origin_callback_ = callback;
1455 if (db_disabled_) {
1456 lru_origin_callback_.Run(GURL());
1457 lru_origin_callback_.Reset();
1458 return;
1461 std::set<GURL>* exceptions = new std::set<GURL>;
1462 for (std::map<GURL, int>::const_iterator p = origins_in_use_.begin();
1463 p != origins_in_use_.end();
1464 ++p) {
1465 if (p->second > 0)
1466 exceptions->insert(p->first);
1468 for (std::map<GURL, int>::const_iterator p = origins_in_error_.begin();
1469 p != origins_in_error_.end();
1470 ++p) {
1471 if (p->second > QuotaManager::kThresholdOfErrorsToBeBlacklisted)
1472 exceptions->insert(p->first);
1475 GURL* url = new GURL;
1476 PostTaskAndReplyWithResultForDBThread(
1477 FROM_HERE,
1478 base::Bind(&GetLRUOriginOnDBThread,
1479 type,
1480 base::Owned(exceptions),
1481 special_storage_policy_,
1482 base::Unretained(url)),
1483 base::Bind(&QuotaManager::DidGetLRUOrigin,
1484 weak_factory_.GetWeakPtr(),
1485 base::Owned(url)));
1488 void QuotaManager::EvictOriginData(
1489 const GURL& origin,
1490 StorageType type,
1491 const EvictOriginDataCallback& callback) {
1492 DCHECK(io_thread_->BelongsToCurrentThread());
1493 DCHECK_EQ(type, kStorageTypeTemporary);
1495 eviction_context_.evicted_origin = origin;
1496 eviction_context_.evicted_type = type;
1497 eviction_context_.evict_origin_data_callback = callback;
1499 DeleteOriginData(origin, type, QuotaClient::kAllClientsMask,
1500 base::Bind(&QuotaManager::DidOriginDataEvicted,
1501 weak_factory_.GetWeakPtr()));
1504 void QuotaManager::GetUsageAndQuotaForEviction(
1505 const UsageAndQuotaCallback& callback) {
1506 DCHECK(io_thread_->BelongsToCurrentThread());
1507 LazyInitialize();
1509 UsageAndQuotaCallbackDispatcher* dispatcher =
1510 new UsageAndQuotaCallbackDispatcher(this);
1511 GetUsageTracker(kStorageTypeTemporary)->
1512 GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
1513 GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
1514 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
1515 dispatcher->WaitForResults(callback);
1518 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
1519 const QuotaCallback& callback,
1520 const int64* new_quota,
1521 bool success) {
1522 QuotaStatusCode status = kQuotaErrorInvalidAccess;
1523 DidDatabaseWork(success);
1524 if (success) {
1525 temporary_quota_override_ = *new_quota;
1526 status = kQuotaStatusOk;
1529 if (callback.is_null())
1530 return;
1532 callback.Run(status, *new_quota);
1535 void QuotaManager::DidGetPersistentHostQuota(const std::string& host,
1536 const int64* quota,
1537 bool success) {
1538 DidDatabaseWork(success);
1539 persistent_host_quota_callbacks_.Run(host, kQuotaStatusOk, *quota);
1542 void QuotaManager::DidSetPersistentHostQuota(const std::string& host,
1543 const QuotaCallback& callback,
1544 const int64* new_quota,
1545 bool success) {
1546 DidDatabaseWork(success);
1547 callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota);
1550 void QuotaManager::DidInitialize(int64* temporary_quota_override,
1551 int64* desired_available_space,
1552 bool success) {
1553 temporary_quota_override_ = *temporary_quota_override;
1554 desired_available_space_ = *desired_available_space;
1555 temporary_quota_initialized_ = true;
1556 DidDatabaseWork(success);
1558 histogram_timer_.Start(FROM_HERE,
1559 base::TimeDelta::FromMilliseconds(
1560 kReportHistogramInterval),
1561 this, &QuotaManager::ReportHistogram);
1563 db_initialization_callbacks_.Run();
1564 GetTemporaryGlobalQuota(
1565 base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota,
1566 weak_factory_.GetWeakPtr()));
1569 void QuotaManager::DidGetLRUOrigin(const GURL* origin,
1570 bool success) {
1571 DidDatabaseWork(success);
1572 // Make sure the returned origin is (still) not in the origin_in_use_ set
1573 // and has not been accessed since we posted the task.
1574 if (origins_in_use_.find(*origin) != origins_in_use_.end() ||
1575 access_notified_origins_.find(*origin) != access_notified_origins_.end())
1576 lru_origin_callback_.Run(GURL());
1577 else
1578 lru_origin_callback_.Run(*origin);
1579 access_notified_origins_.clear();
1580 lru_origin_callback_.Reset();
1583 void QuotaManager::DidGetInitialTemporaryGlobalQuota(
1584 QuotaStatusCode status, int64 quota_unused) {
1585 if (eviction_disabled_)
1586 return;
1588 std::set<GURL>* origins = new std::set<GURL>;
1589 temporary_usage_tracker_->GetCachedOrigins(origins);
1590 // This will call the StartEviction() when initial origin registration
1591 // is completed.
1592 PostTaskAndReplyWithResultForDBThread(
1593 FROM_HERE,
1594 base::Bind(&InitializeTemporaryOriginsInfoOnDBThread,
1595 base::Owned(origins)),
1596 base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo,
1597 weak_factory_.GetWeakPtr()));
1600 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) {
1601 DidDatabaseWork(success);
1602 if (success)
1603 StartEviction();
1606 void QuotaManager::DidGetAvailableSpace(int64 space) {
1607 available_space_callbacks_.Run(kQuotaStatusOk, space);
1610 void QuotaManager::DidDatabaseWork(bool success) {
1611 db_disabled_ = !success;
1614 void QuotaManager::DeleteOnCorrectThread() const {
1615 if (!io_thread_->BelongsToCurrentThread() &&
1616 io_thread_->DeleteSoon(FROM_HERE, this)) {
1617 return;
1619 delete this;
1622 void QuotaManager::PostTaskAndReplyWithResultForDBThread(
1623 const tracked_objects::Location& from_here,
1624 const base::Callback<bool(QuotaDatabase*)>& task,
1625 const base::Callback<void(bool)>& reply) {
1626 // Deleting manager will post another task to DB thread to delete
1627 // |database_|, therefore we can be sure that database_ is alive when this
1628 // task runs.
1629 base::PostTaskAndReplyWithResult(
1630 db_thread_.get(),
1631 from_here,
1632 base::Bind(task, base::Unretained(database_.get())),
1633 reply);
1636 } // namespace storage