summaryrefslogtreecommitdiffstats
path: root/webkit/appcache/appcache_storage_impl.cc
diff options
context:
space:
mode:
authormichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-11 20:38:06 +0000
committermichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-11 20:38:06 +0000
commitcc70801856ea67a98ac0ff0b9064a6b56e67288d (patch)
tree64239c53473984558fe246e99c20fb9b72fb9ff4 /webkit/appcache/appcache_storage_impl.cc
parent27e469a6fb9942076a2cf27d36f071c31c63dd94 (diff)
downloadchromium_src-cc70801856ea67a98ac0ff0b9064a6b56e67288d.zip
chromium_src-cc70801856ea67a98ac0ff0b9064a6b56e67288d.tar.gz
chromium_src-cc70801856ea67a98ac0ff0b9064a6b56e67288d.tar.bz2
Lazily delete unused responses from the disk cache.
TEST=not yet BUG=none Review URL: http://codereview.chromium.org/545001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35937 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache/appcache_storage_impl.cc')
-rw-r--r--webkit/appcache/appcache_storage_impl.cc142
1 files changed, 138 insertions, 4 deletions
diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc
index 3d88727..a7bbdea 100644
--- a/webkit/appcache/appcache_storage_impl.cc
+++ b/webkit/appcache/appcache_storage_impl.cc
@@ -106,7 +106,8 @@ class AppCacheStorageImpl::InitTask : public DatabaseTask {
public:
explicit InitTask(AppCacheStorageImpl* storage)
: DatabaseTask(storage), last_group_id_(0),
- last_cache_id_(0), last_response_id_(0) {}
+ last_cache_id_(0), last_response_id_(0),
+ last_deletable_response_rowid_(0) {}
virtual void Run();
virtual void RunCompleted();
@@ -129,7 +130,14 @@ void AppCacheStorageImpl::InitTask::RunCompleted() {
storage_->last_group_id_ = last_group_id_;
storage_->last_cache_id_ = last_cache_id_;
storage_->last_response_id_ = last_response_id_;
+ storage_->last_deletable_response_rowid_ = last_deletable_response_rowid_;
storage_->origins_with_groups_.swap(origins_with_groups_);
+
+ const int kDelayMillis = 5 * 60 * 1000; // Five minutes.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ storage_->method_factory_.NewRunnableMethod(
+ &AppCacheStorageImpl::DelayedStartDeletingUnusedResponses),
+ kDelayMillis);
}
// CloseConnectionTask -------
@@ -602,11 +610,66 @@ void AppCacheStorageImpl::MakeGroupObsoleteTask::CancelCompletion() {
group_ = NULL;
}
+// GetDeletableResponseIdsTask -------
+
+class AppCacheStorageImpl::GetDeletableResponseIdsTask : public DatabaseTask {
+ public:
+ GetDeletableResponseIdsTask(AppCacheStorageImpl* storage, int64 max_rowid)
+ : DatabaseTask(storage), max_rowid_(max_rowid) {}
+ virtual void Run();
+ virtual void RunCompleted();
+ int64 max_rowid_;
+ std::vector<int64> response_ids_;
+};
+
+void AppCacheStorageImpl::GetDeletableResponseIdsTask::Run() {
+ const int kSqlLimit = 1000;
+ database_->GetDeletableResponseIds(&response_ids_, max_rowid_, kSqlLimit);
+}
+
+void AppCacheStorageImpl::GetDeletableResponseIdsTask::RunCompleted() {
+ if (!response_ids_.empty())
+ storage_->StartDeletingResponses(response_ids_);
+}
+
+// InsertDeletableResponseIdsTask -------
+
+class AppCacheStorageImpl::InsertDeletableResponseIdsTask
+ : public DatabaseTask {
+ public:
+ explicit InsertDeletableResponseIdsTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+ virtual void Run();
+ std::vector<int64> response_ids_;
+};
+
+void AppCacheStorageImpl::InsertDeletableResponseIdsTask::Run() {
+ database_->InsertDeletableResponseIds(response_ids_);
+}
+
+// DeleteDeletableResponseIdsTask -------
+
+class AppCacheStorageImpl::DeleteDeletableResponseIdsTask
+ : public DatabaseTask {
+ public:
+ explicit DeleteDeletableResponseIdsTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+ virtual void Run();
+ std::vector<int64> response_ids_;
+};
+
+void AppCacheStorageImpl::DeleteDeletableResponseIdsTask::Run() {
+ database_->DeleteDeletableResponseIds(response_ids_);
+}
+
// AppCacheStorageImpl ---------------------------------------------------
AppCacheStorageImpl::AppCacheStorageImpl(AppCacheService* service)
: AppCacheStorage(service), is_incognito_(false),
+ is_response_deletion_scheduled_(false),
+ did_start_deleting_responses_(false),
+ last_deletable_response_rowid_(0), database_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}
@@ -818,12 +881,83 @@ AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter(
void AppCacheStorageImpl::DoomResponses(
const GURL& manifest_url, const std::vector<int64>& response_ids) {
- for (std::vector<int64>::const_iterator it = response_ids.begin();
- it != response_ids.end(); ++it) {
- disk_cache()->DoomEntry(Int64ToString(*it));
+ if (response_ids.empty())
+ return;
+
+ // Start deleting them from the disk cache incrementally.
+ StartDeletingResponses(response_ids);
+
+ // Also schedule a database task to record these ids in the
+ // deletable responses table.
+ // TODO(michaeln): There is a race here. If the browser crashes
+ // prior to committing these rows to the database and prior to us
+ // having deleted them from the disk cache, we'll never delete them.
+ scoped_refptr<InsertDeletableResponseIdsTask> task =
+ new InsertDeletableResponseIdsTask(this);
+ task->response_ids_ = response_ids;
+ task->Schedule();
+}
+
+void AppCacheStorageImpl::DelayedStartDeletingUnusedResponses() {
+ // Only if we haven't already begun.
+ if (!did_start_deleting_responses_) {
+ scoped_refptr<GetDeletableResponseIdsTask> task =
+ new GetDeletableResponseIdsTask(this, last_deletable_response_rowid_);
+ task->Schedule();
}
}
+void AppCacheStorageImpl::StartDeletingResponses(
+ const std::vector<int64>& response_ids) {
+ DCHECK(!response_ids.empty());
+ did_start_deleting_responses_ = true;
+ deletable_response_ids_.insert(
+ deletable_response_ids_.end(),
+ response_ids.begin(), response_ids.end());
+ if (!is_response_deletion_scheduled_)
+ ScheduleDeleteOneResponse();
+}
+
+void AppCacheStorageImpl::ScheduleDeleteOneResponse() {
+ DCHECK(!is_response_deletion_scheduled_);
+ const int kDelayMillis = 10;
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &AppCacheStorageImpl::DeleteOneResponse),
+ kDelayMillis);
+ is_response_deletion_scheduled_ = true;
+}
+
+void AppCacheStorageImpl::DeleteOneResponse() {
+ DCHECK(is_response_deletion_scheduled_);
+ DCHECK(!deletable_response_ids_.empty());
+
+ is_response_deletion_scheduled_ = false;
+
+ int64 id = deletable_response_ids_.front();
+ deletable_response_ids_.pop_front();
+ disk_cache()->DoomEntry(Int64ToString(id));
+ deleted_response_ids_.push_back(id);
+
+ const size_t kBatchSize = 50U;
+ if (deleted_response_ids_.size() >= kBatchSize ||
+ deletable_response_ids_.empty()) {
+ scoped_refptr<DeleteDeletableResponseIdsTask> task =
+ new DeleteDeletableResponseIdsTask(this);
+ task->response_ids_.swap(deleted_response_ids_);
+ task->Schedule();
+ }
+
+ if (deletable_response_ids_.empty()) {
+ scoped_refptr<GetDeletableResponseIdsTask> task =
+ new GetDeletableResponseIdsTask(this, last_deletable_response_rowid_);
+ task->Schedule();
+ return;
+ }
+
+ ScheduleDeleteOneResponse();
+}
+
AppCacheStorageImpl::CacheLoadTask*
AppCacheStorageImpl::GetPendingCacheLoadTask(int64 cache_id) {
PendingCacheLoads::iterator found = pending_cache_loads_.find(cache_id);