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"
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)
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%
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
;
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;
98 for (std::set
<GURL
>::const_iterator itr
= origins
.begin();
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
) {
111 if (!database
->SetQuotaConfigValue(
112 QuotaDatabase::kTemporaryQuotaOverrideKey
, *new_quota
)) {
119 bool GetPersistentHostQuotaOnDBThread(const std::string
& host
,
121 QuotaDatabase
* database
) {
123 database
->GetHostQuota(host
, kStorageTypePersistent
, quota
);
127 bool SetPersistentHostQuotaOnDBThread(const std::string
& host
,
129 QuotaDatabase
* database
) {
131 if (database
->SetHostQuota(host
, kStorageTypePersistent
, *new_quota
))
137 bool InitializeOnDBThread(int64
* temporary_quota_override
,
138 int64
* desired_available_space
,
139 QuotaDatabase
* database
) {
141 database
->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey
,
142 temporary_quota_override
);
143 database
->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey
,
144 desired_available_space
);
148 bool GetLRUOriginOnDBThread(StorageType type
,
149 std::set
<GURL
>* exceptions
,
150 SpecialStoragePolicy
* policy
,
152 QuotaDatabase
* database
) {
154 database
->GetLRUOrigin(type
, *exceptions
, policy
, url
);
158 bool DeleteOriginInfoOnDBThread(const GURL
& origin
,
160 QuotaDatabase
* database
) {
162 return database
->DeleteOriginInfo(origin
, type
);
165 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set
<GURL
>* origins
,
166 QuotaDatabase
* database
) {
168 if (database
->IsOriginDatabaseBootstrapped())
171 // Register existing origins with 0 last time access.
172 if (database
->RegisterInitialOriginInfo(*origins
, kStorageTypeTemporary
)) {
173 database
->SetOriginDatabaseBootstrapped(true);
179 bool UpdateAccessTimeOnDBThread(const GURL
& origin
,
181 base::Time accessed_time
,
182 QuotaDatabase
* database
) {
184 return database
->SetOriginLastAccessTime(origin
, type
, accessed_time
);
187 bool UpdateModifiedTimeOnDBThread(const GURL
& origin
,
189 base::Time modified_time
,
190 QuotaDatabase
* 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();
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);
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
) {
235 << "Running out of disk space for profile."
236 << " QuotaManager starts forbidding further quota consumption.";
241 // No more space; cap the quota to the current usage.
245 available_disk_space
-= QuotaManager::kMinimumPreserveForSystem
;
246 if (available_disk_space
< quota
- usage
)
247 return available_disk_space
+ usage
;
252 int64
CalculateTemporaryHostQuota(int64 host_usage
,
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
);
262 void DispatchUsageAndQuotaForWebApps(
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);
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
);
284 quota
= std::min(quota
, QuotaManager::kIncognitoDefaultQuotaLimit
);
285 callback
.Run(status
, usage
, quota
);
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
) {
296 CalculateQuotaWithDiskSpace(
297 usage_and_quota
.available_disk_space
,
302 callback
.Run(status
, usage
, quota
);
307 UsageAndQuota::UsageAndQuota()
309 global_limited_usage(0),
311 available_disk_space(0) {
314 UsageAndQuota::UsageAndQuota(
316 int64 global_limited_usage
,
318 int64 available_disk_space
)
320 global_limited_usage(global_limited_usage
),
322 available_disk_space(available_disk_space
) {
325 class UsageAndQuotaCallbackDispatcher
327 public base::SupportsWeakPtr
<UsageAndQuotaCallbackDispatcher
> {
329 explicit UsageAndQuotaCallbackDispatcher(QuotaManager
* manager
)
330 : QuotaTask(manager
),
332 has_global_limited_usage_(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
;
346 void set_usage(int64 usage
) {
347 usage_and_quota_
.usage
= usage
;
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
;
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_
;
369 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage
,
373 UsageCallback
GetGlobalLimitedUsageCallback() {
374 ++waiting_callbacks_
;
375 has_global_limited_usage_
= true;
377 &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage
,
381 QuotaCallback
GetQuotaCallback() {
382 ++waiting_callbacks_
;
384 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota
,
388 QuotaCallback
GetAvailableSpaceCallback() {
389 ++waiting_callbacks_
;
390 has_available_disk_space_
= true;
391 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace
,
396 void DidGetHostUsage(int64 usage
) {
397 if (status_
== kQuotaStatusUnknown
)
398 status_
= kQuotaStatusOk
;
399 usage_and_quota_
.usage
= usage
;
403 void DidGetGlobalLimitedUsage(int64 limited_usage
) {
404 if (status_
== kQuotaStatusUnknown
)
405 status_
= kQuotaStatusOk
;
406 usage_and_quota_
.global_limited_usage
= limited_usage
;
410 void DidGetQuota(QuotaStatusCode status
, int64 quota
) {
411 if (status_
== kQuotaStatusUnknown
|| status_
== kQuotaStatusOk
)
413 usage_and_quota_
.quota
= quota
;
417 void DidGetAvailableSpace(QuotaStatusCode status
, int64 space
) {
419 if (status_
== kQuotaStatusUnknown
|| status_
== kQuotaStatusOk
)
421 usage_and_quota_
.available_disk_space
= space
;
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.
432 void Aborted() override
{
433 callback_
.Run(kQuotaErrorAbort
, UsageAndQuota());
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_
);
449 void CheckCompleted() {
450 if (--waiting_callbacks_
<= 0)
454 // For sanity checks, they're checked only when DCHECK is on.
456 bool has_global_limited_usage_
;
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
{
471 QuotaManager
* manager
,
472 const GetUsageInfoCallback
& callback
)
473 : QuotaTask(manager
),
475 weak_factory_(this) {
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_
);
501 void Aborted() override
{
502 callback_
.Run(UsageInfoEntries());
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();
513 entries_
.push_back(UsageInfo(iter
->first
, type
, iter
->second
));
515 if (--remaining_trackers_
== 0)
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
{
538 OriginDataDeleter(QuotaManager
* manager
,
541 int quota_client_mask
,
542 const StatusCallback
& callback
)
543 : QuotaTask(manager
),
546 quota_client_mask_(quota_client_mask
),
548 remaining_clients_(-1),
551 weak_factory_(this) {}
554 void Run() override
{
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(
562 base::Bind(&OriginDataDeleter::DidDeleteOriginData
,
563 weak_factory_
.GetWeakPtr()));
566 if (--remaining_clients_
== 0)
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
);
579 callback_
.Run(kQuotaErrorInvalidModification
);
584 void Aborted() override
{
585 callback_
.Run(kQuotaErrorAbort
);
590 void DidDeleteOriginData(QuotaStatusCode status
) {
591 DCHECK_GT(remaining_clients_
, 0);
593 if (status
!= kQuotaStatusOk
)
596 if (--remaining_clients_
== 0)
600 QuotaManager
* manager() const {
601 return static_cast<QuotaManager
*>(observer());
606 int quota_client_mask_
;
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
{
618 HostDataDeleter(QuotaManager
* manager
,
619 const std::string
& host
,
621 int quota_client_mask
,
622 const StatusCallback
& callback
)
623 : QuotaTask(manager
),
626 quota_client_mask_(quota_client_mask
),
628 remaining_clients_(-1),
629 remaining_deleters_(-1),
631 weak_factory_(this) {}
634 void Run() override
{
636 remaining_clients_
= manager()->clients_
.size();
637 for (QuotaClientList::iterator iter
= manager()->clients_
.begin();
638 iter
!= manager()->clients_
.end(); ++iter
) {
639 (*iter
)->GetOriginsForHost(
641 base::Bind(&HostDataDeleter::DidGetOriginsForHost
,
642 weak_factory_
.GetWeakPtr()));
646 void Completed() override
{
647 if (error_count_
== 0) {
648 callback_
.Run(kQuotaStatusOk
);
650 callback_
.Run(kQuotaErrorInvalidModification
);
655 void Aborted() override
{
656 callback_
.Run(kQuotaErrorAbort
);
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();
674 void ScheduleOriginsDeletion() {
675 remaining_deleters_
= origins_
.size();
676 for (std::set
<GURL
>::const_iterator p
= origins_
.begin();
679 OriginDataDeleter
* deleter
=
680 new OriginDataDeleter(
681 manager(), *p
, type_
, quota_client_mask_
,
682 base::Bind(&HostDataDeleter::DidDeleteOriginData
,
683 weak_factory_
.GetWeakPtr()));
688 void DidDeleteOriginData(QuotaStatusCode status
) {
689 DCHECK_GT(remaining_deleters_
, 0);
691 if (status
!= kQuotaStatusOk
)
694 if (--remaining_deleters_
== 0)
698 QuotaManager
* manager() const {
699 return static_cast<QuotaManager
*>(observer());
704 int quota_client_mask_
;
705 std::set
<GURL
> origins_
;
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
{
717 bool GetModifiedSinceOnDBThread(StorageType type
,
718 base::Time modified_since
,
719 QuotaDatabase
* database
) {
721 return database
->GetOriginsModifiedSince(type
, &origins_
, modified_since
);
724 void DidGetModifiedSince(const base::WeakPtr
<QuotaManager
>& manager
,
725 const GetOriginsCallback
& callback
,
729 // The operation was aborted.
730 callback
.Run(std::set
<GURL
>(), type
);
733 manager
->DidDatabaseWork(success
);
734 callback
.Run(origins_
, type
);
738 std::set
<GURL
> origins_
;
741 class QuotaManager::DumpQuotaTableHelper
{
743 bool DumpQuotaTableOnDBThread(QuotaDatabase
* 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
,
753 // The operation was aborted.
754 callback
.Run(QuotaTableEntries());
757 manager
->DidDatabaseWork(success
);
758 callback
.Run(entries_
);
762 bool AppendEntry(const QuotaTableEntry
& entry
) {
763 entries_
.push_back(entry
);
767 QuotaTableEntries entries_
;
770 class QuotaManager::DumpOriginInfoTableHelper
{
772 bool DumpOriginInfoTableOnDBThread(QuotaDatabase
* 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
,
783 // The operation was aborted.
784 callback
.Run(OriginInfoTableEntries());
787 manager
->DidDatabaseWork(success
);
788 callback
.Run(entries_
);
792 bool AppendEntry(const OriginInfoTableEntry
& entry
) {
793 entries_
.push_back(entry
);
797 OriginInfoTableEntries entries_
;
800 // QuotaManager ---------------------------------------------------------------
802 QuotaManager::QuotaManager(
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
)),
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
) {
826 GetUsageInfoTask
* get_usage_info
= new GetUsageInfoTask(this, callback
);
827 get_usage_info
->Start();
830 void QuotaManager::GetUsageAndQuotaForWebApps(
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);
845 DCHECK(origin
== origin
.GetOrigin());
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
;
856 dispatcher
->set_quota(kNoLimit
);
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());
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
,
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
);
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
,
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
];
921 origins_in_use_
.erase(origin
);
924 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id
,
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
) {
938 if (origin
.is_empty() || clients_
.empty()) {
939 callback
.Run(kQuotaStatusOk
);
943 DCHECK(origin
== origin
.GetOrigin());
944 OriginDataDeleter
* deleter
=
945 new OriginDataDeleter(this, origin
, type
, quota_client_mask
, callback
);
949 void QuotaManager::DeleteHostData(const std::string
& host
,
951 int quota_client_mask
,
952 const StatusCallback
& callback
) {
955 if (host
.empty() || clients_
.empty()) {
956 callback
.Run(kQuotaStatusOk
);
960 HostDataDeleter
* deleter
=
961 new HostDataDeleter(this, host
, type
, quota_client_mask
, callback
);
965 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback
& callback
) {
966 if (!available_space_callbacks_
.Add(callback
))
969 PostTaskAndReplyWithResult(db_thread_
.get(),
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
) {
978 if (!temporary_quota_initialized_
) {
979 db_initialization_callbacks_
.Add(base::Bind(
980 &QuotaManager::GetTemporaryGlobalQuota
,
981 weak_factory_
.GetWeakPtr(), callback
));
985 if (temporary_quota_override_
> 0) {
986 callback
.Run(kQuotaStatusOk
, temporary_quota_override_
);
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
) {
1003 if (new_quota
< 0) {
1004 if (!callback
.is_null())
1005 callback
.Run(kQuotaErrorInvalidModification
, -1);
1010 if (!callback
.is_null())
1011 callback
.Run(kQuotaErrorInvalidAccess
, -1);
1015 int64
* new_quota_ptr
= new int64(new_quota
);
1016 PostTaskAndReplyWithResultForDBThread(
1018 base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread
,
1019 base::Unretained(new_quota_ptr
)),
1020 base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota
,
1021 weak_factory_
.GetWeakPtr(),
1023 base::Owned(new_quota_ptr
)));
1026 void QuotaManager::GetPersistentHostQuota(const std::string
& host
,
1027 const QuotaCallback
& callback
) {
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);
1037 if (!persistent_host_quota_callbacks_
.Add(host
, callback
))
1040 int64
* quota_ptr
= new int64(0);
1041 PostTaskAndReplyWithResultForDBThread(
1043 base::Bind(&GetPersistentHostQuotaOnDBThread
,
1045 base::Unretained(quota_ptr
)),
1046 base::Bind(&QuotaManager::DidGetPersistentHostQuota
,
1047 weak_factory_
.GetWeakPtr(),
1049 base::Owned(quota_ptr
)));
1052 void QuotaManager::SetPersistentHostQuota(const std::string
& host
,
1054 const QuotaCallback
& callback
) {
1057 // This could happen if we are called on file:///.
1058 callback
.Run(kQuotaErrorNotSupported
, 0);
1062 if (new_quota
< 0) {
1063 callback
.Run(kQuotaErrorInvalidModification
, -1);
1067 if (kPerHostPersistentQuotaLimit
< new_quota
) {
1068 // Cap the requested size at the per-host quota limit.
1069 new_quota
= kPerHostPersistentQuotaLimit
;
1073 callback
.Run(kQuotaErrorInvalidAccess
, -1);
1077 int64
* new_quota_ptr
= new int64(new_quota
);
1078 PostTaskAndReplyWithResultForDBThread(
1080 base::Bind(&SetPersistentHostQuotaOnDBThread
,
1082 base::Unretained(new_quota_ptr
)),
1083 base::Bind(&QuotaManager::DidSetPersistentHostQuota
,
1084 weak_factory_
.GetWeakPtr(),
1087 base::Owned(new_quota_ptr
)));
1090 void QuotaManager::GetGlobalUsage(StorageType type
,
1091 const GlobalUsageCallback
& callback
) {
1093 DCHECK(GetUsageTracker(type
));
1094 GetUsageTracker(type
)->GetGlobalUsage(callback
);
1097 void QuotaManager::GetHostUsage(const std::string
& host
,
1099 const UsageCallback
& callback
) {
1101 DCHECK(GetUsageTracker(type
));
1102 GetUsageTracker(type
)->GetHostUsage(host
, callback
);
1105 void QuotaManager::GetHostUsage(const std::string
& host
,
1107 QuotaClient::ID client_id
,
1108 const UsageCallback
& callback
) {
1110 DCHECK(GetUsageTracker(type
));
1111 ClientUsageTracker
* tracker
=
1112 GetUsageTracker(type
)->GetClientTracker(client_id
);
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
) {
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();
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
)
1145 if (type
== kStorageTypeQuotaNotManaged
)
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
) {
1155 GetModifiedSinceHelper
* helper
= new GetModifiedSinceHelper
;
1156 PostTaskAndReplyWithResultForDBThread(
1158 base::Bind(&GetModifiedSinceHelper::GetModifiedSinceOnDBThread
,
1159 base::Unretained(helper
),
1162 base::Bind(&GetModifiedSinceHelper::DidGetModifiedSince
,
1163 base::Owned(helper
),
1164 weak_factory_
.GetWeakPtr(),
1169 bool QuotaManager::ResetUsageTracker(StorageType type
) {
1170 DCHECK(GetUsageTracker(type
));
1171 if (GetUsageTracker(type
)->IsWorking())
1174 case kStorageTypeTemporary
:
1175 temporary_usage_tracker_
.reset(new UsageTracker(
1176 clients_
, kStorageTypeTemporary
, special_storage_policy_
.get(),
1177 storage_monitor_
.get()));
1179 case kStorageTypePersistent
:
1180 persistent_usage_tracker_
.reset(new UsageTracker(
1181 clients_
, kStorageTypePersistent
, special_storage_policy_
.get(),
1182 storage_monitor_
.get()));
1184 case kStorageTypeSyncable
:
1185 syncable_usage_tracker_
.reset(new UsageTracker(
1186 clients_
, kStorageTypeSyncable
, special_storage_policy_
.get(),
1187 storage_monitor_
.get()));
1195 void QuotaManager::AddStorageObserver(
1196 StorageObserver
* observer
, const StorageObserver::MonitorParams
& params
) {
1198 storage_monitor_
->AddObserver(observer
, params
);
1201 void QuotaManager::RemoveStorageObserver(StorageObserver
* observer
) {
1203 storage_monitor_
->RemoveObserver(observer
);
1206 void QuotaManager::RemoveStorageObserverForFilter(
1207 StorageObserver
* observer
, const StorageObserver::Filter
& filter
) {
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
));
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());
1230 // Initialization seems to be done already.
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(
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 {
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
:
1276 case kStorageTypeUnknown
:
1282 void QuotaManager::GetCachedOrigins(
1283 StorageType type
, std::set
<GURL
>* origins
) {
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
) {
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
);
1303 PostTaskAndReplyWithResultForDBThread(
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
,
1315 base::Time modified_time
) {
1317 DCHECK(GetUsageTracker(type
));
1318 GetUsageTracker(type
)->UpdateUsageCache(client_id
, origin
, delta
);
1320 PostTaskAndReplyWithResultForDBThread(
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(
1331 base::Bind(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread
,
1332 base::Unretained(helper
)),
1333 base::Bind(&DumpQuotaTableHelper::DidDumpQuotaTable
,
1334 base::Owned(helper
),
1335 weak_factory_
.GetWeakPtr(),
1339 void QuotaManager::DumpOriginInfoTable(
1340 const DumpOriginInfoTableCallback
& callback
) {
1341 DumpOriginInfoTableHelper
* helper
= new DumpOriginInfoTableHelper
;
1342 PostTaskAndReplyWithResultForDBThread(
1344 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread
,
1345 base::Unretained(helper
)),
1346 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable
,
1347 base::Owned(helper
),
1348 weak_factory_
.GetWeakPtr(),
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
) {
1368 PostTaskAndReplyWithResultForDBThread(
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
,
1392 &QuotaManager::DidGetTemporaryGlobalUsageForHistogram
,
1393 weak_factory_
.GetWeakPtr()));
1394 GetGlobalUsage(kStorageTypePersistent
,
1396 &QuotaManager::DidGetPersistentGlobalUsageForHistogram
,
1397 weak_factory_
.GetWeakPtr()));
1400 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
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(),
1414 &unlimited_origins
);
1416 UMA_HISTOGRAM_COUNTS("Quota.NumberOfTemporaryStorageOrigins",
1418 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedTemporaryStorageOrigins",
1420 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedTemporaryStorageOrigins",
1424 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
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(),
1438 &unlimited_origins
);
1440 UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
1442 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
1444 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
1448 void QuotaManager::GetLRUOrigin(
1450 const GetLRUOriginCallback
& callback
) {
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
;
1456 lru_origin_callback_
.Run(GURL());
1457 lru_origin_callback_
.Reset();
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();
1466 exceptions
->insert(p
->first
);
1468 for (std::map
<GURL
, int>::const_iterator p
= origins_in_error_
.begin();
1469 p
!= origins_in_error_
.end();
1471 if (p
->second
> QuotaManager::kThresholdOfErrorsToBeBlacklisted
)
1472 exceptions
->insert(p
->first
);
1475 GURL
* url
= new GURL
;
1476 PostTaskAndReplyWithResultForDBThread(
1478 base::Bind(&GetLRUOriginOnDBThread
,
1480 base::Owned(exceptions
),
1481 special_storage_policy_
,
1482 base::Unretained(url
)),
1483 base::Bind(&QuotaManager::DidGetLRUOrigin
,
1484 weak_factory_
.GetWeakPtr(),
1488 void QuotaManager::EvictOriginData(
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());
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
,
1522 QuotaStatusCode status
= kQuotaErrorInvalidAccess
;
1523 DidDatabaseWork(success
);
1525 temporary_quota_override_
= *new_quota
;
1526 status
= kQuotaStatusOk
;
1529 if (callback
.is_null())
1532 callback
.Run(status
, *new_quota
);
1535 void QuotaManager::DidGetPersistentHostQuota(const std::string
& host
,
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
,
1546 DidDatabaseWork(success
);
1547 callback
.Run(success
? kQuotaStatusOk
: kQuotaErrorInvalidAccess
, *new_quota
);
1550 void QuotaManager::DidInitialize(int64
* temporary_quota_override
,
1551 int64
* desired_available_space
,
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
,
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());
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_
)
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
1592 PostTaskAndReplyWithResultForDBThread(
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
);
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)) {
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
1629 base::PostTaskAndReplyWithResult(
1632 base::Bind(task
, base::Unretained(database_
.get())),
1636 } // namespace storage