diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-17 14:15:17 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-17 14:15:17 +0000 |
commit | 1de3cc5c2349e22d9e755ddad520733ed5f7cb73 (patch) | |
tree | b3ea0438ae9ff502d14ee631f51c3f2d30602cd5 /webkit | |
parent | e875094dcb290ade336d474aed96c7021b26d43a (diff) | |
download | chromium_src-1de3cc5c2349e22d9e755ddad520733ed5f7cb73.zip chromium_src-1de3cc5c2349e22d9e755ddad520733ed5f7cb73.tar.gz chromium_src-1de3cc5c2349e22d9e755ddad520733ed5f7cb73.tar.bz2 |
Revert 105791 (to see if it fixes browser_tests) - 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
TBR=kinuko@chromium.org
Review URL: http://codereview.chromium.org/8319004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105800 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/quota/quota_database.cc | 28 | ||||
-rw-r--r-- | webkit/quota/quota_database.h | 8 | ||||
-rw-r--r-- | webkit/quota/quota_database_unittest.cc | 44 | ||||
-rw-r--r-- | webkit/quota/quota_manager.cc | 623 | ||||
-rw-r--r-- | webkit/quota/quota_manager.h | 91 | ||||
-rw-r--r-- | webkit/quota/quota_manager_unittest.cc | 55 | ||||
-rw-r--r-- | webkit/quota/quota_temporary_storage_evictor.cc | 36 | ||||
-rw-r--r-- | webkit/quota/quota_temporary_storage_evictor.h | 11 | ||||
-rw-r--r-- | webkit/quota/quota_temporary_storage_evictor_unittest.cc | 12 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gypi | 6 |
10 files changed, 454 insertions, 460 deletions
diff --git a/webkit/quota/quota_database.cc b/webkit/quota/quota_database.cc index 0563535..d34451e 100644 --- a/webkit/quota/quota_database.cc +++ b/webkit/quota/quota_database.cc @@ -23,11 +23,12 @@ namespace { // Definitions for database schema. -const int kCurrentVersion = 4; +const int kCurrentVersion = 3; const int kCompatibleVersion = 2; const char kHostQuotaTable[] = "HostQuotaTable"; const char kOriginInfoTable[] = "OriginInfoTable"; +const char kGlobalQuotaKeyPrefix[] = "GlobalQuota-"; const char kIsOriginTableBootstrapped[] = "IsOriginTableBootstrapped"; class HistogramUniquifier { @@ -47,10 +48,13 @@ bool PrepareCachedStatement( return true; } -bool VerifyValidQuotaConfig(const char* key) { - return (key != NULL && - (!strcmp(key, QuotaDatabase::kDesiredAvailableSpaceKey) || - !strcmp(key, QuotaDatabase::kTemporaryQuotaOverrideKey))); +std::string GetGlobalQuotaKey(quota::StorageType type) { + if (type == quota::kStorageTypeTemporary) + return std::string(kGlobalQuotaKeyPrefix) + "temporary"; + else if (type == quota::kStorageTypePersistent) + return std::string(kGlobalQuotaKeyPrefix) + "persistent"; + NOTREACHED() << "Unknown storage type " << type; + return std::string(); } const int kCommitIntervalMs = 30000; @@ -58,10 +62,6 @@ const int kCommitIntervalMs = 30000; } // anonymous namespace // static -const char QuotaDatabase::kDesiredAvailableSpaceKey[] = "DesiredAvailableSpace"; -const char QuotaDatabase::kTemporaryQuotaOverrideKey[] = - "TemporaryQuotaOverride"; - const QuotaDatabase::TableSchema QuotaDatabase::kTables[] = { { kHostQuotaTable, "(host TEXT NOT NULL," @@ -334,18 +334,16 @@ bool QuotaDatabase::DeleteOriginInfo( return true; } -bool QuotaDatabase::GetQuotaConfigValue(const char* key, int64* value) { +bool QuotaDatabase::GetGlobalQuota(StorageType type, int64* quota) { if (!LazyOpen(false)) return false; - DCHECK(VerifyValidQuotaConfig(key)); - return meta_table_->GetValue(key, value); + return meta_table_->GetValue(GetGlobalQuotaKey(type).c_str(), quota); } -bool QuotaDatabase::SetQuotaConfigValue(const char* key, int64 value) { +bool QuotaDatabase::SetGlobalQuota(StorageType type, int64 quota) { if (!LazyOpen(true)) return false; - DCHECK(VerifyValidQuotaConfig(key)); - return meta_table_->SetValue(key, value); + return meta_table_->SetValue(GetGlobalQuotaKey(type).c_str(), quota); } bool QuotaDatabase::GetLRUOrigin( diff --git a/webkit/quota/quota_database.h b/webkit/quota/quota_database.h index 7a816f6..ec437f1 100644 --- a/webkit/quota/quota_database.h +++ b/webkit/quota/quota_database.h @@ -33,10 +33,6 @@ class SpecialStoragePolicy; // All the methods of this class must run on the DB thread. class QuotaDatabase { public: - // Constants for {Get,Set}QuotaConfigValue keys. - static const char kDesiredAvailableSpaceKey[]; - static const char kTemporaryQuotaOverrideKey[]; - // If 'path' is empty, an in memory database will be used. explicit QuotaDatabase(const FilePath& path); ~QuotaDatabase(); @@ -63,8 +59,8 @@ class QuotaDatabase { bool DeleteOriginInfo(const GURL& origin, StorageType type); - bool GetQuotaConfigValue(const char* key, int64* value); - bool SetQuotaConfigValue(const char* key, int64 value); + bool GetGlobalQuota(StorageType type, int64* quota); + bool SetGlobalQuota(StorageType type, int64 quota); // Sets |origin| to the least recently used origin of origins not included // in |exceptions| and not granted the special unlimited storage right. diff --git a/webkit/quota/quota_database_unittest.cc b/webkit/quota/quota_database_unittest.cc index 7045f7f..05001a7 100644 --- a/webkit/quota/quota_database_unittest.cc +++ b/webkit/quota/quota_database_unittest.cc @@ -106,30 +106,26 @@ class QuotaDatabaseTest : public testing::Test { QuotaDatabase db(kDbFile); ASSERT_TRUE(db.LazyOpen(true)); - const char* kTempQuotaKey = QuotaDatabase::kTemporaryQuotaOverrideKey; - const char* kAvailSpaceKey = QuotaDatabase::kDesiredAvailableSpaceKey; - - int64 value = 0; - const int64 kValue1 = 456; - const int64 kValue2 = 123000; - EXPECT_FALSE(db.GetQuotaConfigValue(kTempQuotaKey, &value)); - EXPECT_FALSE(db.GetQuotaConfigValue(kAvailSpaceKey, &value)); - - EXPECT_TRUE(db.SetQuotaConfigValue(kTempQuotaKey, kValue1)); - EXPECT_TRUE(db.GetQuotaConfigValue(kTempQuotaKey, &value)); - EXPECT_EQ(kValue1, value); - - EXPECT_TRUE(db.SetQuotaConfigValue(kTempQuotaKey, kValue2)); - EXPECT_TRUE(db.GetQuotaConfigValue(kTempQuotaKey, &value)); - EXPECT_EQ(kValue2, value); - - EXPECT_TRUE(db.SetQuotaConfigValue(kAvailSpaceKey, kValue1)); - EXPECT_TRUE(db.GetQuotaConfigValue(kAvailSpaceKey, &value)); - EXPECT_EQ(kValue1, value); - - EXPECT_TRUE(db.SetQuotaConfigValue(kAvailSpaceKey, kValue2)); - EXPECT_TRUE(db.GetQuotaConfigValue(kAvailSpaceKey, &value)); - EXPECT_EQ(kValue2, value); + const int kQuota1 = 9999; + const int kQuota2 = 86420; + + int64 quota = -1; + EXPECT_FALSE(db.GetGlobalQuota(kStorageTypeTemporary, "a)); + EXPECT_FALSE(db.GetGlobalQuota(kStorageTypePersistent, "a)); + + EXPECT_TRUE(db.SetGlobalQuota(kStorageTypeTemporary, kQuota1)); + EXPECT_TRUE(db.GetGlobalQuota(kStorageTypeTemporary, "a)); + EXPECT_EQ(kQuota1, quota); + + EXPECT_TRUE(db.SetGlobalQuota(kStorageTypeTemporary, kQuota1 + 1024)); + EXPECT_TRUE(db.GetGlobalQuota(kStorageTypeTemporary, "a)); + EXPECT_EQ(kQuota1 + 1024, quota); + + EXPECT_FALSE(db.GetGlobalQuota(kStorageTypePersistent, "a)); + + EXPECT_TRUE(db.SetGlobalQuota(kStorageTypePersistent, kQuota2)); + EXPECT_TRUE(db.GetGlobalQuota(kStorageTypePersistent, "a)); + EXPECT_EQ(kQuota2, quota); } void OriginLastAccessTimeLRU(const FilePath& kDbFile) { diff --git a/webkit/quota/quota_manager.cc b/webkit/quota/quota_manager.cc index ad71c02..4ade94f 100644 --- a/webkit/quota/quota_manager.cc +++ b/webkit/quota/quota_manager.cc @@ -36,12 +36,38 @@ namespace quota { namespace { +const char kEnableQuotaEviction[] = "enable-quota-eviction"; const int64 kMBytes = 1024 * 1024; const int kMinutesInMilliSeconds = 60 * 1000; -const int64 kIncognitoDefaultTemporaryQuota = 50 * kMBytes; -const int64 kReportHistogramInterval = 60 * 60 * 1000; // 1 hour -const double kTemporaryQuotaRatioToAvail = 0.5; // 50% +// 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; +} void CountOriginType(const std::set<GURL>& origins, SpecialStoragePolicy* policy, @@ -65,6 +91,12 @@ 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"; @@ -74,114 +106,94 @@ const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3; const int QuotaManager::kEvictionIntervalInMilliSeconds = 30 * kMinutesInMilliSeconds; -// 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; -} +const base::TimeDelta QuotaManager::kReportHistogramInterval = + base::TimeDelta::FromMilliseconds(60 * 60 * 1000); // 1 hour // 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 UsageAndQuotaDispatcherCallback Callback; - typedef std::deque<Callback> CallbackList; + typedef std::deque<GetUsageAndQuotaCallback*> CallbackList; static UsageAndQuotaDispatcherTask* Create( - QuotaManager* manager, - bool global, - const HostAndType& host_and_type); + QuotaManager* manager, const std::string& host, StorageType type); // Returns true if it is the first call for this task; which means // the caller needs to call Start(). - bool AddCallback(const Callback& callback) { - callbacks_.push_back(callback); - return (callbacks_.size() == 1); + 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); } - void DidGetGlobalUsage(StorageType type, int64 usage, int64 unlimited_usage) { - DCHECK_EQ(this->type(), type); + void DidGetGlobalUsage(StorageType type, int64 usage, + int64 unlimited_usage) { + DCHECK_EQ(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(this->host(), host); - DCHECK_EQ(this->type(), type); + void DidGetHostUsage(const std::string& host, + StorageType type, + int64 usage) { + DCHECK_EQ(host_, host); + DCHECK_EQ(type_, type); host_usage_ = usage; CheckCompleted(); } - void DidGetHostQuota(QuotaStatusCode status, - const std::string& host, - StorageType type, - 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; + void DidGetGlobalQuota(QuotaStatusCode status, + StorageType type, + int64 quota) { + DCHECK_EQ(type_, type); + quota_status_ = status; + quota_ = 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; + 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; CheckCompleted(); } - bool IsStartable() const { - return !started_ && !callbacks_.empty(); - } - protected: UsageAndQuotaDispatcherTask( QuotaManager* manager, - const HostAndType& host_and_type) + const std::string& host, + StorageType type) : QuotaTask(manager), - host_and_type_(host_and_type), - started_(false), - host_quota_(-1), + host_(host), + type_(type), + 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() {} + virtual ~UsageAndQuotaDispatcherTask() { + STLDeleteContainerPointers(callbacks_.begin(), callbacks_.end()); + STLDeleteContainerPointers(unlimited_callbacks_.begin(), + unlimited_callbacks_.end()); + } // 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 @@ -190,7 +202,8 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { } virtual void Aborted() OVERRIDE { - CallCallbacksAndClear(kQuotaErrorAbort, 0, 0, 0, 0); + CallCallbacksAndClear(&callbacks_, kQuotaErrorAbort, 0, 0); + CallCallbacksAndClear(&unlimited_callbacks_, kQuotaErrorAbort, 0, 0); DeleteSoon(); } @@ -199,50 +212,29 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { } void CallCallbacksAndClear( - 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); + 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; } - callbacks_.clear(); + callbacks->clear(); } QuotaManager* manager() const { return static_cast<QuotaManager*>(observer()); } - 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_; } + std::string host() const { return host_; } + StorageType type() const { return type_; } + int64 quota() const { return 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_; } - - // 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; - } + CallbackList& unlimited_callbacks() { return unlimited_callbacks_; } // Subclasses must call following methods to create a new 'waitable' // callback, which decrements waiting_callbacks when it is called. @@ -256,15 +248,15 @@ class QuotaManager::UsageAndQuotaDispatcherTask : public QuotaTask { return callback_factory_.NewCallback( &UsageAndQuotaDispatcherTask::DidGetHostUsage); } - HostQuotaCallback* NewWaitableHostQuotaCallback() { + QuotaCallback* NewWaitableGlobalQuotaCallback() { ++waiting_callbacks_; return callback_factory_.NewCallback( - &UsageAndQuotaDispatcherTask::DidGetHostQuota); + &UsageAndQuotaDispatcherTask::DidGetGlobalQuota); } - AvailableSpaceCallback* NewWaitableAvailableSpaceCallback() { + HostQuotaCallback* NewWaitableHostQuotaCallback() { ++waiting_callbacks_; return callback_factory_.NewCallback( - &UsageAndQuotaDispatcherTask::DidGetAvailableSpace); + &UsageAndQuotaDispatcherTask::DidGetHostQuota); } private: @@ -272,25 +264,26 @@ 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(host_and_type_) != dispatcher_map.end()); - dispatcher_map.erase(host_and_type_); + DCHECK(dispatcher_map.find(std::make_pair(host_, type_)) != + dispatcher_map.end()); + dispatcher_map.erase(std::make_pair(host_, type_)); CallCompleted(); } } const std::string host_; - const HostAndType host_and_type_; - bool started_; - int64 host_quota_; + const StorageType type_; + int64 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_; @@ -362,8 +355,8 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForTemporary : public QuotaManager::UsageAndQuotaDispatcherTask { public: UsageAndQuotaDispatcherTaskForTemporary( - QuotaManager* manager, const HostAndType& host_and_type) - : UsageAndQuotaDispatcherTask(manager, host_and_type) {} + QuotaManager* manager, const std::string& host) + : UsageAndQuotaDispatcherTask(manager, host, kStorageTypeTemporary) {} protected: virtual void RunBody() OVERRIDE { @@ -371,24 +364,34 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForTemporary NewWaitableGlobalUsageCallback()); manager()->temporary_usage_tracker_->GetHostUsage( host(), NewWaitableHostUsageCallback()); - manager()->GetAvailableSpace(NewWaitableAvailableSpaceCallback()); + manager()->GetTemporaryGlobalQuota(NewWaitableGlobalQuotaCallback()); } virtual void DispatchCallbacks() OVERRIDE { - // 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()); + // 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); + } } }; @@ -396,8 +399,8 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForPersistent : public QuotaManager::UsageAndQuotaDispatcherTask { public: UsageAndQuotaDispatcherTaskForPersistent( - QuotaManager* manager, const HostAndType& host_and_type) - : UsageAndQuotaDispatcherTask(manager, host_and_type) {} + QuotaManager* manager, const std::string& host) + : UsageAndQuotaDispatcherTask(manager, host, kStorageTypePersistent) {} protected: virtual void RunBody() OVERRIDE { @@ -408,51 +411,24 @@ class QuotaManager::UsageAndQuotaDispatcherTaskForPersistent } virtual void DispatchCallbacks() OVERRIDE { - CallCallbacksAndClear(quota_status(), - host_usage(), host_usage(), host_quota(), - available_space()); + CallCallbacksAndClear(&callbacks(), quota_status(), + host_usage(), quota()); + CallCallbacksAndClear(&unlimited_callbacks(), quota_status(), + host_usage(), kint64max); } }; -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, bool global, - const QuotaManager::HostAndType& host_and_type) { - if (global) - return new UsageAndQuotaDispatcherTaskForTemporaryGlobal( - manager, host_and_type); - switch (host_and_type.second) { + QuotaManager* manager, const std::string& host, StorageType type) { + switch (type) { case kStorageTypeTemporary: return new UsageAndQuotaDispatcherTaskForTemporary( - manager, host_and_type); + manager, host); case kStorageTypePersistent: return new UsageAndQuotaDispatcherTaskForPersistent( - manager, host_and_type); + manager, host); default: NOTREACHED(); } @@ -558,72 +534,83 @@ class QuotaManager::DatabaseTaskBase : public QuotaThreadTask { class QuotaManager::InitializeTask : public QuotaManager::DatabaseTaskBase { public: - InitializeTask(QuotaManager* manager) + InitializeTask( + QuotaManager* manager, + const FilePath& profile_path, + bool is_incognito) : DatabaseTaskBase(manager), - temporary_quota_override_(-1), - desired_available_space_(-1) { - DCHECK(manager); + profile_path_(profile_path), + is_incognito_(is_incognito), + need_initialize_origins_(false), + temporary_storage_quota_(-1) { } protected: virtual void RunOnTargetThread() OVERRIDE { - // See if we have overriding temporary quota configuration. - database()->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey, - &temporary_quota_override_); - database()->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey, - &desired_available_space_); + // 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(); } virtual void DatabaseTaskCompleted() OVERRIDE { - manager()->temporary_quota_override_ = temporary_quota_override_; - manager()->desired_available_space_ = desired_available_space_; - manager()->temporary_quota_initialized_ = true; - manager()->DidRunInitializeTask(); + manager()->need_initialize_origins_ = need_initialize_origins_; + manager()->DidInitializeTemporaryGlobalQuota(temporary_storage_quota_); + manager()->histogram_timer_.Start(FROM_HERE, + QuotaManager::kReportHistogramInterval, + manager(), + &QuotaManager::ReportHistogram); } private: - int64 temporary_quota_override_; - int64 desired_available_space_; + FilePath profile_path_; + bool is_incognito_; + bool need_initialize_origins_; + int64 temporary_storage_quota_; }; -class QuotaManager::UpdateTemporaryQuotaOverrideTask +class QuotaManager::UpdateTemporaryGlobalQuotaTask : public QuotaManager::DatabaseTaskBase { public: - UpdateTemporaryQuotaOverrideTask( + UpdateTemporaryGlobalQuotaTask( QuotaManager* manager, int64 new_quota, QuotaCallback* callback) : DatabaseTaskBase(manager), new_quota_(new_quota), - callback_(callback) {} + callback_(callback) { + DCHECK_GE(new_quota, 0); + } protected: virtual void RunOnTargetThread() OVERRIDE { - if (!database()->SetQuotaConfigValue( - QuotaDatabase::kTemporaryQuotaOverrideKey, new_quota_)) { + if (!database()->SetGlobalQuota(kStorageTypeTemporary, new_quota_)) { set_db_disabled(true); - new_quota_ = -1; - return; + new_quota_ = 0; } } virtual void DatabaseTaskCompleted() OVERRIDE { + callback_->Run(db_disabled() ? kQuotaErrorInvalidAccess : kQuotaStatusOk, + kStorageTypeTemporary, new_quota_); if (!db_disabled()) { - manager()->temporary_quota_override_ = new_quota_; - CallCallback(kQuotaStatusOk, kStorageTypeTemporary, new_quota_); - } else { - CallCallback(kQuotaErrorInvalidAccess, kStorageTypeTemporary, new_quota_); + manager()->temporary_global_quota_ = 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_; }; @@ -721,8 +708,9 @@ class QuotaManager::GetLRUOriginTask protected: virtual void RunOnTargetThread() OVERRIDE { - database()->GetLRUOrigin( - type_, exceptions_, special_storage_policy_, &url_); + if (!database()->GetLRUOrigin(type_, exceptions_, + special_storage_policy_, &url_)) + set_db_disabled(true); } virtual void DatabaseTaskCompleted() OVERRIDE { @@ -804,12 +792,13 @@ class QuotaManager::AvailableSpaceQueryTask : public QuotaThreadTask { public: AvailableSpaceQueryTask( QuotaManager* manager, + scoped_refptr<base::MessageLoopProxy> db_message_loop, + const FilePath& profile_path, AvailableSpaceCallback* callback) - : QuotaThreadTask(manager, manager->db_thread_), - profile_path_(manager->profile_path_), + : QuotaThreadTask(manager, db_message_loop), + profile_path_(profile_path), space_(-1), - callback_(callback) { - } + callback_(callback) {} virtual ~AvailableSpaceQueryTask() {} protected: @@ -818,7 +807,7 @@ class QuotaManager::AvailableSpaceQueryTask : public QuotaThreadTask { } virtual void Aborted() OVERRIDE { - callback_.reset(); + callback_->Run(kQuotaErrorAbort, -1); } virtual void Completed() OVERRIDE { @@ -1021,9 +1010,8 @@ QuotaManager::QuotaManager(bool is_incognito, eviction_disabled_(false), io_thread_(io_thread), db_thread_(db_thread), - temporary_quota_initialized_(false), - temporary_quota_override_(-1), - desired_available_space_(-1), + need_initialize_origins_(false), + temporary_global_quota_(-1), special_storage_policy_(special_storage_policy), callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { } @@ -1045,54 +1033,71 @@ void QuotaManager::GetUsageInfo(GetUsageInfoCallback* callback) { void QuotaManager::GetUsageAndQuota( const GURL& origin, StorageType type, - GetUsageAndQuotaCallback* callback) { - GetUsageAndQuotaInternal(origin, type, false /* global */, - base::Bind(&CallGetUsageAndQuotaCallback, - callback, IsStorageUnlimited(origin))); -} + GetUsageAndQuotaCallback* callback_ptr) { + scoped_ptr<GetUsageAndQuotaCallback> callback(callback_ptr); + LazyInitialize(); -void QuotaManager::GetAvailableSpace(AvailableSpaceCallback* callback) { - if (is_incognito_) { - callback->Run(kQuotaStatusOk, kIncognitoDefaultTemporaryQuota); - delete callback; + if (type == kStorageTypeUnknown) { + // Quota only supports temporary/persistent types. + callback->Run(kQuotaErrorNotSupported, 0, 0); return; } - make_scoped_refptr(new AvailableSpaceQueryTask(this, callback))->Start(); + + // 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(); + } +} + +void QuotaManager::GetAvailableSpace(AvailableSpaceCallback* callback) { + scoped_refptr<AvailableSpaceQueryTask> task( + new AvailableSpaceQueryTask(this, db_thread_, profile_path_, callback)); + task->Start(); } void QuotaManager::GetTemporaryGlobalQuota(QuotaCallback* callback) { - if (temporary_quota_override_ > 0) { - callback->Run(kQuotaStatusOk, kStorageTypeTemporary, - temporary_quota_override_); + 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_); delete callback; return; } - GetUsageAndQuotaInternal( - GURL(), kStorageTypeTemporary, true /* global */, - base::Bind(&CallQuotaCallback, callback, kStorageTypeTemporary)); + // They are called upon completion of InitializeTask. + temporary_global_quota_callbacks_.Add(callback); } -void QuotaManager::SetTemporaryGlobalOverrideQuota( - int64 new_quota, QuotaCallback* callback_ptr) { - scoped_ptr<QuotaCallback> callback(callback_ptr); +void QuotaManager::SetTemporaryGlobalQuota(int64 new_quota, + QuotaCallback* callback) { LazyInitialize(); - if (new_quota < 0) { - if (callback.get()) - callback->Run(kQuotaErrorInvalidModification, - kStorageTypeTemporary, -1); + callback->Run(kQuotaErrorInvalidModification, + kStorageTypeTemporary, -1); + delete callback; return; } - if (db_disabled_) { - if (callback.get()) - callback->Run(kQuotaErrorInvalidAccess, - 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; } - - make_scoped_refptr(new UpdateTemporaryQuotaOverrideTask( - this, new_quota, callback.release()))->Start(); } void QuotaManager::GetPersistentHostQuota(const std::string& host, @@ -1191,7 +1196,9 @@ void QuotaManager::LazyInitialize() { new UsageTracker(clients_, kStorageTypePersistent, special_storage_policy_)); - make_scoped_refptr(new InitializeTask(this))->Start(); + scoped_refptr<InitializeTask> task( + new InitializeTask(this, profile_path_, is_incognito_)); + task->Start(); } void QuotaManager::RegisterClient(QuotaClient* client) { @@ -1322,46 +1329,6 @@ 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(); } @@ -1431,20 +1398,58 @@ 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( - const GetUsageAndQuotaForEvictionCallback& callback) { + GetUsageAndQuotaForEvictionCallback* callback) { DCHECK(io_thread_->BelongsToCurrentThread()); - GetUsageAndQuotaInternal( - GURL(), kStorageTypeTemporary, true /* global */, callback); + 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)); } void QuotaManager::StartEviction() { DCHECK(!temporary_storage_evictor_.get()); - 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_.reset(new QuotaTemporaryStorageEvictor(this, + kEvictionIntervalInMilliSeconds)); temporary_storage_evictor_->Start(); } @@ -1503,40 +1508,38 @@ void QuotaManager::DidGetPersistentGlobalUsageForHistogram( unlimited_origins); } -void QuotaManager::DidRunInitializeTask() { - histogram_timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds( - kReportHistogramInterval), - this, &QuotaManager::ReportHistogram); +void QuotaManager::DidInitializeTemporaryGlobalQuota(int64 quota) { + temporary_global_quota_ = quota; + temporary_global_quota_callbacks_.Run( + db_disabled_ ? kQuotaErrorInvalidAccess : kQuotaStatusOk, + kStorageTypeTemporary, quota); - DCHECK(temporary_quota_initialized_); + if (db_disabled_ || eviction_disabled_) + 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(); + if (!need_initialize_origins_) { + StartEviction(); + return; } - // 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)); + // 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)); } -void QuotaManager::DidGetInitialTemporaryGlobalQuota( - QuotaStatusCode status, StorageType type, int64 quota_unused) { +void QuotaManager::DidRunInitialGetTemporaryGlobalUsage( + StorageType type, int64 usage_unused, int64 unlimited_usage_unused) { DCHECK_EQ(type, kStorageTypeTemporary); - - if (eviction_disabled_) - return; - // This will call the StartEviction() when initial origin registration // is completed. - make_scoped_refptr(new InitializeTemporaryOriginsInfoTask( - this, temporary_usage_tracker_.get()))->Start(); + scoped_refptr<InitializeTemporaryOriginsInfoTask> task( + new InitializeTemporaryOriginsInfoTask( + this, temporary_usage_tracker_.get())); + task->Start(); } void QuotaManager::DidGetDatabaseLRUOrigin(const GURL& origin) { diff --git a/webkit/quota/quota_manager.h b/webkit/quota/quota_manager.h index df701d6..2d0de6a 100644 --- a/webkit/quota/quota_manager.h +++ b/webkit/quota/quota_manager.h @@ -45,24 +45,20 @@ class QuotaTemporaryStorageEvictor; class UsageTracker; class MockQuotaManager; -struct QuotaAndUsage { - int64 usage; - int64 unlimited_usage; - int64 quota; - int64 available_disk_space; -}; - // An interface called by QuotaTemporaryStorageEvictor. class QuotaEvictionHandler { public: + virtual ~QuotaEvictionHandler() {} + typedef Callback1<const GURL&>::Type GetLRUOriginCallback; typedef StatusCallback EvictOriginDataCallback; - typedef base::Callback<void(QuotaStatusCode, - const QuotaAndUsage& quota_and_usage)> + typedef Callback5<QuotaStatusCode, + int64 /* usage */, + int64 /* unlimited_usage */, + int64 /* quota */, + int64 /* physical_available */ >::Type GetUsageAndQuotaForEvictionCallback; - virtual ~QuotaEvictionHandler() {} - // Returns the least recently used origin. It might return empty // GURL when there are no evictable origins. virtual void GetLRUOrigin( @@ -75,7 +71,7 @@ class QuotaEvictionHandler { EvictOriginDataCallback* callback) = 0; virtual void GetUsageAndQuotaForEviction( - const GetUsageAndQuotaForEvictionCallback& callback) = 0; + GetUsageAndQuotaForEvictionCallback* callback) = 0; }; struct UsageInfo { @@ -153,11 +149,7 @@ class QuotaManager : public QuotaTaskObserver, // Called by UI and internal modules. void GetAvailableSpace(AvailableSpaceCallback* callback); void GetTemporaryGlobalQuota(QuotaCallback* callback); - - // Ok to call with NULL callback. - void SetTemporaryGlobalOverrideQuota(int64 new_quota, - QuotaCallback* callback); - + void SetTemporaryGlobalQuota(int64 new_quota, QuotaCallback* callback); void GetPersistentHostQuota(const std::string& host, HostQuotaCallback* callback); void SetPersistentHostQuota(const std::string& host, @@ -180,6 +172,11 @@ class QuotaManager : public QuotaTaskObserver, bool ResetUsageTracker(StorageType type); + // Used to determine the total size of the temp pool. + static const int64 kTemporaryStorageQuotaDefaultSize; + static const int64 kTemporaryStorageQuotaMaxSize; + static const int64 kIncognitoDefaultTemporaryQuota; + // Determines the portion of the temp pool that can be // utilized by a single host (ie. 5 for 20%). static const int kPerHostTemporaryPortion; @@ -189,11 +186,12 @@ class QuotaManager : public QuotaTaskObserver, static const int kThresholdOfErrorsToBeBlacklisted; static const int kEvictionIntervalInMilliSeconds; + static const base::TimeDelta kReportHistogramInterval; private: class DatabaseTaskBase; class InitializeTask; - class UpdateTemporaryQuotaOverrideTask; + class UpdateTemporaryGlobalQuotaTask; class GetPersistentHostQuotaTask; class UpdatePersistentHostQuotaTask; class GetLRUOriginTask; @@ -207,7 +205,6 @@ class QuotaManager : public QuotaTaskObserver, class UsageAndQuotaDispatcherTask; class UsageAndQuotaDispatcherTaskForTemporary; class UsageAndQuotaDispatcherTaskForPersistent; - class UsageAndQuotaDispatcherTaskForTemporaryGlobal; class OriginDataDeleter; @@ -225,20 +222,29 @@ class QuotaManager : public QuotaTaskObserver, DumpOriginInfoTableCallback; struct EvictionContext { - EvictionContext() : evicted_type(kStorageTypeUnknown) {} + EvictionContext() + : evicted_type(kStorageTypeUnknown), + usage(0), + unlimited_usage(0), + quota(0) {} virtual ~EvictionContext() {} + GURL evicted_origin; StorageType evicted_type; + scoped_ptr<EvictOriginDataCallback> evict_origin_data_callback; + + scoped_ptr<GetUsageAndQuotaForEvictionCallback> + get_usage_and_quota_callback; + int64 usage; + int64 unlimited_usage; + int64 quota; }; typedef std::pair<std::string, StorageType> HostAndType; typedef std::map<HostAndType, UsageAndQuotaDispatcherTask*> UsageAndQuotaDispatcherTaskMap; - typedef QuotaEvictionHandler::GetUsageAndQuotaForEvictionCallback - UsageAndQuotaDispatcherCallback; - friend class quota_internals::QuotaInternalsProxy; friend struct QuotaManagerDeleter; friend class MockStorageClient; @@ -277,13 +283,6 @@ class QuotaManager : public QuotaTaskObserver, int64 delta, base::Time modified_time); - // |origin| can be empty if |global| is true. - void GetUsageAndQuotaInternal( - const GURL& origin, - StorageType type, - bool global, - const UsageAndQuotaDispatcherCallback& callback); - void DumpQuotaTable(DumpQuotaTableCallback* callback); void DumpOriginInfoTable(DumpOriginInfoTableCallback* callback); @@ -292,12 +291,16 @@ class QuotaManager : public QuotaTaskObserver, void DeleteOriginFromDatabase(const GURL& origin, StorageType type); void DidOriginDataEvicted(QuotaStatusCode status); - void DidGetGlobalUsageAndQuotaForEviction(QuotaStatusCode status, - StorageType type, - int64 usage, - int64 unlimited_usage, - int64 quota, - int64 available_space); + void DidGetAvailableSpaceForEviction( + QuotaStatusCode status, + int64 available_space); + void DidGetGlobalQuotaForEviction( + QuotaStatusCode status, + StorageType type, + int64 quota); + void DidGetGlobalUsageForEviction(StorageType type, + int64 usage, + int64 unlimited_usage); void ReportHistogram(); void DidGetTemporaryGlobalUsageForHistogram(StorageType type, @@ -316,12 +319,11 @@ class QuotaManager : public QuotaTaskObserver, StorageType type, EvictOriginDataCallback* callback) OVERRIDE; virtual void GetUsageAndQuotaForEviction( - const GetUsageAndQuotaForEvictionCallback& callback) OVERRIDE; + GetUsageAndQuotaForEvictionCallback* callback) OVERRIDE; - void DidRunInitializeTask(); - void DidGetInitialTemporaryGlobalQuota(QuotaStatusCode status, - StorageType type, - int64 quota_unused); + void DidInitializeTemporaryGlobalQuota(int64 quota); + void DidRunInitialGetTemporaryGlobalUsage(StorageType type, int64 usage, + int64 unlimited_usage); void DidGetDatabaseLRUOrigin(const GURL& origin); void DeleteOnCorrectThread() const; @@ -336,6 +338,7 @@ class QuotaManager : public QuotaTaskObserver, scoped_refptr<base::MessageLoopProxy> db_thread_; mutable scoped_ptr<QuotaDatabase> database_; + bool need_initialize_origins_; scoped_ptr<GetLRUOriginCallback> lru_origin_callback_; std::set<GURL> access_notified_origins_; @@ -351,10 +354,8 @@ class QuotaManager : public QuotaTaskObserver, UsageAndQuotaDispatcherTaskMap usage_and_quota_dispatchers_; - bool temporary_quota_initialized_; - int64 temporary_quota_override_; - - int64 desired_available_space_; + int64 temporary_global_quota_; + QuotaCallbackQueue temporary_global_quota_callbacks_; // Map from origin to count. std::map<GURL, int> origins_in_use_; diff --git a/webkit/quota/quota_manager_unittest.cc b/webkit/quota/quota_manager_unittest.cc index 3a34e9f..e9f4ab3 100644 --- a/webkit/quota/quota_manager_unittest.cc +++ b/webkit/quota/quota_manager_unittest.cc @@ -6,11 +6,9 @@ #include <sstream> #include <vector> -#include "base/bind.h" #include "base/file_util.h" #include "base/memory/scoped_callback_factory.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/message_loop_proxy.h" #include "base/scoped_temp_dir.h" @@ -19,12 +17,16 @@ #include "base/time.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageQuotaError.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageQuotaType.h" #include "webkit/quota/mock_special_storage_policy.h" #include "webkit/quota/mock_storage_client.h" #include "webkit/quota/quota_database.h" #include "webkit/quota/quota_manager.h" using base::MessageLoopProxy; +using WebKit::WebStorageQuotaError; +using WebKit::WebStorageQuotaType; namespace quota { @@ -41,7 +43,6 @@ class QuotaManagerTest : public testing::Test { public: QuotaManagerTest() : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), - weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), mock_time_counter_(0) { } @@ -102,8 +103,7 @@ class QuotaManagerTest : public testing::Test { void SetTemporaryGlobalQuota(int64 new_quota) { quota_status_ = kQuotaStatusUnknown; quota_ = -1; - quota_manager_->SetTemporaryGlobalOverrideQuota( - new_quota, + quota_manager_->SetTemporaryGlobalQuota(new_quota, callback_factory_.NewCallback( &QuotaManagerTest::DidGetQuota)); } @@ -193,8 +193,8 @@ class QuotaManagerTest : public testing::Test { quota_ = -1; available_space_ = -1; quota_manager_->GetUsageAndQuotaForEviction( - base::Bind(&QuotaManagerTest::DidGetUsageAndQuotaForEviction, - weak_factory_.GetWeakPtr())); + callback_factory_.NewCallback( + &QuotaManagerTest::DidGetUsageAndQuotaForEviction)); } void GetCachedOrigins(StorageType type, std::set<GURL>* origins) { @@ -305,12 +305,12 @@ class QuotaManagerTest : public testing::Test { } void DidGetUsageAndQuotaForEviction(QuotaStatusCode status, - const QuotaAndUsage& quota_and_usage) { + int64 usage, int64 unlimited_usage, int64 quota, int64 available_space) { quota_status_ = status; - usage_ = quota_and_usage.usage; - unlimited_usage_ = quota_and_usage.unlimited_usage; - quota_ = quota_and_usage.quota; - available_space_ = quota_and_usage.available_disk_space; + usage_ = usage; + unlimited_usage_ = unlimited_usage; + quota_ = quota; + available_space_ = available_space; } void DidGetLRUOrigin(const GURL& origin) { @@ -375,7 +375,6 @@ class QuotaManagerTest : public testing::Test { ScopedTempDir data_dir_; base::ScopedCallbackFactory<QuotaManagerTest> callback_factory_; - base::WeakPtrFactory<QuotaManagerTest> weak_factory_; scoped_refptr<QuotaManager> quota_manager_; scoped_refptr<MockSpecialStoragePolicy> mock_special_storage_policy_; @@ -441,7 +440,7 @@ TEST_F(QuotaManagerTest, GetUsageInfo) { TEST_F(QuotaManagerTest, GetUsageAndQuota_Simple) { static const MockOriginData kData[] = { - { "http://foo.com/", kTemp, 10 }, + { "http://foo.com/", kTemp, 10 }, { "http://foo.com/", kPerm, 80 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); @@ -457,6 +456,7 @@ TEST_F(QuotaManagerTest, GetUsageAndQuota_Simple) { EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10, usage()); EXPECT_LE(0, quota()); + EXPECT_GE(QuotaManager::kTemporaryStorageQuotaMaxSize, quota()); int64 quota_returned_for_foo = quota(); GetUsageAndQuota(GURL("http://bar.com/"), kTemp); @@ -534,7 +534,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_MultiOrigins) { { "http://bar.com/", kTemp, 5 }, { "https://bar.com/", kTemp, 7 }, { "http://baz.com/", kTemp, 30 }, - { "http://foo.com/", kPerm, 40 }, + { "http://foo.com/", kPerm, 40 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); @@ -655,9 +655,9 @@ TEST_F(QuotaManagerTest, GetTemporaryUsage_WithModify) { TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_WithAdditionalTasks) { static const MockOriginData kData[] = { - { "http://foo.com/", kTemp, 10 }, - { "http://foo.com:8080/", kTemp, 20 }, - { "http://bar.com/", kTemp, 13 }, + { "http://foo.com/", kTemp, 10 }, + { "http://foo.com:8080/", kTemp, 20 }, + { "http://bar.com/", kTemp, 13 }, { "http://foo.com/", kPerm, 40 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); @@ -689,9 +689,9 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_WithAdditionalTasks) { TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_NukeManager) { static const MockOriginData kData[] = { - { "http://foo.com/", kTemp, 10 }, - { "http://foo.com:8080/", kTemp, 20 }, - { "http://bar.com/", kTemp, 13 }, + { "http://foo.com/", kTemp, 10 }, + { "http://foo.com:8080/", kTemp, 20 }, + { "http://bar.com/", kTemp, 13 }, { "http://foo.com/", kPerm, 40 }, }; RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData))); @@ -1259,10 +1259,10 @@ TEST_F(QuotaManagerTest, EvictOriginDataWithDeletionError) { TEST_F(QuotaManagerTest, GetUsageAndQuotaForEviction) { static const MockOriginData kData[] = { - { "http://foo.com/", kTemp, 1 }, - { "http://foo.com:1/", kTemp, 20 }, + { "http://foo.com/", kTemp, 1 }, + { "http://foo.com:1/", kTemp, 20 }, { "http://foo.com/", kPerm, 300 }, - { "http://unlimited/", kTemp, 4000 }, + { "http://unlimited/", kTemp, 4000 }, }; mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/")); @@ -1388,17 +1388,16 @@ TEST_F(QuotaManagerTest, GetCachedOrigins) { GetCachedOrigins(kTemp, &origins); EXPECT_TRUE(origins.empty()); - // No matter how we make queries the quota manager tries to cache all - // the origins at startup. + // Make the cache hot. GetHostUsage("a.com", kTemp); MessageLoop::current()->RunAllPending(); GetCachedOrigins(kTemp, &origins); - EXPECT_EQ(3U, origins.size()); + EXPECT_EQ(2U, origins.size()); GetHostUsage("b.com", kTemp); MessageLoop::current()->RunAllPending(); GetCachedOrigins(kTemp, &origins); - EXPECT_EQ(3U, origins.size()); + EXPECT_EQ(2U, origins.size()); GetCachedOrigins(kPerm, &origins); EXPECT_TRUE(origins.empty()); diff --git a/webkit/quota/quota_temporary_storage_evictor.cc b/webkit/quota/quota_temporary_storage_evictor.cc index 1ad329a..f4b6750 100644 --- a/webkit/quota/quota_temporary_storage_evictor.cc +++ b/webkit/quota/quota_temporary_storage_evictor.cc @@ -4,7 +4,6 @@ #include "webkit/quota/quota_temporary_storage_evictor.h" -#include "base/bind.h" #include "base/metrics/histogram.h" #include "googleurl/src/gurl.h" #include "webkit/quota/quota_manager.h" @@ -22,16 +21,17 @@ namespace { const int64 kMBytes = 1024 * 1024; -const double kUsageRatioToStartEviction = 0.7; -const int kThresholdOfErrorsToStopEviction = 5; -const base::TimeDelta kHistogramReportInterval = - base::TimeDelta::FromMilliseconds(60 * 60 * 1000); // 1 hour } namespace quota { +const double QuotaTemporaryStorageEvictor::kUsageRatioToStartEviction = 0.7; const int QuotaTemporaryStorageEvictor:: kMinAvailableDiskSpaceToStartEvictionNotSpecified = -1; +const int QuotaTemporaryStorageEvictor::kThresholdOfErrorsToStopEviction = 5; + +const base::TimeDelta QuotaTemporaryStorageEvictor::kHistogramReportInterval = + base::TimeDelta::FromMilliseconds(60 * 60 * 1000); // 1 hour QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor( QuotaEvictionHandler* quota_eviction_handler, @@ -41,8 +41,7 @@ QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor( quota_eviction_handler_(quota_eviction_handler), interval_ms_(interval_ms), repeated_eviction_(true), - callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), - weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { DCHECK(quota_eviction_handler); } @@ -144,33 +143,32 @@ void QuotaTemporaryStorageEvictor::ConsiderEviction() { OnEvictionRoundStarted(); // Get usage and disk space, then continue. - quota_eviction_handler_->GetUsageAndQuotaForEviction( - base::Bind(&QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction, - weak_factory_.GetWeakPtr())); + quota_eviction_handler_->GetUsageAndQuotaForEviction(callback_factory_. + NewCallback( + &QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction)); } void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction( QuotaStatusCode status, - const QuotaAndUsage& qau) { + int64 usage, + int64 unlimited_usage, + int64 quota, + int64 available_disk_space) { DCHECK(CalledOnValidThread()); + DCHECK_GE(usage, unlimited_usage); // unlimited_usage is a subset of usage - // unlimited_usage is a subset of usage - DCHECK_GE(qau.usage, qau.unlimited_usage); - - int64 usage = qau.usage - qau.unlimited_usage; + usage -= unlimited_usage; if (status != kQuotaStatusOk) ++statistics_.num_errors_on_getting_usage_and_quota; int64 usage_overage = std::max( static_cast<int64>(0), - usage - static_cast<int64>(qau.quota * kUsageRatioToStartEviction)); + usage - static_cast<int64>(quota * kUsageRatioToStartEviction)); - // min_available_disk_space_to_start_eviction_ might be < 0 if no value - // is explicitly configured yet. int64 diskspace_shortage = std::max( static_cast<int64>(0), - min_available_disk_space_to_start_eviction_ - qau.available_disk_space); + min_available_disk_space_to_start_eviction_ - available_disk_space); if (!round_statistics_.is_initialized) { round_statistics_.usage_overage_at_round = usage_overage; diff --git a/webkit/quota/quota_temporary_storage_evictor.h b/webkit/quota/quota_temporary_storage_evictor.h index a537171..e65dd80 100644 --- a/webkit/quota/quota_temporary_storage_evictor.h +++ b/webkit/quota/quota_temporary_storage_evictor.h @@ -10,7 +10,6 @@ #include <string> #include "base/memory/scoped_callback_factory.h" -#include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" #include "base/timer.h" #include "webkit/quota/quota_types.h" @@ -24,7 +23,6 @@ class MessageLoopProxy; namespace quota { class QuotaEvictionHandler; -struct QuotaAndUsage; class QuotaTemporaryStorageEvictor : public base::NonThreadSafe { public: @@ -102,7 +100,10 @@ class QuotaTemporaryStorageEvictor : public base::NonThreadSafe { void ConsiderEviction(); void OnGotUsageAndQuotaForEviction( QuotaStatusCode status, - const QuotaAndUsage& quota_and_usage); + int64 usage, + int64 unlimited_usage, + int64 quota, + int64 available_disk_space); void OnGotLRUOrigin(const GURL& origin); void OnEvictionComplete(QuotaStatusCode status); @@ -114,7 +115,10 @@ class QuotaTemporaryStorageEvictor : public base::NonThreadSafe { repeated_eviction_ = repeated_eviction; } + static const double kUsageRatioToStartEviction; static const int kMinAvailableDiskSpaceToStartEvictionNotSpecified; + static const int kThresholdOfErrorsToStopEviction; + static const base::TimeDelta kHistogramReportInterval; int64 min_available_disk_space_to_start_eviction_; @@ -134,7 +138,6 @@ class QuotaTemporaryStorageEvictor : public base::NonThreadSafe { base::RepeatingTimer<QuotaTemporaryStorageEvictor> histogram_timer_; base::ScopedCallbackFactory<QuotaTemporaryStorageEvictor> callback_factory_; - base::WeakPtrFactory<QuotaTemporaryStorageEvictor> weak_factory_; DISALLOW_COPY_AND_ASSIGN(QuotaTemporaryStorageEvictor); }; diff --git a/webkit/quota/quota_temporary_storage_evictor_unittest.cc b/webkit/quota/quota_temporary_storage_evictor_unittest.cc index 398ba50..6e857c7 100644 --- a/webkit/quota/quota_temporary_storage_evictor_unittest.cc +++ b/webkit/quota/quota_temporary_storage_evictor_unittest.cc @@ -7,7 +7,6 @@ #include <list> #include <map> -#include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/message_loop_proxy.h" @@ -49,16 +48,17 @@ class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler { } virtual void GetUsageAndQuotaForEviction( - const GetUsageAndQuotaForEvictionCallback& callback) OVERRIDE { + GetUsageAndQuotaForEvictionCallback* callback) OVERRIDE { if (error_on_get_usage_and_quota_) { - callback.Run(quota::kQuotaErrorInvalidAccess, QuotaAndUsage()); + callback->Run(quota::kQuotaErrorInvalidAccess, 0, 0, 0, 0); + delete callback; return; } if (task_for_get_usage_and_quota_.get()) task_for_get_usage_and_quota_->Run(); - QuotaAndUsage quota_and_usage = { - GetUsage(), unlimited_usage_, quota_, available_space_ }; - callback.Run(quota::kQuotaStatusOk, quota_and_usage); + callback->Run(quota::kQuotaStatusOk, GetUsage(), unlimited_usage_, + quota_, available_space_); + delete callback; } virtual void GetLRUOrigin( diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index ff8c757..886f7f6 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -448,13 +448,13 @@ '../../plugins/ppapi/resource_tracker_unittest.cc', '../../plugins/ppapi/time_conversion_unittest.cc', '../../plugins/ppapi/url_request_info_unittest.cc', - '../../quota/mock_quota_manager.cc', - '../../quota/mock_quota_manager.h', - '../../quota/mock_quota_manager_unittest.cc', '../../quota/mock_special_storage_policy.cc', '../../quota/mock_special_storage_policy.h', '../../quota/mock_storage_client.cc', '../../quota/mock_storage_client.h', + '../../quota/mock_quota_manager.cc', + '../../quota/mock_quota_manager.h', + '../../quota/mock_quota_manager_unittest.cc', '../../quota/quota_database_unittest.cc', '../../quota/quota_manager_unittest.cc', '../../quota/quota_temporary_storage_evictor_unittest.cc', |