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"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/files/file_util.h"
14 #include "base/metrics/histogram.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/sys_info.h"
20 #include "base/task_runner_util.h"
21 #include "base/time/time.h"
22 #include "net/base/net_util.h"
23 #include "storage/browser/quota/client_usage_tracker.h"
24 #include "storage/browser/quota/quota_manager_proxy.h"
25 #include "storage/browser/quota/quota_temporary_storage_evictor.h"
26 #include "storage/browser/quota/storage_monitor.h"
27 #include "storage/browser/quota/usage_tracker.h"
28 #include "storage/common/quota/quota_types.h"
30 #define UMA_HISTOGRAM_MBYTES(name, sample) \
31 UMA_HISTOGRAM_CUSTOM_COUNTS( \
32 (name), static_cast<int>((sample) / kMBytes), \
33 1, 10 * 1024 * 1024 /* 10TB */, 100)
39 const int64 kMBytes
= 1024 * 1024;
40 const int kMinutesInMilliSeconds
= 60 * 1000;
42 const int64 kReportHistogramInterval
= 60 * 60 * 1000; // 1 hour
43 const double kTemporaryQuotaRatioToAvail
= 1.0 / 3.0; // 33%
47 // Arbitrary for now, but must be reasonably small so that
48 // in-memory databases can fit.
49 // TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this.
50 const int64
QuotaManager::kIncognitoDefaultQuotaLimit
= 100 * kMBytes
;
52 const int64
QuotaManager::kNoLimit
= kint64max
;
54 const int QuotaManager::kPerHostTemporaryPortion
= 5; // 20%
56 // Cap size for per-host persistent quota determined by the histogram.
57 // This is a bit lax value because the histogram says nothing about per-host
58 // persistent storage usage and we determined by global persistent storage
59 // usage that is less than 10GB for almost all users.
60 const int64
QuotaManager::kPerHostPersistentQuotaLimit
= 10 * 1024 * kMBytes
;
62 const char QuotaManager::kDatabaseName
[] = "QuotaManager";
64 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted
= 3;
66 // Preserve kMinimumPreserveForSystem disk space for system book-keeping
67 // when returning the quota to unlimited apps/extensions.
68 // TODO(kinuko): This should be like 10% of the actual disk space.
69 // For now we simply use a constant as getting the disk size needs
70 // platform-dependent code. (http://crbug.com/178976)
71 int64
QuotaManager::kMinimumPreserveForSystem
= 1024 * kMBytes
;
73 const int QuotaManager::kEvictionIntervalInMilliSeconds
=
74 30 * kMinutesInMilliSeconds
;
76 // Heuristics: assuming average cloud server allows a few Gigs storage
77 // on the server side and the storage needs to be shared for user data
78 // and by multiple apps.
79 int64
QuotaManager::kSyncableStorageDefaultHostQuota
= 500 * kMBytes
;
83 void CountOriginType(const std::set
<GURL
>& origins
,
84 SpecialStoragePolicy
* policy
,
85 size_t* protected_origins
,
86 size_t* unlimited_origins
) {
87 DCHECK(protected_origins
);
88 DCHECK(unlimited_origins
);
89 *protected_origins
= 0;
90 *unlimited_origins
= 0;
93 for (std::set
<GURL
>::const_iterator itr
= origins
.begin();
96 if (policy
->IsStorageProtected(*itr
))
98 if (policy
->IsStorageUnlimited(*itr
))
103 bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64
* new_quota
,
104 QuotaDatabase
* database
) {
106 if (!database
->SetQuotaConfigValue(
107 QuotaDatabase::kTemporaryQuotaOverrideKey
, *new_quota
)) {
114 bool GetPersistentHostQuotaOnDBThread(const std::string
& host
,
116 QuotaDatabase
* database
) {
118 database
->GetHostQuota(host
, kStorageTypePersistent
, quota
);
122 bool SetPersistentHostQuotaOnDBThread(const std::string
& host
,
124 QuotaDatabase
* database
) {
126 if (database
->SetHostQuota(host
, kStorageTypePersistent
, *new_quota
))
132 bool InitializeOnDBThread(int64
* temporary_quota_override
,
133 int64
* desired_available_space
,
134 QuotaDatabase
* database
) {
136 database
->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey
,
137 temporary_quota_override
);
138 database
->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey
,
139 desired_available_space
);
143 bool GetLRUOriginOnDBThread(StorageType type
,
144 std::set
<GURL
>* exceptions
,
145 SpecialStoragePolicy
* policy
,
147 QuotaDatabase
* database
) {
149 database
->GetLRUOrigin(type
, *exceptions
, policy
, url
);
153 bool DeleteOriginInfoOnDBThread(const GURL
& origin
,
155 QuotaDatabase
* database
) {
157 return database
->DeleteOriginInfo(origin
, type
);
160 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set
<GURL
>* origins
,
161 QuotaDatabase
* database
) {
163 if (database
->IsOriginDatabaseBootstrapped())
166 // Register existing origins with 0 last time access.
167 if (database
->RegisterInitialOriginInfo(*origins
, kStorageTypeTemporary
)) {
168 database
->SetOriginDatabaseBootstrapped(true);
174 bool UpdateAccessTimeOnDBThread(const GURL
& origin
,
176 base::Time accessed_time
,
177 QuotaDatabase
* database
) {
179 return database
->SetOriginLastAccessTime(origin
, type
, accessed_time
);
182 bool UpdateModifiedTimeOnDBThread(const GURL
& origin
,
184 base::Time modified_time
,
185 QuotaDatabase
* database
) {
187 return database
->SetOriginLastModifiedTime(origin
, type
, modified_time
);
190 int64
CallSystemGetAmountOfFreeDiskSpace(const base::FilePath
& profile_path
) {
191 // Ensure the profile path exists.
192 if (!base::CreateDirectory(profile_path
)) {
193 LOG(WARNING
) << "Create directory failed for path" << profile_path
.value();
196 return base::SysInfo::AmountOfFreeDiskSpace(profile_path
);
199 int64
CalculateTemporaryGlobalQuota(int64 global_limited_usage
,
200 int64 available_space
) {
201 DCHECK_GE(global_limited_usage
, 0);
202 int64 avail_space
= available_space
;
203 if (avail_space
< kint64max
- global_limited_usage
) {
204 // We basically calculate the temporary quota by
205 // [available_space + space_used_for_temp] * kTempQuotaRatio,
206 // but make sure we'll have no overflow.
207 avail_space
+= global_limited_usage
;
209 return avail_space
* kTemporaryQuotaRatioToAvail
;
212 void DispatchTemporaryGlobalQuotaCallback(
213 const QuotaCallback
& callback
,
214 QuotaStatusCode status
,
215 const UsageAndQuota
& usage_and_quota
) {
216 if (status
!= kQuotaStatusOk
) {
217 callback
.Run(status
, 0);
221 callback
.Run(status
, CalculateTemporaryGlobalQuota(
222 usage_and_quota
.global_limited_usage
,
223 usage_and_quota
.available_disk_space
));
226 int64
CalculateQuotaWithDiskSpace(
227 int64 available_disk_space
, int64 usage
, int64 quota
) {
228 if (available_disk_space
< QuotaManager::kMinimumPreserveForSystem
) {
230 << "Running out of disk space for profile."
231 << " QuotaManager starts forbidding further quota consumption.";
236 // No more space; cap the quota to the current usage.
240 available_disk_space
-= QuotaManager::kMinimumPreserveForSystem
;
241 if (available_disk_space
< quota
- usage
)
242 return available_disk_space
+ usage
;
247 int64
CalculateTemporaryHostQuota(int64 host_usage
,
249 int64 global_limited_usage
) {
250 DCHECK_GE(global_limited_usage
, 0);
251 int64 host_quota
= global_quota
/ QuotaManager::kPerHostTemporaryPortion
;
252 if (global_limited_usage
> global_quota
)
253 host_quota
= std::min(host_quota
, host_usage
);
257 void DispatchUsageAndQuotaForWebApps(
261 bool can_query_disk_size
,
262 const QuotaManager::GetUsageAndQuotaCallback
& callback
,
263 QuotaStatusCode status
,
264 const UsageAndQuota
& usage_and_quota
) {
265 if (status
!= kQuotaStatusOk
) {
266 callback
.Run(status
, 0, 0);
270 int64 usage
= usage_and_quota
.usage
;
271 int64 quota
= usage_and_quota
.quota
;
273 if (type
== kStorageTypeTemporary
&& !is_unlimited
) {
274 quota
= CalculateTemporaryHostQuota(
275 usage
, quota
, usage_and_quota
.global_limited_usage
);
279 quota
= std::min(quota
, QuotaManager::kIncognitoDefaultQuotaLimit
);
280 callback
.Run(status
, usage
, quota
);
284 // For apps with unlimited permission or can_query_disk_size is true (and not
285 // in incognito mode).
286 // We assume we can expose the actual disk size for them and cap the quota by
287 // the available disk space.
288 if (is_unlimited
|| can_query_disk_size
) {
291 CalculateQuotaWithDiskSpace(
292 usage_and_quota
.available_disk_space
,
297 callback
.Run(status
, usage
, quota
);
302 UsageAndQuota::UsageAndQuota()
304 global_limited_usage(0),
306 available_disk_space(0) {
309 UsageAndQuota::UsageAndQuota(
311 int64 global_limited_usage
,
313 int64 available_disk_space
)
315 global_limited_usage(global_limited_usage
),
317 available_disk_space(available_disk_space
) {
320 class UsageAndQuotaCallbackDispatcher
322 public base::SupportsWeakPtr
<UsageAndQuotaCallbackDispatcher
> {
324 explicit UsageAndQuotaCallbackDispatcher(QuotaManager
* manager
)
325 : QuotaTask(manager
),
327 has_global_limited_usage_(false),
329 has_available_disk_space_(false),
330 status_(kQuotaStatusUnknown
),
331 usage_and_quota_(-1, -1, -1, -1),
332 waiting_callbacks_(1) {}
334 ~UsageAndQuotaCallbackDispatcher() override
{}
336 void WaitForResults(const QuotaManager::UsageAndQuotaCallback
& callback
) {
337 callback_
= callback
;
341 void set_usage(int64 usage
) {
342 usage_and_quota_
.usage
= usage
;
346 void set_global_limited_usage(int64 global_limited_usage
) {
347 usage_and_quota_
.global_limited_usage
= global_limited_usage
;
348 has_global_limited_usage_
= true;
351 void set_quota(int64 quota
) {
352 usage_and_quota_
.quota
= quota
;
356 void set_available_disk_space(int64 available_disk_space
) {
357 usage_and_quota_
.available_disk_space
= available_disk_space
;
358 has_available_disk_space_
= true;
361 UsageCallback
GetHostUsageCallback() {
362 ++waiting_callbacks_
;
364 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage
,
368 UsageCallback
GetGlobalLimitedUsageCallback() {
369 ++waiting_callbacks_
;
370 has_global_limited_usage_
= true;
372 &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage
,
376 QuotaCallback
GetQuotaCallback() {
377 ++waiting_callbacks_
;
379 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota
,
383 QuotaCallback
GetAvailableSpaceCallback() {
384 ++waiting_callbacks_
;
385 has_available_disk_space_
= true;
386 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace
,
391 void DidGetHostUsage(int64 usage
) {
392 if (status_
== kQuotaStatusUnknown
)
393 status_
= kQuotaStatusOk
;
394 usage_and_quota_
.usage
= usage
;
398 void DidGetGlobalLimitedUsage(int64 limited_usage
) {
399 if (status_
== kQuotaStatusUnknown
)
400 status_
= kQuotaStatusOk
;
401 usage_and_quota_
.global_limited_usage
= limited_usage
;
405 void DidGetQuota(QuotaStatusCode status
, int64 quota
) {
406 if (status_
== kQuotaStatusUnknown
|| status_
== kQuotaStatusOk
)
408 usage_and_quota_
.quota
= quota
;
412 void DidGetAvailableSpace(QuotaStatusCode status
, int64 space
) {
414 if (status_
== kQuotaStatusUnknown
|| status_
== kQuotaStatusOk
)
416 usage_and_quota_
.available_disk_space
= space
;
420 void Run() override
{
421 // We initialize waiting_callbacks to 1 so that we won't run
422 // the completion callback until here even some of the callbacks
423 // are dispatched synchronously.
427 void Aborted() override
{
428 callback_
.Run(kQuotaErrorAbort
, UsageAndQuota());
432 void Completed() override
{
433 DCHECK(!has_usage_
|| usage_and_quota_
.usage
>= 0);
434 DCHECK(!has_global_limited_usage_
||
435 usage_and_quota_
.global_limited_usage
>= 0);
436 DCHECK(!has_quota_
|| usage_and_quota_
.quota
>= 0);
437 DCHECK(!has_available_disk_space_
||
438 usage_and_quota_
.available_disk_space
>= 0);
440 callback_
.Run(status_
, usage_and_quota_
);
444 void CheckCompleted() {
445 if (--waiting_callbacks_
<= 0)
449 // For sanity checks, they're checked only when DCHECK is on.
451 bool has_global_limited_usage_
;
453 bool has_available_disk_space_
;
455 QuotaStatusCode status_
;
456 UsageAndQuota usage_and_quota_
;
457 QuotaManager::UsageAndQuotaCallback callback_
;
458 int waiting_callbacks_
;
460 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher
);
463 class QuotaManager::GetUsageInfoTask
: public QuotaTask
{
466 QuotaManager
* manager
,
467 const GetUsageInfoCallback
& callback
)
468 : QuotaTask(manager
),
470 weak_factory_(this) {
474 void Run() override
{
475 remaining_trackers_
= 3;
476 // This will populate cached hosts and usage info.
477 manager()->GetUsageTracker(kStorageTypeTemporary
)->GetGlobalUsage(
478 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage
,
479 weak_factory_
.GetWeakPtr(),
480 kStorageTypeTemporary
));
481 manager()->GetUsageTracker(kStorageTypePersistent
)->GetGlobalUsage(
482 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage
,
483 weak_factory_
.GetWeakPtr(),
484 kStorageTypePersistent
));
485 manager()->GetUsageTracker(kStorageTypeSyncable
)->GetGlobalUsage(
486 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage
,
487 weak_factory_
.GetWeakPtr(),
488 kStorageTypeSyncable
));
491 void Completed() override
{
492 callback_
.Run(entries_
);
496 void Aborted() override
{
497 callback_
.Run(UsageInfoEntries());
502 void AddEntries(StorageType type
, UsageTracker
* tracker
) {
503 std::map
<std::string
, int64
> host_usage
;
504 tracker
->GetCachedHostsUsage(&host_usage
);
505 for (std::map
<std::string
, int64
>::const_iterator iter
= host_usage
.begin();
506 iter
!= host_usage
.end();
508 entries_
.push_back(UsageInfo(iter
->first
, type
, iter
->second
));
510 if (--remaining_trackers_
== 0)
514 void DidGetGlobalUsage(StorageType type
, int64
, int64
) {
515 DCHECK(manager()->GetUsageTracker(type
));
516 AddEntries(type
, manager()->GetUsageTracker(type
));
519 QuotaManager
* manager() const {
520 return static_cast<QuotaManager
*>(observer());
523 GetUsageInfoCallback callback_
;
524 UsageInfoEntries entries_
;
525 int remaining_trackers_
;
526 base::WeakPtrFactory
<GetUsageInfoTask
> weak_factory_
;
528 DISALLOW_COPY_AND_ASSIGN(GetUsageInfoTask
);
531 class QuotaManager::OriginDataDeleter
: public QuotaTask
{
533 OriginDataDeleter(QuotaManager
* manager
,
536 int quota_client_mask
,
537 const StatusCallback
& callback
)
538 : QuotaTask(manager
),
541 quota_client_mask_(quota_client_mask
),
543 remaining_clients_(-1),
546 weak_factory_(this) {}
549 void Run() override
{
551 remaining_clients_
= manager()->clients_
.size();
552 for (QuotaClientList::iterator iter
= manager()->clients_
.begin();
553 iter
!= manager()->clients_
.end(); ++iter
) {
554 if (quota_client_mask_
& (*iter
)->id()) {
555 (*iter
)->DeleteOriginData(
557 base::Bind(&OriginDataDeleter::DidDeleteOriginData
,
558 weak_factory_
.GetWeakPtr()));
561 if (--remaining_clients_
== 0)
567 void Completed() override
{
568 if (error_count_
== 0) {
569 // Only remove the entire origin if we didn't skip any client types.
570 if (skipped_clients_
== 0)
571 manager()->DeleteOriginFromDatabase(origin_
, type_
);
572 callback_
.Run(kQuotaStatusOk
);
574 callback_
.Run(kQuotaErrorInvalidModification
);
579 void Aborted() override
{
580 callback_
.Run(kQuotaErrorAbort
);
585 void DidDeleteOriginData(QuotaStatusCode status
) {
586 DCHECK_GT(remaining_clients_
, 0);
588 if (status
!= kQuotaStatusOk
)
591 if (--remaining_clients_
== 0)
595 QuotaManager
* manager() const {
596 return static_cast<QuotaManager
*>(observer());
601 int quota_client_mask_
;
603 int remaining_clients_
;
604 int skipped_clients_
;
605 StatusCallback callback_
;
607 base::WeakPtrFactory
<OriginDataDeleter
> weak_factory_
;
608 DISALLOW_COPY_AND_ASSIGN(OriginDataDeleter
);
611 class QuotaManager::HostDataDeleter
: public QuotaTask
{
613 HostDataDeleter(QuotaManager
* manager
,
614 const std::string
& host
,
616 int quota_client_mask
,
617 const StatusCallback
& callback
)
618 : QuotaTask(manager
),
621 quota_client_mask_(quota_client_mask
),
623 remaining_clients_(-1),
624 remaining_deleters_(-1),
626 weak_factory_(this) {}
629 void Run() override
{
631 remaining_clients_
= manager()->clients_
.size();
632 for (QuotaClientList::iterator iter
= manager()->clients_
.begin();
633 iter
!= manager()->clients_
.end(); ++iter
) {
634 (*iter
)->GetOriginsForHost(
636 base::Bind(&HostDataDeleter::DidGetOriginsForHost
,
637 weak_factory_
.GetWeakPtr()));
641 void Completed() override
{
642 if (error_count_
== 0) {
643 callback_
.Run(kQuotaStatusOk
);
645 callback_
.Run(kQuotaErrorInvalidModification
);
650 void Aborted() override
{
651 callback_
.Run(kQuotaErrorAbort
);
656 void DidGetOriginsForHost(const std::set
<GURL
>& origins
) {
657 DCHECK_GT(remaining_clients_
, 0);
659 origins_
.insert(origins
.begin(), origins
.end());
661 if (--remaining_clients_
== 0) {
662 if (!origins_
.empty())
663 ScheduleOriginsDeletion();
669 void ScheduleOriginsDeletion() {
670 remaining_deleters_
= origins_
.size();
671 for (std::set
<GURL
>::const_iterator p
= origins_
.begin();
674 OriginDataDeleter
* deleter
=
675 new OriginDataDeleter(
676 manager(), *p
, type_
, quota_client_mask_
,
677 base::Bind(&HostDataDeleter::DidDeleteOriginData
,
678 weak_factory_
.GetWeakPtr()));
683 void DidDeleteOriginData(QuotaStatusCode status
) {
684 DCHECK_GT(remaining_deleters_
, 0);
686 if (status
!= kQuotaStatusOk
)
689 if (--remaining_deleters_
== 0)
693 QuotaManager
* manager() const {
694 return static_cast<QuotaManager
*>(observer());
699 int quota_client_mask_
;
700 std::set
<GURL
> origins_
;
702 int remaining_clients_
;
703 int remaining_deleters_
;
704 StatusCallback callback_
;
706 base::WeakPtrFactory
<HostDataDeleter
> weak_factory_
;
707 DISALLOW_COPY_AND_ASSIGN(HostDataDeleter
);
710 class QuotaManager::GetModifiedSinceHelper
{
712 bool GetModifiedSinceOnDBThread(StorageType type
,
713 base::Time modified_since
,
714 QuotaDatabase
* database
) {
716 return database
->GetOriginsModifiedSince(type
, &origins_
, modified_since
);
719 void DidGetModifiedSince(const base::WeakPtr
<QuotaManager
>& manager
,
720 const GetOriginsCallback
& callback
,
724 // The operation was aborted.
725 callback
.Run(std::set
<GURL
>(), type
);
728 manager
->DidDatabaseWork(success
);
729 callback
.Run(origins_
, type
);
733 std::set
<GURL
> origins_
;
736 class QuotaManager::DumpQuotaTableHelper
{
738 bool DumpQuotaTableOnDBThread(QuotaDatabase
* database
) {
740 return database
->DumpQuotaTable(
741 base::Bind(&DumpQuotaTableHelper::AppendEntry
, base::Unretained(this)));
744 void DidDumpQuotaTable(const base::WeakPtr
<QuotaManager
>& manager
,
745 const DumpQuotaTableCallback
& callback
,
748 // The operation was aborted.
749 callback
.Run(QuotaTableEntries());
752 manager
->DidDatabaseWork(success
);
753 callback
.Run(entries_
);
757 bool AppendEntry(const QuotaTableEntry
& entry
) {
758 entries_
.push_back(entry
);
762 QuotaTableEntries entries_
;
765 class QuotaManager::DumpOriginInfoTableHelper
{
767 bool DumpOriginInfoTableOnDBThread(QuotaDatabase
* database
) {
769 return database
->DumpOriginInfoTable(
770 base::Bind(&DumpOriginInfoTableHelper::AppendEntry
,
771 base::Unretained(this)));
774 void DidDumpOriginInfoTable(const base::WeakPtr
<QuotaManager
>& manager
,
775 const DumpOriginInfoTableCallback
& callback
,
778 // The operation was aborted.
779 callback
.Run(OriginInfoTableEntries());
782 manager
->DidDatabaseWork(success
);
783 callback
.Run(entries_
);
787 bool AppendEntry(const OriginInfoTableEntry
& entry
) {
788 entries_
.push_back(entry
);
792 OriginInfoTableEntries entries_
;
795 // QuotaManager ---------------------------------------------------------------
797 QuotaManager::QuotaManager(
799 const base::FilePath
& profile_path
,
800 const scoped_refptr
<base::SingleThreadTaskRunner
>& io_thread
,
801 const scoped_refptr
<base::SequencedTaskRunner
>& db_thread
,
802 const scoped_refptr
<SpecialStoragePolicy
>& special_storage_policy
)
803 : is_incognito_(is_incognito
),
804 profile_path_(profile_path
),
805 proxy_(new QuotaManagerProxy(this, io_thread
)),
807 eviction_disabled_(false),
808 io_thread_(io_thread
),
809 db_thread_(db_thread
),
810 temporary_quota_initialized_(false),
811 temporary_quota_override_(-1),
812 desired_available_space_(-1),
813 special_storage_policy_(special_storage_policy
),
814 get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace
),
815 storage_monitor_(new StorageMonitor(this)),
816 weak_factory_(this) {
819 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback
& callback
) {
821 GetUsageInfoTask
* get_usage_info
= new GetUsageInfoTask(this, callback
);
822 get_usage_info
->Start();
825 void QuotaManager::GetUsageAndQuotaForWebApps(
828 const GetUsageAndQuotaCallback
& callback
) {
829 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
830 tracked_objects::ScopedTracker
tracking_profile(
831 FROM_HERE_WITH_EXPLICIT_FUNCTION(
832 "477117 QuotaManager::GetUsageAndQuotaForWebApps"));
833 if (type
!= kStorageTypeTemporary
&&
834 type
!= kStorageTypePersistent
&&
835 type
!= kStorageTypeSyncable
) {
836 callback
.Run(kQuotaErrorNotSupported
, 0, 0);
840 DCHECK(origin
== origin
.GetOrigin());
843 bool unlimited
= IsStorageUnlimited(origin
, type
);
844 bool can_query_disk_size
= CanQueryDiskSize(origin
);
846 UsageAndQuotaCallbackDispatcher
* dispatcher
=
847 new UsageAndQuotaCallbackDispatcher(this);
849 UsageAndQuota usage_and_quota
;
851 dispatcher
->set_quota(kNoLimit
);
853 if (type
== kStorageTypeTemporary
) {
854 GetUsageTracker(type
)->GetGlobalLimitedUsage(
855 dispatcher
->GetGlobalLimitedUsageCallback());
856 GetTemporaryGlobalQuota(dispatcher
->GetQuotaCallback());
857 } else if (type
== kStorageTypePersistent
) {
858 GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin
),
859 dispatcher
->GetQuotaCallback());
861 dispatcher
->set_quota(kSyncableStorageDefaultHostQuota
);
865 DCHECK(GetUsageTracker(type
));
866 GetUsageTracker(type
)->GetHostUsage(net::GetHostOrSpecFromURL(origin
),
867 dispatcher
->GetHostUsageCallback());
869 if (!is_incognito_
&& (unlimited
|| can_query_disk_size
))
870 GetAvailableSpace(dispatcher
->GetAvailableSpaceCallback());
872 dispatcher
->WaitForResults(base::Bind(
873 &DispatchUsageAndQuotaForWebApps
,
874 type
, is_incognito_
, unlimited
, can_query_disk_size
,
878 void QuotaManager::GetUsageAndQuota(
879 const GURL
& origin
, StorageType type
,
880 const GetUsageAndQuotaCallback
& callback
) {
881 DCHECK(origin
== origin
.GetOrigin());
883 if (IsStorageUnlimited(origin
, type
)) {
884 callback
.Run(kQuotaStatusOk
, 0, kNoLimit
);
888 GetUsageAndQuotaForWebApps(origin
, type
, callback
);
891 void QuotaManager::NotifyStorageAccessed(
892 QuotaClient::ID client_id
,
893 const GURL
& origin
, StorageType type
) {
894 DCHECK(origin
== origin
.GetOrigin());
895 NotifyStorageAccessedInternal(client_id
, origin
, type
, base::Time::Now());
898 void QuotaManager::NotifyStorageModified(
899 QuotaClient::ID client_id
,
900 const GURL
& origin
, StorageType type
, int64 delta
) {
901 DCHECK(origin
== origin
.GetOrigin());
902 NotifyStorageModifiedInternal(client_id
, origin
, type
, delta
,
906 void QuotaManager::NotifyOriginInUse(const GURL
& origin
) {
907 DCHECK(io_thread_
->BelongsToCurrentThread());
908 origins_in_use_
[origin
]++;
911 void QuotaManager::NotifyOriginNoLongerInUse(const GURL
& origin
) {
912 DCHECK(io_thread_
->BelongsToCurrentThread());
913 DCHECK(IsOriginInUse(origin
));
914 int& count
= origins_in_use_
[origin
];
916 origins_in_use_
.erase(origin
);
919 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id
,
924 DCHECK(GetUsageTracker(type
));
925 GetUsageTracker(type
)->SetUsageCacheEnabled(client_id
, origin
, enabled
);
928 void QuotaManager::DeleteOriginData(
929 const GURL
& origin
, StorageType type
, int quota_client_mask
,
930 const StatusCallback
& callback
) {
933 if (origin
.is_empty() || clients_
.empty()) {
934 callback
.Run(kQuotaStatusOk
);
938 DCHECK(origin
== origin
.GetOrigin());
939 OriginDataDeleter
* deleter
=
940 new OriginDataDeleter(this, origin
, type
, quota_client_mask
, callback
);
944 void QuotaManager::DeleteHostData(const std::string
& host
,
946 int quota_client_mask
,
947 const StatusCallback
& callback
) {
950 if (host
.empty() || clients_
.empty()) {
951 callback
.Run(kQuotaStatusOk
);
955 HostDataDeleter
* deleter
=
956 new HostDataDeleter(this, host
, type
, quota_client_mask
, callback
);
960 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback
& callback
) {
961 if (!available_space_callbacks_
.Add(callback
))
964 PostTaskAndReplyWithResult(db_thread_
.get(),
966 base::Bind(get_disk_space_fn_
, profile_path_
),
967 base::Bind(&QuotaManager::DidGetAvailableSpace
,
968 weak_factory_
.GetWeakPtr()));
971 void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback
& callback
) {
973 if (!temporary_quota_initialized_
) {
974 db_initialization_callbacks_
.Add(base::Bind(
975 &QuotaManager::GetTemporaryGlobalQuota
,
976 weak_factory_
.GetWeakPtr(), callback
));
980 if (temporary_quota_override_
> 0) {
981 callback
.Run(kQuotaStatusOk
, temporary_quota_override_
);
985 UsageAndQuotaCallbackDispatcher
* dispatcher
=
986 new UsageAndQuotaCallbackDispatcher(this);
987 GetUsageTracker(kStorageTypeTemporary
)->
988 GetGlobalLimitedUsage(dispatcher
->GetGlobalLimitedUsageCallback());
989 GetAvailableSpace(dispatcher
->GetAvailableSpaceCallback());
990 dispatcher
->WaitForResults(
991 base::Bind(&DispatchTemporaryGlobalQuotaCallback
, callback
));
994 void QuotaManager::SetTemporaryGlobalOverrideQuota(
995 int64 new_quota
, const QuotaCallback
& callback
) {
999 if (!callback
.is_null())
1000 callback
.Run(kQuotaErrorInvalidModification
, -1);
1005 if (!callback
.is_null())
1006 callback
.Run(kQuotaErrorInvalidAccess
, -1);
1010 int64
* new_quota_ptr
= new int64(new_quota
);
1011 PostTaskAndReplyWithResultForDBThread(
1013 base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread
,
1014 base::Unretained(new_quota_ptr
)),
1015 base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota
,
1016 weak_factory_
.GetWeakPtr(),
1018 base::Owned(new_quota_ptr
)));
1021 void QuotaManager::GetPersistentHostQuota(const std::string
& host
,
1022 const QuotaCallback
& callback
) {
1025 // This could happen if we are called on file:///.
1026 // TODO(kinuko) We may want to respect --allow-file-access-from-files
1027 // command line switch.
1028 callback
.Run(kQuotaStatusOk
, 0);
1032 if (!persistent_host_quota_callbacks_
.Add(host
, callback
))
1035 int64
* quota_ptr
= new int64(0);
1036 PostTaskAndReplyWithResultForDBThread(
1038 base::Bind(&GetPersistentHostQuotaOnDBThread
,
1040 base::Unretained(quota_ptr
)),
1041 base::Bind(&QuotaManager::DidGetPersistentHostQuota
,
1042 weak_factory_
.GetWeakPtr(),
1044 base::Owned(quota_ptr
)));
1047 void QuotaManager::SetPersistentHostQuota(const std::string
& host
,
1049 const QuotaCallback
& callback
) {
1052 // This could happen if we are called on file:///.
1053 callback
.Run(kQuotaErrorNotSupported
, 0);
1057 if (new_quota
< 0) {
1058 callback
.Run(kQuotaErrorInvalidModification
, -1);
1062 if (kPerHostPersistentQuotaLimit
< new_quota
) {
1063 // Cap the requested size at the per-host quota limit.
1064 new_quota
= kPerHostPersistentQuotaLimit
;
1068 callback
.Run(kQuotaErrorInvalidAccess
, -1);
1072 int64
* new_quota_ptr
= new int64(new_quota
);
1073 PostTaskAndReplyWithResultForDBThread(
1075 base::Bind(&SetPersistentHostQuotaOnDBThread
,
1077 base::Unretained(new_quota_ptr
)),
1078 base::Bind(&QuotaManager::DidSetPersistentHostQuota
,
1079 weak_factory_
.GetWeakPtr(),
1082 base::Owned(new_quota_ptr
)));
1085 void QuotaManager::GetGlobalUsage(StorageType type
,
1086 const GlobalUsageCallback
& callback
) {
1088 DCHECK(GetUsageTracker(type
));
1089 GetUsageTracker(type
)->GetGlobalUsage(callback
);
1092 void QuotaManager::GetHostUsage(const std::string
& host
,
1094 const UsageCallback
& callback
) {
1096 DCHECK(GetUsageTracker(type
));
1097 GetUsageTracker(type
)->GetHostUsage(host
, callback
);
1100 void QuotaManager::GetHostUsage(const std::string
& host
,
1102 QuotaClient::ID client_id
,
1103 const UsageCallback
& callback
) {
1105 DCHECK(GetUsageTracker(type
));
1106 ClientUsageTracker
* tracker
=
1107 GetUsageTracker(type
)->GetClientTracker(client_id
);
1112 tracker
->GetHostUsage(host
, callback
);
1115 bool QuotaManager::IsTrackingHostUsage(StorageType type
,
1116 QuotaClient::ID client_id
) const {
1117 UsageTracker
* tracker
= GetUsageTracker(type
);
1118 return tracker
&& tracker
->GetClientTracker(client_id
);
1121 void QuotaManager::GetStatistics(
1122 std::map
<std::string
, std::string
>* statistics
) {
1124 if (temporary_storage_evictor_
) {
1125 std::map
<std::string
, int64
> stats
;
1126 temporary_storage_evictor_
->GetStatistics(&stats
);
1127 for (std::map
<std::string
, int64
>::iterator p
= stats
.begin();
1130 (*statistics
)[p
->first
] = base::Int64ToString(p
->second
);
1134 bool QuotaManager::IsStorageUnlimited(const GURL
& origin
,
1135 StorageType type
) const {
1136 // For syncable storage we should always enforce quota (since the
1137 // quota must be capped by the server limit).
1138 if (type
== kStorageTypeSyncable
)
1140 if (type
== kStorageTypeQuotaNotManaged
)
1142 return special_storage_policy_
.get() &&
1143 special_storage_policy_
->IsStorageUnlimited(origin
);
1146 void QuotaManager::GetOriginsModifiedSince(StorageType type
,
1147 base::Time modified_since
,
1148 const GetOriginsCallback
& callback
) {
1150 GetModifiedSinceHelper
* helper
= new GetModifiedSinceHelper
;
1151 PostTaskAndReplyWithResultForDBThread(
1153 base::Bind(&GetModifiedSinceHelper::GetModifiedSinceOnDBThread
,
1154 base::Unretained(helper
),
1157 base::Bind(&GetModifiedSinceHelper::DidGetModifiedSince
,
1158 base::Owned(helper
),
1159 weak_factory_
.GetWeakPtr(),
1164 bool QuotaManager::ResetUsageTracker(StorageType type
) {
1165 DCHECK(GetUsageTracker(type
));
1166 if (GetUsageTracker(type
)->IsWorking())
1169 case kStorageTypeTemporary
:
1170 temporary_usage_tracker_
.reset(new UsageTracker(
1171 clients_
, kStorageTypeTemporary
, special_storage_policy_
.get(),
1172 storage_monitor_
.get()));
1174 case kStorageTypePersistent
:
1175 persistent_usage_tracker_
.reset(new UsageTracker(
1176 clients_
, kStorageTypePersistent
, special_storage_policy_
.get(),
1177 storage_monitor_
.get()));
1179 case kStorageTypeSyncable
:
1180 syncable_usage_tracker_
.reset(new UsageTracker(
1181 clients_
, kStorageTypeSyncable
, special_storage_policy_
.get(),
1182 storage_monitor_
.get()));
1190 void QuotaManager::AddStorageObserver(
1191 StorageObserver
* observer
, const StorageObserver::MonitorParams
& params
) {
1193 storage_monitor_
->AddObserver(observer
, params
);
1196 void QuotaManager::RemoveStorageObserver(StorageObserver
* observer
) {
1198 storage_monitor_
->RemoveObserver(observer
);
1201 void QuotaManager::RemoveStorageObserverForFilter(
1202 StorageObserver
* observer
, const StorageObserver::Filter
& filter
) {
1204 storage_monitor_
->RemoveObserverForFilter(observer
, filter
);
1207 QuotaManager::~QuotaManager() {
1208 proxy_
->manager_
= NULL
;
1209 std::for_each(clients_
.begin(), clients_
.end(),
1210 std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed
));
1212 db_thread_
->DeleteSoon(FROM_HERE
, database_
.release());
1215 QuotaManager::EvictionContext::EvictionContext()
1216 : evicted_type(kStorageTypeUnknown
) {
1219 QuotaManager::EvictionContext::~EvictionContext() {
1222 void QuotaManager::LazyInitialize() {
1223 DCHECK(io_thread_
->BelongsToCurrentThread());
1225 // Initialization seems to be done already.
1229 // Use an empty path to open an in-memory only databse for incognito.
1230 database_
.reset(new QuotaDatabase(is_incognito_
? base::FilePath() :
1231 profile_path_
.AppendASCII(kDatabaseName
)));
1233 temporary_usage_tracker_
.reset(new UsageTracker(
1234 clients_
, kStorageTypeTemporary
, special_storage_policy_
.get(),
1235 storage_monitor_
.get()));
1236 persistent_usage_tracker_
.reset(new UsageTracker(
1237 clients_
, kStorageTypePersistent
, special_storage_policy_
.get(),
1238 storage_monitor_
.get()));
1239 syncable_usage_tracker_
.reset(new UsageTracker(
1240 clients_
, kStorageTypeSyncable
, special_storage_policy_
.get(),
1241 storage_monitor_
.get()));
1243 int64
* temporary_quota_override
= new int64(-1);
1244 int64
* desired_available_space
= new int64(-1);
1245 PostTaskAndReplyWithResultForDBThread(
1247 base::Bind(&InitializeOnDBThread
,
1248 base::Unretained(temporary_quota_override
),
1249 base::Unretained(desired_available_space
)),
1250 base::Bind(&QuotaManager::DidInitialize
,
1251 weak_factory_
.GetWeakPtr(),
1252 base::Owned(temporary_quota_override
),
1253 base::Owned(desired_available_space
)));
1256 void QuotaManager::RegisterClient(QuotaClient
* client
) {
1257 DCHECK(!database_
.get());
1258 clients_
.push_back(client
);
1261 UsageTracker
* QuotaManager::GetUsageTracker(StorageType type
) const {
1263 case kStorageTypeTemporary
:
1264 return temporary_usage_tracker_
.get();
1265 case kStorageTypePersistent
:
1266 return persistent_usage_tracker_
.get();
1267 case kStorageTypeSyncable
:
1268 return syncable_usage_tracker_
.get();
1269 case kStorageTypeQuotaNotManaged
:
1271 case kStorageTypeUnknown
:
1277 void QuotaManager::GetCachedOrigins(
1278 StorageType type
, std::set
<GURL
>* origins
) {
1281 DCHECK(GetUsageTracker(type
));
1282 GetUsageTracker(type
)->GetCachedOrigins(origins
);
1285 void QuotaManager::NotifyStorageAccessedInternal(
1286 QuotaClient::ID client_id
,
1287 const GURL
& origin
, StorageType type
,
1288 base::Time accessed_time
) {
1290 if (type
== kStorageTypeTemporary
&& !lru_origin_callback_
.is_null()) {
1291 // Record the accessed origins while GetLRUOrigin task is runing
1292 // to filter out them from eviction.
1293 access_notified_origins_
.insert(origin
);
1298 PostTaskAndReplyWithResultForDBThread(
1300 base::Bind(&UpdateAccessTimeOnDBThread
, origin
, type
, accessed_time
),
1301 base::Bind(&QuotaManager::DidDatabaseWork
,
1302 weak_factory_
.GetWeakPtr()));
1305 void QuotaManager::NotifyStorageModifiedInternal(
1306 QuotaClient::ID client_id
,
1310 base::Time modified_time
) {
1312 DCHECK(GetUsageTracker(type
));
1313 GetUsageTracker(type
)->UpdateUsageCache(client_id
, origin
, delta
);
1315 PostTaskAndReplyWithResultForDBThread(
1317 base::Bind(&UpdateModifiedTimeOnDBThread
, origin
, type
, modified_time
),
1318 base::Bind(&QuotaManager::DidDatabaseWork
,
1319 weak_factory_
.GetWeakPtr()));
1322 void QuotaManager::DumpQuotaTable(const DumpQuotaTableCallback
& callback
) {
1323 DumpQuotaTableHelper
* helper
= new DumpQuotaTableHelper
;
1324 PostTaskAndReplyWithResultForDBThread(
1326 base::Bind(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread
,
1327 base::Unretained(helper
)),
1328 base::Bind(&DumpQuotaTableHelper::DidDumpQuotaTable
,
1329 base::Owned(helper
),
1330 weak_factory_
.GetWeakPtr(),
1334 void QuotaManager::DumpOriginInfoTable(
1335 const DumpOriginInfoTableCallback
& callback
) {
1336 DumpOriginInfoTableHelper
* helper
= new DumpOriginInfoTableHelper
;
1337 PostTaskAndReplyWithResultForDBThread(
1339 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread
,
1340 base::Unretained(helper
)),
1341 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable
,
1342 base::Owned(helper
),
1343 weak_factory_
.GetWeakPtr(),
1347 void QuotaManager::StartEviction() {
1348 DCHECK(!temporary_storage_evictor_
.get());
1349 temporary_storage_evictor_
.reset(new QuotaTemporaryStorageEvictor(
1350 this, kEvictionIntervalInMilliSeconds
));
1351 if (desired_available_space_
>= 0)
1352 temporary_storage_evictor_
->set_min_available_disk_space_to_start_eviction(
1353 desired_available_space_
);
1354 temporary_storage_evictor_
->Start();
1357 void QuotaManager::DeleteOriginFromDatabase(
1358 const GURL
& origin
, StorageType type
) {
1363 PostTaskAndReplyWithResultForDBThread(
1365 base::Bind(&DeleteOriginInfoOnDBThread
, origin
, type
),
1366 base::Bind(&QuotaManager::DidDatabaseWork
,
1367 weak_factory_
.GetWeakPtr()));
1370 void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status
) {
1371 DCHECK(io_thread_
->BelongsToCurrentThread());
1373 // We only try evict origins that are not in use, so basically
1374 // deletion attempt for eviction should not fail. Let's record
1375 // the origin if we get error and exclude it from future eviction
1376 // if the error happens consistently (> kThresholdOfErrorsToBeBlacklisted).
1377 if (status
!= kQuotaStatusOk
)
1378 origins_in_error_
[eviction_context_
.evicted_origin
]++;
1380 eviction_context_
.evict_origin_data_callback
.Run(status
);
1381 eviction_context_
.evict_origin_data_callback
.Reset();
1384 void QuotaManager::ReportHistogram() {
1385 GetGlobalUsage(kStorageTypeTemporary
,
1387 &QuotaManager::DidGetTemporaryGlobalUsageForHistogram
,
1388 weak_factory_
.GetWeakPtr()));
1389 GetGlobalUsage(kStorageTypePersistent
,
1391 &QuotaManager::DidGetPersistentGlobalUsageForHistogram
,
1392 weak_factory_
.GetWeakPtr()));
1395 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
1397 int64 unlimited_usage
) {
1398 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfTemporaryStorage", usage
);
1400 std::set
<GURL
> origins
;
1401 GetCachedOrigins(kStorageTypeTemporary
, &origins
);
1403 size_t num_origins
= origins
.size();
1404 size_t protected_origins
= 0;
1405 size_t unlimited_origins
= 0;
1406 CountOriginType(origins
,
1407 special_storage_policy_
.get(),
1409 &unlimited_origins
);
1411 UMA_HISTOGRAM_COUNTS("Quota.NumberOfTemporaryStorageOrigins",
1413 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedTemporaryStorageOrigins",
1415 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedTemporaryStorageOrigins",
1419 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
1421 int64 unlimited_usage
) {
1422 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage
);
1424 std::set
<GURL
> origins
;
1425 GetCachedOrigins(kStorageTypePersistent
, &origins
);
1427 size_t num_origins
= origins
.size();
1428 size_t protected_origins
= 0;
1429 size_t unlimited_origins
= 0;
1430 CountOriginType(origins
,
1431 special_storage_policy_
.get(),
1433 &unlimited_origins
);
1435 UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
1437 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
1439 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
1443 void QuotaManager::GetLRUOrigin(
1445 const GetLRUOriginCallback
& callback
) {
1447 // This must not be called while there's an in-flight task.
1448 DCHECK(lru_origin_callback_
.is_null());
1449 lru_origin_callback_
= callback
;
1451 lru_origin_callback_
.Run(GURL());
1452 lru_origin_callback_
.Reset();
1456 std::set
<GURL
>* exceptions
= new std::set
<GURL
>;
1457 for (std::map
<GURL
, int>::const_iterator p
= origins_in_use_
.begin();
1458 p
!= origins_in_use_
.end();
1461 exceptions
->insert(p
->first
);
1463 for (std::map
<GURL
, int>::const_iterator p
= origins_in_error_
.begin();
1464 p
!= origins_in_error_
.end();
1466 if (p
->second
> QuotaManager::kThresholdOfErrorsToBeBlacklisted
)
1467 exceptions
->insert(p
->first
);
1470 GURL
* url
= new GURL
;
1471 PostTaskAndReplyWithResultForDBThread(
1473 base::Bind(&GetLRUOriginOnDBThread
,
1475 base::Owned(exceptions
),
1476 special_storage_policy_
,
1477 base::Unretained(url
)),
1478 base::Bind(&QuotaManager::DidGetLRUOrigin
,
1479 weak_factory_
.GetWeakPtr(),
1483 void QuotaManager::EvictOriginData(
1486 const EvictOriginDataCallback
& callback
) {
1487 DCHECK(io_thread_
->BelongsToCurrentThread());
1488 DCHECK_EQ(type
, kStorageTypeTemporary
);
1490 eviction_context_
.evicted_origin
= origin
;
1491 eviction_context_
.evicted_type
= type
;
1492 eviction_context_
.evict_origin_data_callback
= callback
;
1494 DeleteOriginData(origin
, type
, QuotaClient::kAllClientsMask
,
1495 base::Bind(&QuotaManager::DidOriginDataEvicted
,
1496 weak_factory_
.GetWeakPtr()));
1499 void QuotaManager::GetUsageAndQuotaForEviction(
1500 const UsageAndQuotaCallback
& callback
) {
1501 DCHECK(io_thread_
->BelongsToCurrentThread());
1504 UsageAndQuotaCallbackDispatcher
* dispatcher
=
1505 new UsageAndQuotaCallbackDispatcher(this);
1506 GetUsageTracker(kStorageTypeTemporary
)->
1507 GetGlobalLimitedUsage(dispatcher
->GetGlobalLimitedUsageCallback());
1508 GetTemporaryGlobalQuota(dispatcher
->GetQuotaCallback());
1509 GetAvailableSpace(dispatcher
->GetAvailableSpaceCallback());
1510 dispatcher
->WaitForResults(callback
);
1513 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
1514 const QuotaCallback
& callback
,
1515 const int64
* new_quota
,
1517 QuotaStatusCode status
= kQuotaErrorInvalidAccess
;
1518 DidDatabaseWork(success
);
1520 temporary_quota_override_
= *new_quota
;
1521 status
= kQuotaStatusOk
;
1524 if (callback
.is_null())
1527 callback
.Run(status
, *new_quota
);
1530 void QuotaManager::DidGetPersistentHostQuota(const std::string
& host
,
1533 DidDatabaseWork(success
);
1534 persistent_host_quota_callbacks_
.Run(host
, kQuotaStatusOk
, *quota
);
1537 void QuotaManager::DidSetPersistentHostQuota(const std::string
& host
,
1538 const QuotaCallback
& callback
,
1539 const int64
* new_quota
,
1541 DidDatabaseWork(success
);
1542 callback
.Run(success
? kQuotaStatusOk
: kQuotaErrorInvalidAccess
, *new_quota
);
1545 void QuotaManager::DidInitialize(int64
* temporary_quota_override
,
1546 int64
* desired_available_space
,
1548 temporary_quota_override_
= *temporary_quota_override
;
1549 desired_available_space_
= *desired_available_space
;
1550 temporary_quota_initialized_
= true;
1551 DidDatabaseWork(success
);
1553 histogram_timer_
.Start(FROM_HERE
,
1554 base::TimeDelta::FromMilliseconds(
1555 kReportHistogramInterval
),
1556 this, &QuotaManager::ReportHistogram
);
1558 db_initialization_callbacks_
.Run();
1559 GetTemporaryGlobalQuota(
1560 base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota
,
1561 weak_factory_
.GetWeakPtr()));
1564 void QuotaManager::DidGetLRUOrigin(const GURL
* origin
,
1566 DidDatabaseWork(success
);
1567 // Make sure the returned origin is (still) not in the origin_in_use_ set
1568 // and has not been accessed since we posted the task.
1569 if (origins_in_use_
.find(*origin
) != origins_in_use_
.end() ||
1570 access_notified_origins_
.find(*origin
) != access_notified_origins_
.end())
1571 lru_origin_callback_
.Run(GURL());
1573 lru_origin_callback_
.Run(*origin
);
1574 access_notified_origins_
.clear();
1575 lru_origin_callback_
.Reset();
1578 void QuotaManager::DidGetInitialTemporaryGlobalQuota(
1579 QuotaStatusCode status
, int64 quota_unused
) {
1580 if (eviction_disabled_
)
1583 std::set
<GURL
>* origins
= new std::set
<GURL
>;
1584 temporary_usage_tracker_
->GetCachedOrigins(origins
);
1585 // This will call the StartEviction() when initial origin registration
1587 PostTaskAndReplyWithResultForDBThread(
1589 base::Bind(&InitializeTemporaryOriginsInfoOnDBThread
,
1590 base::Owned(origins
)),
1591 base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo
,
1592 weak_factory_
.GetWeakPtr()));
1595 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success
) {
1596 DidDatabaseWork(success
);
1601 void QuotaManager::DidGetAvailableSpace(int64 space
) {
1602 available_space_callbacks_
.Run(kQuotaStatusOk
, space
);
1605 void QuotaManager::DidDatabaseWork(bool success
) {
1606 db_disabled_
= !success
;
1609 void QuotaManager::DeleteOnCorrectThread() const {
1610 if (!io_thread_
->BelongsToCurrentThread() &&
1611 io_thread_
->DeleteSoon(FROM_HERE
, this)) {
1617 void QuotaManager::PostTaskAndReplyWithResultForDBThread(
1618 const tracked_objects::Location
& from_here
,
1619 const base::Callback
<bool(QuotaDatabase
*)>& task
,
1620 const base::Callback
<void(bool)>& reply
) {
1621 // Deleting manager will post another task to DB thread to delete
1622 // |database_|, therefore we can be sure that database_ is alive when this
1624 base::PostTaskAndReplyWithResult(
1627 base::Bind(task
, base::Unretained(database_
.get())),
1631 } // namespace storage