diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-10 23:29:09 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-10 23:29:09 +0000 |
commit | e0184cbde1634faa300d63c7880b5acf312f45d6 (patch) | |
tree | 69ef5ba562bbc68276fddd3279c6ca7e8e27d025 /webkit/appcache/appcache_storage_impl.cc | |
parent | b7d94558973c6c6f2776f68a4d34d20cd5303ac5 (diff) | |
download | chromium_src-e0184cbde1634faa300d63c7880b5acf312f45d6.zip chromium_src-e0184cbde1634faa300d63c7880b5acf312f45d6.tar.gz chromium_src-e0184cbde1634faa300d63c7880b5acf312f45d6.tar.bz2 |
AppCache + Quota integration
* Notify the QuotaManager of accesses and modifications to the amount of storage utlized.
* Implement the QuotaClient interface so the manager can query the appcache for usage and delete data.
* When storing appcaches, use QuotaManager GetUsageAndQuota and respect the limit.
* Remove the old and unsed support for storing per-origin quota values in the appcache DB.
BUG=61676
TEST=unittests
Review URL: http://codereview.chromium.org/7031065
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@88746 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache/appcache_storage_impl.cc')
-rw-r--r-- | webkit/appcache/appcache_storage_impl.cc | 142 |
1 files changed, 111 insertions, 31 deletions
diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index fe325a1..ef2a1b5 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -4,6 +4,8 @@ #include "webkit/appcache/appcache_storage_impl.h" +#include <set> + #include "app/sql/connection.h" #include "app/sql/transaction.h" #include "base/file_util.h" @@ -19,9 +21,12 @@ #include "webkit/appcache/appcache_group.h" #include "webkit/appcache/appcache_histograms.h" #include "webkit/appcache/appcache_policy.h" +#include "webkit/appcache/appcache_quota_client.h" #include "webkit/appcache/appcache_response.h" #include "webkit/appcache/appcache_service.h" #include "webkit/appcache/appcache_thread.h" +#include "webkit/quota/quota_client.h" +#include "webkit/quota/quota_manager.h" #include "webkit/quota/special_storage_policy.h" namespace { @@ -33,6 +38,9 @@ void DeleteDirectory(const FilePath& path) { namespace appcache { +// Hard coded default when not using quota management. +static const int kDefaultQuota = 5 * 1024 * 1024; + static const int kMaxDiskCacheSize = 250 * 1024 * 1024; static const int kMaxMemDiskCacheSize = 10 * 1024 * 1024; static const FilePath::CharType kDiskCacheDirectoryName[] = @@ -146,14 +154,14 @@ class AppCacheStorageImpl::InitTask : public DatabaseTask { int64 last_cache_id_; int64 last_response_id_; int64 last_deletable_response_rowid_; - std::set<GURL> origins_with_groups_; + std::map<GURL, int64> usage_map_; }; void AppCacheStorageImpl::InitTask::Run() { database_->FindLastStorageIds( &last_group_id_, &last_cache_id_, &last_response_id_, &last_deletable_response_rowid_); - database_->FindOriginsWithGroups(&origins_with_groups_); + database_->GetAllOriginUsage(&usage_map_); } void AppCacheStorageImpl::InitTask::RunCompleted() { @@ -163,14 +171,16 @@ void AppCacheStorageImpl::InitTask::RunCompleted() { storage_->last_deletable_response_rowid_ = last_deletable_response_rowid_; if (!storage_->is_disabled()) { - storage_->origins_with_groups_.swap(origins_with_groups_); - + storage_->usage_map_.swap(usage_map_); const int kDelayMillis = 5 * 60 * 1000; // Five minutes. MessageLoop::current()->PostDelayedTask(FROM_HERE, storage_->method_factory_.NewRunnableMethod( &AppCacheStorageImpl::DelayedStartDeletingUnusedResponses), kDelayMillis); } + + if (storage_->service()->quota_client()) + storage_->service()->quota_client()->NotifyAppCacheReady(); } // CloseConnectionTask ------- @@ -302,6 +312,8 @@ void AppCacheStorageImpl::StoreOrLoadTask::CreateCacheAndGroupFromRecords( cache->get()->GetEntry(*iter)->add_types(AppCacheEntry::FOREIGN); } + storage_->NotifyStorageAccessed(group_record_.origin); + // TODO(michaeln): Maybe verify that the responses we expect to exist // do actually exist in the disk_cache (and if not then what?) } @@ -395,6 +407,10 @@ class AppCacheStorageImpl::StoreGroupAndCacheTask : public StoreOrLoadTask { StoreGroupAndCacheTask(AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache); + void GetQuotaThenSchedule(); + void OnQuotaCallback( + quota::QuotaStatusCode status, int64 usage, int64 quota); + virtual void Run(); virtual void RunCompleted(); virtual void CancelCompletion(); @@ -403,7 +419,8 @@ class AppCacheStorageImpl::StoreGroupAndCacheTask : public StoreOrLoadTask { scoped_refptr<AppCache> cache_; bool success_; bool would_exceed_quota_; - int64 quota_override_; + int64 space_available_; + int64 new_origin_usage_; std::vector<int64> newly_deletable_response_ids_; }; @@ -411,7 +428,7 @@ AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask( AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache) : StoreOrLoadTask(storage), group_(group), cache_(newest_cache), success_(false), would_exceed_quota_(false), - quota_override_(-1) { + space_available_(-1), new_origin_usage_(-1) { group_record_.group_id = group->group_id(); group_record_.manifest_url = group->manifest_url(); group_record_.origin = group_record_.manifest_url.GetOrigin(); @@ -419,12 +436,43 @@ AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask( group, &cache_record_, &entry_records_, &fallback_namespace_records_, &online_whitelist_records_); +} - if (storage->service()->special_storage_policy() && - storage->service()->special_storage_policy()->IsStorageUnlimited( - group_record_.origin)) { - quota_override_ = kint64max; +void AppCacheStorageImpl::StoreGroupAndCacheTask::GetQuotaThenSchedule() { + quota::QuotaManager* quota_manager = NULL; + if (storage_->service()->quota_manager_proxy()) { + quota_manager = + storage_->service()->quota_manager_proxy()->quota_manager(); + } + + if (!quota_manager) { + if (storage_->service()->special_storage_policy() && + storage_->service()->special_storage_policy()->IsStorageUnlimited( + group_record_.origin)) + space_available_ = kint64max; + Schedule(); + return; + } + + // We have to ask the quota manager for the value. + AddRef(); // balanced in the OnQuotaCallback + storage_->pending_quota_queries_.insert(this); + quota_manager->GetUsageAndQuota( + group_record_.origin, quota::kStorageTypeTemporary, + NewCallback(this, &StoreGroupAndCacheTask::OnQuotaCallback)); +} + +void AppCacheStorageImpl::StoreGroupAndCacheTask::OnQuotaCallback( + quota::QuotaStatusCode status, int64 usage, int64 quota) { + if (storage_) { + if (status == quota::kQuotaStatusOk) + space_available_ = std::max(static_cast<int64>(0), quota - usage); + else + space_available_ = 0; + storage_->pending_quota_queries_.erase(this); + Schedule(); } + Release(); // balanced in GetQuotaThenSchedule } void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { @@ -437,6 +485,8 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { if (!transaction.Begin()) return; + int64 old_origin_usage = database_->GetOriginUsage(group_record_.origin); + AppCacheDatabase::GroupRecord existing_group; success_ = database_->FindGroup(group_record_.group_id, &existing_group); if (!success_) { @@ -494,11 +544,29 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { if (!success_) return; - int64 quota = (quota_override_ >= 0) ? - quota_override_ : - database_->GetOriginQuota(group_record_.origin); + new_origin_usage_ = database_->GetOriginUsage(group_record_.origin); + + // Only check quota when the new usage exceeds the old usage. + if (new_origin_usage_ <= old_origin_usage) { + success_ = transaction.Commit(); + return; + } - if (database_->GetOriginUsage(group_record_.origin) > quota) { + // Use a simple hard-coded value when not using quota management. + if (space_available_ == -1) { + if (new_origin_usage_ > kDefaultQuota) { + would_exceed_quota_ = true; + success_ = false; + return; + } + success_ = transaction.Commit(); + return; + } + + // Check limits based on the space availbable given to us via the + // quota system. + int64 delta = new_origin_usage_ - old_origin_usage; + if (delta > space_available_) { would_exceed_quota_ = true; success_ = false; return; @@ -509,7 +577,8 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() { if (success_) { - storage_->origins_with_groups_.insert(group_->manifest_url().GetOrigin()); + storage_->UpdateUsageMapAndNotify( + group_->manifest_url().GetOrigin(), new_origin_usage_); if (cache_ != group_->newest_complete_cache()) { cache_->set_complete(true); group_->AddCache(cache_); @@ -523,6 +592,9 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() { would_exceed_quota_)); group_ = NULL; cache_ = NULL; + + // TODO(michaeln): if (would_exceed_quota_) what if the current usage + // also exceeds the quota? http://crbug.com/83968 } void AppCacheStorageImpl::StoreGroupAndCacheTask::CancelCompletion() { @@ -837,15 +909,17 @@ class AppCacheStorageImpl::MakeGroupObsoleteTask : public DatabaseTask { scoped_refptr<AppCacheGroup> group_; int64 group_id_; + GURL origin_; bool success_; - std::set<GURL> origins_with_groups_; + int64 new_origin_usage_; std::vector<int64> newly_deletable_response_ids_; }; AppCacheStorageImpl::MakeGroupObsoleteTask::MakeGroupObsoleteTask( AppCacheStorageImpl* storage, AppCacheGroup* group) : DatabaseTask(storage), group_(group), group_id_(group->group_id()), - success_(false) { + origin_(group->manifest_url().GetOrigin()), + success_(false), new_origin_usage_(-1) { } void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() { @@ -861,10 +935,13 @@ void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() { AppCacheDatabase::GroupRecord group_record; if (!database_->FindGroup(group_id_, &group_record)) { // This group doesn't exists in the database, nothing todo here. + new_origin_usage_ = database_->GetOriginUsage(origin_); success_ = true; return; } + DCHECK_EQ(group_record.origin, origin_); + AppCacheDatabase::CacheRecord cache_record; if (database_->FindCacheForGroup(group_id_, &cache_record)) { database_->FindResponseIdsForCacheAsVector(cache_record.cache_id, @@ -881,16 +958,15 @@ void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() { success_ = database_->DeleteGroup(group_id_); } - success_ = success_ && - database_->FindOriginsWithGroups(&origins_with_groups_) && - transaction.Commit(); + new_origin_usage_ = database_->GetOriginUsage(origin_); + success_ = success_ && transaction.Commit(); } void AppCacheStorageImpl::MakeGroupObsoleteTask::RunCompleted() { if (success_) { group_->set_obsolete(true); if (!storage_->is_disabled()) { - storage_->origins_with_groups_.swap(origins_with_groups_); + storage_->UpdateUsageMapAndNotify(origin_, new_origin_usage_); group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_); // Also remove from the working set, caches for an 'obsolete' group @@ -970,8 +1046,11 @@ class AppCacheStorageImpl::UpdateGroupLastAccessTimeTask : public DatabaseTask { public: UpdateGroupLastAccessTimeTask( - AppCacheStorageImpl* storage, int64 group_id, base::Time time) - : DatabaseTask(storage), group_id_(group_id), last_access_time_(time) {} + AppCacheStorageImpl* storage, AppCacheGroup* group, base::Time time) + : DatabaseTask(storage), group_id_(group->group_id()), + last_access_time_(time) { + storage->NotifyStorageAccessed(group->manifest_url().GetOrigin()); + } virtual void Run(); @@ -1002,6 +1081,9 @@ AppCacheStorageImpl::AppCacheStorageImpl(AppCacheService* service) AppCacheStorageImpl::~AppCacheStorageImpl() { STLDeleteElements(&pending_simple_tasks_); + std::for_each(pending_quota_queries_.begin(), + pending_quota_queries_.end(), + std::mem_fun(&DatabaseTask::CancelCompletion)); std::for_each(scheduled_database_tasks_.begin(), scheduled_database_tasks_.end(), std::mem_fun(&DatabaseTask::CancelCompletion)); @@ -1030,7 +1112,7 @@ void AppCacheStorageImpl::Disable() { return; VLOG(1) << "Disabling appcache storage."; is_disabled_ = true; - origins_with_groups_.clear(); + ClearUsageMapAndNotify(); working_set()->Disable(); if (disk_cache_.get()) disk_cache_->Disable(); @@ -1058,7 +1140,7 @@ void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) { if (cache->owning_group()) { scoped_refptr<DatabaseTask> update_task( new UpdateGroupLastAccessTimeTask( - this, cache->owning_group()->group_id(), base::Time::Now())); + this, cache->owning_group(), base::Time::Now())); update_task->Schedule(); } return; @@ -1087,7 +1169,7 @@ void AppCacheStorageImpl::LoadOrCreateGroup( delegate->OnGroupLoaded(group, manifest_url); scoped_refptr<DatabaseTask> update_task( new UpdateGroupLastAccessTimeTask( - this, group->group_id(), base::Time::Now())); + this, group, base::Time::Now())); update_task->Schedule(); return; } @@ -1098,8 +1180,7 @@ void AppCacheStorageImpl::LoadOrCreateGroup( return; } - if (origins_with_groups_.find(manifest_url.GetOrigin()) == - origins_with_groups_.end()) { + if (usage_map_.find(manifest_url.GetOrigin()) == usage_map_.end()) { // No need to query the database, return a new group immediately. scoped_refptr<AppCacheGroup> group(new AppCacheGroup( service_, manifest_url, NewGroupId())); @@ -1124,7 +1205,7 @@ void AppCacheStorageImpl::StoreGroupAndNewestCache( scoped_refptr<StoreGroupAndCacheTask> task( new StoreGroupAndCacheTask(this, group, newest_cache)); task->AddDelegate(GetOrCreateDelegateReference(delegate)); - task->Schedule(); + task->GetQuotaThenSchedule(); } void AppCacheStorageImpl::FindResponseForMainRequest( @@ -1168,8 +1249,7 @@ void AppCacheStorageImpl::FindResponseForMainRequest( } } - if (IsInitTaskComplete() && - origins_with_groups_.find(origin) == origins_with_groups_.end()) { + if (IsInitTaskComplete() && usage_map_.find(origin) == usage_map_.end()) { // No need to query the database, return async'ly but without going thru // the DB thread. scoped_refptr<AppCacheGroup> no_group; |