summaryrefslogtreecommitdiffstats
path: root/webkit/quota/quota_manager.cc
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-17 11:48:21 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-17 11:48:21 +0000
commit3f220df6bcdc125049cfdeb0ee6db58d9d0746fc (patch)
treec90da7a3a1c01783a938f9ba433a39f347979637 /webkit/quota/quota_manager.cc
parent4aa8c42f6198b4dbe1e85b00a93ba6a87e29d778 (diff)
downloadchromium_src-3f220df6bcdc125049cfdeb0ee6db58d9d0746fc.zip
chromium_src-3f220df6bcdc125049cfdeb0ee6db58d9d0746fc.tar.gz
chromium_src-3f220df6bcdc125049cfdeb0ee6db58d9d0746fc.tar.bz2
Change default global temporary quota limit to 50% of available space
BUG=94363 TEST=test_shell_tests:Quota* Review URL: http://codereview.chromium.org/7806014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105791 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/quota/quota_manager.cc')
-rw-r--r--webkit/quota/quota_manager.cc623
1 files changed, 310 insertions, 313 deletions
diff --git a/webkit/quota/quota_manager.cc b/webkit/quota/quota_manager.cc
index 4ade94f..ad71c02 100644
--- a/webkit/quota/quota_manager.cc
+++ b/webkit/quota/quota_manager.cc
@@ -36,38 +36,12 @@ namespace quota {
namespace {
-const char kEnableQuotaEviction[] = "enable-quota-eviction";
const int64 kMBytes = 1024 * 1024;
const int kMinutesInMilliSeconds = 60 * 1000;
-// Returns the initial size of the temporary storage quota.
-// (This just gives a default initial size; once its initial size is determined
-// it won't automatically be adjusted.)
-int64 GetInitialTemporaryStorageQuotaSize(const FilePath& path,
- bool is_incognito) {
- int64 free_space = base::SysInfo::AmountOfFreeDiskSpace(path);
- UMA_HISTOGRAM_MBYTES("Quota.FreeDiskSpaceForProfile", free_space);
-
- // Returns 0 (disables the temporary storage) if the available space is
- // less than the twice of the default quota size.
- if (free_space < QuotaManager::kTemporaryStorageQuotaDefaultSize * 2)
- return 0;
-
- if (is_incognito)
- return QuotaManager::kIncognitoDefaultTemporaryQuota;
-
- // Returns the default quota size while it is more than 5% of the
- // available space.
- if (free_space < QuotaManager::kTemporaryStorageQuotaDefaultSize * 20)
- return QuotaManager::kTemporaryStorageQuotaDefaultSize;
-
- // Returns the 5% of the available space while it does not exceed the
- // maximum quota size (1GB).
- if (free_space < QuotaManager::kTemporaryStorageQuotaMaxSize * 20)
- return free_space / 20;
-
- return QuotaManager::kTemporaryStorageQuotaMaxSize;
-}
+const int64 kIncognitoDefaultTemporaryQuota = 50 * kMBytes;
+const int64 kReportHistogramInterval = 60 * 60 * 1000; // 1 hour
+const double kTemporaryQuotaRatioToAvail = 0.5; // 50%
void CountOriginType(const std::set<GURL>& origins,
SpecialStoragePolicy* policy,
@@ -91,12 +65,6 @@ void CountOriginType(const std::set<GURL>& origins,
} // anonymous namespace
-// TODO(kinuko): We will need to have different sizes for different platforms
-// (e.g. larger for desktop etc) and may want to have them in preferences.
-const int64 QuotaManager::kTemporaryStorageQuotaDefaultSize = 50 * kMBytes;
-const int64 QuotaManager::kTemporaryStorageQuotaMaxSize = 1 * 1024 * kMBytes;
-const int64 QuotaManager::kIncognitoDefaultTemporaryQuota = 50 * kMBytes;
-
const int QuotaManager::kPerHostTemporaryPortion = 5; // 20%
const char QuotaManager::kDatabaseName[] = "QuotaManager";
@@ -106,94 +74,114 @@ const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3;
const int QuotaManager::kEvictionIntervalInMilliSeconds =
30 * kMinutesInMilliSeconds;
-const base::TimeDelta QuotaManager::kReportHistogramInterval =
- base::TimeDelta::FromMilliseconds(60 * 60 * 1000); // 1 hour
+// Callback translators.
+void CallGetUsageAndQuotaCallback(
+ QuotaManager::GetUsageAndQuotaCallback* callback,
+ bool unlimited,
+ QuotaStatusCode status,
+ const QuotaAndUsage& quota_and_usage) {
+ int64 usage =
+ unlimited ? quota_and_usage.unlimited_usage : quota_and_usage.usage;
+ int64 quota = unlimited ? kint64max : quota_and_usage.quota;
+ callback->Run(status, usage, quota);
+ delete callback;
+}
+
+void CallQuotaCallback(
+ QuotaCallback* callback,
+ StorageType type,
+ QuotaStatusCode status,
+ const QuotaAndUsage& quota_and_usage) {
+ callback->Run(status, type, quota_and_usage.quota);
+ delete callback;
+}
// This class is for posting GetUsage/GetQuota tasks, gathering
// results and dispatching GetAndQuota callbacks.
// This class is self-destructed.
class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask {
public:
- typedef std::deque<GetUsageAndQuotaCallback*> CallbackList;
+ typedef UsageAndQuotaDispatcherCallback Callback;
+ typedef std::deque<Callback> CallbackList;
static UsageAndQuotaDispatcherTask* Create(
- QuotaManager* manager, const std::string& host, StorageType type);
+ QuotaManager* manager,
+ bool global,
+ const HostAndType& host_and_type);
// Returns true if it is the first call for this task; which means
// the caller needs to call Start().
- bool AddCallback(GetUsageAndQuotaCallback* callback, bool unlimited) {
- if (unlimited)
- unlimited_callbacks_.push_back(callback);
- else
- callbacks_.push_back(callback);
- return (callbacks_.size() + unlimited_callbacks_.size() == 1);
+ bool AddCallback(const Callback& callback) {
+ callbacks_.push_back(callback);
+ return (callbacks_.size() == 1);
}
- void DidGetGlobalUsage(StorageType type, int64 usage,
- int64 unlimited_usage) {
- DCHECK_EQ(type_, type);
+ void DidGetGlobalUsage(StorageType type, int64 usage, int64 unlimited_usage) {
+ DCHECK_EQ(this->type(), type);
DCHECK_GE(usage, unlimited_usage);
+ if (quota_status_ == kQuotaStatusUnknown)
+ quota_status_ = kQuotaStatusOk;
global_usage_ = usage;
global_unlimited_usage_ = unlimited_usage;
CheckCompleted();
}
- void DidGetHostUsage(const std::string& host,
- StorageType type,
- int64 usage) {
- DCHECK_EQ(host_, host);
- DCHECK_EQ(type_, type);
+ void DidGetHostUsage(const std::string& host, StorageType type, int64 usage) {
+ DCHECK_EQ(this->host(), host);
+ DCHECK_EQ(this->type(), type);
host_usage_ = usage;
CheckCompleted();
}
- void DidGetGlobalQuota(QuotaStatusCode status,
- StorageType type,
- int64 quota) {
- DCHECK_EQ(type_, type);
- quota_status_ = status;
- quota_ = quota;
- CheckCompleted();
- }
-
void DidGetHostQuota(QuotaStatusCode status,
const std::string& host,
StorageType type,
- int64 quota) {
- DCHECK_EQ(host_, host);
- DCHECK_EQ(type_, type);
- quota_status_ = status;
- quota_ = quota;
+ int64 host_quota) {
+ DCHECK_EQ(this->host(), host);
+ DCHECK_EQ(this->type(), type);
+ if (quota_status_ == kQuotaStatusUnknown || quota_status_ == kQuotaStatusOk)
+ quota_status_ = status;
+ host_quota_ = host_quota;
CheckCompleted();
}
+ void DidGetAvailableSpace(QuotaStatusCode status, int64 space) {
+ DCHECK_GE(space, 0);
+ if (quota_status_ == kQuotaStatusUnknown || quota_status_ == kQuotaStatusOk)
+ quota_status_ = status;
+ available_space_ = space;
+ CheckCompleted();
+ }
+
+ bool IsStartable() const {
+ return !started_ && !callbacks_.empty();
+ }
+
protected:
UsageAndQuotaDispatcherTask(
QuotaManager* manager,
- const std::string& host,
- StorageType type)
+ const HostAndType& host_and_type)
: QuotaTask(manager),
- host_(host),
- type_(type),
- quota_(-1),
+ host_and_type_(host_and_type),
+ started_(false),
+ host_quota_(-1),
global_usage_(-1),
global_unlimited_usage_(-1),
host_usage_(-1),
+ available_space_(-1),
quota_status_(kQuotaStatusUnknown),
waiting_callbacks_(1),
callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
- virtual ~UsageAndQuotaDispatcherTask() {
- STLDeleteContainerPointers(callbacks_.begin(), callbacks_.end());
- STLDeleteContainerPointers(unlimited_callbacks_.begin(),
- unlimited_callbacks_.end());
- }
+ virtual ~UsageAndQuotaDispatcherTask() {}
// Subclasses must implement them.
virtual void RunBody() = 0;
virtual void DispatchCallbacks() = 0;
virtual void Run() OVERRIDE {
+ DCHECK(!started_);
+ started_ = true;
RunBody();
// We initialize waiting_callbacks to 1 so that we won't run
// the completion callback until here even some of the callbacks
@@ -202,8 +190,7 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask {
}
virtual void Aborted() OVERRIDE {
- CallCallbacksAndClear(&callbacks_, kQuotaErrorAbort, 0, 0);
- CallCallbacksAndClear(&unlimited_callbacks_, kQuotaErrorAbort, 0, 0);
+ CallCallbacksAndClear(kQuotaErrorAbort, 0, 0, 0, 0);
DeleteSoon();
}
@@ -212,29 +199,50 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask {
}
void CallCallbacksAndClear(
- CallbackList* callbacks, QuotaStatusCode status,
- int64 usage, int64 quota) {
- for (CallbackList::iterator iter = callbacks->begin();
- iter != callbacks->end(); ++iter) {
- (*iter)->Run(status, usage, quota);
- delete *iter;
+ QuotaStatusCode status,
+ int64 usage, int64 unlimited_usage, int64 quota,
+ int64 available_space) {
+ QuotaAndUsage qau = { usage, unlimited_usage, quota, available_space };
+ for (CallbackList::iterator iter = callbacks_.begin();
+ iter != callbacks_.end(); ++iter) {
+ (*iter).Run(status, qau);
}
- callbacks->clear();
+ callbacks_.clear();
}
QuotaManager* manager() const {
return static_cast<QuotaManager*>(observer());
}
- std::string host() const { return host_; }
- StorageType type() const { return type_; }
- int64 quota() const { return quota_; }
+ std::string host() const { return host_and_type_.first; }
+ virtual StorageType type() const { return host_and_type_.second; }
+ int64 host_quota() const { return host_quota_; }
int64 global_usage() const { return global_usage_; }
int64 global_unlimited_usage() const { return global_unlimited_usage_; }
int64 host_usage() const { return host_usage_; }
+ int64 available_space() const { return available_space_; }
QuotaStatusCode quota_status() const { return quota_status_; }
CallbackList& callbacks() { return callbacks_; }
- CallbackList& unlimited_callbacks() { return unlimited_callbacks_; }
+
+ // The main logic that determines the temporary global quota.
+ int64 temporary_global_quota() const {
+ DCHECK_EQ(type(), kStorageTypeTemporary);
+ DCHECK(manager());
+ DCHECK_GE(global_usage(), global_unlimited_usage());
+ if (manager()->temporary_quota_override_ > 0) {
+ // If the user has specified an explicit temporary quota, use the value.
+ return manager()->temporary_quota_override_;
+ }
+ int64 limited_usage = global_usage() - global_unlimited_usage();
+ int64 avail_space = available_space();
+ if (avail_space < kint64max - limited_usage) {
+ // We basically calculate the temporary quota by
+ // [available_space + space_used_for_temp] * kTempQuotaRatio,
+ // but make sure we'll have no overflow.
+ avail_space += limited_usage;
+ }
+ return avail_space * kTemporaryQuotaRatioToAvail;
+ }
// Subclasses must call following methods to create a new 'waitable'
// callback, which decrements waiting_callbacks when it is called.
@@ -248,15 +256,15 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask {
return callback_factory_.NewCallback(
&UsageAndQuotaDispatcherTask::DidGetHostUsage);
}
- QuotaCallback* NewWaitableGlobalQuotaCallback() {
+ HostQuotaCallback* NewWaitableHostQuotaCallback() {
++waiting_callbacks_;
return callback_factory_.NewCallback(
- &UsageAndQuotaDispatcherTask::DidGetGlobalQuota);
+ &UsageAndQuotaDispatcherTask::DidGetHostQuota);
}
- HostQuotaCallback* NewWaitableHostQuotaCallback() {
+ AvailableSpaceCallback* NewWaitableAvailableSpaceCallback() {
++waiting_callbacks_;
return callback_factory_.NewCallback(
- &UsageAndQuotaDispatcherTask::DidGetHostQuota);
+ &UsageAndQuotaDispatcherTask::DidGetAvailableSpace);
}
private:
@@ -264,26 +272,25 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask {
if (--waiting_callbacks_ <= 0) {
DispatchCallbacks();
DCHECK(callbacks_.empty());
- DCHECK(unlimited_callbacks_.empty());
UsageAndQuotaDispatcherTaskMap& dispatcher_map =
manager()->usage_and_quota_dispatchers_;
- DCHECK(dispatcher_map.find(std::make_pair(host_, type_)) !=
- dispatcher_map.end());
- dispatcher_map.erase(std::make_pair(host_, type_));
+ DCHECK(dispatcher_map.find(host_and_type_) != dispatcher_map.end());
+ dispatcher_map.erase(host_and_type_);
CallCompleted();
}
}
const std::string host_;
- const StorageType type_;
- int64 quota_;
+ const HostAndType host_and_type_;
+ bool started_;
+ int64 host_quota_;
int64 global_usage_;
int64 global_unlimited_usage_;
int64 host_usage_;
+ int64 available_space_;
QuotaStatusCode quota_status_;
CallbackList callbacks_;
- CallbackList unlimited_callbacks_;
int waiting_callbacks_;
ScopedCallbackFactory<UsageAndQuotaDispatcherTask> callback_factory_;
@@ -355,8 +362,8 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForTemporary
: public QuotaManager::UsageAndQuotaDispatcherTask {
public:
UsageAndQuotaDispatcherTaskForTemporary(
- QuotaManager* manager, const std::string& host)
- : UsageAndQuotaDispatcherTask(manager, host, kStorageTypeTemporary) {}
+ QuotaManager* manager, const HostAndType& host_and_type)
+ : UsageAndQuotaDispatcherTask(manager, host_and_type) {}
protected:
virtual void RunBody() OVERRIDE {
@@ -364,34 +371,24 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForTemporary
NewWaitableGlobalUsageCallback());
manager()->temporary_usage_tracker_->GetHostUsage(
host(), NewWaitableHostUsageCallback());
- manager()->GetTemporaryGlobalQuota(NewWaitableGlobalQuotaCallback());
+ manager()->GetAvailableSpace(NewWaitableAvailableSpaceCallback());
}
virtual void DispatchCallbacks() OVERRIDE {
- // Due to a mismatch of models between same-origin (required by stds) vs
- // per-host (as this info is viewed in the UI) vs the extension systems
- // notion of webextents (the basis of granting unlimited rights),
- // we can end up with both 'unlimited' and 'limited' callbacks to invoke.
- // Should be rare, but it can happen.
-
- CallCallbacksAndClear(&unlimited_callbacks(), quota_status(),
- host_usage(), kint64max);
-
- if (!callbacks().empty()) {
- // Allow an individual host to utilize a fraction of the total
- // pool available for temp storage.
- int64 host_quota = quota() / kPerHostTemporaryPortion;
-
- // But if total temp usage is over-budget, stop letting new data in
- // until we reclaim space.
- DCHECK_GE(global_usage(), global_unlimited_usage());
- int64 limited_global_usage = global_usage() - global_unlimited_usage();
- if (limited_global_usage > quota())
- host_quota = std::min(host_quota, host_usage());
-
- CallCallbacksAndClear(&callbacks(), quota_status(),
- host_usage(), host_quota);
- }
+ // Allow an individual host to utilize a fraction of the total
+ // pool available for temp storage.
+ int64 host_quota = temporary_global_quota() / kPerHostTemporaryPortion;
+
+ // But if total temp usage is over-budget, stop letting new data in
+ // until we reclaim space.
+ DCHECK_GE(global_usage(), global_unlimited_usage());
+ int64 limited_global_usage = global_usage() - global_unlimited_usage();
+ if (limited_global_usage > temporary_global_quota())
+ host_quota = std::min(host_quota, host_usage());
+
+ CallCallbacksAndClear(quota_status(),
+ host_usage(), host_usage(), host_quota,
+ available_space());
}
};
@@ -399,8 +396,8 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForPersistent
: public QuotaManager::UsageAndQuotaDispatcherTask {
public:
UsageAndQuotaDispatcherTaskForPersistent(
- QuotaManager* manager, const std::string& host)
- : UsageAndQuotaDispatcherTask(manager, host, kStorageTypePersistent) {}
+ QuotaManager* manager, const HostAndType& host_and_type)
+ : UsageAndQuotaDispatcherTask(manager, host_and_type) {}
protected:
virtual void RunBody() OVERRIDE {
@@ -411,24 +408,51 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForPersistent
}
virtual void DispatchCallbacks() OVERRIDE {
- CallCallbacksAndClear(&callbacks(), quota_status(),
- host_usage(), quota());
- CallCallbacksAndClear(&unlimited_callbacks(), quota_status(),
- host_usage(), kint64max);
+ CallCallbacksAndClear(quota_status(),
+ host_usage(), host_usage(), host_quota(),
+ available_space());
}
};
+class QuotaManager::UsageAndQuotaDispatcherTaskForTemporaryGlobal
+ : public QuotaManager::UsageAndQuotaDispatcherTask {
+ public:
+ UsageAndQuotaDispatcherTaskForTemporaryGlobal(
+ QuotaManager* manager, const HostAndType& host_and_type)
+ : UsageAndQuotaDispatcherTask(manager, host_and_type) {}
+
+ protected:
+ virtual void RunBody() OVERRIDE {
+ manager()->temporary_usage_tracker_->GetGlobalUsage(
+ NewWaitableGlobalUsageCallback());
+ manager()->GetAvailableSpace(NewWaitableAvailableSpaceCallback());
+ }
+
+ virtual void DispatchCallbacks() OVERRIDE {
+ CallCallbacksAndClear(quota_status(),
+ global_usage(), global_unlimited_usage(),
+ temporary_global_quota(),
+ available_space());
+ }
+
+ virtual StorageType type() const { return kStorageTypeTemporary; }
+};
+
// static
QuotaManager::UsageAndQuotaDispatcherTask*
QuotaManager::UsageAndQuotaDispatcherTask::Create(
- QuotaManager* manager, const std::string& host, StorageType type) {
- switch (type) {
+ QuotaManager* manager, bool global,
+ const QuotaManager::HostAndType& host_and_type) {
+ if (global)
+ return new UsageAndQuotaDispatcherTaskForTemporaryGlobal(
+ manager, host_and_type);
+ switch (host_and_type.second) {
case kStorageTypeTemporary:
return new UsageAndQuotaDispatcherTaskForTemporary(
- manager, host);
+ manager, host_and_type);
case kStorageTypePersistent:
return new UsageAndQuotaDispatcherTaskForPersistent(
- manager, host);
+ manager, host_and_type);
default:
NOTREACHED();
}
@@ -534,83 +558,72 @@ class QuotaManager::DatabaseTaskBase : public QuotaThreadTask {
class QuotaManager::InitializeTask : public QuotaManager::DatabaseTaskBase {
public:
- InitializeTask(
- QuotaManager* manager,
- const FilePath& profile_path,
- bool is_incognito)
+ InitializeTask(QuotaManager* manager)
: DatabaseTaskBase(manager),
- profile_path_(profile_path),
- is_incognito_(is_incognito),
- need_initialize_origins_(false),
- temporary_storage_quota_(-1) {
+ temporary_quota_override_(-1),
+ desired_available_space_(-1) {
+ DCHECK(manager);
}
protected:
virtual void RunOnTargetThread() OVERRIDE {
- // Initializes the global temporary quota.
- if (!database()->GetGlobalQuota(
- kStorageTypeTemporary, &temporary_storage_quota_)) {
- // If the temporary storage quota size has not been initialized,
- // make up one and store it in the database.
- temporary_storage_quota_ = GetInitialTemporaryStorageQuotaSize(
- profile_path_, is_incognito_);
- UMA_HISTOGRAM_MBYTES("Quota.InitialTemporaryGlobalStorageQuota",
- temporary_storage_quota_);
- if (!database()->SetGlobalQuota(
- kStorageTypeTemporary, temporary_storage_quota_)) {
- set_db_disabled(true);
- }
- }
- if (!db_disabled())
- need_initialize_origins_ = !database()->IsOriginDatabaseBootstrapped();
+ // See if we have overriding temporary quota configuration.
+ database()->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey,
+ &temporary_quota_override_);
+ database()->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey,
+ &desired_available_space_);
}
virtual void DatabaseTaskCompleted() OVERRIDE {
- manager()->need_initialize_origins_ = need_initialize_origins_;
- manager()->DidInitializeTemporaryGlobalQuota(temporary_storage_quota_);
- manager()->histogram_timer_.Start(FROM_HERE,
- QuotaManager::kReportHistogramInterval,
- manager(),
- &QuotaManager::ReportHistogram);
+ manager()->temporary_quota_override_ = temporary_quota_override_;
+ manager()->desired_available_space_ = desired_available_space_;
+ manager()->temporary_quota_initialized_ = true;
+ manager()->DidRunInitializeTask();
}
private:
- FilePath profile_path_;
- bool is_incognito_;
- bool need_initialize_origins_;
- int64 temporary_storage_quota_;
+ int64 temporary_quota_override_;
+ int64 desired_available_space_;
};
-class QuotaManager::UpdateTemporaryGlobalQuotaTask
+class QuotaManager::UpdateTemporaryQuotaOverrideTask
: public QuotaManager::DatabaseTaskBase {
public:
- UpdateTemporaryGlobalQuotaTask(
+ UpdateTemporaryQuotaOverrideTask(
QuotaManager* manager,
int64 new_quota,
QuotaCallback* callback)
: DatabaseTaskBase(manager),
new_quota_(new_quota),
- callback_(callback) {
- DCHECK_GE(new_quota, 0);
- }
+ callback_(callback) {}
protected:
virtual void RunOnTargetThread() OVERRIDE {
- if (!database()->SetGlobalQuota(kStorageTypeTemporary, new_quota_)) {
+ if (!database()->SetQuotaConfigValue(
+ QuotaDatabase::kTemporaryQuotaOverrideKey, new_quota_)) {
set_db_disabled(true);
- new_quota_ = 0;
+ new_quota_ = -1;
+ return;
}
}
virtual void DatabaseTaskCompleted() OVERRIDE {
- callback_->Run(db_disabled() ? kQuotaErrorInvalidAccess : kQuotaStatusOk,
- kStorageTypeTemporary, new_quota_);
if (!db_disabled()) {
- manager()->temporary_global_quota_ = new_quota_;
+ manager()->temporary_quota_override_ = new_quota_;
+ CallCallback(kQuotaStatusOk, kStorageTypeTemporary, new_quota_);
+ } else {
+ CallCallback(kQuotaErrorInvalidAccess, kStorageTypeTemporary, new_quota_);
}
}
private:
+ void CallCallback(QuotaStatusCode status, StorageType type, int64 quota) {
+ if (callback_.get()) {
+ callback_->Run(status, type, quota);
+ callback_.reset();
+ }
+ }
+
int64 new_quota_;
scoped_ptr<QuotaCallback> callback_;
};
@@ -708,9 +721,8 @@ class QuotaManager::GetLRUOriginTask
protected:
virtual void RunOnTargetThread() OVERRIDE {
- if (!database()->GetLRUOrigin(type_, exceptions_,
- special_storage_policy_, &url_))
- set_db_disabled(true);
+ database()->GetLRUOrigin(
+ type_, exceptions_, special_storage_policy_, &url_);
}
virtual void DatabaseTaskCompleted() OVERRIDE {
@@ -792,13 +804,12 @@ class QuotaManager::AvailableSpaceQueryTask : public QuotaThreadTask {
public:
AvailableSpaceQueryTask(
QuotaManager* manager,
- scoped_refptr<base::MessageLoopProxy> db_message_loop,
- const FilePath& profile_path,
AvailableSpaceCallback* callback)
- : QuotaThreadTask(manager, db_message_loop),
- profile_path_(profile_path),
+ : QuotaThreadTask(manager, manager->db_thread_),
+ profile_path_(manager->profile_path_),
space_(-1),
- callback_(callback) {}
+ callback_(callback) {
+ }
virtual ~AvailableSpaceQueryTask() {}
protected:
@@ -807,7 +818,7 @@ class QuotaManager::AvailableSpaceQueryTask : public QuotaThreadTask {
}
virtual void Aborted() OVERRIDE {
- callback_->Run(kQuotaErrorAbort, -1);
+ callback_.reset();
}
virtual void Completed() OVERRIDE {
@@ -1010,8 +1021,9 @@ QuotaManager::QuotaManager(bool is_incognito,
eviction_disabled_(false),
io_thread_(io_thread),
db_thread_(db_thread),
- need_initialize_origins_(false),
- temporary_global_quota_(-1),
+ temporary_quota_initialized_(false),
+ temporary_quota_override_(-1),
+ desired_available_space_(-1),
special_storage_policy_(special_storage_policy),
callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}
@@ -1033,71 +1045,54 @@ void QuotaManager::GetUsageInfo(GetUsageInfoCallback* callback) {
void QuotaManager::GetUsageAndQuota(
const GURL& origin, StorageType type,
- GetUsageAndQuotaCallback* callback_ptr) {
- scoped_ptr<GetUsageAndQuotaCallback> callback(callback_ptr);
- LazyInitialize();
-
- if (type == kStorageTypeUnknown) {
- // Quota only supports temporary/persistent types.
- callback->Run(kQuotaErrorNotSupported, 0, 0);
- return;
- }
-
- // note: returns host usage and quota
- std::string host = net::GetHostOrSpecFromURL(origin);
- UsageAndQuotaDispatcherTaskMap::iterator found =
- usage_and_quota_dispatchers_.find(std::make_pair(host, type));
- if (found == usage_and_quota_dispatchers_.end()) {
- UsageAndQuotaDispatcherTask* dispatcher =
- UsageAndQuotaDispatcherTask::Create(this, host, type);
- found = usage_and_quota_dispatchers_.insert(
- std::make_pair(std::make_pair(host, type), dispatcher)).first;
- }
- if (found->second->AddCallback(
- callback.release(), IsStorageUnlimited(origin))) {
- found->second->Start();
- }
+ GetUsageAndQuotaCallback* callback) {
+ GetUsageAndQuotaInternal(origin, type, false /* global */,
+ base::Bind(&CallGetUsageAndQuotaCallback,
+ callback, IsStorageUnlimited(origin)));
}
void QuotaManager::GetAvailableSpace(AvailableSpaceCallback* callback) {
- scoped_refptr<AvailableSpaceQueryTask> task(
- new AvailableSpaceQueryTask(this, db_thread_, profile_path_, callback));
- task->Start();
+ if (is_incognito_) {
+ callback->Run(kQuotaStatusOk, kIncognitoDefaultTemporaryQuota);
+ delete callback;
+ return;
+ }
+ make_scoped_refptr(new AvailableSpaceQueryTask(this, callback))->Start();
}
void QuotaManager::GetTemporaryGlobalQuota(QuotaCallback* callback) {
- LazyInitialize();
- if (temporary_global_quota_ >= 0) {
- // TODO(kinuko): We may want to adjust the quota when the current
- // available space in the hard drive is getting tight.
- callback->Run(kQuotaStatusOk,
- kStorageTypeTemporary, temporary_global_quota_);
+ if (temporary_quota_override_ > 0) {
+ callback->Run(kQuotaStatusOk, kStorageTypeTemporary,
+ temporary_quota_override_);
delete callback;
return;
}
- // They are called upon completion of InitializeTask.
- temporary_global_quota_callbacks_.Add(callback);
+ GetUsageAndQuotaInternal(
+ GURL(), kStorageTypeTemporary, true /* global */,
+ base::Bind(&CallQuotaCallback, callback, kStorageTypeTemporary));
}
-void QuotaManager::SetTemporaryGlobalQuota(int64 new_quota,
- QuotaCallback* callback) {
+void QuotaManager::SetTemporaryGlobalOverrideQuota(
+ int64 new_quota, QuotaCallback* callback_ptr) {
+ scoped_ptr<QuotaCallback> callback(callback_ptr);
LazyInitialize();
+
if (new_quota < 0) {
- callback->Run(kQuotaErrorInvalidModification,
- kStorageTypeTemporary, -1);
- delete callback;
+ if (callback.get())
+ callback->Run(kQuotaErrorInvalidModification,
+ kStorageTypeTemporary, -1);
return;
}
- if (!db_disabled_) {
- scoped_refptr<UpdateTemporaryGlobalQuotaTask> task(
- new UpdateTemporaryGlobalQuotaTask(this, new_quota, callback));
- task->Start();
- } else {
- callback->Run(kQuotaErrorInvalidAccess,
- kStorageTypeTemporary, -1);
- delete callback;
+ if (db_disabled_) {
+ if (callback.get())
+ callback->Run(kQuotaErrorInvalidAccess,
+ kStorageTypeTemporary, -1);
+ return;
}
+
+ make_scoped_refptr(new UpdateTemporaryQuotaOverrideTask(
+ this, new_quota, callback.release()))->Start();
}
void QuotaManager::GetPersistentHostQuota(const std::string& host,
@@ -1196,9 +1191,7 @@ void QuotaManager::LazyInitialize() {
new UsageTracker(clients_, kStorageTypePersistent,
special_storage_policy_));
- scoped_refptr<InitializeTask> task(
- new InitializeTask(this, profile_path_, is_incognito_));
- task->Start();
+ make_scoped_refptr(new InitializeTask(this))->Start();
}
void QuotaManager::RegisterClient(QuotaClient* client) {
@@ -1329,6 +1322,46 @@ void QuotaManager::NotifyStorageModifiedInternal(
this, origin, type, modified_time))->Start();
}
+void QuotaManager::GetUsageAndQuotaInternal(
+ const GURL& origin, StorageType type, bool global,
+ const UsageAndQuotaDispatcherCallback& callback) {
+ LazyInitialize();
+
+ StorageType requested_type = type;
+ if (type == kStorageTypeUnknown) {
+ // Quota only supports temporary/persistent types.
+ callback.Run(kQuotaErrorNotSupported, QuotaAndUsage());
+ return;
+ }
+
+ // Special internal type for querying global usage and quota.
+ const int kStorageTypeTemporaryGlobal = kStorageTypeTemporary + 100;
+ if (global) {
+ DCHECK_EQ(kStorageTypeTemporary, type);
+ type = static_cast<StorageType>(kStorageTypeTemporaryGlobal);
+ }
+
+ std::string host = net::GetHostOrSpecFromURL(origin);
+ HostAndType host_and_type = std::make_pair(host, type);
+ UsageAndQuotaDispatcherTaskMap::iterator found =
+ usage_and_quota_dispatchers_.find(host_and_type);
+ if (found == usage_and_quota_dispatchers_.end()) {
+ UsageAndQuotaDispatcherTask* dispatcher =
+ UsageAndQuotaDispatcherTask::Create(this, global, host_and_type);
+ found = usage_and_quota_dispatchers_.insert(
+ std::make_pair(host_and_type, dispatcher)).first;
+ }
+ // Start the dispatcher if it is the first one and temporary_quota_override
+ // is already initialized iff the requested type is temporary.
+ // (The first dispatcher task for temporary will be kicked in
+ // DidRunInitializeTask if temporary_quota_initialized_ is false here.)
+ if (found->second->AddCallback(callback) &&
+ (requested_type != kStorageTypeTemporary ||
+ temporary_quota_initialized_)) {
+ found->second->Start();
+ }
+}
+
void QuotaManager::DumpQuotaTable(DumpQuotaTableCallback* callback) {
make_scoped_refptr(new DumpQuotaTableTask(this, callback))->Start();
}
@@ -1398,58 +1431,20 @@ void QuotaManager::EvictOriginData(
&QuotaManager::DidOriginDataEvicted));
}
-void QuotaManager::DidGetAvailableSpaceForEviction(
- QuotaStatusCode status,
- int64 available_space) {
- eviction_context_.get_usage_and_quota_callback->Run(status,
- eviction_context_.usage,
- eviction_context_.unlimited_usage,
- eviction_context_.quota, available_space);
- eviction_context_.get_usage_and_quota_callback.reset();
-}
-
-void QuotaManager::DidGetGlobalQuotaForEviction(
- QuotaStatusCode status,
- StorageType type,
- int64 quota) {
- DCHECK_EQ(type, kStorageTypeTemporary);
- if (status != kQuotaStatusOk) {
- eviction_context_.get_usage_and_quota_callback->Run(
- status, 0, 0, 0, 0);
- eviction_context_.get_usage_and_quota_callback.reset();
- return;
- }
-
- eviction_context_.quota = quota;
- GetAvailableSpace(callback_factory_.
- NewCallback(&QuotaManager::DidGetAvailableSpaceForEviction));
-}
-
-void QuotaManager::DidGetGlobalUsageForEviction(
- StorageType type, int64 usage, int64 unlimited_usage) {
- DCHECK_EQ(type, kStorageTypeTemporary);
- DCHECK_GE(usage, unlimited_usage);
- eviction_context_.usage = usage;
- eviction_context_.unlimited_usage = unlimited_usage;
- GetTemporaryGlobalQuota(callback_factory_.
- NewCallback(&QuotaManager::DidGetGlobalQuotaForEviction));
-}
-
void QuotaManager::GetUsageAndQuotaForEviction(
- GetUsageAndQuotaForEvictionCallback* callback) {
+ const GetUsageAndQuotaForEvictionCallback& callback) {
DCHECK(io_thread_->BelongsToCurrentThread());
- DCHECK(!eviction_context_.get_usage_and_quota_callback.get());
-
- eviction_context_.get_usage_and_quota_callback.reset(callback);
- // TODO(dmikurube): Make kStorageTypeTemporary an argument.
- GetGlobalUsage(kStorageTypeTemporary, callback_factory_.
- NewCallback(&QuotaManager::DidGetGlobalUsageForEviction));
+ GetUsageAndQuotaInternal(
+ GURL(), kStorageTypeTemporary, true /* global */, callback);
}
void QuotaManager::StartEviction() {
DCHECK(!temporary_storage_evictor_.get());
- temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(this,
- kEvictionIntervalInMilliSeconds));
+ temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(
+ this, kEvictionIntervalInMilliSeconds));
+ if (desired_available_space_ >= 0)
+ temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction(
+ desired_available_space_);
temporary_storage_evictor_->Start();
}
@@ -1508,38 +1503,40 @@ void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
unlimited_origins);
}
-void QuotaManager::DidInitializeTemporaryGlobalQuota(int64 quota) {
- temporary_global_quota_ = quota;
- temporary_global_quota_callbacks_.Run(
- db_disabled_ ? kQuotaErrorInvalidAccess : kQuotaStatusOk,
- kStorageTypeTemporary, quota);
+void QuotaManager::DidRunInitializeTask() {
+ histogram_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(
+ kReportHistogramInterval),
+ this, &QuotaManager::ReportHistogram);
- if (db_disabled_ || eviction_disabled_)
- return;
+ DCHECK(temporary_quota_initialized_);
- if (!need_initialize_origins_) {
- StartEviction();
- return;
+ // Kick the tasks that have been waiting for the
+ // temporary_quota_initialized_ to be initialized (if there're any).
+ for (UsageAndQuotaDispatcherTaskMap::iterator iter =
+ usage_and_quota_dispatchers_.begin();
+ iter != usage_and_quota_dispatchers_.end(); ++iter) {
+ if (iter->second->IsStartable())
+ iter->second->Start();
}
- // We seem to need to initialize the origin table in the database.
- // Kick the first GetGlobalUsage for temporary storage to cache a list
- // of origins that have data in temporary storage to register them
- // in the database. (We'll need the global temporary usage anyway
- // for eviction later.)
- temporary_usage_tracker_->GetGlobalUsage(callback_factory_.NewCallback(
- &QuotaManager::DidRunInitialGetTemporaryGlobalUsage));
+ // Kick the first GetTemporaryGlobalQuota. This internally fetches (and
+ // caches) the usage of all origins and checks the available disk space.
+ GetTemporaryGlobalQuota(callback_factory_.NewCallback(
+ &QuotaManager::DidGetInitialTemporaryGlobalQuota));
}
-void QuotaManager::DidRunInitialGetTemporaryGlobalUsage(
- StorageType type, int64 usage_unused, int64 unlimited_usage_unused) {
+void QuotaManager::DidGetInitialTemporaryGlobalQuota(
+ QuotaStatusCode status, StorageType type, int64 quota_unused) {
DCHECK_EQ(type, kStorageTypeTemporary);
+
+ if (eviction_disabled_)
+ return;
+
// This will call the StartEviction() when initial origin registration
// is completed.
- scoped_refptr<InitializeTemporaryOriginsInfoTask> task(
- new InitializeTemporaryOriginsInfoTask(
- this, temporary_usage_tracker_.get()));
- task->Start();
+ make_scoped_refptr(new InitializeTemporaryOriginsInfoTask(
+ this, temporary_usage_tracker_.get()))->Start();
}
void QuotaManager::DidGetDatabaseLRUOrigin(const GURL& origin) {