1 // Copyright (c) 2012 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 "webkit/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/file_util.h"
17 #include "base/files/file_path.h"
18 #include "base/metrics/histogram.h"
19 #include "base/sequenced_task_runner.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/sys_info.h"
23 #include "base/task_runner_util.h"
24 #include "base/time.h"
25 #include "net/base/net_util.h"
26 #include "webkit/quota/quota_database.h"
27 #include "webkit/quota/quota_temporary_storage_evictor.h"
28 #include "webkit/quota/quota_types.h"
29 #include "webkit/quota/usage_tracker.h"
31 #define UMA_HISTOGRAM_MBYTES(name, sample) \
32 UMA_HISTOGRAM_CUSTOM_COUNTS( \
33 (name), static_cast<int>((sample) / kMBytes), \
34 1, 10 * 1024 * 1024 /* 10TB */, 100)
40 const int64 kMBytes
= 1024 * 1024;
41 const int kMinutesInMilliSeconds
= 60 * 1000;
43 const int64 kIncognitoDefaultTemporaryQuota
= 50 * kMBytes
;
44 const int64 kReportHistogramInterval
= 60 * 60 * 1000; // 1 hour
45 const double kTemporaryQuotaRatioToAvail
= 0.5; // 50%
47 void CountOriginType(const std::set
<GURL
>& origins
,
48 SpecialStoragePolicy
* policy
,
49 size_t* protected_origins
,
50 size_t* unlimited_origins
) {
51 DCHECK(protected_origins
);
52 DCHECK(unlimited_origins
);
53 *protected_origins
= 0;
54 *unlimited_origins
= 0;
57 for (std::set
<GURL
>::const_iterator itr
= origins
.begin();
60 if (policy
->IsStorageProtected(*itr
))
62 if (policy
->IsStorageUnlimited(*itr
))
67 bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64
* new_quota
,
68 QuotaDatabase
* database
) {
70 if (!database
->SetQuotaConfigValue(
71 QuotaDatabase::kTemporaryQuotaOverrideKey
, *new_quota
)) {
78 bool GetPersistentHostQuotaOnDBThread(const std::string
& host
,
80 QuotaDatabase
* database
) {
82 database
->GetHostQuota(host
, kStorageTypePersistent
, quota
);
86 bool SetPersistentHostQuotaOnDBThread(const std::string
& host
,
88 QuotaDatabase
* database
) {
90 if (database
->SetHostQuota(host
, kStorageTypePersistent
, *new_quota
))
96 bool InitializeOnDBThread(int64
* temporary_quota_override
,
97 int64
* desired_available_space
,
98 QuotaDatabase
* database
) {
100 database
->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey
,
101 temporary_quota_override
);
102 database
->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey
,
103 desired_available_space
);
107 bool GetLRUOriginOnDBThread(StorageType type
,
108 std::set
<GURL
>* exceptions
,
109 SpecialStoragePolicy
* policy
,
111 QuotaDatabase
* database
) {
113 database
->GetLRUOrigin(type
, *exceptions
, policy
, url
);
117 bool DeleteOriginInfoOnDBThread(const GURL
& origin
,
119 QuotaDatabase
* database
) {
121 return database
->DeleteOriginInfo(origin
, type
);
124 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set
<GURL
>* origins
,
125 QuotaDatabase
* database
) {
127 if (database
->IsOriginDatabaseBootstrapped())
130 // Register existing origins with 0 last time access.
131 if (database
->RegisterInitialOriginInfo(*origins
, kStorageTypeTemporary
)) {
132 database
->SetOriginDatabaseBootstrapped(true);
138 bool UpdateAccessTimeOnDBThread(const GURL
& origin
,
140 base::Time accessed_time
,
141 QuotaDatabase
* database
) {
143 return database
->SetOriginLastAccessTime(origin
, type
, accessed_time
);
146 bool UpdateModifiedTimeOnDBThread(const GURL
& origin
,
148 base::Time modified_time
,
149 QuotaDatabase
* database
) {
151 return database
->SetOriginLastModifiedTime(origin
, type
, modified_time
);
154 int64
CallSystemGetAmountOfFreeDiskSpace(const base::FilePath
& profile_path
) {
155 // Ensure the profile path exists.
156 if(!file_util::CreateDirectory(profile_path
)) {
157 LOG(WARNING
) << "Create directory failed for path" << profile_path
.value();
160 return base::SysInfo::AmountOfFreeDiskSpace(profile_path
);
163 } // anonymous namespace
165 const int64
QuotaManager::kNoLimit
= kint64max
;
167 const int QuotaManager::kPerHostTemporaryPortion
= 5; // 20%
169 const char QuotaManager::kDatabaseName
[] = "QuotaManager";
171 // Preserve kMinimumPreserveForSystem disk space for system book-keeping
172 // when returning the quota to unlimited apps/extensions.
173 // TODO(kinuko): This should be like 10% of the actual disk space.
174 // For now we simply use a constant as getting the disk size needs
175 // platform-dependent code. (http://crbug.com/178976)
176 const int64
QuotaManager::kMinimumPreserveForSystem
= 1024 * kMBytes
;
178 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted
= 3;
180 const int QuotaManager::kEvictionIntervalInMilliSeconds
=
181 30 * kMinutesInMilliSeconds
;
183 // Heuristics: assuming average cloud server allows a few Gigs storage
184 // on the server side and the storage needs to be shared for user data
185 // and by multiple apps.
186 int64
QuotaManager::kSyncableStorageDefaultHostQuota
= 500 * kMBytes
;
188 int64
CalculateQuotaForInstalledApp(
189 int64 available_disk_space
, int64 usage
, int64 quota
) {
190 if (available_disk_space
< QuotaManager::kMinimumPreserveForSystem
) {
191 // No more space; cap the quota to the current usage.
195 available_disk_space
-= QuotaManager::kMinimumPreserveForSystem
;
196 if (available_disk_space
< quota
- usage
)
197 return available_disk_space
+ usage
;
202 // Callback translators.
203 void CallGetUsageAndQuotaCallback(
204 const QuotaManager::GetUsageAndQuotaCallback
& callback
,
206 bool is_installed_app
,
207 QuotaStatusCode status
,
208 const QuotaAndUsage
& quota_and_usage
) {
209 // Regular limited case.
211 if (is_installed_app
) {
212 // Cap the quota by the available disk space.
213 callback
.Run(status
, quota_and_usage
.usage
,
214 CalculateQuotaForInstalledApp(
215 quota_and_usage
.available_disk_space
,
216 quota_and_usage
.usage
,
217 quota_and_usage
.quota
));
220 callback
.Run(status
, quota_and_usage
.usage
, quota_and_usage
.quota
);
224 int64 usage
= quota_and_usage
.unlimited_usage
;
226 // Unlimited case: for non-installed apps just return unlimited quota.
227 // TODO(kinuko): We should probably always return the capped disk space
228 // for internal quota clients (while we still would not want to expose
229 // the actual usage to webapps). http://crbug.com/179040
230 if (!is_installed_app
) {
231 callback
.Run(status
, usage
, QuotaManager::kNoLimit
);
235 // For installed unlimited apps.
236 callback
.Run(status
, usage
,
237 CalculateQuotaForInstalledApp(
238 quota_and_usage
.available_disk_space
,
239 usage
, QuotaManager::kNoLimit
));
242 void CallQuotaCallback(
243 const QuotaCallback
& callback
,
244 QuotaStatusCode status
,
245 const QuotaAndUsage
& quota_and_usage
) {
246 callback
.Run(status
, quota_and_usage
.quota
);
249 // This class is for posting GetUsage/GetQuota tasks, gathering
250 // results and dispatching GetAndQuota callbacks.
251 // This class is self-destructed.
252 class QuotaManager::UsageAndQuotaDispatcherTask
: public QuotaTask
{
254 typedef UsageAndQuotaDispatcherCallback Callback
;
255 typedef std::deque
<Callback
> CallbackList
;
257 static UsageAndQuotaDispatcherTask
* Create(
258 QuotaManager
* manager
,
260 const HostAndType
& host_and_type
);
262 // Returns true if it is the first call for this task; which means
263 // the caller needs to call Start().
264 bool AddCallback(const Callback
& callback
) {
265 callbacks_
.push_back(callback
);
266 return (callbacks_
.size() == 1);
269 void DidGetGlobalUsage(StorageType type
, int64 usage
, int64 unlimited_usage
) {
270 DCHECK_EQ(this->type(), type
);
271 DCHECK_GE(usage
, unlimited_usage
);
272 if (quota_status_
== kQuotaStatusUnknown
)
273 quota_status_
= kQuotaStatusOk
;
274 global_usage_
= usage
;
275 global_unlimited_usage_
= unlimited_usage
;
279 void DidGetHostUsage(const std::string
& host
, StorageType type
, int64 usage
) {
280 DCHECK_EQ(this->host(), host
);
281 DCHECK_EQ(this->type(), type
);
282 if (quota_status_
== kQuotaStatusUnknown
)
283 quota_status_
= kQuotaStatusOk
;
288 void DidGetHostQuota(const std::string
& host
,
290 QuotaStatusCode status
,
292 DCHECK_EQ(this->host(), host
);
293 DCHECK_EQ(this->type(), type
);
294 if (quota_status_
== kQuotaStatusUnknown
|| quota_status_
== kQuotaStatusOk
)
295 quota_status_
= status
;
296 host_quota_
= host_quota
;
300 void DidGetAvailableSpace(QuotaStatusCode status
, int64 space
) {
302 if (quota_status_
== kQuotaStatusUnknown
|| quota_status_
== kQuotaStatusOk
)
303 quota_status_
= status
;
304 available_space_
= space
;
308 bool IsStartable() const {
309 return !started_
&& !callbacks_
.empty();
313 UsageAndQuotaDispatcherTask(
314 QuotaManager
* manager
,
315 const HostAndType
& host_and_type
)
316 : QuotaTask(manager
),
317 host_and_type_(host_and_type
),
321 global_unlimited_usage_(-1),
323 available_space_(-1),
324 quota_status_(kQuotaStatusUnknown
),
325 waiting_callbacks_(1),
326 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
328 virtual ~UsageAndQuotaDispatcherTask() {}
330 // Subclasses must implement them.
331 virtual void RunBody() = 0;
332 virtual void DispatchCallbacks() = 0;
334 virtual void Run() OVERRIDE
{
338 // We initialize waiting_callbacks to 1 so that we won't run
339 // the completion callback until here even some of the callbacks
340 // are dispatched synchronously.
344 virtual void Aborted() OVERRIDE
{
345 CallCallbacksAndClear(kQuotaErrorAbort
, 0, 0, 0, 0);
349 virtual void Completed() OVERRIDE
{
353 void CallCallbacksAndClear(
354 QuotaStatusCode status
,
355 int64 usage
, int64 unlimited_usage
, int64 quota
,
356 int64 available_space
) {
357 QuotaAndUsage qau
= { usage
, unlimited_usage
, quota
, available_space
};
358 for (CallbackList::iterator iter
= callbacks_
.begin();
359 iter
!= callbacks_
.end(); ++iter
) {
360 (*iter
).Run(status
, qau
);
365 QuotaManager
* manager() const {
366 return static_cast<QuotaManager
*>(observer());
369 std::string
host() const { return host_and_type_
.first
; }
370 virtual StorageType
type() const { return host_and_type_
.second
; }
371 int64
host_quota() const { return host_quota_
; }
372 int64
global_usage() const { return global_usage_
; }
373 int64
global_unlimited_usage() const { return global_unlimited_usage_
; }
374 int64
host_usage() const { return host_usage_
; }
375 int64
available_space() const { return available_space_
; }
376 QuotaStatusCode
quota_status() const { return quota_status_
; }
377 CallbackList
& callbacks() { return callbacks_
; }
379 // The main logic that determines the temporary global quota.
380 int64
temporary_global_quota() const {
381 DCHECK_EQ(type(), kStorageTypeTemporary
);
383 DCHECK_GE(global_usage(), global_unlimited_usage());
384 if (manager()->temporary_quota_override_
> 0) {
385 // If the user has specified an explicit temporary quota, use the value.
386 return manager()->temporary_quota_override_
;
388 int64 limited_usage
= global_usage() - global_unlimited_usage();
389 int64 avail_space
= available_space();
390 if (avail_space
< kint64max
- limited_usage
) {
391 // We basically calculate the temporary quota by
392 // [available_space + space_used_for_temp] * kTempQuotaRatio,
393 // but make sure we'll have no overflow.
394 avail_space
+= limited_usage
;
396 return avail_space
* kTemporaryQuotaRatioToAvail
;
399 // Subclasses must call following methods to create a new 'waitable'
400 // callback, which decrements waiting_callbacks when it is called.
401 GlobalUsageCallback
NewWaitableGlobalUsageCallback() {
402 ++waiting_callbacks_
;
403 return base::Bind(&UsageAndQuotaDispatcherTask::DidGetGlobalUsage
,
404 weak_factory_
.GetWeakPtr());
406 UsageCallback
NewWaitableHostUsageCallback() {
407 ++waiting_callbacks_
;
408 return base::Bind(&UsageAndQuotaDispatcherTask::DidGetHostUsage
,
409 weak_factory_
.GetWeakPtr(), host(), type());
411 QuotaCallback
NewWaitableHostQuotaCallback() {
412 ++waiting_callbacks_
;
413 return base::Bind(&UsageAndQuotaDispatcherTask::DidGetHostQuota
,
414 weak_factory_
.GetWeakPtr(), host(), type());
416 AvailableSpaceCallback
NewWaitableAvailableSpaceCallback() {
417 ++waiting_callbacks_
;
418 return base::Bind(&UsageAndQuotaDispatcherTask::DidGetAvailableSpace
,
419 weak_factory_
.GetWeakPtr());
424 void CheckCompleted() {
425 if (--waiting_callbacks_
<= 0) {
427 DCHECK(callbacks_
.empty());
429 UsageAndQuotaDispatcherTaskMap
& dispatcher_map
=
430 manager()->usage_and_quota_dispatchers_
;
431 DCHECK(dispatcher_map
.find(host_and_type_
) != dispatcher_map
.end());
432 dispatcher_map
.erase(host_and_type_
);
437 const std::string host_
;
438 const HostAndType host_and_type_
;
442 int64 global_unlimited_usage_
;
444 int64 available_space_
;
445 QuotaStatusCode quota_status_
;
446 CallbackList callbacks_
;
447 int waiting_callbacks_
;
448 base::WeakPtrFactory
<UsageAndQuotaDispatcherTask
> weak_factory_
;
450 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaDispatcherTask
);
453 class QuotaManager::GetUsageInfoTask
: public QuotaTask
{
455 typedef QuotaManager::GetUsageInfoTask self_type
;
459 QuotaManager
* manager
,
460 const GetUsageInfoCallback
& callback
)
461 : QuotaTask(manager
),
463 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
467 virtual void Run() OVERRIDE
{
468 remaining_trackers_
= 3;
469 // This will populate cached hosts and usage info.
470 manager()->GetUsageTracker(kStorageTypeTemporary
)->GetGlobalUsage(
471 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage
,
472 weak_factory_
.GetWeakPtr()));
473 manager()->GetUsageTracker(kStorageTypePersistent
)->GetGlobalUsage(
474 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage
,
475 weak_factory_
.GetWeakPtr()));
476 manager()->GetUsageTracker(kStorageTypeSyncable
)->GetGlobalUsage(
477 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage
,
478 weak_factory_
.GetWeakPtr()));
481 virtual void Completed() OVERRIDE
{
482 callback_
.Run(entries_
);
486 virtual void Aborted() OVERRIDE
{
487 callback_
.Run(UsageInfoEntries());
492 void AddEntries(StorageType type
, UsageTracker
* tracker
) {
493 std::map
<std::string
, int64
> host_usage
;
494 tracker
->GetCachedHostsUsage(&host_usage
);
495 for (std::map
<std::string
, int64
>::const_iterator iter
= host_usage
.begin();
496 iter
!= host_usage
.end();
498 entries_
.push_back(UsageInfo(iter
->first
, type
, iter
->second
));
500 if (--remaining_trackers_
== 0)
504 void DidGetGlobalUsage(StorageType type
, int64
, int64
) {
505 AddEntries(type
, manager()->GetUsageTracker(type
));
508 QuotaManager
* manager() const {
509 return static_cast<QuotaManager
*>(observer());
512 GetUsageInfoCallback callback_
;
513 UsageInfoEntries entries_
;
514 base::WeakPtrFactory
<GetUsageInfoTask
> weak_factory_
;
515 int remaining_trackers_
;
517 DISALLOW_COPY_AND_ASSIGN(GetUsageInfoTask
);
520 class QuotaManager::UsageAndQuotaDispatcherTaskForTemporary
521 : public QuotaManager::UsageAndQuotaDispatcherTask
{
523 UsageAndQuotaDispatcherTaskForTemporary(
524 QuotaManager
* manager
, const HostAndType
& host_and_type
)
525 : UsageAndQuotaDispatcherTask(manager
, host_and_type
) {}
528 virtual void RunBody() OVERRIDE
{
529 manager()->GetUsageTracker(type())->GetGlobalUsage(
530 NewWaitableGlobalUsageCallback());
531 manager()->GetUsageTracker(type())->GetHostUsage(
532 host(), NewWaitableHostUsageCallback());
533 manager()->GetAvailableSpace(NewWaitableAvailableSpaceCallback());
536 virtual void DispatchCallbacks() OVERRIDE
{
537 // Allow an individual host to utilize a fraction of the total
538 // pool available for temp storage.
539 int64 host_quota
= temporary_global_quota() / kPerHostTemporaryPortion
;
541 // But if total temp usage is over-budget, stop letting new data in
542 // until we reclaim space.
543 DCHECK_GE(global_usage(), global_unlimited_usage());
544 int64 limited_global_usage
= global_usage() - global_unlimited_usage();
545 if (limited_global_usage
> temporary_global_quota())
546 host_quota
= std::min(host_quota
, host_usage());
548 CallCallbacksAndClear(quota_status(),
549 host_usage(), host_usage(), host_quota
,
554 class QuotaManager::UsageAndQuotaDispatcherTaskForPersistent
555 : public QuotaManager::UsageAndQuotaDispatcherTask
{
557 UsageAndQuotaDispatcherTaskForPersistent(
558 QuotaManager
* manager
, const HostAndType
& host_and_type
)
559 : UsageAndQuotaDispatcherTask(manager
, host_and_type
) {}
562 virtual void RunBody() OVERRIDE
{
563 manager()->GetUsageTracker(type())->GetHostUsage(
564 host(), NewWaitableHostUsageCallback());
565 manager()->GetPersistentHostQuota(
566 host(), NewWaitableHostQuotaCallback());
567 manager()->GetAvailableSpace(NewWaitableAvailableSpaceCallback());
570 virtual void DispatchCallbacks() OVERRIDE
{
571 CallCallbacksAndClear(quota_status(),
572 host_usage(), host_usage(), host_quota(),
577 class QuotaManager::UsageAndQuotaDispatcherTaskForSyncable
578 : public QuotaManager::UsageAndQuotaDispatcherTask
{
580 UsageAndQuotaDispatcherTaskForSyncable(
581 QuotaManager
* manager
, const HostAndType
& host_and_type
)
582 : UsageAndQuotaDispatcherTask(manager
, host_and_type
) {}
585 virtual void RunBody() OVERRIDE
{
586 manager()->GetUsageTracker(type())->GetHostUsage(
587 host(), NewWaitableHostUsageCallback());
590 virtual void DispatchCallbacks() OVERRIDE
{
591 // TODO(kinuko): We should reflect the backend's actual quota instead
592 // of returning a fixed default value.
593 CallCallbacksAndClear(quota_status(),
594 host_usage(), host_usage(),
595 kSyncableStorageDefaultHostQuota
,
600 class QuotaManager::UsageAndQuotaDispatcherTaskForTemporaryGlobal
601 : public QuotaManager::UsageAndQuotaDispatcherTask
{
603 UsageAndQuotaDispatcherTaskForTemporaryGlobal(
604 QuotaManager
* manager
, const HostAndType
& host_and_type
)
605 : UsageAndQuotaDispatcherTask(manager
, host_and_type
) {}
608 virtual void RunBody() OVERRIDE
{
609 manager()->GetUsageTracker(type())->GetGlobalUsage(
610 NewWaitableGlobalUsageCallback());
611 manager()->GetAvailableSpace(NewWaitableAvailableSpaceCallback());
614 virtual void DispatchCallbacks() OVERRIDE
{
615 CallCallbacksAndClear(quota_status(),
616 global_usage(), global_unlimited_usage(),
617 temporary_global_quota(),
621 virtual StorageType
type() const OVERRIDE
{ return kStorageTypeTemporary
; }
625 QuotaManager::UsageAndQuotaDispatcherTask
*
626 QuotaManager::UsageAndQuotaDispatcherTask::Create(
627 QuotaManager
* manager
, bool global
,
628 const QuotaManager::HostAndType
& host_and_type
) {
630 return new UsageAndQuotaDispatcherTaskForTemporaryGlobal(
631 manager
, host_and_type
);
632 switch (host_and_type
.second
) {
633 case kStorageTypeTemporary
:
634 return new UsageAndQuotaDispatcherTaskForTemporary(
635 manager
, host_and_type
);
636 case kStorageTypePersistent
:
637 return new UsageAndQuotaDispatcherTaskForPersistent(
638 manager
, host_and_type
);
639 case kStorageTypeSyncable
:
640 return new UsageAndQuotaDispatcherTaskForSyncable(
641 manager
, host_and_type
);
648 class QuotaManager::OriginDataDeleter
: public QuotaTask
{
650 OriginDataDeleter(QuotaManager
* manager
,
653 int quota_client_mask
,
654 const StatusCallback
& callback
)
655 : QuotaTask(manager
),
658 quota_client_mask_(quota_client_mask
),
660 remaining_clients_(-1),
663 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
666 virtual void Run() OVERRIDE
{
668 remaining_clients_
= manager()->clients_
.size();
669 for (QuotaClientList::iterator iter
= manager()->clients_
.begin();
670 iter
!= manager()->clients_
.end(); ++iter
) {
671 if (quota_client_mask_
& (*iter
)->id()) {
672 (*iter
)->DeleteOriginData(
674 base::Bind(&OriginDataDeleter::DidDeleteOriginData
,
675 weak_factory_
.GetWeakPtr()));
678 if (--remaining_clients_
== 0)
684 virtual void Completed() OVERRIDE
{
685 if (error_count_
== 0) {
686 // Only remove the entire origin if we didn't skip any client types.
687 if (skipped_clients_
== 0)
688 manager()->DeleteOriginFromDatabase(origin_
, type_
);
689 callback_
.Run(kQuotaStatusOk
);
691 callback_
.Run(kQuotaErrorInvalidModification
);
696 virtual void Aborted() OVERRIDE
{
697 callback_
.Run(kQuotaErrorAbort
);
701 void DidDeleteOriginData(QuotaStatusCode status
) {
702 DCHECK_GT(remaining_clients_
, 0);
704 if (status
!= kQuotaStatusOk
)
707 if (--remaining_clients_
== 0)
711 QuotaManager
* manager() const {
712 return static_cast<QuotaManager
*>(observer());
717 int quota_client_mask_
;
719 int remaining_clients_
;
720 int skipped_clients_
;
721 StatusCallback callback_
;
723 base::WeakPtrFactory
<OriginDataDeleter
> weak_factory_
;
724 DISALLOW_COPY_AND_ASSIGN(OriginDataDeleter
);
727 class QuotaManager::HostDataDeleter
: public QuotaTask
{
729 HostDataDeleter(QuotaManager
* manager
,
730 const std::string
& host
,
732 int quota_client_mask
,
733 const StatusCallback
& callback
)
734 : QuotaTask(manager
),
737 quota_client_mask_(quota_client_mask
),
739 remaining_clients_(-1),
740 remaining_deleters_(-1),
742 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
745 virtual void Run() OVERRIDE
{
747 remaining_clients_
= manager()->clients_
.size();
748 for (QuotaClientList::iterator iter
= manager()->clients_
.begin();
749 iter
!= manager()->clients_
.end(); ++iter
) {
750 (*iter
)->GetOriginsForHost(
752 base::Bind(&HostDataDeleter::DidGetOriginsForHost
,
753 weak_factory_
.GetWeakPtr()));
757 virtual void Completed() OVERRIDE
{
758 if (error_count_
== 0) {
759 callback_
.Run(kQuotaStatusOk
);
761 callback_
.Run(kQuotaErrorInvalidModification
);
766 virtual void Aborted() OVERRIDE
{
767 callback_
.Run(kQuotaErrorAbort
);
771 void DidGetOriginsForHost(const std::set
<GURL
>& origins
, StorageType type
) {
772 DCHECK_GT(remaining_clients_
, 0);
774 origins_
.insert(origins
.begin(), origins
.end());
776 if (--remaining_clients_
== 0) {
777 if (!origins_
.empty())
778 ScheduleOriginsDeletion();
784 void ScheduleOriginsDeletion() {
785 remaining_deleters_
= origins_
.size();
786 for (std::set
<GURL
>::const_iterator p
= origins_
.begin();
789 OriginDataDeleter
* deleter
=
790 new OriginDataDeleter(
791 manager(), *p
, type_
, quota_client_mask_
,
792 base::Bind(&HostDataDeleter::DidDeleteOriginData
,
793 weak_factory_
.GetWeakPtr()));
798 void DidDeleteOriginData(QuotaStatusCode status
) {
799 DCHECK_GT(remaining_deleters_
, 0);
801 if (status
!= kQuotaStatusOk
)
804 if (--remaining_deleters_
== 0)
808 QuotaManager
* manager() const {
809 return static_cast<QuotaManager
*>(observer());
814 int quota_client_mask_
;
815 std::set
<GURL
> origins_
;
817 int remaining_clients_
;
818 int remaining_deleters_
;
819 StatusCallback callback_
;
821 base::WeakPtrFactory
<HostDataDeleter
> weak_factory_
;
822 DISALLOW_COPY_AND_ASSIGN(HostDataDeleter
);
825 class QuotaManager::GetModifiedSinceHelper
{
827 bool GetModifiedSinceOnDBThread(StorageType type
,
828 base::Time modified_since
,
829 QuotaDatabase
* database
) {
831 return database
->GetOriginsModifiedSince(type
, &origins_
, modified_since
);
834 void DidGetModifiedSince(QuotaManager
* manager
,
835 const GetOriginsCallback
& callback
,
839 // The operation was aborted.
840 callback
.Run(std::set
<GURL
>(), type
);
843 manager
->DidDatabaseWork(success
);
844 callback
.Run(origins_
, type
);
848 std::set
<GURL
> origins_
;
851 class QuotaManager::DumpQuotaTableHelper
{
853 bool DumpQuotaTableOnDBThread(QuotaDatabase
* database
) {
855 return database
->DumpQuotaTable(
856 new TableCallback(base::Bind(&DumpQuotaTableHelper::AppendEntry
,
857 base::Unretained(this))));
860 void DidDumpQuotaTable(QuotaManager
* manager
,
861 const DumpQuotaTableCallback
& callback
,
864 // The operation was aborted.
865 callback
.Run(QuotaTableEntries());
868 manager
->DidDatabaseWork(success
);
869 callback
.Run(entries_
);
873 typedef QuotaDatabase::QuotaTableCallback TableCallback
;
875 bool AppendEntry(const QuotaTableEntry
& entry
) {
876 entries_
.push_back(entry
);
880 QuotaTableEntries entries_
;
883 class QuotaManager::DumpOriginInfoTableHelper
{
885 bool DumpOriginInfoTableOnDBThread(QuotaDatabase
* database
) {
887 return database
->DumpOriginInfoTable(
888 new TableCallback(base::Bind(&DumpOriginInfoTableHelper::AppendEntry
,
889 base::Unretained(this))));
892 void DidDumpOriginInfoTable(QuotaManager
* manager
,
893 const DumpOriginInfoTableCallback
& callback
,
896 // The operation was aborted.
897 callback
.Run(OriginInfoTableEntries());
900 manager
->DidDatabaseWork(success
);
901 callback
.Run(entries_
);
905 typedef QuotaDatabase::OriginInfoTableCallback TableCallback
;
907 bool AppendEntry(const OriginInfoTableEntry
& entry
) {
908 entries_
.push_back(entry
);
912 OriginInfoTableEntries entries_
;
915 // QuotaManager ---------------------------------------------------------------
917 QuotaManager::QuotaManager(bool is_incognito
,
918 const base::FilePath
& profile_path
,
919 base::SingleThreadTaskRunner
* io_thread
,
920 base::SequencedTaskRunner
* db_thread
,
921 SpecialStoragePolicy
* special_storage_policy
)
922 : is_incognito_(is_incognito
),
923 profile_path_(profile_path
),
924 proxy_(new QuotaManagerProxy(
925 ALLOW_THIS_IN_INITIALIZER_LIST(this), io_thread
)),
927 eviction_disabled_(false),
928 io_thread_(io_thread
),
929 db_thread_(db_thread
),
930 temporary_quota_initialized_(false),
931 temporary_quota_override_(-1),
932 desired_available_space_(-1),
933 special_storage_policy_(special_storage_policy
),
934 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
935 get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace
) {
938 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback
& callback
) {
940 GetUsageInfoTask
* get_usage_info
= new GetUsageInfoTask(this, callback
);
941 get_usage_info
->Start();
944 void QuotaManager::GetUsageAndQuota(
945 const GURL
& origin
, StorageType type
,
946 const GetUsageAndQuotaCallback
& callback
) {
947 DCHECK(origin
== origin
.GetOrigin());
948 GetUsageAndQuotaInternal(
949 origin
, type
, false /* global */,
950 base::Bind(&CallGetUsageAndQuotaCallback
, callback
,
951 IsStorageUnlimited(origin
, type
), IsInstalledApp(origin
)));
954 void QuotaManager::NotifyStorageAccessed(
955 QuotaClient::ID client_id
,
956 const GURL
& origin
, StorageType type
) {
957 DCHECK(origin
== origin
.GetOrigin());
958 NotifyStorageAccessedInternal(client_id
, origin
, type
, base::Time::Now());
961 void QuotaManager::NotifyStorageModified(
962 QuotaClient::ID client_id
,
963 const GURL
& origin
, StorageType type
, int64 delta
) {
964 DCHECK(origin
== origin
.GetOrigin());
965 NotifyStorageModifiedInternal(client_id
, origin
, type
, delta
,
969 void QuotaManager::NotifyOriginInUse(const GURL
& origin
) {
970 DCHECK(io_thread_
->BelongsToCurrentThread());
971 origins_in_use_
[origin
]++;
974 void QuotaManager::NotifyOriginNoLongerInUse(const GURL
& origin
) {
975 DCHECK(io_thread_
->BelongsToCurrentThread());
976 DCHECK(IsOriginInUse(origin
));
977 int& count
= origins_in_use_
[origin
];
979 origins_in_use_
.erase(origin
);
982 void QuotaManager::DeleteOriginData(
983 const GURL
& origin
, StorageType type
, int quota_client_mask
,
984 const StatusCallback
& callback
) {
987 if (origin
.is_empty() || clients_
.empty()) {
988 callback
.Run(kQuotaStatusOk
);
992 DCHECK(origin
== origin
.GetOrigin());
993 OriginDataDeleter
* deleter
=
994 new OriginDataDeleter(this, origin
, type
, quota_client_mask
, callback
);
998 void QuotaManager::DeleteHostData(const std::string
& host
,
1000 int quota_client_mask
,
1001 const StatusCallback
& callback
) {
1004 if (host
.empty() || clients_
.empty()) {
1005 callback
.Run(kQuotaStatusOk
);
1009 HostDataDeleter
* deleter
=
1010 new HostDataDeleter(this, host
, type
, quota_client_mask
, callback
);
1014 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback
& callback
) {
1015 if (is_incognito_
) {
1016 callback
.Run(kQuotaStatusOk
, kIncognitoDefaultTemporaryQuota
);
1020 PostTaskAndReplyWithResult(
1023 base::Bind(get_disk_space_fn_
, profile_path_
),
1024 base::Bind(&QuotaManager::DidGetAvailableSpace
,
1025 weak_factory_
.GetWeakPtr(),
1029 void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback
& callback
) {
1030 if (temporary_quota_override_
> 0) {
1031 callback
.Run(kQuotaStatusOk
, temporary_quota_override_
);
1034 GetUsageAndQuotaInternal(
1035 GURL(), kStorageTypeTemporary
, true /* global */,
1036 base::Bind(&CallQuotaCallback
, callback
));
1039 void QuotaManager::SetTemporaryGlobalOverrideQuota(
1040 int64 new_quota
, const QuotaCallback
& callback
) {
1043 if (new_quota
< 0) {
1044 if (!callback
.is_null())
1045 callback
.Run(kQuotaErrorInvalidModification
, -1);
1050 if (callback
.is_null())
1051 callback
.Run(kQuotaErrorInvalidAccess
, -1);
1055 int64
* new_quota_ptr
= new int64(new_quota
);
1056 PostTaskAndReplyWithResultForDBThread(
1058 base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread
,
1059 base::Unretained(new_quota_ptr
)),
1060 base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota
,
1061 weak_factory_
.GetWeakPtr(),
1063 base::Owned(new_quota_ptr
)));
1066 void QuotaManager::GetPersistentHostQuota(const std::string
& host
,
1067 const QuotaCallback
& callback
) {
1070 // This could happen if we are called on file:///.
1071 // TODO(kinuko) We may want to respect --allow-file-access-from-files
1072 // command line switch.
1073 callback
.Run(kQuotaStatusOk
, 0);
1077 int64
* quota_ptr
= new int64(0);
1078 PostTaskAndReplyWithResultForDBThread(
1080 base::Bind(&GetPersistentHostQuotaOnDBThread
,
1082 base::Unretained(quota_ptr
)),
1083 base::Bind(&QuotaManager::DidGetPersistentHostQuota
,
1084 weak_factory_
.GetWeakPtr(),
1087 base::Owned(quota_ptr
)));
1090 void QuotaManager::SetPersistentHostQuota(const std::string
& host
,
1092 const QuotaCallback
& callback
) {
1095 // This could happen if we are called on file:///.
1096 callback
.Run(kQuotaErrorNotSupported
, 0);
1099 if (new_quota
< 0) {
1100 callback
.Run(kQuotaErrorInvalidModification
, -1);
1105 callback
.Run(kQuotaErrorInvalidAccess
, -1);
1109 int64
* new_quota_ptr
= new int64(new_quota
);
1110 PostTaskAndReplyWithResultForDBThread(
1112 base::Bind(&SetPersistentHostQuotaOnDBThread
,
1114 base::Unretained(new_quota_ptr
)),
1115 base::Bind(&QuotaManager::DidSetPersistentHostQuota
,
1116 weak_factory_
.GetWeakPtr(),
1119 base::Owned(new_quota_ptr
)));
1122 void QuotaManager::GetGlobalUsage(StorageType type
,
1123 const GlobalUsageCallback
& callback
) {
1125 GetUsageTracker(type
)->GetGlobalUsage(callback
);
1128 void QuotaManager::GetHostUsage(const std::string
& host
,
1130 const UsageCallback
& callback
) {
1132 GetUsageTracker(type
)->GetHostUsage(host
, callback
);
1135 void QuotaManager::GetStatistics(
1136 std::map
<std::string
, std::string
>* statistics
) {
1138 if (temporary_storage_evictor_
.get()) {
1139 std::map
<std::string
, int64
> stats
;
1140 temporary_storage_evictor_
->GetStatistics(&stats
);
1141 for (std::map
<std::string
, int64
>::iterator p
= stats
.begin();
1144 (*statistics
)[p
->first
] = base::Int64ToString(p
->second
);
1148 bool QuotaManager::IsStorageUnlimited(const GURL
& origin
,
1149 StorageType type
) const {
1150 // For syncable storage we should always enforce quota (since the
1151 // quota must be capped by the server limit).
1152 if (type
== kStorageTypeSyncable
)
1154 return special_storage_policy_
.get() &&
1155 special_storage_policy_
->IsStorageUnlimited(origin
);
1158 void QuotaManager::GetOriginsModifiedSince(StorageType type
,
1159 base::Time modified_since
,
1160 const GetOriginsCallback
& callback
) {
1162 GetModifiedSinceHelper
* helper
= new GetModifiedSinceHelper
;
1163 PostTaskAndReplyWithResultForDBThread(
1165 base::Bind(&GetModifiedSinceHelper::GetModifiedSinceOnDBThread
,
1166 base::Unretained(helper
),
1169 base::Bind(&GetModifiedSinceHelper::DidGetModifiedSince
,
1170 base::Owned(helper
),
1171 weak_factory_
.GetWeakPtr(),
1176 bool QuotaManager::ResetUsageTracker(StorageType type
) {
1177 DCHECK(GetUsageTracker(type
));
1178 if (GetUsageTracker(type
)->IsWorking())
1181 case kStorageTypeTemporary
:
1182 temporary_usage_tracker_
.reset(
1183 new UsageTracker(clients_
, kStorageTypeTemporary
,
1184 special_storage_policy_
));
1186 case kStorageTypePersistent
:
1187 persistent_usage_tracker_
.reset(
1188 new UsageTracker(clients_
, kStorageTypePersistent
,
1189 special_storage_policy_
));
1191 case kStorageTypeSyncable
:
1192 syncable_usage_tracker_
.reset(
1193 new UsageTracker(clients_
, kStorageTypeSyncable
,
1194 special_storage_policy_
));
1202 QuotaManager::~QuotaManager() {
1203 proxy_
->manager_
= NULL
;
1204 std::for_each(clients_
.begin(), clients_
.end(),
1205 std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed
));
1206 if (database_
.get())
1207 db_thread_
->DeleteSoon(FROM_HERE
, database_
.release());
1210 QuotaManager::EvictionContext::EvictionContext()
1211 : evicted_type(kStorageTypeUnknown
) {
1214 QuotaManager::EvictionContext::~EvictionContext() {
1217 void QuotaManager::LazyInitialize() {
1218 DCHECK(io_thread_
->BelongsToCurrentThread());
1219 if (database_
.get()) {
1220 // Initialization seems to be done already.
1224 // Use an empty path to open an in-memory only databse for incognito.
1225 database_
.reset(new QuotaDatabase(is_incognito_
? base::FilePath() :
1226 profile_path_
.AppendASCII(kDatabaseName
)));
1228 temporary_usage_tracker_
.reset(
1229 new UsageTracker(clients_
, kStorageTypeTemporary
,
1230 special_storage_policy_
));
1231 persistent_usage_tracker_
.reset(
1232 new UsageTracker(clients_
, kStorageTypePersistent
,
1233 special_storage_policy_
));
1234 syncable_usage_tracker_
.reset(
1235 new UsageTracker(clients_
, kStorageTypeSyncable
,
1236 special_storage_policy_
));
1238 int64
* temporary_quota_override
= new int64(-1);
1239 int64
* desired_available_space
= new int64(-1);
1240 PostTaskAndReplyWithResultForDBThread(
1242 base::Bind(&InitializeOnDBThread
,
1243 base::Unretained(temporary_quota_override
),
1244 base::Unretained(desired_available_space
)),
1245 base::Bind(&QuotaManager::DidInitialize
,
1246 weak_factory_
.GetWeakPtr(),
1247 base::Owned(temporary_quota_override
),
1248 base::Owned(desired_available_space
)));
1251 void QuotaManager::RegisterClient(QuotaClient
* client
) {
1252 DCHECK(!database_
.get());
1253 clients_
.push_back(client
);
1256 UsageTracker
* QuotaManager::GetUsageTracker(StorageType type
) const {
1258 case kStorageTypeTemporary
:
1259 return temporary_usage_tracker_
.get();
1260 case kStorageTypePersistent
:
1261 return persistent_usage_tracker_
.get();
1262 case kStorageTypeSyncable
:
1263 return syncable_usage_tracker_
.get();
1270 void QuotaManager::GetCachedOrigins(
1271 StorageType type
, std::set
<GURL
>* origins
) {
1274 DCHECK(GetUsageTracker(type
));
1275 GetUsageTracker(type
)->GetCachedOrigins(origins
);
1278 void QuotaManager::NotifyStorageAccessedInternal(
1279 QuotaClient::ID client_id
,
1280 const GURL
& origin
, StorageType type
,
1281 base::Time accessed_time
) {
1283 if (type
== kStorageTypeTemporary
&& !lru_origin_callback_
.is_null()) {
1284 // Record the accessed origins while GetLRUOrigin task is runing
1285 // to filter out them from eviction.
1286 access_notified_origins_
.insert(origin
);
1291 PostTaskAndReplyWithResultForDBThread(
1293 base::Bind(&UpdateAccessTimeOnDBThread
, origin
, type
, accessed_time
),
1294 base::Bind(&QuotaManager::DidDatabaseWork
,
1295 weak_factory_
.GetWeakPtr()));
1298 void QuotaManager::NotifyStorageModifiedInternal(
1299 QuotaClient::ID client_id
,
1303 base::Time modified_time
) {
1305 GetUsageTracker(type
)->UpdateUsageCache(client_id
, origin
, delta
);
1307 PostTaskAndReplyWithResultForDBThread(
1309 base::Bind(&UpdateModifiedTimeOnDBThread
, origin
, type
, modified_time
),
1310 base::Bind(&QuotaManager::DidDatabaseWork
,
1311 weak_factory_
.GetWeakPtr()));
1314 void QuotaManager::GetUsageAndQuotaInternal(
1315 const GURL
& origin
, StorageType type
, bool global
,
1316 const UsageAndQuotaDispatcherCallback
& callback
) {
1319 StorageType requested_type
= type
;
1320 if (type
== kStorageTypeUnknown
) {
1321 // Quota only supports temporary/persistent types.
1322 callback
.Run(kQuotaErrorNotSupported
, QuotaAndUsage());
1326 // Special internal type for querying global usage and quota.
1327 const int kStorageTypeTemporaryGlobal
= kStorageTypeTemporary
+ 100;
1329 DCHECK_EQ(kStorageTypeTemporary
, type
);
1330 type
= static_cast<StorageType
>(kStorageTypeTemporaryGlobal
);
1333 std::string host
= net::GetHostOrSpecFromURL(origin
);
1334 HostAndType host_and_type
= std::make_pair(host
, type
);
1335 UsageAndQuotaDispatcherTaskMap::iterator found
=
1336 usage_and_quota_dispatchers_
.find(host_and_type
);
1337 if (found
== usage_and_quota_dispatchers_
.end()) {
1338 UsageAndQuotaDispatcherTask
* dispatcher
=
1339 UsageAndQuotaDispatcherTask::Create(this, global
, host_and_type
);
1340 found
= usage_and_quota_dispatchers_
.insert(
1341 std::make_pair(host_and_type
, dispatcher
)).first
;
1343 // Start the dispatcher if it is the first one and temporary_quota_override
1344 // is already initialized iff the requested type is temporary.
1345 // (The first dispatcher task for temporary will be kicked in
1346 // DidInitialize if temporary_quota_initialized_ is false here.)
1347 if (found
->second
->AddCallback(callback
) &&
1348 (requested_type
!= kStorageTypeTemporary
||
1349 temporary_quota_initialized_
)) {
1350 found
->second
->Start();
1354 void QuotaManager::DumpQuotaTable(const DumpQuotaTableCallback
& callback
) {
1355 DumpQuotaTableHelper
* helper
= new DumpQuotaTableHelper
;
1356 PostTaskAndReplyWithResultForDBThread(
1358 base::Bind(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread
,
1359 base::Unretained(helper
)),
1360 base::Bind(&DumpQuotaTableHelper::DidDumpQuotaTable
,
1361 base::Owned(helper
),
1362 weak_factory_
.GetWeakPtr(),
1366 void QuotaManager::DumpOriginInfoTable(
1367 const DumpOriginInfoTableCallback
& callback
) {
1368 DumpOriginInfoTableHelper
* helper
= new DumpOriginInfoTableHelper
;
1369 PostTaskAndReplyWithResultForDBThread(
1371 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread
,
1372 base::Unretained(helper
)),
1373 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable
,
1374 base::Owned(helper
),
1375 weak_factory_
.GetWeakPtr(),
1379 void QuotaManager::StartEviction() {
1380 DCHECK(!temporary_storage_evictor_
.get());
1381 temporary_storage_evictor_
.reset(new QuotaTemporaryStorageEvictor(
1382 this, kEvictionIntervalInMilliSeconds
));
1383 if (desired_available_space_
>= 0)
1384 temporary_storage_evictor_
->set_min_available_disk_space_to_start_eviction(
1385 desired_available_space_
);
1386 temporary_storage_evictor_
->Start();
1389 void QuotaManager::DeleteOriginFromDatabase(
1390 const GURL
& origin
, StorageType type
) {
1395 PostTaskAndReplyWithResultForDBThread(
1397 base::Bind(&DeleteOriginInfoOnDBThread
, origin
, type
),
1398 base::Bind(&QuotaManager::DidDatabaseWork
,
1399 weak_factory_
.GetWeakPtr()));
1402 void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status
) {
1403 DCHECK(io_thread_
->BelongsToCurrentThread());
1405 // We only try evict origins that are not in use, so basically
1406 // deletion attempt for eviction should not fail. Let's record
1407 // the origin if we get error and exclude it from future eviction
1408 // if the error happens consistently (> kThresholdOfErrorsToBeBlacklisted).
1409 if (status
!= kQuotaStatusOk
)
1410 origins_in_error_
[eviction_context_
.evicted_origin
]++;
1412 eviction_context_
.evict_origin_data_callback
.Run(status
);
1413 eviction_context_
.evict_origin_data_callback
.Reset();
1416 void QuotaManager::ReportHistogram() {
1417 GetGlobalUsage(kStorageTypeTemporary
,
1419 &QuotaManager::DidGetTemporaryGlobalUsageForHistogram
,
1420 weak_factory_
.GetWeakPtr()));
1421 GetGlobalUsage(kStorageTypePersistent
,
1423 &QuotaManager::DidGetPersistentGlobalUsageForHistogram
,
1424 weak_factory_
.GetWeakPtr()));
1427 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
1430 int64 unlimited_usage
) {
1431 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfTemporaryStorage", usage
);
1433 std::set
<GURL
> origins
;
1434 GetCachedOrigins(type
, &origins
);
1436 size_t num_origins
= origins
.size();
1437 size_t protected_origins
= 0;
1438 size_t unlimited_origins
= 0;
1439 CountOriginType(origins
, special_storage_policy_
,
1440 &protected_origins
, &unlimited_origins
);
1442 UMA_HISTOGRAM_COUNTS("Quota.NumberOfTemporaryStorageOrigins",
1444 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedTemporaryStorageOrigins",
1446 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedTemporaryStorageOrigins",
1450 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
1453 int64 unlimited_usage
) {
1454 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage
);
1456 std::set
<GURL
> origins
;
1457 GetCachedOrigins(type
, &origins
);
1459 size_t num_origins
= origins
.size();
1460 size_t protected_origins
= 0;
1461 size_t unlimited_origins
= 0;
1462 CountOriginType(origins
, special_storage_policy_
,
1463 &protected_origins
, &unlimited_origins
);
1465 UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
1467 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
1469 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
1473 void QuotaManager::GetLRUOrigin(
1475 const GetLRUOriginCallback
& callback
) {
1477 // This must not be called while there's an in-flight task.
1478 DCHECK(lru_origin_callback_
.is_null());
1479 lru_origin_callback_
= callback
;
1481 lru_origin_callback_
.Run(GURL());
1482 lru_origin_callback_
.Reset();
1486 std::set
<GURL
>* exceptions
= new std::set
<GURL
>;
1487 for (std::map
<GURL
, int>::const_iterator p
= origins_in_use_
.begin();
1488 p
!= origins_in_use_
.end();
1491 exceptions
->insert(p
->first
);
1493 for (std::map
<GURL
, int>::const_iterator p
= origins_in_error_
.begin();
1494 p
!= origins_in_error_
.end();
1496 if (p
->second
> QuotaManager::kThresholdOfErrorsToBeBlacklisted
)
1497 exceptions
->insert(p
->first
);
1500 GURL
* url
= new GURL
;
1501 PostTaskAndReplyWithResultForDBThread(
1503 base::Bind(&GetLRUOriginOnDBThread
,
1505 base::Owned(exceptions
),
1506 special_storage_policy_
,
1507 base::Unretained(url
)),
1508 base::Bind(&QuotaManager::DidGetLRUOrigin
,
1509 weak_factory_
.GetWeakPtr(),
1513 void QuotaManager::EvictOriginData(
1516 const EvictOriginDataCallback
& callback
) {
1517 DCHECK(io_thread_
->BelongsToCurrentThread());
1518 DCHECK_EQ(type
, kStorageTypeTemporary
);
1520 eviction_context_
.evicted_origin
= origin
;
1521 eviction_context_
.evicted_type
= type
;
1522 eviction_context_
.evict_origin_data_callback
= callback
;
1524 DeleteOriginData(origin
, type
, QuotaClient::kAllClientsMask
,
1525 base::Bind(&QuotaManager::DidOriginDataEvicted
,
1526 weak_factory_
.GetWeakPtr()));
1529 void QuotaManager::GetUsageAndQuotaForEviction(
1530 const GetUsageAndQuotaForEvictionCallback
& callback
) {
1531 DCHECK(io_thread_
->BelongsToCurrentThread());
1532 GetUsageAndQuotaInternal(
1533 GURL(), kStorageTypeTemporary
, true /* global */, callback
);
1536 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
1537 const QuotaCallback
& callback
,
1538 const int64
* new_quota
,
1540 QuotaStatusCode status
= kQuotaErrorInvalidAccess
;
1541 DidDatabaseWork(success
);
1543 temporary_quota_override_
= *new_quota
;
1544 status
= kQuotaStatusOk
;
1547 if (callback
.is_null())
1550 callback
.Run(status
, *new_quota
);
1553 void QuotaManager::DidGetPersistentHostQuota(const QuotaCallback
& callback
,
1554 const std::string
& host
,
1557 DidDatabaseWork(success
);
1558 callback
.Run(kQuotaStatusOk
, *quota
);
1561 void QuotaManager::DidSetPersistentHostQuota(const std::string
& host
,
1562 const QuotaCallback
& callback
,
1563 const int64
* new_quota
,
1565 DidDatabaseWork(success
);
1566 callback
.Run(success
? kQuotaStatusOk
: kQuotaErrorInvalidAccess
, *new_quota
);
1569 void QuotaManager::DidInitialize(int64
* temporary_quota_override
,
1570 int64
* desired_available_space
,
1572 temporary_quota_override_
= *temporary_quota_override
;
1573 desired_available_space_
= *desired_available_space
;
1574 temporary_quota_initialized_
= true;
1575 DidDatabaseWork(success
);
1577 histogram_timer_
.Start(FROM_HERE
,
1578 base::TimeDelta::FromMilliseconds(
1579 kReportHistogramInterval
),
1580 this, &QuotaManager::ReportHistogram
);
1582 DCHECK(temporary_quota_initialized_
);
1584 // Kick the tasks that have been waiting for the
1585 // temporary_quota_initialized_ to be initialized (if there're any).
1586 for (UsageAndQuotaDispatcherTaskMap::iterator iter
=
1587 usage_and_quota_dispatchers_
.begin();
1588 iter
!= usage_and_quota_dispatchers_
.end(); ++iter
) {
1589 if (iter
->second
->IsStartable())
1590 iter
->second
->Start();
1593 // Kick the first GetTemporaryGlobalQuota. This internally fetches (and
1594 // caches) the usage of all origins and checks the available disk space.
1595 GetTemporaryGlobalQuota(
1596 base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota
,
1597 weak_factory_
.GetWeakPtr()));
1600 void QuotaManager::DidGetLRUOrigin(const GURL
* origin
,
1602 DidDatabaseWork(success
);
1603 // Make sure the returned origin is (still) not in the origin_in_use_ set
1604 // and has not been accessed since we posted the task.
1605 if (origins_in_use_
.find(*origin
) != origins_in_use_
.end() ||
1606 access_notified_origins_
.find(*origin
) != access_notified_origins_
.end())
1607 lru_origin_callback_
.Run(GURL());
1609 lru_origin_callback_
.Run(*origin
);
1610 access_notified_origins_
.clear();
1611 lru_origin_callback_
.Reset();
1614 void QuotaManager::DidGetInitialTemporaryGlobalQuota(
1615 QuotaStatusCode status
, int64 quota_unused
) {
1616 if (eviction_disabled_
)
1619 std::set
<GURL
>* origins
= new std::set
<GURL
>;
1620 temporary_usage_tracker_
->GetCachedOrigins(origins
);
1621 // This will call the StartEviction() when initial origin registration
1623 PostTaskAndReplyWithResultForDBThread(
1625 base::Bind(&InitializeTemporaryOriginsInfoOnDBThread
,
1626 base::Owned(origins
)),
1627 base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo
,
1628 weak_factory_
.GetWeakPtr()));
1631 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success
) {
1632 DidDatabaseWork(success
);
1637 void QuotaManager::DidGetAvailableSpace(const AvailableSpaceCallback
& callback
,
1639 callback
.Run(kQuotaStatusOk
, space
);
1642 void QuotaManager::DidDatabaseWork(bool success
) {
1643 db_disabled_
= !success
;
1646 void QuotaManager::DeleteOnCorrectThread() const {
1647 if (!io_thread_
->BelongsToCurrentThread() &&
1648 io_thread_
->DeleteSoon(FROM_HERE
, this)) {
1654 void QuotaManager::PostTaskAndReplyWithResultForDBThread(
1655 const tracked_objects::Location
& from_here
,
1656 const base::Callback
<bool(QuotaDatabase
*)>& task
,
1657 const base::Callback
<void(bool)>& reply
) {
1658 // Deleting manager will post another task to DB thread to delete
1659 // |database_|, therefore we can be sure that database_ is alive when this
1661 base::PostTaskAndReplyWithResult(
1664 base::Bind(task
, base::Unretained(database_
.get())),
1668 // QuotaManagerProxy ----------------------------------------------------------
1670 void QuotaManagerProxy::RegisterClient(QuotaClient
* client
) {
1671 if (!io_thread_
->BelongsToCurrentThread() &&
1672 io_thread_
->PostTask(
1674 base::Bind(&QuotaManagerProxy::RegisterClient
, this, client
))) {
1679 manager_
->RegisterClient(client
);
1681 client
->OnQuotaManagerDestroyed();
1684 void QuotaManagerProxy::NotifyStorageAccessed(
1685 QuotaClient::ID client_id
,
1688 if (!io_thread_
->BelongsToCurrentThread()) {
1689 io_thread_
->PostTask(
1691 base::Bind(&QuotaManagerProxy::NotifyStorageAccessed
, this, client_id
,
1697 manager_
->NotifyStorageAccessed(client_id
, origin
, type
);
1700 void QuotaManagerProxy::NotifyStorageModified(
1701 QuotaClient::ID client_id
,
1705 if (!io_thread_
->BelongsToCurrentThread()) {
1706 io_thread_
->PostTask(
1708 base::Bind(&QuotaManagerProxy::NotifyStorageModified
, this, client_id
,
1709 origin
, type
, delta
));
1714 manager_
->NotifyStorageModified(client_id
, origin
, type
, delta
);
1717 void QuotaManagerProxy::NotifyOriginInUse(
1718 const GURL
& origin
) {
1719 if (!io_thread_
->BelongsToCurrentThread()) {
1720 io_thread_
->PostTask(
1722 base::Bind(&QuotaManagerProxy::NotifyOriginInUse
, this, origin
));
1727 manager_
->NotifyOriginInUse(origin
);
1730 void QuotaManagerProxy::NotifyOriginNoLongerInUse(
1731 const GURL
& origin
) {
1732 if (!io_thread_
->BelongsToCurrentThread()) {
1733 io_thread_
->PostTask(
1735 base::Bind(&QuotaManagerProxy::NotifyOriginNoLongerInUse
, this,
1740 manager_
->NotifyOriginNoLongerInUse(origin
);
1743 QuotaManager
* QuotaManagerProxy::quota_manager() const {
1744 DCHECK(!io_thread_
|| io_thread_
->BelongsToCurrentThread());
1748 QuotaManagerProxy::QuotaManagerProxy(
1749 QuotaManager
* manager
, base::SingleThreadTaskRunner
* io_thread
)
1750 : manager_(manager
), io_thread_(io_thread
) {
1753 QuotaManagerProxy::~QuotaManagerProxy() {
1756 } // namespace quota