Chromium Code Reviews| Index: content/browser/service_worker/service_worker_storage.cc |
| diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc |
| index 4f714195ce0ea688daffbebcf25093034b944c16..840eecebe29897b4bd29ef2a7bd0248b374bf454 100644 |
| --- a/content/browser/service_worker/service_worker_storage.cc |
| +++ b/content/browser/service_worker/service_worker_storage.cc |
| @@ -4,6 +4,7 @@ |
| #include "content/browser/service_worker/service_worker_storage.h" |
| +#include "base/barrier_closure.h" |
| #include "base/bind_helpers.h" |
| #include "base/files/file_util.h" |
| #include "base/message_loop/message_loop.h" |
| @@ -14,8 +15,8 @@ |
| #include "base/trace_event/trace_event.h" |
| #include "content/browser/service_worker/service_worker_context_core.h" |
| #include "content/browser/service_worker/service_worker_disk_cache.h" |
| +#include "content/browser/service_worker/service_worker_disk_cache_migrator.h" |
| #include "content/browser/service_worker/service_worker_info.h" |
| -#include "content/browser/service_worker/service_worker_metrics.h" |
| #include "content/browser/service_worker/service_worker_registration.h" |
| #include "content/browser/service_worker/service_worker_utils.h" |
| #include "content/browser/service_worker/service_worker_version.h" |
| @@ -60,7 +61,8 @@ void CompleteFindSoon( |
| const base::FilePath::CharType kDatabaseName[] = |
| FILE_PATH_LITERAL("Database"); |
| const base::FilePath::CharType kDiskCacheName[] = |
| - FILE_PATH_LITERAL("Cache"); |
| + FILE_PATH_LITERAL("ScriptCache"); |
| +const base::FilePath::CharType kOldDiskCacheName[] = FILE_PATH_LITERAL("Cache"); |
| const int kMaxMemDiskCacheSize = 10 * 1024 * 1024; |
| const int kMaxDiskCacheSize = 250 * 1024 * 1024; |
| @@ -929,6 +931,7 @@ ServiceWorkerStorage::ServiceWorkerStorage( |
| disk_cache_thread_(disk_cache_thread), |
| quota_manager_proxy_(quota_manager_proxy), |
| special_storage_policy_(special_storage_policy), |
| + needs_disk_cache_migration_(false), |
| is_purge_pending_(false), |
| has_checked_for_stale_resources_(false), |
| weak_factory_(this) { |
| @@ -949,6 +952,13 @@ base::FilePath ServiceWorkerStorage::GetDiskCachePath() { |
| .Append(kDiskCacheName); |
| } |
| +base::FilePath ServiceWorkerStorage::GetOldDiskCachePath() { |
| + if (path_.empty()) |
| + return base::FilePath(); |
| + return path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory) |
| + .Append(kOldDiskCacheName); |
| +} |
| + |
| bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { |
| if (!context_) |
| return false; |
| @@ -969,9 +979,8 @@ bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { |
| state_ = INITIALIZING; |
| database_task_manager_->GetTaskRunner()->PostTask( |
| FROM_HERE, |
| - base::Bind(&ReadInitialDataFromDB, |
| - database_.get(), |
| - base::ThreadTaskRunnerHandle::Get(), |
| + base::Bind(&ReadInitialDataFromDB, database_.get(), |
| + base::ThreadTaskRunnerHandle::Get(), GetOldDiskCachePath(), |
| base::Bind(&ServiceWorkerStorage::DidReadInitialData, |
| weak_factory_.GetWeakPtr()))); |
| return false; |
| @@ -979,6 +988,7 @@ bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { |
| void ServiceWorkerStorage::DidReadInitialData( |
| InitialData* data, |
| + bool needs_disk_cache_migration, |
| ServiceWorkerDatabase::Status status) { |
| DCHECK(data); |
| DCHECK_EQ(INITIALIZING, state_); |
| @@ -989,6 +999,7 @@ void ServiceWorkerStorage::DidReadInitialData( |
| next_resource_id_ = data->next_resource_id; |
| registered_origins_.swap(data->origins); |
| state_ = INITIALIZED; |
| + needs_disk_cache_migration_ = needs_disk_cache_migration; |
|
michaeln
2015/06/08 21:36:33
Curiosity: I wish we didn't have to migrate at all
nhiroki
2015/06/09 15:41:56
Yeah... it's definitely simpler and easier to achi
|
| } else { |
| DVLOG(2) << "Failed to initialize: " |
| << ServiceWorkerDatabase::StatusToString(status); |
| @@ -1368,30 +1379,160 @@ ServiceWorkerStorage::FindInstallingRegistrationForId( |
| } |
| ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() { |
| + DCHECK_EQ(INITIALIZED, state_); |
| if (disk_cache_) |
| return disk_cache_.get(); |
| - disk_cache_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
| + disk_cache_ = ServiceWorkerDiskCache::CreateWithSimpleBackend(); |
| - base::FilePath path = GetDiskCachePath(); |
| - if (path.empty()) { |
| + if (GetDiskCachePath().empty()) { |
| int rv = disk_cache_->InitWithMemBackend(kMaxMemDiskCacheSize, |
| net::CompletionCallback()); |
| DCHECK_EQ(net::OK, rv); |
| return disk_cache_.get(); |
| } |
| + if (needs_disk_cache_migration_) { |
| + // Defer the start of initialization until the migration is complete. |
| + disk_cache_->set_is_waiting_to_initialize(true); |
| + PrepareDiskCacheForMigration(); |
| + return disk_cache_.get(); |
| + } |
| + |
| + // DiskCache has already been migrated. |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_NOT_NECESSARY); |
| + InitializeDiskCache(); |
| + |
| + return disk_cache_.get(); |
| +} |
| + |
| +void ServiceWorkerStorage::PrepareDiskCacheForMigration() { |
| + scoped_ptr<ServiceWorkerDiskCache> src_disk_cache = |
| + ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
| + ServiceWorkerDiskCache* src_disk_cache_ptr = src_disk_cache.get(); |
| + scoped_ptr<ServiceWorkerDiskCache> dest_disk_cache = |
| + ServiceWorkerDiskCache::CreateWithSimpleBackend(); |
| + ServiceWorkerDiskCache* dest_disk_cache_ptr = dest_disk_cache.get(); |
| + bool* is_failed = new bool(false); |
| + |
| + // This closure is called when both diskcaches are initialized. |
| + base::Closure barrier_closure = base::BarrierClosure( |
| + 2, base::Bind( |
| + &ServiceWorkerStorage::DidPrepareDiskCacheForMigration, |
| + weak_factory_.GetWeakPtr(), base::Passed(src_disk_cache.Pass()), |
| + base::Passed(dest_disk_cache.Pass()), base::Owned(is_failed))); |
| + |
| + // Initialize the src DiskCache. |
| + net::CompletionCallback src_callback = |
| + base::Bind(&ServiceWorkerStorage::DidInitializeDiskCacheForMigration, |
| + weak_factory_.GetWeakPtr(), is_failed, barrier_closure); |
| + int result = src_disk_cache_ptr->InitWithDiskBackend( |
| + GetOldDiskCachePath(), kMaxDiskCacheSize, false /* force */, |
| + disk_cache_thread_, src_callback); |
| + if (result != net::ERR_IO_PENDING) |
| + src_callback.Run(result); |
| + |
| + // Initialize the dest DiskCache. |
|
michaeln
2015/06/08 21:36:33
Since a migration attempt can be started multiple
nhiroki
2015/06/09 15:41:56
Done.
|
| + net::CompletionCallback dest_callback = |
| + base::Bind(&ServiceWorkerStorage::DidInitializeDiskCacheForMigration, |
| + weak_factory_.GetWeakPtr(), is_failed, barrier_closure); |
| + result = dest_disk_cache_ptr->InitWithDiskBackend( |
| + GetDiskCachePath(), kMaxDiskCacheSize, false /* force */, |
| + disk_cache_thread_, dest_callback); |
| + if (result != net::ERR_IO_PENDING) |
| + dest_callback.Run(result); |
| +} |
| + |
| +void ServiceWorkerStorage::DidInitializeDiskCacheForMigration( |
| + bool* is_failed, |
| + const base::Closure& barrier_closure, |
| + int result) { |
| + if (result != net::OK) |
| + *is_failed = true; |
| + barrier_closure.Run(); |
| +} |
| + |
| +void ServiceWorkerStorage::DidPrepareDiskCacheForMigration( |
| + scoped_ptr<ServiceWorkerDiskCache> src_disk_cache, |
| + scoped_ptr<ServiceWorkerDiskCache> dest_disk_cache, |
| + bool* is_failed) { |
| + if (*is_failed) { |
| + LOG(ERROR) << "Failed to initialize the diskcache."; |
| + src_disk_cache.reset(); |
| + dest_disk_cache.reset(); |
| + AbortDiskCacheMigration(ServiceWorkerMetrics::MIGRATION_ERROR_INITIALIZE); |
| + return; |
| + } |
| + |
| + // Start migrating resources stored in the src DiskCache. |
| + scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator( |
| + new ServiceWorkerDiskCacheMigrator(src_disk_cache.get(), |
| + dest_disk_cache.get())); |
| + ServiceWorkerDiskCacheMigrator* migrator_ptr = migrator.get(); |
| + migrator_ptr->Start(base::Bind( |
|
michaeln
2015/06/08 21:36:33
The migrator will continue to run even after Servi
nhiroki
2015/06/09 15:41:56
I changed the storage to own the migrator. When th
|
| + &ServiceWorkerStorage::DidMigrateDiskCache, weak_factory_.GetWeakPtr(), |
| + base::Passed(migrator.Pass()), base::Passed(src_disk_cache.Pass()), |
| + base::Passed(dest_disk_cache.Pass()))); |
|
michaeln
2015/06/08 21:36:33
having ownership of src and dst bound into the clo
nhiroki
2015/06/09 15:41:57
Moved the initialization code from storage to migr
|
| +} |
| + |
| +void ServiceWorkerStorage::DidMigrateDiskCache( |
| + scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator, |
| + scoped_ptr<ServiceWorkerDiskCache> src_disk_cache, |
| + scoped_ptr<ServiceWorkerDiskCache> dest_disk_cache, |
| + ServiceWorkerStatusCode status) { |
| + migrator.reset(); |
| + src_disk_cache.reset(); |
| + dest_disk_cache.reset(); |
| + |
| + if (status != SERVICE_WORKER_OK) { |
| + LOG(ERROR) << "Failed to migrate the diskcache: " |
| + << ServiceWorkerStatusToString(status); |
| + AbortDiskCacheMigration(ServiceWorkerMetrics::MIGRATION_ERROR_FAILED); |
| + return; |
| + } |
| + |
| + // Delete the old DiskCache directory. |
| + PostTaskAndReplyWithResult( |
| + disk_cache_thread_.get(), FROM_HERE, |
| + base::Bind(&base::DeleteFile, GetOldDiskCachePath(), true), |
| + base::Bind(&ServiceWorkerStorage::DidDeleteOldDiskCache, |
| + weak_factory_.GetWeakPtr())); |
| +} |
| + |
| +void ServiceWorkerStorage::DidDeleteOldDiskCache(bool deleted) { |
| + if (!deleted) { |
| + LOG(ERROR) << "Failed to delete the old diskcache directory"; |
| + AbortDiskCacheMigration( |
|
michaeln
2015/06/08 21:36:33
Seems unfortunate to let this error prevent migrat
nhiroki
2015/06/09 15:41:57
Changed this sequence. The latest patchset records
|
| + ServiceWorkerMetrics::MIGRATION_ERROR_DELETE_DISK_CACHE); |
| + return; |
| + } |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_OK); |
| + InitializeDiskCache(); |
| +} |
| + |
| +void ServiceWorkerStorage::AbortDiskCacheMigration( |
|
michaeln
2015/06/08 21:36:33
This method doesn't actually abort anything, it ha
nhiroki
2015/06/09 15:41:57
(This function is gone)
|
| + ServiceWorkerMetrics::DiskCacheMigrationResult result) { |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult(result); |
| + |
| + // Give up initialization and recreate the whole storage. |
| + ScheduleDeleteAndStartOver(); |
| + |
| + // Delete the old disk directory because DeleteAndStartOver doesn't. |
| + disk_cache_thread_->PostTask(FROM_HERE, |
| + base::Bind(base::IgnoreResult(&base::DeleteFile), |
| + GetOldDiskCachePath(), true)); |
| +} |
| + |
| +void ServiceWorkerStorage::InitializeDiskCache() { |
| + disk_cache_->set_is_waiting_to_initialize(false); |
| int rv = disk_cache_->InitWithDiskBackend( |
| - path, |
| - kMaxDiskCacheSize, |
| - false, |
| - disk_cache_thread_, |
| + GetDiskCachePath(), kMaxDiskCacheSize, false, disk_cache_thread_, |
| base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized, |
| weak_factory_.GetWeakPtr())); |
| if (rv != net::ERR_IO_PENDING) |
| OnDiskCacheInitialized(rv); |
| - |
| - return disk_cache_.get(); |
| } |
| void ServiceWorkerStorage::OnDiskCacheInitialized(int rv) { |
| @@ -1534,6 +1675,7 @@ void ServiceWorkerStorage::CollectStaleResourcesFromDB( |
| void ServiceWorkerStorage::ReadInitialDataFromDB( |
| ServiceWorkerDatabase* database, |
| scoped_refptr<base::SequencedTaskRunner> original_task_runner, |
| + const base::FilePath& old_disk_cache_path, |
| const InitializeCallback& callback) { |
| DCHECK(database); |
| scoped_ptr<ServiceWorkerStorage::InitialData> data( |
| @@ -1545,13 +1687,19 @@ void ServiceWorkerStorage::ReadInitialDataFromDB( |
| &data->next_resource_id); |
| if (status != ServiceWorkerDatabase::STATUS_OK) { |
| original_task_runner->PostTask( |
| - FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); |
| + FROM_HERE, base::Bind(callback, base::Owned(data.release()), |
| + false /* needs_disk_cache_migration */, status)); |
| return; |
| } |
| + bool needs_disk_cache_migration = false; |
| + if (!old_disk_cache_path.empty()) |
| + needs_disk_cache_migration = base::DirectoryExists(old_disk_cache_path); |
|
michaeln
2015/06/08 21:36:33
I'm wondering about pathological cases where migra
nhiroki
2015/06/09 15:41:57
Added INITDATA_DISKCACHE_VERSION field in the data
|
| + |
| status = database->GetOriginsWithRegistrations(&data->origins); |
| original_task_runner->PostTask( |
| - FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); |
| + FROM_HERE, base::Bind(callback, base::Owned(data.release()), |
| + needs_disk_cache_migration, status)); |
| } |
| void ServiceWorkerStorage::DeleteRegistrationFromDB( |