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..7b66d027ffdd4d01e8ee28324039085d42ffd838 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" |
@@ -57,10 +57,13 @@ void CompleteFindSoon( |
base::Bind(&CompleteFindNow, registration, status, callback)); |
} |
-const base::FilePath::CharType kDatabaseName[] = |
- FILE_PATH_LITERAL("Database"); |
-const base::FilePath::CharType kDiskCacheName[] = |
- FILE_PATH_LITERAL("Cache"); |
+const char kDatabaseName[] = "Database"; |
+const char kDiskCacheName[] = "ScriptCache"; |
+const char kOldDiskCacheName[] = "Cache"; |
+ |
+// Version 2 means that the diskcache was migrated from BlockFile backend to |
+// Simple backend (http://crbug.com/487482). |
michaeln
2015/06/11 00:52:38
How are we handling android? It already uses the s
nhiroki
2015/06/11 21:04:50
Done in the separate CL:
https://codereview.chromi
|
+const int64 kCurrentDiskCacheVersion = 2; |
const int kMaxMemDiskCacheSize = 10 * 1024 * 1024; |
const int kMaxDiskCacheSize = 250 * 1024 * 1024; |
@@ -225,6 +228,16 @@ DidDeleteRegistrationParams::~DidDeleteRegistrationParams() { |
ServiceWorkerStorage::~ServiceWorkerStorage() { |
ClearSessionOnlyOrigins(); |
weak_factory_.InvalidateWeakPtrs(); |
+ if (disk_cache_migrator_) { |
+ // The migrator will be aborted during the migration. To sweep out partial |
+ // results before the next attempt, register the diskcache directory as a |
+ // purgeable file. |
+ database_task_manager_->GetTaskRunner()->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ base::IgnoreResult(&ServiceWorkerDatabase::WritePurgeableFile), |
+ base::Unretained(database_.get()), kDiskCacheName)); |
+ } |
database_task_manager_->GetTaskRunner()->DeleteSoon(FROM_HERE, |
database_.release()); |
} |
@@ -929,6 +942,7 @@ ServiceWorkerStorage::ServiceWorkerStorage( |
disk_cache_thread_(disk_cache_thread), |
quota_manager_proxy_(quota_manager_proxy), |
special_storage_policy_(special_storage_policy), |
+ current_disk_cache_version_(-1), |
is_purge_pending_(false), |
has_checked_for_stale_resources_(false), |
weak_factory_(this) { |
@@ -939,14 +953,21 @@ base::FilePath ServiceWorkerStorage::GetDatabasePath() { |
if (path_.empty()) |
return base::FilePath(); |
return path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory) |
- .Append(kDatabaseName); |
+ .AppendASCII(kDatabaseName); |
} |
base::FilePath ServiceWorkerStorage::GetDiskCachePath() { |
if (path_.empty()) |
return base::FilePath(); |
return path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory) |
- .Append(kDiskCacheName); |
+ .AppendASCII(kDiskCacheName); |
+} |
+ |
+base::FilePath ServiceWorkerStorage::GetOldDiskCachePath() { |
+ if (path_.empty()) |
+ return base::FilePath(); |
+ return path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory) |
+ .AppendASCII(kOldDiskCacheName); |
} |
bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { |
@@ -969,8 +990,7 @@ bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { |
state_ = INITIALIZING; |
database_task_manager_->GetTaskRunner()->PostTask( |
FROM_HERE, |
- base::Bind(&ReadInitialDataFromDB, |
- database_.get(), |
+ base::Bind(&ReadInitialDataFromDB, database_.get(), |
base::ThreadTaskRunnerHandle::Get(), |
base::Bind(&ServiceWorkerStorage::DidReadInitialData, |
weak_factory_.GetWeakPtr()))); |
@@ -979,27 +999,52 @@ bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) { |
void ServiceWorkerStorage::DidReadInitialData( |
InitialData* data, |
+ int64 current_disk_cache_version, |
+ const std::vector<std::string>& purgeable_files, |
ServiceWorkerDatabase::Status status) { |
DCHECK(data); |
DCHECK_EQ(INITIALIZING, state_); |
- if (status == ServiceWorkerDatabase::STATUS_OK) { |
- next_registration_id_ = data->next_registration_id; |
- next_version_id_ = data->next_version_id; |
- next_resource_id_ = data->next_resource_id; |
- registered_origins_.swap(data->origins); |
- state_ = INITIALIZED; |
- } else { |
+ if (status != ServiceWorkerDatabase::STATUS_OK) { |
DVLOG(2) << "Failed to initialize: " |
<< ServiceWorkerDatabase::StatusToString(status); |
ScheduleDeleteAndStartOver(); |
- } |
- for (std::vector<base::Closure>::const_iterator it = pending_tasks_.begin(); |
- it != pending_tasks_.end(); ++it) { |
- RunSoon(FROM_HERE, *it); |
+ // These tasks should run before DeleteAndStartOver is complete, and should |
+ // fail due to the disabled storage. |
+ for (const base::Closure& pending_task : pending_tasks_) |
+ RunSoon(FROM_HERE, pending_task); |
+ pending_tasks_.clear(); |
+ return; |
} |
+ |
+ next_registration_id_ = data->next_registration_id; |
+ next_version_id_ = data->next_version_id; |
+ next_resource_id_ = data->next_resource_id; |
+ registered_origins_.swap(data->origins); |
+ state_ = INITIALIZED; |
+ current_disk_cache_version_ = current_disk_cache_version; |
+ |
+ for (const base::Closure& pending_task : pending_tasks_) |
+ RunSoon(FROM_HERE, pending_task); |
pending_tasks_.clear(); |
+ |
+ if (path_.empty()) { |
+ // On-memory storage should not have to purge files. |
+ DCHECK(purgeable_files.empty()); |
+ return; |
+ } |
+ |
+ const base::FilePath service_worker_directory = |
+ path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory); |
+ for (const std::string& filename : purgeable_files) { |
michaeln
2015/06/11 00:52:38
Can you defer the start of purging with BrowserThr
nhiroki
2015/06/11 21:04:50
Done. Purging is deferred until an initial diskcac
|
+ PostTaskAndReplyWithResult( |
+ disk_cache_thread_.get(), FROM_HERE, |
+ base::Bind(&base::DeleteFile, |
+ service_worker_directory.AppendASCII(filename), true), |
michaeln
2015/06/11 00:52:38
Having a general'ish purpose file deletion mechani
nhiroki
2015/06/11 21:04:50
(This code is gone)
|
+ base::Bind(&ServiceWorkerStorage::DidPurgeFile, |
+ weak_factory_.GetWeakPtr())); |
+ } |
} |
void ServiceWorkerStorage::DidFindRegistrationForDocument( |
@@ -1105,6 +1150,12 @@ void ServiceWorkerStorage::ReturnFoundRegistration( |
CompleteFindNow(registration, SERVICE_WORKER_OK, callback); |
} |
+void ServiceWorkerStorage::DidWriteDatabase( |
+ ServiceWorkerDatabase::Status status) { |
+ if (status != ServiceWorkerDatabase::STATUS_OK) |
+ ScheduleDeleteAndStartOver(); |
+} |
+ |
void ServiceWorkerStorage::DidGetRegistrations( |
const GetRegistrationsInfosCallback& callback, |
RegistrationList* registrations, |
@@ -1368,30 +1419,112 @@ ServiceWorkerStorage::FindInstallingRegistrationForId( |
} |
ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() { |
+ DCHECK_EQ(INITIALIZED, state_); |
if (disk_cache_) |
return disk_cache_.get(); |
- disk_cache_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend(); |
michaeln
2015/06/11 00:52:38
Ooops, does this cause the blockfile backend to be
nhiroki
2015/06/11 21:04:50
Fixed in the separate CL:
https://codereview.chrom
|
+ 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 (current_disk_cache_version_ < kCurrentDiskCacheVersion) { |
+ // Defer the start of initialization until the migration is complete. |
+ disk_cache_->set_is_waiting_to_initialize(true); |
+ MigrateDiskCache(); |
+ return disk_cache_.get(); |
+ } |
+ DCHECK_EQ(kCurrentDiskCacheVersion, current_disk_cache_version_); |
+ |
+ // DiskCache has already been migrated. |
+ ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
+ ServiceWorkerMetrics::MIGRATION_NOT_NECESSARY); |
+ InitializeDiskCache(); |
+ |
+ return disk_cache_.get(); |
+} |
+ |
+void ServiceWorkerStorage::MigrateDiskCache() { |
+ 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())); |
+} |
+ |
+void ServiceWorkerStorage::DidMigrateDiskCache(ServiceWorkerStatusCode status) { |
+ disk_cache_migrator_.reset(); |
+ |
+ // Add the old diskcache directory to the purgeable file list. |
+ PostTaskAndReplyWithResult( |
+ database_task_manager_->GetTaskRunner(), FROM_HERE, |
+ base::Bind(&ServiceWorkerDatabase::WritePurgeableFile, |
+ base::Unretained(database_.get()), kOldDiskCacheName), |
+ base::Bind(&ServiceWorkerStorage::DidWriteDatabase, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ // Delete the old DiskCache directory. |
+ PostTaskAndReplyWithResult( |
+ disk_cache_thread_.get(), FROM_HERE, |
+ base::Bind(&base::DeleteFile, GetOldDiskCachePath(), true), |
+ base::Bind(&ServiceWorkerStorage::DidPurgeFile, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ if (status != SERVICE_WORKER_OK) { |
+ LOG(ERROR) << "Failed to migrate the diskcache: " |
+ << ServiceWorkerStatusToString(status); |
+ ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
+ ServiceWorkerMetrics::MIGRATION_ERROR_FAILED); |
+ |
+ // Give up the migration and recreate the whole storage. |
+ ScheduleDeleteAndStartOver(); |
+ return; |
+ } |
+ |
+ ServiceWorkerMetrics::RecordDiskCacheMigrationResult( |
+ ServiceWorkerMetrics::MIGRATION_OK); |
+ |
+ // Update the disk cache version. |
michaeln
2015/06/11 00:52:38
I'm wondering about the order of the operations in
nhiroki
2015/06/11 21:04:50
Revised these operations. The new version...
(1)
|
+ current_disk_cache_version_ = kCurrentDiskCacheVersion; |
+ PostTaskAndReplyWithResult( |
+ database_task_manager_->GetTaskRunner(), FROM_HERE, |
+ base::Bind(&ServiceWorkerDatabase::WriteDiskCacheVersion, |
+ base::Unretained(database_.get()), kCurrentDiskCacheVersion), |
+ base::Bind(&ServiceWorkerStorage::DidWriteDatabase, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ InitializeDiskCache(); |
+} |
+ |
+void ServiceWorkerStorage::DidPurgeFile(bool deleted) { |
+ if (!deleted) { |
+ LOG(ERROR) << "Failed to delete the file."; |
+ // Retry to delete when the browser restarts. |
+ return; |
+ } |
+ |
+ // Remove the file from the purgeable file list. |
+ PostTaskAndReplyWithResult( |
+ database_task_manager_->GetTaskRunner(), FROM_HERE, |
+ base::Bind(&ServiceWorkerDatabase::ClearPurgeableFile, |
+ base::Unretained(database_.get()), kOldDiskCacheName), |
+ base::Bind(&ServiceWorkerStorage::DidWriteDatabase, |
+ weak_factory_.GetWeakPtr())); |
+} |
+ |
+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) { |
@@ -1538,6 +1671,7 @@ void ServiceWorkerStorage::ReadInitialDataFromDB( |
DCHECK(database); |
scoped_ptr<ServiceWorkerStorage::InitialData> data( |
new ServiceWorkerStorage::InitialData()); |
+ int64 disk_cache_version = -1; |
ServiceWorkerDatabase::Status status = |
database->GetNextAvailableIds(&data->next_registration_id, |
@@ -1545,13 +1679,35 @@ 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()), disk_cache_version, |
+ std::vector<std::string>(), status)); |
+ return; |
+ } |
+ |
+ status = database->ReadDiskCacheVersion(&disk_cache_version); |
+ if (status != ServiceWorkerDatabase::STATUS_OK) { |
+ original_task_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, base::Owned(data.release()), disk_cache_version, |
+ std::vector<std::string>(), status)); |
return; |
} |
status = database->GetOriginsWithRegistrations(&data->origins); |
+ if (status != ServiceWorkerDatabase::STATUS_OK) { |
+ original_task_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback, base::Owned(data.release()), disk_cache_version, |
+ std::vector<std::string>(), status)); |
+ return; |
+ } |
+ |
+ std::vector<std::string> purgeable_files; |
+ status = database->GetPurgeableFiles(&purgeable_files); |
original_task_runner->PostTask( |
- FROM_HERE, base::Bind(callback, base::Owned(data.release()), status)); |
+ FROM_HERE, base::Bind(callback, base::Owned(data.release()), |
+ disk_cache_version, purgeable_files, status)); |
} |
void ServiceWorkerStorage::DeleteRegistrationFromDB( |