Chromium Code Reviews| 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..ffffebf48bb45c76d3f5caf7627647a43309ba4d 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,224 @@ |
| #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 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); |
| + 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())); |
| + } |
| + |
| + 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 +251,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, |
|
kinuko
2014/08/23 06:07:44
This is not used and passing the rawptr here feels
jkarlin
2014/08/25 18:30:02
Done.
|
| + 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 +335,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 +359,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 +376,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->AsWeakPtr(), |
| + 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 +507,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( |
| + 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->AsWeakPtr(); |
| + |
| + 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 |
|
kinuko
2014/08/23 06:07:43
This comment confused me, since we're passing Weak
jkarlin
2014/08/25 18:30:02
Fixed. Thanks.
|
| } |
| -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::CreateCacheDidWriteIndex( |
| + const CacheAndErrorCallback& callback, |
| + base::WeakPtr<ServiceWorkerCache> cache, |
| + bool success) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (!cache) { |
| + callback.Run(false, CACHE_STORAGE_ERROR_STORAGE); |
|
kinuko
2014/08/23 06:07:43
Is returning STORAGE_ERROR expected here?
jkarlin
2014/08/25 18:30:02
Done.
|
| + return; |
| + } |
| + cache->CreateBackend(base::Bind(&ServiceWorkerCacheStorage::DidCreateBackend, |
| + weak_factory_.GetWeakPtr(), |
| + cache, |
| + callback)); |
| +} |
| + |
| +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); |