| Index: content/browser/service_worker/service_worker_cache_storage.cc
|
| diff --git a/content/browser/service_worker/service_worker_cache_storage.cc b/content/browser/service_worker/service_worker_cache_storage.cc
|
| index d679d3e6242b235f2bc67eab5e4251d334ef72ba..629ae832a7eff5ed5059477690e95b2f8c4a61b2 100644
|
| --- a/content/browser/service_worker/service_worker_cache_storage.cc
|
| +++ b/content/browser/service_worker/service_worker_cache_storage.cc
|
| @@ -8,6 +8,7 @@
|
|
|
| #include "base/file_util.h"
|
| #include "base/files/memory_mapped_file.h"
|
| +#include "base/memory/ref_counted.h"
|
| #include "base/sha1.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| @@ -15,74 +16,225 @@
|
| #include "content/browser/service_worker/service_worker_cache.pb.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "net/base/directory_lister.h"
|
| +#include "net/base/net_errors.h"
|
|
|
| namespace content {
|
|
|
| // Handles the loading and clean up of ServiceWorkerCache objects.
|
| -class ServiceWorkerCacheStorage::CacheLoader {
|
| +class ServiceWorkerCacheStorage::CacheLoader
|
| + : public base::RefCountedThreadSafe<
|
| + ServiceWorkerCacheStorage::CacheLoader> {
|
| public:
|
| + typedef base::Callback<void(scoped_ptr<ServiceWorkerCache>)> CacheCallback;
|
| + typedef base::Callback<void(bool)> BoolCallback;
|
| + typedef base::Callback<void(scoped_ptr<std::vector<std::string> >)>
|
| + StringsCallback;
|
| +
|
| + explicit CacheLoader(base::SequencedTaskRunner* cache_task_runner)
|
| + : cache_task_runner_(cache_task_runner) {}
|
| +
|
| + // Loads the given cache_name, the cache is NULL if it fails. If the cache
|
| + // doesn't exist a new one is created.
|
| + virtual void LoadCache(const std::string& cache_name,
|
| + const CacheCallback& callback) = 0;
|
| +
|
| + // Deletes any pre-existing cache of the same name and then loads it.
|
| + virtual void CreateCache(const std::string& cache_name,
|
| + const CacheCallback& callback) = 0;
|
| +
|
| + // After the backend has been deleted, do any extra house keeping such as
|
| + // removing the cache's directory.
|
| + virtual void CleanUpDeletedCache(const std::string& key,
|
| + const BoolCallback& callback) = 0;
|
| +
|
| + // Writes the cache names (and sizes) to disk if applicable.
|
| + virtual void WriteIndex(CacheMap* caches, const BoolCallback& callback) = 0;
|
| +
|
| + // Loads the cache names from disk if applicable.
|
| + virtual void LoadIndex(scoped_ptr<std::vector<std::string> > cache_names,
|
| + const StringsCallback& callback) = 0;
|
| +
|
| + protected:
|
| + friend class base::RefCountedThreadSafe<
|
| + ServiceWorkerCacheStorage::CacheLoader>;
|
| +
|
| virtual ~CacheLoader() {};
|
| - virtual ServiceWorkerCache* LoadCache(const std::string& cache_name) = 0;
|
| - // Creates a new cache, deleting any pre-existing cache of the same name.
|
| - virtual ServiceWorkerCache* CreateCache(const std::string& cache_name) = 0;
|
| - virtual bool CleanUpDeletedCache(const std::string& key) = 0;
|
| - virtual bool WriteIndex(CacheMap* caches) = 0;
|
| - virtual void LoadIndex(std::vector<std::string>* cache_names) = 0;
|
| + virtual void LoadCacheImpl(const std::string&) {}
|
| +
|
| + scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
|
| +
|
| };
|
|
|
| class ServiceWorkerCacheStorage::MemoryLoader
|
| : public ServiceWorkerCacheStorage::CacheLoader {
|
| public:
|
| - virtual content::ServiceWorkerCache* LoadCache(
|
| - const std::string& cache_name) OVERRIDE {
|
| + explicit MemoryLoader(base::SequencedTaskRunner* cache_task_runner)
|
| + : CacheLoader(cache_task_runner) {}
|
| + virtual void LoadCache(const std::string& cache_name,
|
| + const CacheCallback& callback) OVERRIDE {
|
| NOTREACHED();
|
| - return NULL;
|
| }
|
|
|
| - virtual ServiceWorkerCache* CreateCache(
|
| - const std::string& cache_name) OVERRIDE {
|
| - return ServiceWorkerCache::CreateMemoryCache(cache_name);
|
| + virtual void CreateCache(const std::string& cache_name,
|
| + const CacheCallback& callback) OVERRIDE {
|
| + scoped_ptr<ServiceWorkerCache> cache =
|
| + ServiceWorkerCache::CreateMemoryCache(cache_name);
|
| + callback.Run(cache.Pass());
|
| }
|
|
|
| - virtual bool CleanUpDeletedCache(const std::string& cache_name) OVERRIDE {
|
| - return true;
|
| + virtual void CleanUpDeletedCache(const std::string& cache_name,
|
| + const BoolCallback& callback) OVERRIDE {
|
| + callback.Run(true);
|
| }
|
|
|
| - virtual bool WriteIndex(CacheMap* caches) OVERRIDE { return false; }
|
| + virtual void WriteIndex(CacheMap* caches,
|
| + const BoolCallback& callback) OVERRIDE {
|
| + callback.Run(false);
|
| + }
|
|
|
| - virtual void LoadIndex(std::vector<std::string>* cache_names) OVERRIDE {
|
| - return;
|
| + virtual void LoadIndex(scoped_ptr<std::vector<std::string> > cache_names,
|
| + const StringsCallback& callback) OVERRIDE {
|
| + callback.Run(cache_names.Pass());
|
| }
|
| +
|
| + private:
|
| + virtual ~MemoryLoader() {}
|
| };
|
|
|
| class ServiceWorkerCacheStorage::SimpleCacheLoader
|
| : public ServiceWorkerCacheStorage::CacheLoader {
|
| public:
|
| - explicit SimpleCacheLoader(const base::FilePath& origin_path)
|
| - : origin_path_(origin_path) {}
|
| + SimpleCacheLoader(const base::FilePath& origin_path,
|
| + base::SequencedTaskRunner* cache_task_runner)
|
| + : CacheLoader(cache_task_runner), origin_path_(origin_path) {}
|
| +
|
| + virtual void LoadCache(const std::string& cache_name,
|
| + const CacheCallback& callback) OVERRIDE {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // 1. Create the cache's directory if necessary. (LoadCreateDirectoryInPool)
|
| + // 2. Create the cache object. (LoadDidCreateDirectory)
|
| +
|
| + cache_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::LoadCreateDirectoryInPool,
|
| + this,
|
| + CreatePersistentCachePath(origin_path_, cache_name),
|
| + cache_name,
|
| + callback,
|
| + base::MessageLoopProxy::current()));
|
| + }
|
| +
|
| + void LoadCreateDirectoryInPool(
|
| + const base::FilePath& path,
|
| + const std::string& cache_name,
|
| + const CacheCallback& callback,
|
| + const scoped_refptr<base::MessageLoopProxy>& original_loop) {
|
| + DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + bool rv = base::CreateDirectory(path);
|
| + original_loop->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::LoadDidCreateDirectory,
|
| + this,
|
| + cache_name,
|
| + callback,
|
| + rv));
|
| + }
|
| +
|
| + void LoadDidCreateDirectory(const std::string& cache_name,
|
| + const CacheCallback& callback,
|
| + bool dir_rv) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!dir_rv) {
|
| + callback.Run(scoped_ptr<ServiceWorkerCache>());
|
| + return;
|
| + }
|
| + base::FilePath cache_path =
|
| + CreatePersistentCachePath(origin_path_, cache_name);
|
| + scoped_ptr<ServiceWorkerCache> cache(
|
| + ServiceWorkerCache::CreatePersistentCache(cache_path, cache_name));
|
| + callback.Run(cache.Pass());
|
| + }
|
| +
|
| + virtual void CreateCache(const std::string& cache_name,
|
| + const CacheCallback& callback) OVERRIDE {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // 1. Delete the cache's directory if it exists.
|
| + // (CreateCacheDeleteFilesInPool)
|
| + // 2. Load the cache. (LoadCreateDirectoryInPool)
|
| +
|
| + base::FilePath cache_path =
|
| + CreatePersistentCachePath(origin_path_, cache_name);
|
| +
|
| + cache_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::CreateCacheDeleteFilesInPool,
|
| + this,
|
| + cache_path,
|
| + cache_name,
|
| + callback,
|
| + base::MessageLoopProxy::current()));
|
| + }
|
|
|
| - virtual ServiceWorkerCache* LoadCache(
|
| - const std::string& cache_name) OVERRIDE {
|
| - base::CreateDirectory(CreatePersistentCachePath(origin_path_, cache_name));
|
| - return ServiceWorkerCache::CreatePersistentCache(
|
| - CreatePersistentCachePath(origin_path_, cache_name), cache_name);
|
| + void CreateCacheDeleteFilesInPool(
|
| + const base::FilePath& cache_path,
|
| + const std::string& cache_name,
|
| + const CacheCallback& callback,
|
| + const scoped_refptr<base::MessageLoopProxy>& original_loop) {
|
| + DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + base::FilePath path(cache_path);
|
| + if (base::PathExists(path))
|
| + base::DeleteFile(path, /* recursive */ true);
|
| +
|
| + // Jump straight into LoadCache on the same thread.
|
| + base::MessageLoopProxy::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::LoadCreateDirectoryInPool,
|
| + this,
|
| + cache_path,
|
| + cache_name,
|
| + callback,
|
| + original_loop));
|
| }
|
|
|
| - virtual ServiceWorkerCache* CreateCache(
|
| - const std::string& cache_name) OVERRIDE {
|
| + virtual void CleanUpDeletedCache(const std::string& cache_name,
|
| + const BoolCallback& callback) OVERRIDE {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // 1. Delete the cache's directory. (CleanUpDeleteCacheDirInPool)
|
| +
|
| base::FilePath cache_path =
|
| CreatePersistentCachePath(origin_path_, cache_name);
|
| - if (base::PathExists(cache_path))
|
| - base::DeleteFile(cache_path, /* recursive */ true);
|
| - return LoadCache(cache_name);
|
| + cache_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool,
|
| + this,
|
| + cache_path,
|
| + callback,
|
| + base::MessageLoopProxy::current()));
|
| }
|
|
|
| - virtual bool CleanUpDeletedCache(const std::string& cache_name) OVERRIDE {
|
| - return base::DeleteFile(CreatePersistentCachePath(origin_path_, cache_name),
|
| - true);
|
| + void CleanUpDeleteCacheDirInPool(
|
| + const base::FilePath& cache_path,
|
| + const BoolCallback& callback,
|
| + const scoped_refptr<base::MessageLoopProxy>& original_loop) {
|
| + DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + bool rv = base::DeleteFile(cache_path, true);
|
| + original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
|
| }
|
|
|
| - virtual bool WriteIndex(CacheMap* caches) OVERRIDE {
|
| + virtual void WriteIndex(CacheMap* caches,
|
| + const BoolCallback& callback) OVERRIDE {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // 1. Create the index file as a string. (WriteIndex)
|
| + // 2. Write the file to disk. (WriteIndexWriteToFileInPool)
|
| +
|
| ServiceWorkerCacheStorageIndex index;
|
|
|
| for (CacheMap::const_iterator iter(caches); !iter.IsAtEnd();
|
| @@ -100,23 +252,79 @@ class ServiceWorkerCacheStorage::SimpleCacheLoader
|
| base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp");
|
| base::FilePath index_path = origin_path_.AppendASCII("index.txt");
|
|
|
| - int bytes_written =
|
| - base::WriteFile(tmp_path, serialized.c_str(), serialized.size());
|
| - if (bytes_written != implicit_cast<int>(serialized.size())) {
|
| + cache_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
|
| + this,
|
| + tmp_path,
|
| + index_path,
|
| + serialized,
|
| + caches,
|
| + callback,
|
| + base::MessageLoopProxy::current()));
|
| + }
|
| +
|
| + void WriteIndexWriteToFileInPool(
|
| + const base::FilePath& tmp_path,
|
| + const base::FilePath& index_path,
|
| + const std::string& data,
|
| + CacheMap* caches,
|
| + const BoolCallback& callback,
|
| + const scoped_refptr<base::MessageLoopProxy>& original_loop) {
|
| + DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
|
| + if (bytes_written != implicit_cast<int>(data.size())) {
|
| base::DeleteFile(tmp_path, /* recursive */ false);
|
| - return false;
|
| + original_loop->PostTask(FROM_HERE, base::Bind(callback, false));
|
| }
|
|
|
| // Atomically rename the temporary index file to become the real one.
|
| - return base::ReplaceFile(tmp_path, index_path, NULL);
|
| + bool rv = base::ReplaceFile(tmp_path, index_path, NULL);
|
| + original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
|
| }
|
|
|
| - virtual void LoadIndex(std::vector<std::string>* names) OVERRIDE {
|
| + virtual void LoadIndex(scoped_ptr<std::vector<std::string> > names,
|
| + const StringsCallback& callback) OVERRIDE {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + // 1. Read the file from disk. (LoadIndexReadFileInPool)
|
| + // 2. Parse file and return the names of the caches (LoadIndexDidReadFile)
|
| +
|
| base::FilePath index_path = origin_path_.AppendASCII("index.txt");
|
|
|
| - std::string serialized;
|
| - if (!base::ReadFileToString(index_path, &serialized))
|
| - return;
|
| + cache_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::LoadIndexReadFileInPool,
|
| + this,
|
| + index_path,
|
| + base::Passed(names.Pass()),
|
| + callback,
|
| + base::MessageLoopProxy::current()));
|
| + }
|
| +
|
| + void LoadIndexReadFileInPool(
|
| + const base::FilePath& index_path,
|
| + scoped_ptr<std::vector<std::string> > names,
|
| + const StringsCallback& callback,
|
| + const scoped_refptr<base::MessageLoopProxy>& original_loop) {
|
| + DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
|
| +
|
| + std::string body;
|
| + base::ReadFileToString(index_path, &body);
|
| +
|
| + original_loop->PostTask(FROM_HERE,
|
| + base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile,
|
| + this,
|
| + base::Passed(names.Pass()),
|
| + callback,
|
| + body));
|
| + }
|
| +
|
| + void LoadIndexDidReadFile(scoped_ptr<std::vector<std::string> > names,
|
| + const StringsCallback& callback,
|
| + const std::string& serialized) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| ServiceWorkerCacheStorageIndex index;
|
| index.ParseFromString(serialized);
|
| @@ -128,10 +336,12 @@ class ServiceWorkerCacheStorage::SimpleCacheLoader
|
|
|
| // TODO(jkarlin): Delete caches that are in the directory and not returned
|
| // in LoadIndex.
|
| - return;
|
| + callback.Run(names.Pass());
|
| }
|
|
|
| private:
|
| + virtual ~SimpleCacheLoader() {}
|
| +
|
| std::string HexedHash(const std::string& value) {
|
| std::string value_hash = base::SHA1HashString(value);
|
| std::string valued_hexed_hash = base::StringToLowerASCII(
|
| @@ -150,12 +360,15 @@ class ServiceWorkerCacheStorage::SimpleCacheLoader
|
| ServiceWorkerCacheStorage::ServiceWorkerCacheStorage(
|
| const base::FilePath& path,
|
| bool memory_only,
|
| - const scoped_refptr<base::MessageLoopProxy>& callback_loop)
|
| - : initialized_(false), origin_path_(path), callback_loop_(callback_loop) {
|
| + base::SequencedTaskRunner* cache_task_runner)
|
| + : initialized_(false),
|
| + origin_path_(path),
|
| + cache_task_runner_(cache_task_runner),
|
| + weak_factory_(this) {
|
| if (memory_only)
|
| - cache_loader_.reset(new MemoryLoader());
|
| + cache_loader_ = new MemoryLoader(cache_task_runner_);
|
| else
|
| - cache_loader_.reset(new SimpleCacheLoader(origin_path_));
|
| + cache_loader_ = new SimpleCacheLoader(origin_path_, cache_task_runner_);
|
| }
|
|
|
| ServiceWorkerCacheStorage::~ServiceWorkerCacheStorage() {
|
| @@ -164,114 +377,130 @@ ServiceWorkerCacheStorage::~ServiceWorkerCacheStorage() {
|
| void ServiceWorkerCacheStorage::CreateCache(
|
| const std::string& cache_name,
|
| const CacheAndErrorCallback& callback) {
|
| - LazyInit();
|
| -
|
| - if (cache_name.empty()) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, 0, CACHE_STORAGE_ERROR_EMPTY_KEY));
|
| + if (!initialized_) {
|
| + LazyInit(base::Bind(&ServiceWorkerCacheStorage::CreateCache,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache_name,
|
| + callback));
|
| return;
|
| }
|
|
|
| - if (GetLoadedCache(cache_name)) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, 0, CACHE_STORAGE_ERROR_EXISTS));
|
| + if (cache_name.empty()) {
|
| + callback.Run(0, CACHE_STORAGE_ERROR_EMPTY_KEY);
|
| return;
|
| }
|
|
|
| - ServiceWorkerCache* cache = cache_loader_->CreateCache(cache_name);
|
| -
|
| - if (!cache) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, 0, CACHE_STORAGE_ERROR_STORAGE));
|
| + if (GetLoadedCache(cache_name)) {
|
| + callback.Run(0, CACHE_STORAGE_ERROR_EXISTS);
|
| return;
|
| }
|
|
|
| - InitCache(cache);
|
| -
|
| - cache_loader_->WriteIndex(&cache_map_);
|
| -
|
| - cache->CreateBackend(
|
| - base::Bind(&ServiceWorkerCacheStorage::InitializeCacheCallback,
|
| - base::Unretained(this),
|
| - cache,
|
| + cache_loader_->CreateCache(
|
| + cache_name,
|
| + base::Bind(&ServiceWorkerCacheStorage::CreateCacheDidCreateCache,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache_name,
|
| callback));
|
| }
|
|
|
| void ServiceWorkerCacheStorage::GetCache(
|
| const std::string& cache_name,
|
| const CacheAndErrorCallback& callback) {
|
| - LazyInit();
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!initialized_) {
|
| + LazyInit(base::Bind(&ServiceWorkerCacheStorage::GetCache,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache_name,
|
| + callback));
|
| + return;
|
| + }
|
|
|
| if (cache_name.empty()) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, 0, CACHE_STORAGE_ERROR_EMPTY_KEY));
|
| + callback.Run(0, CACHE_STORAGE_ERROR_EMPTY_KEY);
|
| return;
|
| }
|
|
|
| ServiceWorkerCache* cache = GetLoadedCache(cache_name);
|
| if (!cache) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, 0, CACHE_STORAGE_ERROR_NOT_FOUND));
|
| + callback.Run(0, CACHE_STORAGE_ERROR_NOT_FOUND);
|
| return;
|
| }
|
|
|
| - cache->CreateBackend(
|
| - base::Bind(&ServiceWorkerCacheStorage::InitializeCacheCallback,
|
| - base::Unretained(this),
|
| - cache,
|
| - callback));
|
| + cache->CreateBackend(base::Bind(&ServiceWorkerCacheStorage::DidCreateBackend,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache->GetWeakPtr(),
|
| + callback));
|
| }
|
|
|
| void ServiceWorkerCacheStorage::HasCache(const std::string& cache_name,
|
| const BoolAndErrorCallback& callback) {
|
| - LazyInit();
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!initialized_) {
|
| + LazyInit(base::Bind(&ServiceWorkerCacheStorage::HasCache,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache_name,
|
| + callback));
|
| + return;
|
| + }
|
|
|
| if (cache_name.empty()) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, false, CACHE_STORAGE_ERROR_EMPTY_KEY));
|
| + callback.Run(false, CACHE_STORAGE_ERROR_EMPTY_KEY);
|
| return;
|
| }
|
|
|
| bool has_cache = GetLoadedCache(cache_name) != NULL;
|
|
|
| - callback_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(
|
| - callback, has_cache, CACHE_STORAGE_ERROR_NO_ERROR));
|
| + callback.Run(has_cache, CACHE_STORAGE_ERROR_NO_ERROR);
|
| }
|
|
|
| void ServiceWorkerCacheStorage::DeleteCache(
|
| const std::string& cache_name,
|
| const BoolAndErrorCallback& callback) {
|
| - LazyInit();
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!initialized_) {
|
| + LazyInit(base::Bind(&ServiceWorkerCacheStorage::DeleteCache,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache_name,
|
| + callback));
|
| + return;
|
| + }
|
|
|
| if (cache_name.empty()) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, false, CACHE_STORAGE_ERROR_EMPTY_KEY));
|
| + callback.Run(false, CACHE_STORAGE_ERROR_EMPTY_KEY);
|
| return;
|
| }
|
|
|
| ServiceWorkerCache* cache = GetLoadedCache(cache_name);
|
| if (!cache) {
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, false, CACHE_STORAGE_ERROR_NOT_FOUND));
|
| + callback.Run(false, CACHE_STORAGE_ERROR_NOT_FOUND);
|
| return;
|
| }
|
|
|
| name_map_.erase(cache_name);
|
| cache_map_.Remove(cache->id()); // deletes cache
|
|
|
| - cache_loader_->WriteIndex(&cache_map_); // Update the index.
|
| -
|
| - cache_loader_->CleanUpDeletedCache(cache_name);
|
| -
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, true, CACHE_STORAGE_ERROR_NO_ERROR));
|
| + // Update the Index
|
| + cache_loader_->WriteIndex(
|
| + &cache_map_,
|
| + base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache_name,
|
| + callback));
|
| }
|
|
|
| void ServiceWorkerCacheStorage::EnumerateCaches(
|
| const StringsAndErrorCallback& callback) {
|
| - LazyInit();
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!initialized_) {
|
| + LazyInit(base::Bind(&ServiceWorkerCacheStorage::EnumerateCaches,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback));
|
| + return;
|
| + }
|
|
|
| std::vector<std::string> names;
|
| for (NameMap::const_iterator it = name_map_.begin(); it != name_map_.end();
|
| @@ -279,52 +508,181 @@ void ServiceWorkerCacheStorage::EnumerateCaches(
|
| names.push_back(it->first);
|
| }
|
|
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, names, CACHE_STORAGE_ERROR_NO_ERROR));
|
| + callback.Run(names, CACHE_STORAGE_ERROR_NO_ERROR);
|
| }
|
|
|
| -void ServiceWorkerCacheStorage::InitializeCacheCallback(
|
| - const ServiceWorkerCache* cache,
|
| +void ServiceWorkerCacheStorage::DidCreateBackend(
|
| + const base::WeakPtr<ServiceWorkerCache>& cache,
|
| const CacheAndErrorCallback& callback,
|
| bool success) {
|
| - if (!success) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!success || !cache) {
|
| // TODO(jkarlin): This should delete the directory and try again in case
|
| // the cache is simply corrupt.
|
| - callback_loop_->PostTask(
|
| - FROM_HERE, base::Bind(callback, 0, CACHE_STORAGE_ERROR_STORAGE));
|
| + callback.Run(0, CACHE_STORAGE_ERROR_STORAGE);
|
| return;
|
| }
|
| - callback_loop_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(callback, cache->id(), CACHE_STORAGE_ERROR_NO_ERROR));
|
| + callback.Run(cache->id(), CACHE_STORAGE_ERROR_NO_ERROR);
|
| }
|
|
|
| // Init is run lazily so that it is called on the proper MessageLoop.
|
| -void ServiceWorkerCacheStorage::LazyInit() {
|
| - if (initialized_)
|
| +void ServiceWorkerCacheStorage::LazyInit(const base::Closure& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(!initialized_);
|
| +
|
| + init_callbacks_.push_back(callback);
|
| +
|
| + // If this isn't the first call to LazyInit then return as the initialization
|
| + // has already started.
|
| + if (init_callbacks_.size() > 1u)
|
| return;
|
|
|
| - std::vector<std::string> indexed_cache_names;
|
| - cache_loader_->LoadIndex(&indexed_cache_names);
|
| + // 1. Get the list of cache names (async call)
|
| + // 2. For each cache name, load the cache (async call)
|
| + // 3. Once each load is complete, update the map variables.
|
| + // 4. Call the list of waiting callbacks.
|
|
|
| - for (std::vector<std::string>::const_iterator it =
|
| - indexed_cache_names.begin();
|
| - it != indexed_cache_names.end();
|
| - ++it) {
|
| - ServiceWorkerCache* cache = cache_loader_->LoadCache(*it);
|
| - InitCache(cache);
|
| + scoped_ptr<std::vector<std::string> > indexed_cache_names(
|
| + new std::vector<std::string>());
|
| +
|
| + cache_loader_->LoadIndex(
|
| + indexed_cache_names.Pass(),
|
| + base::Bind(&ServiceWorkerCacheStorage::LazyInitDidLoadIndex,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback));
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::LazyInitDidLoadIndex(
|
| + const base::Closure& callback,
|
| + scoped_ptr<std::vector<std::string> > indexed_cache_names) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (indexed_cache_names->empty()) {
|
| + LazyInitDone();
|
| + return;
|
| + }
|
| +
|
| + std::vector<std::string>::const_iterator iter = indexed_cache_names->begin();
|
| + std::vector<std::string>::const_iterator iter_next = iter + 1;
|
| +
|
| + cache_loader_->LoadCache(
|
| + *iter,
|
| + base::Bind(&ServiceWorkerCacheStorage::LazyInitIterateAndLoadCacheName,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback,
|
| + base::Passed(indexed_cache_names.Pass()),
|
| + iter_next));
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::LazyInitIterateAndLoadCacheName(
|
| + const base::Closure& callback,
|
| + scoped_ptr<std::vector<std::string> > indexed_cache_names,
|
| + const std::vector<std::string>::const_iterator& iter,
|
| + scoped_ptr<ServiceWorkerCache> cache) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (cache)
|
| + AddCacheToMaps(cache.Pass());
|
| +
|
| + if (iter == indexed_cache_names->end()) {
|
| + LazyInitDone();
|
| + return;
|
| }
|
| +
|
| + std::vector<std::string>::const_iterator iter_next = iter + 1;
|
| + cache_loader_->LoadCache(
|
| + *iter,
|
| + base::Bind(&ServiceWorkerCacheStorage::LazyInitIterateAndLoadCacheName,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback,
|
| + base::Passed(indexed_cache_names.Pass()),
|
| + iter_next));
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::LazyInitDone() {
|
| initialized_ = true;
|
| + for (std::vector<base::Closure>::iterator it = init_callbacks_.begin();
|
| + it != init_callbacks_.end();
|
| + ++it) {
|
| + it->Run();
|
| + }
|
| + init_callbacks_.clear();
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::AddCacheToMaps(
|
| + scoped_ptr<ServiceWorkerCache> cache) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + ServiceWorkerCache* cache_ptr = cache.release();
|
| + CacheID id = cache_map_.Add(cache_ptr);
|
| + name_map_.insert(std::make_pair(cache_ptr->name(), id));
|
| + cache_ptr->set_id(id);
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::CreateCacheDidCreateCache(
|
| + const std::string& cache_name,
|
| + const CacheAndErrorCallback& callback,
|
| + scoped_ptr<ServiceWorkerCache> cache) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (!cache) {
|
| + callback.Run(0, CACHE_STORAGE_ERROR_STORAGE);
|
| + return;
|
| + }
|
| +
|
| + base::WeakPtr<ServiceWorkerCache> cache_ptr = cache->GetWeakPtr();
|
| +
|
| + AddCacheToMaps(cache.Pass());
|
| +
|
| + cache_loader_->WriteIndex(
|
| + &cache_map_,
|
| + base::Bind(
|
| + &ServiceWorkerCacheStorage::CreateCacheDidWriteIndex,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback,
|
| + cache_ptr)); // cache is owned by this->CacheMap and won't be deleted
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::CreateCacheDidWriteIndex(
|
| + const CacheAndErrorCallback& callback,
|
| + const base::WeakPtr<ServiceWorkerCache>& cache,
|
| + bool success) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + if (!cache) {
|
| + callback.Run(false, CACHE_STORAGE_ERROR_STORAGE);
|
| + return;
|
| + }
|
| + cache->CreateBackend(base::Bind(&ServiceWorkerCacheStorage::DidCreateBackend,
|
| + weak_factory_.GetWeakPtr(),
|
| + cache,
|
| + callback));
|
| }
|
|
|
| -void ServiceWorkerCacheStorage::InitCache(ServiceWorkerCache* cache) {
|
| - CacheID id = cache_map_.Add(cache);
|
| - name_map_.insert(std::make_pair(cache->name(), id));
|
| - cache->set_id(id);
|
| +void ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex(
|
| + const std::string& cache_name,
|
| + const BoolAndErrorCallback& callback,
|
| + bool success) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + cache_loader_->CleanUpDeletedCache(
|
| + cache_name,
|
| + base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidCleanUp,
|
| + weak_factory_.GetWeakPtr(),
|
| + callback));
|
| +}
|
| +
|
| +void ServiceWorkerCacheStorage::DeleteCacheDidCleanUp(
|
| + const BoolAndErrorCallback& callback,
|
| + bool success) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + callback.Run(true, CACHE_STORAGE_ERROR_NO_ERROR);
|
| }
|
|
|
| ServiceWorkerCache* ServiceWorkerCacheStorage::GetLoadedCache(
|
| const std::string& cache_name) const {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| DCHECK(initialized_);
|
|
|
| NameMap::const_iterator it = name_map_.find(cache_name);
|
|
|