Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1136)

Unified Diff: webkit/browser/appcache/appcache_storage_impl.cc

Issue 344493002: Move all remaining appcache-related code to content namespace (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webkit/browser/appcache/appcache_storage_impl.cc
diff --git a/webkit/browser/appcache/appcache_storage_impl.cc b/webkit/browser/appcache/appcache_storage_impl.cc
deleted file mode 100644
index 62563d7ff1b5f2bb637f2f3fc294f6c6922d6a9a..0000000000000000000000000000000000000000
--- a/webkit/browser/appcache/appcache_storage_impl.cc
+++ /dev/null
@@ -1,1860 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "webkit/browser/appcache/appcache_storage_impl.h"
-
-#include <algorithm>
-#include <functional>
-#include <set>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "net/base/cache_type.h"
-#include "net/base/net_errors.h"
-#include "sql/connection.h"
-#include "sql/transaction.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_database.h"
-#include "webkit/browser/appcache/appcache_entry.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_histograms.h"
-#include "webkit/browser/appcache/appcache_quota_client.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-#include "webkit/browser/quota/quota_client.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/browser/quota/special_storage_policy.h"
-
-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 base::FilePath::CharType kDiskCacheDirectoryName[] =
- FILE_PATH_LITERAL("Cache");
-
-namespace {
-
-// Helpers for clearing data from the AppCacheDatabase.
-bool DeleteGroupAndRelatedRecords(AppCacheDatabase* database,
- int64 group_id,
- std::vector<int64>* deletable_response_ids) {
- AppCacheDatabase::CacheRecord cache_record;
- bool success = false;
- if (database->FindCacheForGroup(group_id, &cache_record)) {
- database->FindResponseIdsForCacheAsVector(cache_record.cache_id,
- deletable_response_ids);
- success =
- database->DeleteGroup(group_id) &&
- database->DeleteCache(cache_record.cache_id) &&
- database->DeleteEntriesForCache(cache_record.cache_id) &&
- database->DeleteNamespacesForCache(cache_record.cache_id) &&
- database->DeleteOnlineWhiteListForCache(cache_record.cache_id) &&
- database->InsertDeletableResponseIds(*deletable_response_ids);
- } else {
- NOTREACHED() << "A existing group without a cache is unexpected";
- success = database->DeleteGroup(group_id);
- }
- return success;
-}
-
-// Destroys |database|. If there is appcache data to be deleted
-// (|force_keep_session_state| is false), deletes session-only appcache data.
-void ClearSessionOnlyOrigins(
- AppCacheDatabase* database,
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy,
- bool force_keep_session_state) {
- scoped_ptr<AppCacheDatabase> database_to_delete(database);
-
- // If saving session state, only delete the database.
- if (force_keep_session_state)
- return;
-
- bool has_session_only_appcaches =
- special_storage_policy.get() &&
- special_storage_policy->HasSessionOnlyOrigins();
-
- // Clearning only session-only databases, and there are none.
- if (!has_session_only_appcaches)
- return;
-
- std::set<GURL> origins;
- database->FindOriginsWithGroups(&origins);
- if (origins.empty())
- return; // nothing to delete
-
- sql::Connection* connection = database->db_connection();
- if (!connection) {
- NOTREACHED() << "Missing database connection.";
- return;
- }
-
- std::set<GURL>::const_iterator origin;
- for (origin = origins.begin(); origin != origins.end(); ++origin) {
- if (!special_storage_policy->IsStorageSessionOnly(*origin))
- continue;
- if (special_storage_policy.get() &&
- special_storage_policy->IsStorageProtected(*origin))
- continue;
-
- std::vector<AppCacheDatabase::GroupRecord> groups;
- database->FindGroupsForOrigin(*origin, &groups);
- std::vector<AppCacheDatabase::GroupRecord>::const_iterator group;
- for (group = groups.begin(); group != groups.end(); ++group) {
- sql::Transaction transaction(connection);
- if (!transaction.Begin()) {
- NOTREACHED() << "Failed to start transaction";
- return;
- }
- std::vector<int64> deletable_response_ids;
- bool success = DeleteGroupAndRelatedRecords(database,
- group->group_id,
- &deletable_response_ids);
- success = success && transaction.Commit();
- DCHECK(success);
- } // for each group
- } // for each origin
-}
-
-} // namespace
-
-// DatabaseTask -----------------------------------------
-
-class AppCacheStorageImpl::DatabaseTask
- : public base::RefCountedThreadSafe<DatabaseTask> {
- public:
- explicit DatabaseTask(AppCacheStorageImpl* storage)
- : storage_(storage), database_(storage->database_),
- io_thread_(base::MessageLoopProxy::current()) {
- DCHECK(io_thread_.get());
- }
-
- void AddDelegate(DelegateReference* delegate_reference) {
- delegates_.push_back(make_scoped_refptr(delegate_reference));
- }
-
- // Schedules a task to be Run() on the DB thread. Tasks
- // are run in the order in which they are scheduled.
- void Schedule();
-
- // Called on the DB thread.
- virtual void Run() = 0;
-
- // Called on the IO thread after Run() has completed.
- virtual void RunCompleted() {}
-
- // Once scheduled a task cannot be cancelled, but the
- // call to RunCompleted may be. This method should only be
- // called on the IO thread. This is used by AppCacheStorageImpl
- // to cancel the completion calls when AppCacheStorageImpl is
- // destructed. This method may be overriden to release or delete
- // additional data associated with the task that is not DB thread
- // safe. If overriden, this base class method must be called from
- // within the override.
- virtual void CancelCompletion();
-
- protected:
- friend class base::RefCountedThreadSafe<DatabaseTask>;
- virtual ~DatabaseTask() {}
-
- AppCacheStorageImpl* storage_;
- AppCacheDatabase* database_;
- DelegateReferenceVector delegates_;
-
- private:
- void CallRun(base::TimeTicks schedule_time);
- void CallRunCompleted(base::TimeTicks schedule_time);
- void OnFatalError();
-
- scoped_refptr<base::MessageLoopProxy> io_thread_;
-};
-
-void AppCacheStorageImpl::DatabaseTask::Schedule() {
- DCHECK(storage_);
- DCHECK(io_thread_->BelongsToCurrentThread());
- if (!storage_->database_)
- return;
-
- if (storage_->db_thread_->PostTask(
- FROM_HERE,
- base::Bind(&DatabaseTask::CallRun, this, base::TimeTicks::Now()))) {
- storage_->scheduled_database_tasks_.push_back(this);
- } else {
- NOTREACHED() << "Thread for database tasks is not running.";
- }
-}
-
-void AppCacheStorageImpl::DatabaseTask::CancelCompletion() {
- DCHECK(io_thread_->BelongsToCurrentThread());
- delegates_.clear();
- storage_ = NULL;
-}
-
-void AppCacheStorageImpl::DatabaseTask::CallRun(
- base::TimeTicks schedule_time) {
- AppCacheHistograms::AddTaskQueueTimeSample(
- base::TimeTicks::Now() - schedule_time);
- if (!database_->is_disabled()) {
- base::TimeTicks run_time = base::TimeTicks::Now();
- Run();
- AppCacheHistograms::AddTaskRunTimeSample(
- base::TimeTicks::Now() - run_time);
-
- if (database_->was_corruption_detected()) {
- AppCacheHistograms::CountCorruptionDetected();
- database_->Disable();
- }
- if (database_->is_disabled()) {
- io_thread_->PostTask(
- FROM_HERE,
- base::Bind(&DatabaseTask::OnFatalError, this));
- }
- }
- io_thread_->PostTask(
- FROM_HERE,
- base::Bind(&DatabaseTask::CallRunCompleted, this,
- base::TimeTicks::Now()));
-}
-
-void AppCacheStorageImpl::DatabaseTask::CallRunCompleted(
- base::TimeTicks schedule_time) {
- AppCacheHistograms::AddCompletionQueueTimeSample(
- base::TimeTicks::Now() - schedule_time);
- if (storage_) {
- DCHECK(io_thread_->BelongsToCurrentThread());
- DCHECK(storage_->scheduled_database_tasks_.front() == this);
- storage_->scheduled_database_tasks_.pop_front();
- base::TimeTicks run_time = base::TimeTicks::Now();
- RunCompleted();
- AppCacheHistograms::AddCompletionRunTimeSample(
- base::TimeTicks::Now() - run_time);
- delegates_.clear();
- }
-}
-
-void AppCacheStorageImpl::DatabaseTask::OnFatalError() {
- if (storage_) {
- DCHECK(io_thread_->BelongsToCurrentThread());
- storage_->Disable();
- storage_->DeleteAndStartOver();
- }
-}
-
-// InitTask -------
-
-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_deletable_response_rowid_(0) {
- if (!storage->is_incognito_) {
- db_file_path_ =
- storage->cache_directory_.Append(kAppCacheDatabaseName);
- disk_cache_directory_ =
- storage->cache_directory_.Append(kDiskCacheDirectoryName);
- }
- }
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~InitTask() {}
-
- private:
- base::FilePath db_file_path_;
- base::FilePath disk_cache_directory_;
- int64 last_group_id_;
- int64 last_cache_id_;
- int64 last_response_id_;
- int64 last_deletable_response_rowid_;
- std::map<GURL, int64> usage_map_;
-};
-
-void AppCacheStorageImpl::InitTask::Run() {
- // If there is no sql database, ensure there is no disk cache either.
- if (!db_file_path_.empty() &&
- !base::PathExists(db_file_path_) &&
- base::DirectoryExists(disk_cache_directory_)) {
- base::DeleteFile(disk_cache_directory_, true);
- if (base::DirectoryExists(disk_cache_directory_)) {
- database_->Disable(); // This triggers OnFatalError handling.
- return;
- }
- }
-
- database_->FindLastStorageIds(
- &last_group_id_, &last_cache_id_, &last_response_id_,
- &last_deletable_response_rowid_);
- database_->GetAllOriginUsage(&usage_map_);
-}
-
-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_;
-
- if (!storage_->is_disabled()) {
- storage_->usage_map_.swap(usage_map_);
- const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AppCacheStorageImpl::DelayedStartDeletingUnusedResponses,
- storage_->weak_factory_.GetWeakPtr()),
- kDelay);
- }
-
- if (storage_->service()->quota_client())
- storage_->service()->quota_client()->NotifyAppCacheReady();
-}
-
-// DisableDatabaseTask -------
-
-class AppCacheStorageImpl::DisableDatabaseTask : public DatabaseTask {
- public:
- explicit DisableDatabaseTask(AppCacheStorageImpl* storage)
- : DatabaseTask(storage) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE { database_->Disable(); }
-
- protected:
- virtual ~DisableDatabaseTask() {}
-};
-
-// GetAllInfoTask -------
-
-class AppCacheStorageImpl::GetAllInfoTask : public DatabaseTask {
- public:
- explicit GetAllInfoTask(AppCacheStorageImpl* storage)
- : DatabaseTask(storage),
- info_collection_(new AppCacheInfoCollection()) {
- }
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~GetAllInfoTask() {}
-
- private:
- scoped_refptr<AppCacheInfoCollection> info_collection_;
-};
-
-void AppCacheStorageImpl::GetAllInfoTask::Run() {
- std::set<GURL> origins;
- database_->FindOriginsWithGroups(&origins);
- for (std::set<GURL>::const_iterator origin = origins.begin();
- origin != origins.end(); ++origin) {
- AppCacheInfoVector& infos =
- info_collection_->infos_by_origin[*origin];
- std::vector<AppCacheDatabase::GroupRecord> groups;
- database_->FindGroupsForOrigin(*origin, &groups);
- for (std::vector<AppCacheDatabase::GroupRecord>::const_iterator
- group = groups.begin();
- group != groups.end(); ++group) {
- AppCacheDatabase::CacheRecord cache_record;
- database_->FindCacheForGroup(group->group_id, &cache_record);
- AppCacheInfo info;
- info.manifest_url = group->manifest_url;
- info.creation_time = group->creation_time;
- info.size = cache_record.cache_size;
- info.last_access_time = group->last_access_time;
- info.last_update_time = cache_record.update_time;
- info.cache_id = cache_record.cache_id;
- info.group_id = group->group_id;
- info.is_complete = true;
- infos.push_back(info);
- }
- }
-}
-
-void AppCacheStorageImpl::GetAllInfoTask::RunCompleted() {
- DCHECK(delegates_.size() == 1);
- FOR_EACH_DELEGATE(delegates_, OnAllInfo(info_collection_.get()));
-}
-
-// StoreOrLoadTask -------
-
-class AppCacheStorageImpl::StoreOrLoadTask : public DatabaseTask {
- protected:
- explicit StoreOrLoadTask(AppCacheStorageImpl* storage)
- : DatabaseTask(storage) {}
- virtual ~StoreOrLoadTask() {}
-
- bool FindRelatedCacheRecords(int64 cache_id);
- void CreateCacheAndGroupFromRecords(
- scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group);
-
- AppCacheDatabase::GroupRecord group_record_;
- AppCacheDatabase::CacheRecord cache_record_;
- std::vector<AppCacheDatabase::EntryRecord> entry_records_;
- std::vector<AppCacheDatabase::NamespaceRecord>
- intercept_namespace_records_;
- std::vector<AppCacheDatabase::NamespaceRecord>
- fallback_namespace_records_;
- std::vector<AppCacheDatabase::OnlineWhiteListRecord>
- online_whitelist_records_;
-};
-
-bool AppCacheStorageImpl::StoreOrLoadTask::FindRelatedCacheRecords(
- int64 cache_id) {
- return database_->FindEntriesForCache(cache_id, &entry_records_) &&
- database_->FindNamespacesForCache(
- cache_id, &intercept_namespace_records_,
- &fallback_namespace_records_) &&
- database_->FindOnlineWhiteListForCache(
- cache_id, &online_whitelist_records_);
-}
-
-void AppCacheStorageImpl::StoreOrLoadTask::CreateCacheAndGroupFromRecords(
- scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group) {
- DCHECK(storage_ && cache && group);
-
- (*cache) = storage_->working_set_.GetCache(cache_record_.cache_id);
- if (cache->get()) {
- (*group) = cache->get()->owning_group();
- DCHECK(group->get());
- DCHECK_EQ(group_record_.group_id, group->get()->group_id());
-
- // TODO(michaeln): histogram is fishing for clues to crbug/95101
- if (!cache->get()->GetEntry(group_record_.manifest_url)) {
- AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
- AppCacheHistograms::CALLSITE_0);
- }
-
- storage_->NotifyStorageAccessed(group_record_.origin);
- return;
- }
-
- (*cache) = new AppCache(storage_, cache_record_.cache_id);
- cache->get()->InitializeWithDatabaseRecords(
- cache_record_, entry_records_,
- intercept_namespace_records_,
- fallback_namespace_records_,
- online_whitelist_records_);
- cache->get()->set_complete(true);
-
- (*group) = storage_->working_set_.GetGroup(group_record_.manifest_url);
- if (group->get()) {
- DCHECK(group_record_.group_id == group->get()->group_id());
- group->get()->AddCache(cache->get());
-
- // TODO(michaeln): histogram is fishing for clues to crbug/95101
- if (!cache->get()->GetEntry(group_record_.manifest_url)) {
- AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
- AppCacheHistograms::CALLSITE_1);
- }
- } else {
- (*group) = new AppCacheGroup(
- storage_, group_record_.manifest_url,
- group_record_.group_id);
- group->get()->set_creation_time(group_record_.creation_time);
- group->get()->AddCache(cache->get());
-
- // TODO(michaeln): histogram is fishing for clues to crbug/95101
- if (!cache->get()->GetEntry(group_record_.manifest_url)) {
- AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
- AppCacheHistograms::CALLSITE_2);
- }
- }
- DCHECK(group->get()->newest_complete_cache() == cache->get());
-
- // We have to update foriegn entries if MarkEntryAsForeignTasks
- // are in flight.
- std::vector<GURL> urls;
- storage_->GetPendingForeignMarkingsForCache(cache->get()->cache_id(), &urls);
- for (std::vector<GURL>::iterator iter = urls.begin();
- iter != urls.end(); ++iter) {
- DCHECK(cache->get()->GetEntry(*iter));
- 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?)
-}
-
-// CacheLoadTask -------
-
-class AppCacheStorageImpl::CacheLoadTask : public StoreOrLoadTask {
- public:
- CacheLoadTask(int64 cache_id, AppCacheStorageImpl* storage)
- : StoreOrLoadTask(storage), cache_id_(cache_id),
- success_(false) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~CacheLoadTask() {}
-
- private:
- int64 cache_id_;
- bool success_;
-};
-
-void AppCacheStorageImpl::CacheLoadTask::Run() {
- success_ =
- database_->FindCache(cache_id_, &cache_record_) &&
- database_->FindGroup(cache_record_.group_id, &group_record_) &&
- FindRelatedCacheRecords(cache_id_);
-
- if (success_)
- database_->UpdateGroupLastAccessTime(group_record_.group_id,
- base::Time::Now());
-}
-
-void AppCacheStorageImpl::CacheLoadTask::RunCompleted() {
- storage_->pending_cache_loads_.erase(cache_id_);
- scoped_refptr<AppCache> cache;
- scoped_refptr<AppCacheGroup> group;
- if (success_ && !storage_->is_disabled()) {
- DCHECK(cache_record_.cache_id == cache_id_);
- CreateCacheAndGroupFromRecords(&cache, &group);
- }
- FOR_EACH_DELEGATE(delegates_, OnCacheLoaded(cache.get(), cache_id_));
-}
-
-// GroupLoadTask -------
-
-class AppCacheStorageImpl::GroupLoadTask : public StoreOrLoadTask {
- public:
- GroupLoadTask(GURL manifest_url, AppCacheStorageImpl* storage)
- : StoreOrLoadTask(storage), manifest_url_(manifest_url),
- success_(false) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~GroupLoadTask() {}
-
- private:
- GURL manifest_url_;
- bool success_;
-};
-
-void AppCacheStorageImpl::GroupLoadTask::Run() {
- success_ =
- database_->FindGroupForManifestUrl(manifest_url_, &group_record_) &&
- database_->FindCacheForGroup(group_record_.group_id, &cache_record_) &&
- FindRelatedCacheRecords(cache_record_.cache_id);
-
- if (success_)
- database_->UpdateGroupLastAccessTime(group_record_.group_id,
- base::Time::Now());
-}
-
-void AppCacheStorageImpl::GroupLoadTask::RunCompleted() {
- storage_->pending_group_loads_.erase(manifest_url_);
- scoped_refptr<AppCacheGroup> group;
- scoped_refptr<AppCache> cache;
- if (!storage_->is_disabled()) {
- if (success_) {
- DCHECK(group_record_.manifest_url == manifest_url_);
- CreateCacheAndGroupFromRecords(&cache, &group);
- } else {
- group = storage_->working_set_.GetGroup(manifest_url_);
- if (!group.get()) {
- group =
- new AppCacheGroup(storage_, manifest_url_, storage_->NewGroupId());
- }
- }
- }
- FOR_EACH_DELEGATE(delegates_, OnGroupLoaded(group.get(), manifest_url_));
-}
-
-// StoreGroupAndCacheTask -------
-
-class AppCacheStorageImpl::StoreGroupAndCacheTask : public StoreOrLoadTask {
- public:
- StoreGroupAndCacheTask(AppCacheStorageImpl* storage, AppCacheGroup* group,
- AppCache* newest_cache);
-
- void GetQuotaThenSchedule();
- void OnQuotaCallback(
- quota::QuotaStatusCode status, int64 usage, int64 quota);
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
- virtual void CancelCompletion() OVERRIDE;
-
- protected:
- virtual ~StoreGroupAndCacheTask() {}
-
- private:
- scoped_refptr<AppCacheGroup> group_;
- scoped_refptr<AppCache> cache_;
- bool success_;
- bool would_exceed_quota_;
- int64 space_available_;
- int64 new_origin_usage_;
- std::vector<int64> newly_deletable_response_ids_;
-};
-
-AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask(
- AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache)
- : StoreOrLoadTask(storage), group_(group), cache_(newest_cache),
- success_(false), would_exceed_quota_(false),
- 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();
- newest_cache->ToDatabaseRecords(
- group,
- &cache_record_, &entry_records_,
- &intercept_namespace_records_,
- &fallback_namespace_records_,
- &online_whitelist_records_);
-}
-
-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.
- storage_->pending_quota_queries_.insert(this);
- quota_manager->GetUsageAndQuota(
- group_record_.origin, quota::kStorageTypeTemporary,
- base::Bind(&StoreGroupAndCacheTask::OnQuotaCallback, this));
-}
-
-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();
- }
-}
-
-void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() {
- DCHECK(!success_);
- sql::Connection* connection = database_->db_connection();
- if (!connection)
- return;
-
- sql::Transaction transaction(connection);
- 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_) {
- group_record_.creation_time = base::Time::Now();
- group_record_.last_access_time = base::Time::Now();
- success_ = database_->InsertGroup(&group_record_);
- } else {
- DCHECK(group_record_.group_id == existing_group.group_id);
- DCHECK(group_record_.manifest_url == existing_group.manifest_url);
- DCHECK(group_record_.origin == existing_group.origin);
-
- database_->UpdateGroupLastAccessTime(group_record_.group_id,
- base::Time::Now());
-
- AppCacheDatabase::CacheRecord cache;
- if (database_->FindCacheForGroup(group_record_.group_id, &cache)) {
- // Get the set of response ids in the old cache.
- std::set<int64> existing_response_ids;
- database_->FindResponseIdsForCacheAsSet(cache.cache_id,
- &existing_response_ids);
-
- // Remove those that remain in the new cache.
- std::vector<AppCacheDatabase::EntryRecord>::const_iterator entry_iter =
- entry_records_.begin();
- while (entry_iter != entry_records_.end()) {
- existing_response_ids.erase(entry_iter->response_id);
- ++entry_iter;
- }
-
- // The rest are deletable.
- std::set<int64>::const_iterator id_iter = existing_response_ids.begin();
- while (id_iter != existing_response_ids.end()) {
- newly_deletable_response_ids_.push_back(*id_iter);
- ++id_iter;
- }
-
- success_ =
- database_->DeleteCache(cache.cache_id) &&
- database_->DeleteEntriesForCache(cache.cache_id) &&
- database_->DeleteNamespacesForCache(cache.cache_id) &&
- database_->DeleteOnlineWhiteListForCache(cache.cache_id) &&
- database_->InsertDeletableResponseIds(newly_deletable_response_ids_);
- // TODO(michaeln): store group_id too with deletable ids
- } else {
- NOTREACHED() << "A existing group without a cache is unexpected";
- }
- }
-
- success_ =
- success_ &&
- database_->InsertCache(&cache_record_) &&
- database_->InsertEntryRecords(entry_records_) &&
- database_->InsertNamespaceRecords(intercept_namespace_records_) &&
- database_->InsertNamespaceRecords(fallback_namespace_records_) &&
- database_->InsertOnlineWhiteListRecords(online_whitelist_records_);
-
- if (!success_)
- return;
-
- 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;
- }
-
- // 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;
- }
-
- success_ = transaction.Commit();
-}
-
-void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() {
- if (success_) {
- storage_->UpdateUsageMapAndNotify(
- group_->manifest_url().GetOrigin(), new_origin_usage_);
- if (cache_.get() != group_->newest_complete_cache()) {
- cache_->set_complete(true);
- group_->AddCache(cache_.get());
- }
- if (group_->creation_time().is_null())
- group_->set_creation_time(group_record_.creation_time);
- group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_);
- }
- FOR_EACH_DELEGATE(
- delegates_,
- OnGroupAndNewestCacheStored(
- group_.get(), cache_.get(), success_, 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() {
- // Overriden to safely drop our reference to the group and cache
- // which are not thread safe refcounted.
- DatabaseTask::CancelCompletion();
- group_ = NULL;
- cache_ = NULL;
-}
-
-// FindMainResponseTask -------
-
-// Helpers for FindMainResponseTask::Run()
-namespace {
-class SortByCachePreference
- : public std::binary_function<
- AppCacheDatabase::EntryRecord,
- AppCacheDatabase::EntryRecord,
- bool> {
- public:
- SortByCachePreference(int64 preferred_id, const std::set<int64>& in_use_ids)
- : preferred_id_(preferred_id), in_use_ids_(in_use_ids) {
- }
- bool operator()(
- const AppCacheDatabase::EntryRecord& lhs,
- const AppCacheDatabase::EntryRecord& rhs) {
- return compute_value(lhs) > compute_value(rhs);
- }
- private:
- int compute_value(const AppCacheDatabase::EntryRecord& entry) {
- if (entry.cache_id == preferred_id_)
- return 100;
- else if (in_use_ids_.find(entry.cache_id) != in_use_ids_.end())
- return 50;
- return 0;
- }
- int64 preferred_id_;
- const std::set<int64>& in_use_ids_;
-};
-
-bool SortByLength(
- const AppCacheDatabase::NamespaceRecord& lhs,
- const AppCacheDatabase::NamespaceRecord& rhs) {
- return lhs.namespace_.namespace_url.spec().length() >
- rhs.namespace_.namespace_url.spec().length();
-}
-
-class NetworkNamespaceHelper {
- public:
- explicit NetworkNamespaceHelper(AppCacheDatabase* database)
- : database_(database) {
- }
-
- bool IsInNetworkNamespace(const GURL& url, int64 cache_id) {
- typedef std::pair<WhiteListMap::iterator, bool> InsertResult;
- InsertResult result = namespaces_map_.insert(
- WhiteListMap::value_type(cache_id, NamespaceVector()));
- if (result.second)
- GetOnlineWhiteListForCache(cache_id, &result.first->second);
- return AppCache::FindNamespace(result.first->second, url) != NULL;
- }
-
- private:
- void GetOnlineWhiteListForCache(
- int64 cache_id, NamespaceVector* namespaces) {
- DCHECK(namespaces && namespaces->empty());
- typedef std::vector<AppCacheDatabase::OnlineWhiteListRecord>
- WhiteListVector;
- WhiteListVector records;
- if (!database_->FindOnlineWhiteListForCache(cache_id, &records))
- return;
- WhiteListVector::const_iterator iter = records.begin();
- while (iter != records.end()) {
- namespaces->push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, iter->namespace_url, GURL(),
- iter->is_pattern));
- ++iter;
- }
- }
-
- // Key is cache id
- typedef std::map<int64, NamespaceVector> WhiteListMap;
- WhiteListMap namespaces_map_;
- AppCacheDatabase* database_;
-};
-
-} // namespace
-
-class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask {
- public:
- FindMainResponseTask(AppCacheStorageImpl* storage,
- const GURL& url,
- const GURL& preferred_manifest_url,
- const AppCacheWorkingSet::GroupMap* groups_in_use)
- : DatabaseTask(storage), url_(url),
- preferred_manifest_url_(preferred_manifest_url),
- cache_id_(kAppCacheNoCacheId), group_id_(0) {
- if (groups_in_use) {
- for (AppCacheWorkingSet::GroupMap::const_iterator it =
- groups_in_use->begin();
- it != groups_in_use->end(); ++it) {
- AppCacheGroup* group = it->second;
- AppCache* cache = group->newest_complete_cache();
- if (group->is_obsolete() || !cache)
- continue;
- cache_ids_in_use_.insert(cache->cache_id());
- }
- }
- }
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~FindMainResponseTask() {}
-
- private:
- typedef std::vector<AppCacheDatabase::NamespaceRecord*>
- NamespaceRecordPtrVector;
-
- bool FindExactMatch(int64 preferred_id);
- bool FindNamespaceMatch(int64 preferred_id);
- bool FindNamespaceHelper(
- int64 preferred_cache_id,
- AppCacheDatabase::NamespaceRecordVector* namespaces,
- NetworkNamespaceHelper* network_namespace_helper);
- bool FindFirstValidNamespace(const NamespaceRecordPtrVector& namespaces);
-
- GURL url_;
- GURL preferred_manifest_url_;
- std::set<int64> cache_ids_in_use_;
- AppCacheEntry entry_;
- AppCacheEntry fallback_entry_;
- GURL namespace_entry_url_;
- int64 cache_id_;
- int64 group_id_;
- GURL manifest_url_;
-};
-
-void AppCacheStorageImpl::FindMainResponseTask::Run() {
- // NOTE: The heuristics around choosing amoungst multiple candidates
- // is underspecified, and just plain not fully understood. This needs
- // to be refined.
-
- // The 'preferred_manifest_url' is the url of the manifest associated
- // with the page that opened or embedded the page being loaded now.
- // We have a strong preference to use resources from that cache.
- // We also have a lesser bias to use resources from caches that are currently
- // being used by other unrelated pages.
- // TODO(michaeln): come up with a 'preferred_manifest_url' in more cases
- // - when navigating a frame whose current contents are from an appcache
- // - when clicking an href in a frame that is appcached
- int64 preferred_cache_id = kAppCacheNoCacheId;
- if (!preferred_manifest_url_.is_empty()) {
- AppCacheDatabase::GroupRecord preferred_group;
- AppCacheDatabase::CacheRecord preferred_cache;
- if (database_->FindGroupForManifestUrl(
- preferred_manifest_url_, &preferred_group) &&
- database_->FindCacheForGroup(
- preferred_group.group_id, &preferred_cache)) {
- preferred_cache_id = preferred_cache.cache_id;
- }
- }
-
- if (FindExactMatch(preferred_cache_id) ||
- FindNamespaceMatch(preferred_cache_id)) {
- // We found something.
- DCHECK(cache_id_ != kAppCacheNoCacheId && !manifest_url_.is_empty() &&
- group_id_ != 0);
- return;
- }
-
- // We didn't find anything.
- DCHECK(cache_id_ == kAppCacheNoCacheId && manifest_url_.is_empty() &&
- group_id_ == 0);
-}
-
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindExactMatch(int64 preferred_cache_id) {
- std::vector<AppCacheDatabase::EntryRecord> entries;
- if (database_->FindEntriesForUrl(url_, &entries) && !entries.empty()) {
- // Sort them in order of preference, from the preferred_cache first,
- // followed by hits from caches that are 'in use', then the rest.
- std::sort(entries.begin(), entries.end(),
- SortByCachePreference(preferred_cache_id, cache_ids_in_use_));
-
- // Take the first with a valid, non-foreign entry.
- std::vector<AppCacheDatabase::EntryRecord>::iterator iter;
- for (iter = entries.begin(); iter < entries.end(); ++iter) {
- AppCacheDatabase::GroupRecord group_record;
- if ((iter->flags & AppCacheEntry::FOREIGN) ||
- !database_->FindGroupForCache(iter->cache_id, &group_record)) {
- continue;
- }
- manifest_url_ = group_record.manifest_url;
- group_id_ = group_record.group_id;
- entry_ = AppCacheEntry(iter->flags, iter->response_id);
- cache_id_ = iter->cache_id;
- return true; // We found an exact match.
- }
- }
- return false;
-}
-
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindNamespaceMatch(int64 preferred_cache_id) {
- AppCacheDatabase::NamespaceRecordVector all_intercepts;
- AppCacheDatabase::NamespaceRecordVector all_fallbacks;
- if (!database_->FindNamespacesForOrigin(
- url_.GetOrigin(), &all_intercepts, &all_fallbacks)
- || (all_intercepts.empty() && all_fallbacks.empty())) {
- return false;
- }
-
- NetworkNamespaceHelper network_namespace_helper(database_);
- if (FindNamespaceHelper(preferred_cache_id,
- &all_intercepts,
- &network_namespace_helper) ||
- FindNamespaceHelper(preferred_cache_id,
- &all_fallbacks,
- &network_namespace_helper)) {
- return true;
- }
- return false;
-}
-
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindNamespaceHelper(
- int64 preferred_cache_id,
- AppCacheDatabase::NamespaceRecordVector* namespaces,
- NetworkNamespaceHelper* network_namespace_helper) {
- // Sort them by length, longer matches within the same cache/bucket take
- // precedence.
- std::sort(namespaces->begin(), namespaces->end(), SortByLength);
-
- NamespaceRecordPtrVector preferred_namespaces;
- NamespaceRecordPtrVector inuse_namespaces;
- NamespaceRecordPtrVector other_namespaces;
- std::vector<AppCacheDatabase::NamespaceRecord>::iterator iter;
- for (iter = namespaces->begin(); iter < namespaces->end(); ++iter) {
- // Skip those that aren't a match.
- if (!iter->namespace_.IsMatch(url_))
- continue;
-
- // Skip namespaces where the requested url falls into a network
- // namespace of its containing appcache.
- if (network_namespace_helper->IsInNetworkNamespace(url_, iter->cache_id))
- continue;
-
- // Bin them into one of our three buckets.
- if (iter->cache_id == preferred_cache_id)
- preferred_namespaces.push_back(&(*iter));
- else if (cache_ids_in_use_.find(iter->cache_id) != cache_ids_in_use_.end())
- inuse_namespaces.push_back(&(*iter));
- else
- other_namespaces.push_back(&(*iter));
- }
-
- if (FindFirstValidNamespace(preferred_namespaces) ||
- FindFirstValidNamespace(inuse_namespaces) ||
- FindFirstValidNamespace(other_namespaces))
- return true; // We found one.
-
- // We didn't find anything.
- return false;
-}
-
-bool AppCacheStorageImpl::
-FindMainResponseTask::FindFirstValidNamespace(
- const NamespaceRecordPtrVector& namespaces) {
- // Take the first with a valid, non-foreign entry.
- NamespaceRecordPtrVector::const_iterator iter;
- for (iter = namespaces.begin(); iter < namespaces.end(); ++iter) {
- AppCacheDatabase::EntryRecord entry_record;
- if (database_->FindEntry((*iter)->cache_id, (*iter)->namespace_.target_url,
- &entry_record)) {
- AppCacheDatabase::GroupRecord group_record;
- if ((entry_record.flags & AppCacheEntry::FOREIGN) ||
- !database_->FindGroupForCache(entry_record.cache_id, &group_record)) {
- continue;
- }
- manifest_url_ = group_record.manifest_url;
- group_id_ = group_record.group_id;
- cache_id_ = (*iter)->cache_id;
- namespace_entry_url_ = (*iter)->namespace_.target_url;
- if ((*iter)->namespace_.type == APPCACHE_FALLBACK_NAMESPACE)
- fallback_entry_ = AppCacheEntry(entry_record.flags,
- entry_record.response_id);
- else
- entry_ = AppCacheEntry(entry_record.flags, entry_record.response_id);
- return true; // We found one.
- }
- }
- return false; // We didn't find a match.
-}
-
-void AppCacheStorageImpl::FindMainResponseTask::RunCompleted() {
- storage_->CallOnMainResponseFound(
- &delegates_, url_, entry_, namespace_entry_url_, fallback_entry_,
- cache_id_, group_id_, manifest_url_);
-}
-
-// MarkEntryAsForeignTask -------
-
-class AppCacheStorageImpl::MarkEntryAsForeignTask : public DatabaseTask {
- public:
- MarkEntryAsForeignTask(
- AppCacheStorageImpl* storage, const GURL& url, int64 cache_id)
- : DatabaseTask(storage), cache_id_(cache_id), entry_url_(url) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~MarkEntryAsForeignTask() {}
-
- private:
- int64 cache_id_;
- GURL entry_url_;
-};
-
-void AppCacheStorageImpl::MarkEntryAsForeignTask::Run() {
- database_->AddEntryFlags(entry_url_, cache_id_, AppCacheEntry::FOREIGN);
-}
-
-void AppCacheStorageImpl::MarkEntryAsForeignTask::RunCompleted() {
- DCHECK(storage_->pending_foreign_markings_.front().first == entry_url_ &&
- storage_->pending_foreign_markings_.front().second == cache_id_);
- storage_->pending_foreign_markings_.pop_front();
-}
-
-// MakeGroupObsoleteTask -------
-
-class AppCacheStorageImpl::MakeGroupObsoleteTask : public DatabaseTask {
- public:
- MakeGroupObsoleteTask(AppCacheStorageImpl* storage,
- AppCacheGroup* group,
- int response_code);
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
- virtual void CancelCompletion() OVERRIDE;
-
- protected:
- virtual ~MakeGroupObsoleteTask() {}
-
- private:
- scoped_refptr<AppCacheGroup> group_;
- int64 group_id_;
- GURL origin_;
- bool success_;
- int response_code_;
- int64 new_origin_usage_;
- std::vector<int64> newly_deletable_response_ids_;
-};
-
-AppCacheStorageImpl::MakeGroupObsoleteTask::MakeGroupObsoleteTask(
- AppCacheStorageImpl* storage,
- AppCacheGroup* group,
- int response_code)
- : DatabaseTask(storage),
- group_(group),
- group_id_(group->group_id()),
- origin_(group->manifest_url().GetOrigin()),
- success_(false),
- response_code_(response_code),
- new_origin_usage_(-1) {}
-
-void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() {
- DCHECK(!success_);
- sql::Connection* connection = database_->db_connection();
- if (!connection)
- return;
-
- sql::Transaction transaction(connection);
- if (!transaction.Begin())
- return;
-
- 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_);
- success_ = DeleteGroupAndRelatedRecords(database_,
- group_id_,
- &newly_deletable_response_ids_);
-
- 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_->UpdateUsageMapAndNotify(origin_, new_origin_usage_);
- group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_);
-
- // Also remove from the working set, caches for an 'obsolete' group
- // may linger in use, but the group itself cannot be looked up by
- // 'manifest_url' in the working set any longer.
- storage_->working_set()->RemoveGroup(group_.get());
- }
- }
- FOR_EACH_DELEGATE(
- delegates_, OnGroupMadeObsolete(group_.get(), success_, response_code_));
- group_ = NULL;
-}
-
-void AppCacheStorageImpl::MakeGroupObsoleteTask::CancelCompletion() {
- // Overriden to safely drop our reference to the group
- // which is not thread safe refcounted.
- DatabaseTask::CancelCompletion();
- group_ = NULL;
-}
-
-// GetDeletableResponseIdsTask -------
-
-class AppCacheStorageImpl::GetDeletableResponseIdsTask : public DatabaseTask {
- public:
- GetDeletableResponseIdsTask(AppCacheStorageImpl* storage, int64 max_rowid)
- : DatabaseTask(storage), max_rowid_(max_rowid) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
- virtual void RunCompleted() OVERRIDE;
-
- protected:
- virtual ~GetDeletableResponseIdsTask() {}
-
- private:
- int64 max_rowid_;
- std::vector<int64> response_ids_;
-};
-
-void AppCacheStorageImpl::GetDeletableResponseIdsTask::Run() {
- const int kSqlLimit = 1000;
- database_->GetDeletableResponseIds(&response_ids_, max_rowid_, kSqlLimit);
- // TODO(michaeln): retrieve group_ids too
-}
-
-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) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
-
- std::vector<int64> response_ids_;
-
- protected:
- virtual ~InsertDeletableResponseIdsTask() {}
-};
-
-void AppCacheStorageImpl::InsertDeletableResponseIdsTask::Run() {
- database_->InsertDeletableResponseIds(response_ids_);
- // TODO(michaeln): store group_ids too
-}
-
-// DeleteDeletableResponseIdsTask -------
-
-class AppCacheStorageImpl::DeleteDeletableResponseIdsTask
- : public DatabaseTask {
- public:
- explicit DeleteDeletableResponseIdsTask(AppCacheStorageImpl* storage)
- : DatabaseTask(storage) {}
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
-
- std::vector<int64> response_ids_;
-
- protected:
- virtual ~DeleteDeletableResponseIdsTask() {}
-};
-
-void AppCacheStorageImpl::DeleteDeletableResponseIdsTask::Run() {
- database_->DeleteDeletableResponseIds(response_ids_);
-}
-
-// UpdateGroupLastAccessTimeTask -------
-
-class AppCacheStorageImpl::UpdateGroupLastAccessTimeTask
- : public DatabaseTask {
- public:
- UpdateGroupLastAccessTimeTask(
- AppCacheStorageImpl* storage, AppCacheGroup* group, base::Time time)
- : DatabaseTask(storage), group_id_(group->group_id()),
- last_access_time_(time) {
- storage->NotifyStorageAccessed(group->manifest_url().GetOrigin());
- }
-
- // DatabaseTask:
- virtual void Run() OVERRIDE;
-
- protected:
- virtual ~UpdateGroupLastAccessTimeTask() {}
-
- private:
- int64 group_id_;
- base::Time last_access_time_;
-};
-
-void AppCacheStorageImpl::UpdateGroupLastAccessTimeTask::Run() {
- database_->UpdateGroupLastAccessTime(group_id_, last_access_time_);
-}
-
-
-// AppCacheStorageImpl ---------------------------------------------------
-
-AppCacheStorageImpl::AppCacheStorageImpl(AppCacheServiceImpl* service)
- : AppCacheStorage(service),
- is_incognito_(false),
- is_response_deletion_scheduled_(false),
- did_start_deleting_responses_(false),
- last_deletable_response_rowid_(0),
- database_(NULL),
- is_disabled_(false),
- weak_factory_(this) {
-}
-
-AppCacheStorageImpl::~AppCacheStorageImpl() {
- 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));
-
- if (database_ &&
- !db_thread_->PostTask(
- FROM_HERE,
- base::Bind(&ClearSessionOnlyOrigins, database_,
- make_scoped_refptr(service_->special_storage_policy()),
- service()->force_keep_session_state()))) {
- delete database_;
- }
- database_ = NULL; // So no further database tasks can be scheduled.
-}
-
-void AppCacheStorageImpl::Initialize(const base::FilePath& cache_directory,
- base::MessageLoopProxy* db_thread,
- base::MessageLoopProxy* cache_thread) {
- DCHECK(db_thread);
-
- cache_directory_ = cache_directory;
- is_incognito_ = cache_directory_.empty();
-
- base::FilePath db_file_path;
- if (!is_incognito_)
- db_file_path = cache_directory_.Append(kAppCacheDatabaseName);
- database_ = new AppCacheDatabase(db_file_path);
-
- db_thread_ = db_thread;
- cache_thread_ = cache_thread;
-
- scoped_refptr<InitTask> task(new InitTask(this));
- task->Schedule();
-}
-
-void AppCacheStorageImpl::Disable() {
- if (is_disabled_)
- return;
- VLOG(1) << "Disabling appcache storage.";
- is_disabled_ = true;
- ClearUsageMapAndNotify();
- working_set()->Disable();
- if (disk_cache_)
- disk_cache_->Disable();
- scoped_refptr<DisableDatabaseTask> task(new DisableDatabaseTask(this));
- task->Schedule();
-}
-
-void AppCacheStorageImpl::GetAllInfo(Delegate* delegate) {
- DCHECK(delegate);
- scoped_refptr<GetAllInfoTask> task(new GetAllInfoTask(this));
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- task->Schedule();
-}
-
-void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) {
- DCHECK(delegate);
- if (is_disabled_) {
- delegate->OnCacheLoaded(NULL, id);
- return;
- }
-
- AppCache* cache = working_set_.GetCache(id);
- if (cache) {
- delegate->OnCacheLoaded(cache, id);
- if (cache->owning_group()) {
- scoped_refptr<DatabaseTask> update_task(
- new UpdateGroupLastAccessTimeTask(
- this, cache->owning_group(), base::Time::Now()));
- update_task->Schedule();
- }
- return;
- }
- scoped_refptr<CacheLoadTask> task(GetPendingCacheLoadTask(id));
- if (task.get()) {
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- return;
- }
- task = new CacheLoadTask(id, this);
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- task->Schedule();
- pending_cache_loads_[id] = task.get();
-}
-
-void AppCacheStorageImpl::LoadOrCreateGroup(
- const GURL& manifest_url, Delegate* delegate) {
- DCHECK(delegate);
- if (is_disabled_) {
- delegate->OnGroupLoaded(NULL, manifest_url);
- return;
- }
-
- AppCacheGroup* group = working_set_.GetGroup(manifest_url);
- if (group) {
- delegate->OnGroupLoaded(group, manifest_url);
- scoped_refptr<DatabaseTask> update_task(
- new UpdateGroupLastAccessTimeTask(
- this, group, base::Time::Now()));
- update_task->Schedule();
- return;
- }
-
- scoped_refptr<GroupLoadTask> task(GetPendingGroupLoadTask(manifest_url));
- if (task.get()) {
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- return;
- }
-
- 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(
- this, manifest_url, NewGroupId()));
- delegate->OnGroupLoaded(group.get(), manifest_url);
- return;
- }
-
- task = new GroupLoadTask(manifest_url, this);
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- task->Schedule();
- pending_group_loads_[manifest_url] = task.get();
-}
-
-void AppCacheStorageImpl::StoreGroupAndNewestCache(
- AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) {
- // TODO(michaeln): distinguish between a simple update of an existing
- // cache that just adds new master entry(s), and the insertion of a
- // whole new cache. The StoreGroupAndCacheTask as written will handle
- // the simple update case in a very heavy weight way (delete all and
- // the reinsert all over again).
- DCHECK(group && delegate && newest_cache);
- scoped_refptr<StoreGroupAndCacheTask> task(
- new StoreGroupAndCacheTask(this, group, newest_cache));
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- task->GetQuotaThenSchedule();
-
- // TODO(michaeln): histogram is fishing for clues to crbug/95101
- if (!newest_cache->GetEntry(group->manifest_url())) {
- AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
- AppCacheHistograms::CALLSITE_3);
- }
-}
-
-void AppCacheStorageImpl::FindResponseForMainRequest(
- const GURL& url, const GURL& preferred_manifest_url,
- Delegate* delegate) {
- DCHECK(delegate);
-
- const GURL* url_ptr = &url;
- GURL url_no_ref;
- if (url.has_ref()) {
- GURL::Replacements replacements;
- replacements.ClearRef();
- url_no_ref = url.ReplaceComponents(replacements);
- url_ptr = &url_no_ref;
- }
-
- const GURL origin = url.GetOrigin();
-
- // First look in our working set for a direct hit without having to query
- // the database.
- const AppCacheWorkingSet::GroupMap* groups_in_use =
- working_set()->GetGroupsInOrigin(origin);
- if (groups_in_use) {
- if (!preferred_manifest_url.is_empty()) {
- AppCacheWorkingSet::GroupMap::const_iterator found =
- groups_in_use->find(preferred_manifest_url);
- if (found != groups_in_use->end() &&
- FindResponseForMainRequestInGroup(
- found->second, *url_ptr, delegate)) {
- return;
- }
- } else {
- for (AppCacheWorkingSet::GroupMap::const_iterator it =
- groups_in_use->begin();
- it != groups_in_use->end(); ++it) {
- if (FindResponseForMainRequestInGroup(
- it->second, *url_ptr, delegate)) {
- return;
- }
- }
- }
- }
-
- 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;
- scoped_refptr<AppCache> no_cache;
- ScheduleSimpleTask(
- base::Bind(&AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse,
- weak_factory_.GetWeakPtr(), url, AppCacheEntry(), no_group,
- no_cache,
- make_scoped_refptr(GetOrCreateDelegateReference(delegate))));
- return;
- }
-
- // We have to query the database, schedule a database task to do so.
- scoped_refptr<FindMainResponseTask> task(
- new FindMainResponseTask(this, *url_ptr, preferred_manifest_url,
- groups_in_use));
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- task->Schedule();
-}
-
-bool AppCacheStorageImpl::FindResponseForMainRequestInGroup(
- AppCacheGroup* group, const GURL& url, Delegate* delegate) {
- AppCache* cache = group->newest_complete_cache();
- if (group->is_obsolete() || !cache)
- return false;
-
- AppCacheEntry* entry = cache->GetEntry(url);
- if (!entry || entry->IsForeign())
- return false;
-
- ScheduleSimpleTask(
- base::Bind(&AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse,
- weak_factory_.GetWeakPtr(), url, *entry,
- make_scoped_refptr(group), make_scoped_refptr(cache),
- make_scoped_refptr(GetOrCreateDelegateReference(delegate))));
- return true;
-}
-
-void AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse(
- const GURL& url,
- const AppCacheEntry& found_entry,
- scoped_refptr<AppCacheGroup> group,
- scoped_refptr<AppCache> cache,
- scoped_refptr<DelegateReference> delegate_ref) {
- if (delegate_ref->delegate) {
- DelegateReferenceVector delegates(1, delegate_ref);
- CallOnMainResponseFound(
- &delegates, url, found_entry,
- GURL(), AppCacheEntry(),
- cache.get() ? cache->cache_id() : kAppCacheNoCacheId,
- group.get() ? group->group_id() : kAppCacheNoCacheId,
- group.get() ? group->manifest_url() : GURL());
- }
-}
-
-void AppCacheStorageImpl::CallOnMainResponseFound(
- DelegateReferenceVector* delegates,
- const GURL& url, const AppCacheEntry& entry,
- const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
- int64 cache_id, int64 group_id, const GURL& manifest_url) {
- FOR_EACH_DELEGATE(
- (*delegates),
- OnMainResponseFound(url, entry,
- namespace_entry_url, fallback_entry,
- cache_id, group_id, manifest_url));
-}
-
-void AppCacheStorageImpl::FindResponseForSubRequest(
- AppCache* cache, const GURL& url,
- AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
- bool* found_network_namespace) {
- DCHECK(cache && cache->is_complete());
-
- // When a group is forcibly deleted, all subresource loads for pages
- // using caches in the group will result in a synthesized network errors.
- // Forcible deletion is not a function that is covered by the HTML5 spec.
- if (cache->owning_group()->is_being_deleted()) {
- *found_entry = AppCacheEntry();
- *found_fallback_entry = AppCacheEntry();
- *found_network_namespace = false;
- return;
- }
-
- GURL fallback_namespace_not_used;
- GURL intercept_namespace_not_used;
- cache->FindResponseForRequest(
- url, found_entry, &intercept_namespace_not_used,
- found_fallback_entry, &fallback_namespace_not_used,
- found_network_namespace);
-}
-
-void AppCacheStorageImpl::MarkEntryAsForeign(
- const GURL& entry_url, int64 cache_id) {
- AppCache* cache = working_set_.GetCache(cache_id);
- if (cache) {
- AppCacheEntry* entry = cache->GetEntry(entry_url);
- DCHECK(entry);
- if (entry)
- entry->add_types(AppCacheEntry::FOREIGN);
- }
- scoped_refptr<MarkEntryAsForeignTask> task(
- new MarkEntryAsForeignTask(this, entry_url, cache_id));
- task->Schedule();
- pending_foreign_markings_.push_back(std::make_pair(entry_url, cache_id));
-}
-
-void AppCacheStorageImpl::MakeGroupObsolete(AppCacheGroup* group,
- Delegate* delegate,
- int response_code) {
- DCHECK(group && delegate);
- scoped_refptr<MakeGroupObsoleteTask> task(
- new MakeGroupObsoleteTask(this, group, response_code));
- task->AddDelegate(GetOrCreateDelegateReference(delegate));
- task->Schedule();
-}
-
-AppCacheResponseReader* AppCacheStorageImpl::CreateResponseReader(
- const GURL& manifest_url, int64 group_id, int64 response_id) {
- return new AppCacheResponseReader(response_id, group_id, disk_cache());
-}
-
-AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter(
- const GURL& manifest_url, int64 group_id) {
- return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
-}
-
-void AppCacheStorageImpl::DoomResponses(
- const GURL& manifest_url, const std::vector<int64>& response_ids) {
- if (response_ids.empty())
- return;
-
- // Start deleting them from the disk cache lazily.
- 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::DeleteResponses(
- const GURL& manifest_url, const std::vector<int64>& response_ids) {
- if (response_ids.empty())
- return;
- StartDeletingResponses(response_ids);
-}
-
-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 base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
- weak_factory_.GetWeakPtr()),
- kDelay);
- is_response_deletion_scheduled_ = true;
-}
-
-void AppCacheStorageImpl::DeleteOneResponse() {
- DCHECK(is_response_deletion_scheduled_);
- DCHECK(!deletable_response_ids_.empty());
-
- if (!disk_cache()) {
- DCHECK(is_disabled_);
- deletable_response_ids_.clear();
- deleted_response_ids_.clear();
- is_response_deletion_scheduled_ = false;
- return;
- }
-
- // TODO(michaeln): add group_id to DoomEntry args
- int64 id = deletable_response_ids_.front();
- int rv = disk_cache_->DoomEntry(
- id, base::Bind(&AppCacheStorageImpl::OnDeletedOneResponse,
- base::Unretained(this)));
- if (rv != net::ERR_IO_PENDING)
- OnDeletedOneResponse(rv);
-}
-
-void AppCacheStorageImpl::OnDeletedOneResponse(int rv) {
- is_response_deletion_scheduled_ = false;
- if (is_disabled_)
- return;
-
- int64 id = deletable_response_ids_.front();
- deletable_response_ids_.pop_front();
- if (rv != net::ERR_ABORTED)
- 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);
- if (found != pending_cache_loads_.end())
- return found->second;
- return NULL;
-}
-
-AppCacheStorageImpl::GroupLoadTask*
-AppCacheStorageImpl::GetPendingGroupLoadTask(const GURL& manifest_url) {
- PendingGroupLoads::iterator found = pending_group_loads_.find(manifest_url);
- if (found != pending_group_loads_.end())
- return found->second;
- return NULL;
-}
-
-void AppCacheStorageImpl::GetPendingForeignMarkingsForCache(
- int64 cache_id, std::vector<GURL>* urls) {
- PendingForeignMarkings::iterator iter = pending_foreign_markings_.begin();
- while (iter != pending_foreign_markings_.end()) {
- if (iter->second == cache_id)
- urls->push_back(iter->first);
- ++iter;
- }
-}
-
-void AppCacheStorageImpl::ScheduleSimpleTask(const base::Closure& task) {
- pending_simple_tasks_.push_back(task);
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&AppCacheStorageImpl::RunOnePendingSimpleTask,
- weak_factory_.GetWeakPtr()));
-}
-
-void AppCacheStorageImpl::RunOnePendingSimpleTask() {
- DCHECK(!pending_simple_tasks_.empty());
- base::Closure task = pending_simple_tasks_.front();
- pending_simple_tasks_.pop_front();
- task.Run();
-}
-
-AppCacheDiskCache* AppCacheStorageImpl::disk_cache() {
- DCHECK(IsInitTaskComplete());
-
- if (is_disabled_)
- return NULL;
-
- if (!disk_cache_) {
- int rv = net::OK;
- disk_cache_.reset(new AppCacheDiskCache);
- if (is_incognito_) {
- rv = disk_cache_->InitWithMemBackend(
- kMaxMemDiskCacheSize,
- base::Bind(&AppCacheStorageImpl::OnDiskCacheInitialized,
- base::Unretained(this)));
- } else {
- rv = disk_cache_->InitWithDiskBackend(
- cache_directory_.Append(kDiskCacheDirectoryName),
- kMaxDiskCacheSize,
- false,
- cache_thread_.get(),
- base::Bind(&AppCacheStorageImpl::OnDiskCacheInitialized,
- base::Unretained(this)));
- }
-
- if (rv != net::ERR_IO_PENDING)
- OnDiskCacheInitialized(rv);
- }
- return disk_cache_.get();
-}
-
-void AppCacheStorageImpl::OnDiskCacheInitialized(int rv) {
- if (rv != net::OK) {
- LOG(ERROR) << "Failed to open the appcache diskcache.";
- AppCacheHistograms::CountInitResult(AppCacheHistograms::DISK_CACHE_ERROR);
-
- // We're unable to open the disk cache, this is a fatal error that we can't
- // really recover from. We handle it by temporarily disabling the appcache
- // deleting the directory on disk and reinitializing the appcache system.
- Disable();
- if (rv != net::ERR_ABORTED)
- DeleteAndStartOver();
- }
-}
-
-void AppCacheStorageImpl::DeleteAndStartOver() {
- DCHECK(is_disabled_);
- if (!is_incognito_) {
- VLOG(1) << "Deleting existing appcache data and starting over.";
- // We can have tasks in flight to close file handles on both the db
- // and cache threads, we need to allow those tasks to cycle thru
- // prior to deleting the files and calling reinit.
- cache_thread_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&base::DoNothing),
- base::Bind(&AppCacheStorageImpl::DeleteAndStartOverPart2,
- weak_factory_.GetWeakPtr()));
- }
-}
-
-void AppCacheStorageImpl::DeleteAndStartOverPart2() {
- db_thread_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&base::DeleteFile),
- cache_directory_, true),
- base::Bind(&AppCacheStorageImpl::CallScheduleReinitialize,
- weak_factory_.GetWeakPtr()));
-}
-
-void AppCacheStorageImpl::CallScheduleReinitialize() {
- service_->ScheduleReinitialize();
- // note: 'this' may be deleted at this point.
-}
-
-} // namespace appcache

Powered by Google App Engine
This is Rietveld 408576698