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 b0c59e037b0dc89c26df81b5d30e45f53644db80..8d726e5e5d824979fcd7ae7c0a1090c72b4ec647 100644 |
| --- a/content/browser/service_worker/service_worker_storage.cc |
| +++ b/content/browser/service_worker/service_worker_storage.cc |
| @@ -14,8 +14,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 +60,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; |
| @@ -207,7 +208,8 @@ void ResponseComparer::OnReadDataComplete(int result) { |
| ServiceWorkerStorage::InitialData::InitialData() |
| : next_registration_id(kInvalidServiceWorkerRegistrationId), |
| next_version_id(kInvalidServiceWorkerVersionId), |
| - next_resource_id(kInvalidServiceWorkerResourceId) { |
| + next_resource_id(kInvalidServiceWorkerResourceId), |
| + migration_state(ServiceWorkerDatabase::DISKCACHE_UNKNOWN_STATE) { |
| } |
| ServiceWorkerStorage::InitialData::~InitialData() { |
| @@ -928,6 +930,8 @@ ServiceWorkerStorage::ServiceWorkerStorage( |
| disk_cache_thread_(disk_cache_thread), |
| quota_manager_proxy_(quota_manager_proxy), |
| special_storage_policy_(special_storage_policy), |
| + disk_cache_migration_state_( |
| + ServiceWorkerDatabase::DISKCACHE_UNKNOWN_STATE), |
|
michaeln
2015/06/12 20:47:58
is_migration_needed_(false) // we don't know yet
i
nhiroki
2015/06/15 16:43:27
Done.
|
| is_purge_pending_(false), |
| has_checked_for_stale_resources_(false), |
| weak_factory_(this) { |
| @@ -948,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; |
| @@ -987,6 +998,7 @@ void ServiceWorkerStorage::DidReadInitialData( |
| next_version_id_ = data->next_version_id; |
| next_resource_id_ = data->next_resource_id; |
| registered_origins_.swap(data->origins); |
| + disk_cache_migration_state_ = data->migration_state; |
| state_ = INITIALIZED; |
| } else { |
| DVLOG(2) << "Failed to initialize: " |
| @@ -1104,6 +1116,16 @@ void ServiceWorkerStorage::ReturnFoundRegistration( |
| CompleteFindNow(registration, SERVICE_WORKER_OK, callback); |
| } |
| +void ServiceWorkerStorage::DidWriteDatabase( |
| + const base::Closure& continuation, |
| + ServiceWorkerDatabase::Status status) { |
| + if (status != ServiceWorkerDatabase::STATUS_OK) { |
| + ScheduleDeleteAndStartOver(); |
| + return; |
| + } |
| + continuation.Run(); |
| +} |
| + |
| void ServiceWorkerStorage::DidGetRegistrations( |
| const GetRegistrationsCallback& callback, |
| RegistrationList* registration_data_list, |
| @@ -1407,10 +1429,11 @@ 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()) { |
| @@ -1420,17 +1443,111 @@ ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() { |
| return disk_cache_.get(); |
| } |
| + switch (disk_cache_migration_state_) { |
| + case ServiceWorkerDatabase::DISKCACHE_NOT_USED: { |
|
michaeln
2015/06/12 01:55:45
Hmmm, maybe this state doesn't need to be here? Lo
nhiroki
2015/06/12 03:12:14
In this case, how can we avoid an unnecessary migr
nhiroki
2015/06/12 03:32:33
This can avoid an extra thread hopping, but needs
michaeln
2015/06/12 20:47:58
my head hurts :)
|
| + // Defer the start of initialization until a migration state is updated. |
| + disk_cache_->set_is_waiting_to_initialize(true); |
| + base::Closure continuation = |
| + base::Bind(&ServiceWorkerStorage::InitializeDiskCache, |
| + weak_factory_.GetWeakPtr()); |
| + PostTaskAndReplyWithResult( |
| + database_task_manager_->GetTaskRunner(), FROM_HERE, |
| + base::Bind(&ServiceWorkerDatabase::WriteDiskCacheMigrationState, |
| + base::Unretained(database_.get()), |
| + ServiceWorkerDatabase::DISKCACHE_MIGRATED), |
| + base::Bind(&ServiceWorkerStorage::DidWriteDatabase, |
| + weak_factory_.GetWeakPtr(), continuation)); |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_NOT_NECESSARY); |
| + break; |
| + } |
| + case ServiceWorkerDatabase::DISKCACHE_NEEDS_TO_MIGRATE: { |
| + // Defer the start of initialization until a migration is complete. |
| + disk_cache_->set_is_waiting_to_initialize(true); |
| + DCHECK(!disk_cache_migrator_); |
| + disk_cache_migrator_.reset(new ServiceWorkerDiskCacheMigrator( |
| + GetOldDiskCachePath(), GetDiskCachePath(), kMaxDiskCacheSize, |
| + disk_cache_thread_)); |
| + disk_cache_migrator_->Start( |
| + base::Bind(&ServiceWorkerStorage::DidMigrateDiskCache, |
| + weak_factory_.GetWeakPtr())); |
| + break; |
| + } |
| + case ServiceWorkerDatabase::DISKCACHE_NEEDS_TO_DELETE_OLD: { |
| + // A migration was complete, but an old diskcache still exists. |
| + base::Closure continuation = base::Bind(&base::DoNothing); |
| + database_task_manager_->GetTaskRunner()->PostTask( |
|
michaeln
2015/06/12 01:55:45
Is there a reason to not schedule this task va Bro
nhiroki
2015/06/12 03:12:14
I didn't know this helper. There should be no obst
|
| + FROM_HERE, |
| + base::Bind(&DeleteOldDiskCacheInDB, database_.get(), |
| + base::ThreadTaskRunnerHandle::Get(), GetOldDiskCachePath(), |
| + base::Bind(&ServiceWorkerStorage::DidWriteDatabase, |
| + weak_factory_.GetWeakPtr(), continuation))); |
| + |
| + // Don't have to wait for the completion of deleting the old diskcache. |
| + // Immediately continue to initialize. |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_NOT_NECESSARY); |
| + InitializeDiskCache(); |
| + break; |
| + } |
| + case ServiceWorkerDatabase::DISKCACHE_MIGRATED: { |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_NOT_NECESSARY); |
| + InitializeDiskCache(); |
| + break; |
| + } |
| + case ServiceWorkerDatabase::DISKCACHE_UNKNOWN_STATE: { |
| + NOTREACHED(); |
| + break; |
| + } |
| + } |
| + |
| + return disk_cache_.get(); |
| +} |
| + |
| +void ServiceWorkerStorage::DidMigrateDiskCache(ServiceWorkerStatusCode status) { |
| + disk_cache_migrator_.reset(); |
| + |
| + if (status != SERVICE_WORKER_OK) { |
| + LOG(ERROR) << "Failed to migrate the diskcache: " |
| + << ServiceWorkerStatusToString(status); |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_ERROR_FAILED); |
| + |
| + // Give up a migration and recreate the whole storage. |
| + ScheduleDeleteAndStartOver(); |
| + |
| + // Delete the old diskcache. |
| + disk_cache_thread_->PostTask( |
| + FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile), |
| + GetOldDiskCachePath(), true)); |
| + return; |
| + } |
| + |
| + // The migration was complete, but an old diskcache still exists. |
| + base::Closure continuation = base::Bind(&base::DoNothing); |
| + database_task_manager_->GetTaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&DeleteOldDiskCacheInDB, database_.get(), |
| + base::ThreadTaskRunnerHandle::Get(), GetOldDiskCachePath(), |
| + base::Bind(&ServiceWorkerStorage::DidWriteDatabase, |
| + weak_factory_.GetWeakPtr(), continuation))); |
| + |
| + // Don't have to wait for the completion of deleting the old diskcache. |
| + // Immediately continue to initialize. |
| + ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
| + ServiceWorkerMetrics::MIGRATION_OK); |
| + InitializeDiskCache(); |
| +} |
| + |
| +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) { |
| @@ -1588,11 +1705,44 @@ void ServiceWorkerStorage::ReadInitialDataFromDB( |
| return; |
| } |
| + status = database->ReadDiskCacheMigrationState(&data->migration_state); |
| + if (status != ServiceWorkerDatabase::STATUS_OK) { |
| + original_task_runner->PostTask( |
| + FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); |
| + return; |
| + } |
| + |
| status = database->GetOriginsWithRegistrations(&data->origins); |
| original_task_runner->PostTask( |
| FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); |
| } |
| +void ServiceWorkerStorage::DeleteOldDiskCacheInDB( |
| + ServiceWorkerDatabase* database, |
| + scoped_refptr<base::SequencedTaskRunner> original_task_runner, |
| + const base::FilePath& disk_cache_path, |
| + const DatabaseStatusCallback& callback) { |
| + DCHECK(database); |
| + ServiceWorkerDatabase::Status status = database->WriteDiskCacheMigrationState( |
| + ServiceWorkerDatabase::DISKCACHE_NEEDS_TO_DELETE_OLD); |
| + if (status != ServiceWorkerDatabase::STATUS_OK) { |
| + original_task_runner->PostTask(FROM_HERE, base::Bind(callback, status)); |
| + return; |
| + } |
| + |
| + if (!base::DeleteFile(disk_cache_path, true)) { |
| + // Ignore a failure. A migration state has already been recorded in the |
| + // database and a retry happens on the next diskcache initialization. |
| + original_task_runner->PostTask( |
| + FROM_HERE, base::Bind(callback, ServiceWorkerDatabase::STATUS_OK)); |
| + return; |
| + } |
| + |
| + status = database->WriteDiskCacheMigrationState( |
| + ServiceWorkerDatabase::DISKCACHE_MIGRATED); |
| + original_task_runner->PostTask(FROM_HERE, base::Bind(callback, status)); |
| +} |
| + |
| void ServiceWorkerStorage::DeleteRegistrationFromDB( |
| ServiceWorkerDatabase* database, |
| scoped_refptr<base::SequencedTaskRunner> original_task_runner, |