// 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 "content/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 "content/browser/appcache/appcache.h"
#include "content/browser/appcache/appcache_database.h"
#include "content/browser/appcache/appcache_entry.h"
#include "content/browser/appcache/appcache_group.h"
#include "content/browser/appcache/appcache_histograms.h"
#include "content/browser/appcache/appcache_quota_client.h"
#include "content/browser/appcache/appcache_response.h"
#include "content/browser/appcache/appcache_service_impl.h"
#include "net/base/cache_type.h"
#include "net/base/net_errors.h"
#include "sql/connection.h"
#include "sql/transaction.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 content {

// 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 &&
      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;
  DCHECK(special_storage_policy);
  for (origin = origins.begin(); origin != origins.end(); ++origin) {
    if (!special_storage_policy->IsStorageSessionOnly(*origin))
      continue;
    if (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_EQ(1U, delegates_.size());
  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, AppCacheNamespaceVector()));
    if (result.second)
      GetOnlineWhiteListForCache(cache_id, &result.first->second);
    return AppCache::FindNamespace(result.first->second, url) != NULL;
  }

 private:
  void GetOnlineWhiteListForCache(
      int64 cache_id, AppCacheNamespaceVector* 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(
            AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, iter->namespace_url,
                GURL(), iter->is_pattern));
      ++iter;
    }
  }

  // Key is cache id
  typedef std::map<int64, AppCacheNamespaceVector> 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 content
