summaryrefslogtreecommitdiffstats
path: root/content/browser/service_worker
diff options
context:
space:
mode:
authornhiroki@chromium.org <nhiroki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-07 09:15:27 +0000
committernhiroki@chromium.org <nhiroki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-07 09:15:27 +0000
commitb37a5d1929e39d39324227b0dc98f4525f5bb2c7 (patch)
treeb54ba0509f98ab63ad522506f96224c070b7f73e /content/browser/service_worker
parent6c65f2bacb106236ad7edf63d7280839c716c2f3 (diff)
downloadchromium_src-b37a5d1929e39d39324227b0dc98f4525f5bb2c7.zip
chromium_src-b37a5d1929e39d39324227b0dc98f4525f5bb2c7.tar.gz
chromium_src-b37a5d1929e39d39324227b0dc98f4525f5bb2c7.tar.bz2
ServiceWorker: Initialize ServiceWorkerStorage with ServiceWorkerDatabase
This patch implements initial wiring part ServiceWorkerStorage and ServiceWorkerDatabase. - The storage owns the database that lives on dedicated task runner. - The storage queries the database about available ids and registered origins on initialization. - The storage gets disabled when database operation fails. - Fixing some bugs of the database detected by tests after wiring. BUG=369464 TEST=content_unittests --gtest_filter=ServiceWorker* R=michaeln@chromium.org Review URL: https://codereview.chromium.org/268453002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268691 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/service_worker')
-rw-r--r--content/browser/service_worker/service_worker_database.cc21
-rw-r--r--content/browser/service_worker/service_worker_database_unittest.cc9
-rw-r--r--content/browser/service_worker/service_worker_storage.cc187
-rw-r--r--content/browser/service_worker/service_worker_storage.h44
-rw-r--r--content/browser/service_worker/service_worker_storage_unittest.cc9
5 files changed, 220 insertions, 50 deletions
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index 18e7102..588c4d7 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -231,6 +231,7 @@ ServiceWorkerDatabase::ServiceWorkerDatabase(const base::FilePath& path)
is_disabled_(false),
was_corruption_detected_(false),
is_initialized_(false) {
+ sequence_checker_.DetachFromSequence();
}
ServiceWorkerDatabase::~ServiceWorkerDatabase() {
@@ -247,8 +248,15 @@ bool ServiceWorkerDatabase::GetNextAvailableIds(
DCHECK(next_avail_version_id);
DCHECK(next_avail_resource_id);
- if (!LazyOpen(false) || is_disabled_)
- return false;
+ if (!LazyOpen(false)) {
+ if (is_disabled_)
+ return false;
+ // Database has never been used.
+ *next_avail_registration_id = 0;
+ *next_avail_version_id = 0;
+ *next_avail_resource_id = 0;
+ return true;
+ }
if (!ReadNextAvailableId(kNextRegIdKey, &next_avail_registration_id_) ||
!ReadNextAvailableId(kNextVerIdKey, &next_avail_version_id_) ||
@@ -267,8 +275,13 @@ bool ServiceWorkerDatabase::GetOriginsWithRegistrations(
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(origins);
- if (!LazyOpen(false) || is_disabled_)
- return false;
+ if (!LazyOpen(false)) {
+ if (is_disabled_)
+ return false;
+ // Database has never been used.
+ origins->clear();
+ return true;
+ }
scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
for (itr->Seek(kUniqueOriginKey); itr->Valid(); itr->Next()) {
diff --git a/content/browser/service_worker/service_worker_database_unittest.cc b/content/browser/service_worker/service_worker_database_unittest.cc
index b0cae286..ae8f2d6 100644
--- a/content/browser/service_worker/service_worker_database_unittest.cc
+++ b/content/browser/service_worker/service_worker_database_unittest.cc
@@ -139,9 +139,12 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
CreateDatabase(database_dir.path()));
AvailableIds ids;
- // Should be false because the database hasn't been opened.
- EXPECT_FALSE(database->GetNextAvailableIds(
+ // The database has never been used, so returns initial values.
+ EXPECT_TRUE(database->GetNextAvailableIds(
&ids.reg_id, &ids.ver_id, &ids.res_id));
+ EXPECT_EQ(0, ids.reg_id);
+ EXPECT_EQ(0, ids.ver_id);
+ EXPECT_EQ(0, ids.res_id);
ASSERT_TRUE(database->LazyOpen(true));
EXPECT_TRUE(database->GetNextAvailableIds(
@@ -188,7 +191,7 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
std::set<GURL> origins;
- EXPECT_FALSE(database->GetOriginsWithRegistrations(&origins));
+ EXPECT_TRUE(database->GetOriginsWithRegistrations(&origins));
EXPECT_TRUE(origins.empty());
std::vector<Resource> resources;
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index 07addb2..607d146 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -6,14 +6,17 @@
#include <string>
+#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
+#include "base/task_runner_util.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_info.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"
+#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h"
#include "webkit/browser/quota/quota_manager_proxy.h"
@@ -22,6 +25,9 @@ namespace content {
namespace {
+typedef base::Callback<void(ServiceWorkerStorage::InitialData* data,
+ bool success)> InitializeCallback;
+
void RunSoon(const tracked_objects::Location& from_here,
const base::Closure& closure) {
base::MessageLoop::current()->PostTask(from_here, closure);
@@ -45,42 +51,77 @@ void CompleteFindSoon(
const base::FilePath::CharType kServiceWorkerDirectory[] =
FILE_PATH_LITERAL("ServiceWorker");
-
const int kMaxMemDiskCacheSize = 10 * 1024 * 1024;
void EmptyCompletionCallback(int) {}
+void InitializeOnDatabaseTaskRunner(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ const InitializeCallback& callback) {
+ DCHECK(database);
+ ServiceWorkerStorage::InitialData* data =
+ new ServiceWorkerStorage::InitialData();
+ bool success =
+ database->GetNextAvailableIds(&data->next_registration_id,
+ &data->next_version_id,
+ &data->next_resource_id) &&
+ database->GetOriginsWithRegistrations(&data->origins);
+ original_task_runner->PostTask(
+ FROM_HERE, base::Bind(callback, base::Owned(data), success));
+}
+
} // namespace
+ServiceWorkerStorage::InitialData::InitialData()
+ : next_registration_id(kInvalidServiceWorkerRegistrationId),
+ next_version_id(kInvalidServiceWorkerVersionId),
+ next_resource_id(kInvalidServiceWorkerResourceId) {
+}
+
+ServiceWorkerStorage::InitialData::~InitialData() {
+}
+
ServiceWorkerStorage::ServiceWorkerStorage(
const base::FilePath& path,
base::WeakPtr<ServiceWorkerContextCore> context,
base::SequencedTaskRunner* database_task_runner,
quota::QuotaManagerProxy* quota_manager_proxy)
- : last_registration_id_(0),
- last_version_id_(0),
- last_resource_id_(0),
- simulated_lazy_initted_(false),
+ : next_registration_id_(kInvalidServiceWorkerRegistrationId),
+ next_version_id_(kInvalidServiceWorkerVersionId),
+ next_resource_id_(kInvalidServiceWorkerResourceId),
+ state_(UNINITIALIZED),
context_(context),
database_task_runner_(database_task_runner),
- quota_manager_proxy_(quota_manager_proxy) {
+ quota_manager_proxy_(quota_manager_proxy),
+ weak_factory_(this) {
if (!path.empty())
path_ = path.Append(kServiceWorkerDirectory);
+
+ // TODO(nhiroki): Create a database on-disk after the database schema gets
+ // stable.
+ database_.reset(new ServiceWorkerDatabase(base::FilePath()));
}
ServiceWorkerStorage::~ServiceWorkerStorage() {
+ weak_factory_.InvalidateWeakPtrs();
+ database_task_runner_->DeleteSoon(FROM_HERE, database_.release());
}
void ServiceWorkerStorage::FindRegistrationForPattern(
const GURL& scope,
const FindRegistrationCallback& callback) {
- simulated_lazy_initted_ = true;
scoped_refptr<ServiceWorkerRegistration> null_registration;
- if (!context_) {
- CompleteFindSoon(
- FROM_HERE, null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
+ if (!LazyInitialize(base::Bind(
+ &ServiceWorkerStorage::FindRegistrationForPattern,
+ weak_factory_.GetWeakPtr(), scope, callback))) {
+ if (state_ != INITIALIZING || !context_) {
+ CompleteFindSoon(FROM_HERE, null_registration,
+ SERVICE_WORKER_ERROR_FAILED, callback);
+ }
return;
}
+ DCHECK_EQ(INITIALIZED, state_);
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForPattern(scope);
@@ -124,12 +165,15 @@ void ServiceWorkerStorage::FindRegistrationForPattern(
void ServiceWorkerStorage::FindRegistrationForDocument(
const GURL& document_url,
const FindRegistrationCallback& callback) {
- simulated_lazy_initted_ = true;
scoped_refptr<ServiceWorkerRegistration> null_registration;
- if (!context_) {
- CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
+ if (!LazyInitialize(base::Bind(
+ &ServiceWorkerStorage::FindRegistrationForDocument,
+ weak_factory_.GetWeakPtr(), document_url, callback))) {
+ if (state_ != INITIALIZING || !context_)
+ CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
return;
}
+ DCHECK_EQ(INITIALIZED, state_);
// See if there are any registrations for the origin.
OriginRegistrationsMap::const_iterator
@@ -195,12 +239,16 @@ void ServiceWorkerStorage::FindRegistrationForDocument(
void ServiceWorkerStorage::FindRegistrationForId(
int64 registration_id,
const FindRegistrationCallback& callback) {
- simulated_lazy_initted_ = true;
scoped_refptr<ServiceWorkerRegistration> null_registration;
- if (!context_) {
- CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
+ if (!LazyInitialize(base::Bind(
+ &ServiceWorkerStorage::FindRegistrationForId,
+ weak_factory_.GetWeakPtr(), registration_id, callback))) {
+ if (state_ != INITIALIZING || !context_)
+ CompleteFindNow(null_registration, SERVICE_WORKER_ERROR_FAILED, callback);
return;
}
+ DCHECK_EQ(INITIALIZED, state_);
+
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForId(registration_id);
if (installing_registration) {
@@ -226,14 +274,19 @@ void ServiceWorkerStorage::FindRegistrationForId(
void ServiceWorkerStorage::GetAllRegistrations(
const GetAllRegistrationInfosCallback& callback) {
- simulated_lazy_initted_ = true;
- std::vector<ServiceWorkerRegistrationInfo> registrations;
- if (!context_) {
- RunSoon(FROM_HERE, base::Bind(callback, registrations));
+ if (!LazyInitialize(base::Bind(
+ &ServiceWorkerStorage::GetAllRegistrations,
+ weak_factory_.GetWeakPtr(), callback))) {
+ if (state_ != INITIALIZING || !context_) {
+ RunSoon(FROM_HERE, base::Bind(
+ callback, std::vector<ServiceWorkerRegistrationInfo>()));
+ }
return;
}
+ DCHECK_EQ(INITIALIZED, state_);
// Add all stored registrations.
+ std::vector<ServiceWorkerRegistrationInfo> registrations;
for (RegistrationPtrMap::const_iterator it = registrations_by_id_.begin();
it != registrations_by_id_.end(); ++it) {
ServiceWorkerRegistration* registration =
@@ -270,8 +323,9 @@ void ServiceWorkerStorage::StoreRegistration(
const StatusCallback& callback) {
DCHECK(registration);
DCHECK(version);
- DCHECK(simulated_lazy_initted_);
- if (!context_) {
+
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED);
+ if (state_ != INITIALIZED || !context_) {
RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
return;
}
@@ -295,11 +349,13 @@ void ServiceWorkerStorage::StoreRegistration(
RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_OK));
}
- void ServiceWorkerStorage::UpdateToActiveState(
- ServiceWorkerRegistration* registration,
- const StatusCallback& callback) {
- DCHECK(simulated_lazy_initted_);
- if (!context_) {
+void ServiceWorkerStorage::UpdateToActiveState(
+ ServiceWorkerRegistration* registration,
+ const StatusCallback& callback) {
+ DCHECK(registration);
+
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED);
+ if (state_ != INITIALIZED || !context_) {
RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
return;
}
@@ -318,7 +374,12 @@ void ServiceWorkerStorage::StoreRegistration(
void ServiceWorkerStorage::DeleteRegistration(
int64 registration_id,
const StatusCallback& callback) {
- DCHECK(simulated_lazy_initted_);
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED);
+ if (state_ != INITIALIZED || !context_) {
+ RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
+ return;
+ }
+
RegistrationPtrMap::iterator
found = registrations_by_id_.find(registration_id);
if (found == registrations_by_id_.end()) {
@@ -353,18 +414,24 @@ ServiceWorkerStorage::CreateResponseWriter(int64 response_id) {
}
int64 ServiceWorkerStorage::NewRegistrationId() {
- DCHECK(simulated_lazy_initted_);
- return ++last_registration_id_;
+ if (state_ == DISABLED)
+ return kInvalidServiceWorkerRegistrationId;
+ DCHECK_EQ(INITIALIZED, state_);
+ return next_registration_id_++;
}
int64 ServiceWorkerStorage::NewVersionId() {
- DCHECK(simulated_lazy_initted_);
- return ++last_version_id_;
+ if (state_ == DISABLED)
+ return kInvalidServiceWorkerVersionId;
+ DCHECK_EQ(INITIALIZED, state_);
+ return next_version_id_++;
}
int64 ServiceWorkerStorage::NewResourceId() {
- DCHECK(simulated_lazy_initted_);
- return ++last_resource_id_;
+ if (state_ == DISABLED)
+ return kInvalidServiceWorkerResourceId;
+ DCHECK_EQ(INITIALIZED, state_);
+ return next_resource_id_++;
}
void ServiceWorkerStorage::NotifyInstallingRegistration(
@@ -377,6 +444,58 @@ void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
installing_registrations_.erase(registration->id());
}
+bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) {
+ if (!context_)
+ return false;
+
+ switch (state_) {
+ case INITIALIZED:
+ return true;
+ case DISABLED:
+ return false;
+ case INITIALIZING:
+ pending_tasks_.push_back(callback);
+ return false;
+ case UNINITIALIZED:
+ pending_tasks_.push_back(callback);
+ // Fall-through.
+ }
+
+ state_ = INITIALIZING;
+ database_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&InitializeOnDatabaseTaskRunner,
+ database_.get(),
+ base::MessageLoopProxy::current(),
+ base::Bind(&ServiceWorkerStorage::DidInitialize,
+ weak_factory_.GetWeakPtr())));
+ return false;
+}
+
+void ServiceWorkerStorage::DidInitialize(
+ InitialData* data,
+ bool success) {
+ DCHECK(data);
+ DCHECK_EQ(INITIALIZING, state_);
+
+ if (success) {
+ 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 {
+ DLOG(WARNING) << "Failed to initialize.";
+ state_ = DISABLED;
+ }
+
+ for (std::vector<base::Closure>::const_iterator it = pending_tasks_.begin();
+ it != pending_tasks_.end(); ++it) {
+ RunSoon(FROM_HERE, *it);
+ }
+ pending_tasks_.clear();
+}
+
scoped_refptr<ServiceWorkerRegistration>
ServiceWorkerStorage::CreateRegistration(
const ServiceWorkerDatabase::RegistrationData* data) {
diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h
index 4c06e2f..369273a 100644
--- a/content/browser/service_worker/service_worker_storage.h
+++ b/content/browser/service_worker/service_worker_storage.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_
#include <map>
+#include <set>
#include <vector>
#include "base/bind.h"
@@ -51,6 +52,16 @@ class CONTENT_EXPORT ServiceWorkerStorage {
void(ServiceWorkerStatusCode status, int result)>
CompareCallback;
+ struct InitialData {
+ int64 next_registration_id;
+ int64 next_version_id;
+ int64 next_resource_id;
+ std::set<GURL> origins;
+
+ InitialData();
+ ~InitialData();
+ };
+
ServiceWorkerStorage(const base::FilePath& path,
base::WeakPtr<ServiceWorkerContextCore> context,
base::SequencedTaskRunner* database_task_runner,
@@ -116,6 +127,12 @@ class CONTENT_EXPORT ServiceWorkerStorage {
private:
friend class ServiceWorkerStorageTest;
+ bool LazyInitialize(
+ const base::Closure& callback);
+ void DidInitialize(
+ InitialData* data,
+ bool success);
+
scoped_refptr<ServiceWorkerRegistration> CreateRegistration(
const ServiceWorkerDatabase::RegistrationData* data);
ServiceWorkerRegistration* FindInstallingRegistrationForDocument(
@@ -146,17 +163,36 @@ class CONTENT_EXPORT ServiceWorkerStorage {
// Lazy disk_cache getter.
ServiceWorkerDiskCache* disk_cache();
- int64 last_registration_id_;
- int64 last_version_id_;
- int64 last_resource_id_;
- bool simulated_lazy_initted_;
+ // Origins having registations.
+ std::set<GURL> registered_origins_;
+
+ // Pending database tasks waiting for initialization.
+ std::vector<base::Closure> pending_tasks_;
+
+ int64 next_registration_id_;
+ int64 next_version_id_;
+ int64 next_resource_id_;
+
+ enum State {
+ UNINITIALIZED,
+ INITIALIZING,
+ INITIALIZED,
+ DISABLED,
+ };
+ State state_;
base::FilePath path_;
base::WeakPtr<ServiceWorkerContextCore> context_;
+
+ // Only accessed on |database_task_runner_|.
+ scoped_ptr<ServiceWorkerDatabase> database_;
+
scoped_refptr<base::SequencedTaskRunner> database_task_runner_;
scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
scoped_ptr<ServiceWorkerDiskCache> disk_cache_;
+ base::WeakPtrFactory<ServiceWorkerStorage> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerStorage);
};
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index 6d8b30f..9637929 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -79,7 +79,6 @@ class ServiceWorkerStorageTest : public testing::Test {
NULL,
scoped_ptr<ServiceWorkerProcessManager>()));
context_ptr_ = context_->AsWeakPtr();
- storage()->simulated_lazy_initted_ = true;
}
virtual void TearDown() OVERRIDE {
@@ -98,8 +97,8 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
const GURL kScope("http://www.test.com/scope/*");
const GURL kScript("http://www.test.com/script.js");
const GURL kDocumentUrl("http://www.test.com/scope/document.html");
- const int64 kRegistrationId = storage()->NewRegistrationId();
- const int64 kVersionId = storage()->NewVersionId();
+ const int64 kRegistrationId = 0;
+ const int64 kVersionId = 0;
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_OK;
@@ -307,8 +306,8 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
const GURL kScope("http://www.test.com/scope/*");
const GURL kScript("http://www.test.com/script.js");
const GURL kDocumentUrl("http://www.test.com/scope/document.html");
- const int64 kRegistrationId = storage()->NewRegistrationId();
- const int64 kVersionId = storage()->NewVersionId();
+ const int64 kRegistrationId = 0;
+ const int64 kVersionId = 0;
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_OK;