Implement registration job ordering

To handle the case of multiple registration requests coming in at the same time,
the ServiceWorkerJobCoordinator now keeps a queue of registration events for each pattern.

When a new registration request comes in for a pattern, it looks to see if the most recent request (at the back of the queue) is identical, and if so, piggy-backs on that request rather than creating a new one.

BUG=285976

Review URL: https://codereview.chromium.org/126603002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243999 0039d316-1c4b-4281-b951-d872f2087c98
parent ee6110b8
...@@ -4,10 +4,38 @@ ...@@ -4,10 +4,38 @@
#include "content/browser/service_worker/service_worker_job_coordinator.h" #include "content/browser/service_worker/service_worker_job_coordinator.h"
#include "base/stl_util.h"
#include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_registration.h"
namespace content { namespace content {
ServiceWorkerJobCoordinator::JobQueue::JobQueue() {}
ServiceWorkerJobCoordinator::JobQueue::~JobQueue() {
STLDeleteElements(&jobs_);
}
void ServiceWorkerJobCoordinator::JobQueue::Push(
scoped_ptr<ServiceWorkerRegisterJob> job,
const ServiceWorkerRegisterJob::RegistrationCallback& callback) {
if (jobs_.empty()) {
job->Start();
jobs_.push_back(job.release());
} else if (!job->Equals(jobs_.back())) {
jobs_.push_back(job.release());
}
DCHECK(!jobs_.empty());
jobs_.back()->AddCallback(callback);
}
void ServiceWorkerJobCoordinator::JobQueue::Pop(ServiceWorkerRegisterJob* job) {
DCHECK(job == jobs_.front());
jobs_.pop_front();
if (!jobs_.empty())
jobs_.front()->Start();
}
ServiceWorkerJobCoordinator::ServiceWorkerJobCoordinator( ServiceWorkerJobCoordinator::ServiceWorkerJobCoordinator(
ServiceWorkerStorage* storage) ServiceWorkerStorage* storage)
: storage_(storage), weak_factory_(this) {} : storage_(storage), weak_factory_(this) {}
...@@ -18,55 +46,46 @@ void ServiceWorkerJobCoordinator::Register( ...@@ -18,55 +46,46 @@ void ServiceWorkerJobCoordinator::Register(
const GURL& pattern, const GURL& pattern,
const GURL& script_url, const GURL& script_url,
const ServiceWorkerRegisterJob::RegistrationCallback& callback) { const ServiceWorkerRegisterJob::RegistrationCallback& callback) {
scoped_ptr<ServiceWorkerRegisterJob> job(new ServiceWorkerRegisterJob( scoped_ptr<ServiceWorkerRegisterJob> job = make_scoped_ptr(
storage_, new ServiceWorkerRegisterJob(storage_,
base::Bind(&ServiceWorkerJobCoordinator::RegisterComplete, this,
weak_factory_.GetWeakPtr(), pattern,
callback))); script_url,
job->StartRegister(pattern, script_url); ServiceWorkerRegisterJob::REGISTER));
registration_jobs_.push_back(job.release()); jobs_[pattern].Push(job.Pass(), callback);
} }
void ServiceWorkerJobCoordinator::Unregister( void ServiceWorkerJobCoordinator::Unregister(
const GURL& pattern, const GURL& pattern,
const ServiceWorkerRegisterJob::UnregistrationCallback& callback) { const ServiceWorkerRegisterJob::UnregistrationCallback& callback) {
scoped_ptr<ServiceWorkerRegisterJob> job(new ServiceWorkerRegisterJob(
storage_,
base::Bind(&ServiceWorkerJobCoordinator::UnregisterComplete,
weak_factory_.GetWeakPtr(),
callback)));
job->StartUnregister(pattern);
registration_jobs_.push_back(job.release());
}
void ServiceWorkerJobCoordinator::EraseJob(ServiceWorkerRegisterJob* job) { scoped_ptr<ServiceWorkerRegisterJob> job = make_scoped_ptr(
ScopedVector<ServiceWorkerRegisterJob>::iterator job_position = new ServiceWorkerRegisterJob(storage_,
registration_jobs_.begin(); this,
for (; job_position != registration_jobs_.end(); ++job_position) { pattern,
if (*job_position == job) { GURL(),
registration_jobs_.erase(job_position); ServiceWorkerRegisterJob::UNREGISTER));
return; jobs_[pattern]
} .Push(job.Pass(),
} base::Bind(&ServiceWorkerJobCoordinator::UnregisterComplete,
NOTREACHED() << "Deleting non-existent job. "; weak_factory_.GetWeakPtr(),
callback));
} }
void ServiceWorkerJobCoordinator::RegisterComplete( void ServiceWorkerJobCoordinator::FinishJob(const GURL& pattern,
const ServiceWorkerRegisterJob::RegistrationCallback& callback, ServiceWorkerRegisterJob* job) {
ServiceWorkerRegisterJob* job, RegistrationJobMap::iterator pending_jobs = jobs_.find(pattern);
ServiceWorkerRegistrationStatus status, DCHECK(pending_jobs != jobs_.end()) << "Deleting non-existent job.";
ServiceWorkerRegistration* registration) { pending_jobs->second.Pop(job);
callback.Run(status, registration); if (pending_jobs->second.empty())
EraseJob(job); jobs_.erase(pending_jobs);
} }
void ServiceWorkerJobCoordinator::UnregisterComplete( void ServiceWorkerJobCoordinator::UnregisterComplete(
const ServiceWorkerRegisterJob::UnregistrationCallback& callback, const ServiceWorkerRegisterJob::UnregistrationCallback& callback,
ServiceWorkerRegisterJob* job,
ServiceWorkerRegistrationStatus status, ServiceWorkerRegistrationStatus status,
ServiceWorkerRegistration* previous_registration) { const scoped_refptr<ServiceWorkerRegistration>& previous_registration) {
callback.Run(status); callback.Run(status);
EraseJob(job);
} }
} // namespace content } // namespace content
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_JOB_COORDINATOR_H_ #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_JOB_COORDINATOR_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_JOB_COORDINATOR_H_ #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_JOB_COORDINATOR_H_
#include <deque>
#include <map>
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/scoped_vector.h"
#include "content/browser/service_worker/service_worker_register_job.h" #include "content/browser/service_worker/service_worker_register_job.h"
#include "content/browser/service_worker/service_worker_registration_status.h" #include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_storage.h" #include "content/browser/service_worker/service_worker_storage.h"
...@@ -21,7 +23,7 @@ class ServiceWorkerRegistration; ...@@ -21,7 +23,7 @@ class ServiceWorkerRegistration;
// operations are run through instances of ServiceWorkerRegisterJob. // operations are run through instances of ServiceWorkerRegisterJob.
class CONTENT_EXPORT ServiceWorkerJobCoordinator { class CONTENT_EXPORT ServiceWorkerJobCoordinator {
public: public:
ServiceWorkerJobCoordinator(ServiceWorkerStorage* storage); explicit ServiceWorkerJobCoordinator(ServiceWorkerStorage* storage);
~ServiceWorkerJobCoordinator(); ~ServiceWorkerJobCoordinator();
void Register(const GURL& pattern, void Register(const GURL& pattern,
...@@ -32,34 +34,41 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator { ...@@ -32,34 +34,41 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator {
const GURL& pattern, const GURL& pattern,
const ServiceWorkerRegisterJob::UnregistrationCallback& callback); const ServiceWorkerRegisterJob::UnregistrationCallback& callback);
// Jobs are removed whenever they are finished or canceled.
void FinishJob(const GURL& pattern, ServiceWorkerRegisterJob* job);
private: private:
friend class ServiceWorkerRegisterJob; friend class ServiceWorkerRegisterJob;
typedef ScopedVector<ServiceWorkerRegisterJob> RegistrationJobList; class JobQueue {
public:
JobQueue();
~JobQueue();
// Jobs are removed whenever they are finished or canceled. void Push(scoped_ptr<ServiceWorkerRegisterJob> job,
void EraseJob(ServiceWorkerRegisterJob* job); const ServiceWorkerRegisterJob::RegistrationCallback& callback);
// Called at ServiceWorkerRegisterJob completion. void Pop(ServiceWorkerRegisterJob* job);
void RegisterComplete(
const ServiceWorkerRegisterJob::RegistrationCallback& callback, bool empty() { return jobs_.empty(); }
ServiceWorkerRegisterJob* job,
ServiceWorkerRegistrationStatus status, private:
ServiceWorkerRegistration* registration); std::deque<ServiceWorkerRegisterJob*> jobs_;
};
typedef std::map<GURL, JobQueue> RegistrationJobMap;
// Called at ServiceWorkerRegisterJob completion. // Called at ServiceWorkerRegisterJob completion.
void UnregisterComplete( void UnregisterComplete(
const ServiceWorkerRegisterJob::UnregistrationCallback& callback, const ServiceWorkerRegisterJob::UnregistrationCallback& callback,
ServiceWorkerRegisterJob* job,
ServiceWorkerRegistrationStatus status, ServiceWorkerRegistrationStatus status,
ServiceWorkerRegistration* registration); const scoped_refptr<ServiceWorkerRegistration>& registration);
// The ServiceWorkerStorage object should always outlive this // The ServiceWorkerStorage object should always outlive this
ServiceWorkerStorage* storage_; ServiceWorkerStorage* storage_;
base::WeakPtrFactory<ServiceWorkerJobCoordinator> weak_factory_; base::WeakPtrFactory<ServiceWorkerJobCoordinator> weak_factory_;
// A list of currently running jobs. This is a temporary structure until we
// start managing overlapping registrations explicitly. RegistrationJobMap jobs_;
RegistrationJobList registration_jobs_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerJobCoordinator); DISALLOW_COPY_AND_ASSIGN(ServiceWorkerJobCoordinator);
}; };
......
...@@ -368,4 +368,155 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) { ...@@ -368,4 +368,155 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
ASSERT_EQ(new_registration, old_registration); ASSERT_EQ(new_registration, old_registration);
} }
// Register and then unregister the pattern, in parallel. Job coordinator should
// process jobs until the last job.
TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
GURL pattern("http://www.example.com/*");
GURL script_url("http://www.example.com/service_worker.js");
bool registration_called = false;
scoped_refptr<ServiceWorkerRegistration> registration;
job_coordinator_->Register(
pattern,
script_url,
SaveRegistration(REGISTRATION_OK, &registration_called, &registration));
bool unregistration_called = false;
job_coordinator_->Unregister(
pattern, SaveUnregistration(REGISTRATION_OK, &unregistration_called));
ASSERT_FALSE(registration_called);
ASSERT_FALSE(unregistration_called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(registration_called);
ASSERT_TRUE(unregistration_called);
ASSERT_TRUE(registration->is_shutdown());
bool find_called = false;
storage_->FindRegistrationForPattern(
pattern,
SaveFoundRegistration(
false, REGISTRATION_OK, &find_called, &registration));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
}
// Register conflicting scripts for the same pattern. The most recent
// registration should win, and the old registration should have been
// shutdown.
TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
GURL pattern("http://www.example.com/*");
GURL script_url1("http://www.example.com/service_worker1.js");
bool registration1_called = false;
scoped_refptr<ServiceWorkerRegistration> registration1;
job_coordinator_->Register(
pattern,
script_url1,
SaveRegistration(REGISTRATION_OK, &registration1_called, &registration1));
GURL script_url2("http://www.example.com/service_worker2.js");
bool registration2_called = false;
scoped_refptr<ServiceWorkerRegistration> registration2;
job_coordinator_->Register(
pattern,
script_url2,
SaveRegistration(REGISTRATION_OK, &registration2_called, &registration2));
ASSERT_FALSE(registration1_called);
ASSERT_FALSE(registration2_called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(registration1_called);
ASSERT_TRUE(registration2_called);
scoped_refptr<ServiceWorkerRegistration> registration;
bool find_called = false;
storage_->FindRegistrationForPattern(
pattern,
SaveFoundRegistration(
true, REGISTRATION_OK, &find_called, &registration));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(registration1->is_shutdown());
EXPECT_FALSE(registration2->is_shutdown());
ASSERT_EQ(registration2, registration);
}
// Register the exact same pattern + script. Requests should be
// coalesced such that both callers get the exact same registration
// object.
TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
GURL pattern("http://www.example.com/*");
GURL script_url("http://www.example.com/service_worker1.js");
bool registration1_called = false;
scoped_refptr<ServiceWorkerRegistration> registration1;
job_coordinator_->Register(
pattern,
script_url,
SaveRegistration(REGISTRATION_OK, &registration1_called, &registration1));
bool registration2_called = false;
scoped_refptr<ServiceWorkerRegistration> registration2;
job_coordinator_->Register(
pattern,
script_url,
SaveRegistration(REGISTRATION_OK, &registration2_called, &registration2));
ASSERT_FALSE(registration1_called);
ASSERT_FALSE(registration2_called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(registration1_called);
ASSERT_TRUE(registration2_called);
ASSERT_EQ(registration1, registration2);
scoped_refptr<ServiceWorkerRegistration> registration;
bool find_called = false;
storage_->FindRegistrationForPattern(
pattern,
SaveFoundRegistration(
true, REGISTRATION_OK, &find_called, &registration));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(registration, registration1);
}
// Call simulataneous unregister calls.
TEST_F(ServiceWorkerJobTest, ParallelUnreg) {
GURL pattern("http://www.example.com/*");
GURL script_url("http://www.example.com/service_worker.js");
bool unregistration1_called = false;
job_coordinator_->Unregister(
pattern, SaveUnregistration(REGISTRATION_OK, &unregistration1_called));
bool unregistration2_called = false;
job_coordinator_->Unregister(
pattern, SaveUnregistration(REGISTRATION_OK, &unregistration2_called));
ASSERT_FALSE(unregistration1_called);
ASSERT_FALSE(unregistration2_called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(unregistration1_called);
ASSERT_TRUE(unregistration2_called);
// There isn't really a way to test that they are being coalesced,
// but we can make sure they can exist simultaneously without
// crashing.
scoped_refptr<ServiceWorkerRegistration> registration;
bool find_called = false;
storage_->FindRegistrationForPattern(
pattern,
SaveFoundRegistration(
false, REGISTRATION_OK, &find_called, &registration));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
}
} // namespace content } // namespace content
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "content/browser/service_worker/service_worker_register_job.h" #include "content/browser/service_worker/service_worker_register_job.h"
#include <vector>
#include "content/browser/service_worker/service_worker_job_coordinator.h"
#include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_registration.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -12,13 +15,38 @@ namespace content { ...@@ -12,13 +15,38 @@ namespace content {
ServiceWorkerRegisterJob::ServiceWorkerRegisterJob( ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
ServiceWorkerStorage* storage, ServiceWorkerStorage* storage,
const RegistrationCompleteCallback& callback) ServiceWorkerJobCoordinator* coordinator,
: storage_(storage), callback_(callback), weak_factory_(this) {} const GURL& pattern,
const GURL& script_url,
RegistrationType type)
: storage_(storage),
coordinator_(coordinator),
pattern_(pattern),
script_url_(script_url),
type_(type),
weak_factory_(this) {}
ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {} ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {}
void ServiceWorkerRegisterJob::StartRegister(const GURL& pattern, void ServiceWorkerRegisterJob::AddCallback(
const GURL& script_url) { const RegistrationCallback& callback) {
callbacks_.push_back(callback);
}
void ServiceWorkerRegisterJob::Start() {
if (type_ == REGISTER)
StartRegister();
else
StartUnregister();
}
bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJob* job) {
return job->type_ == type_ &&
(type_ == ServiceWorkerRegisterJob::UNREGISTER ||
job->script_url_ == script_url_);
}
void ServiceWorkerRegisterJob::StartRegister() {
// Set up a chain of callbacks, in reverse order. Each of these // Set up a chain of callbacks, in reverse order. Each of these
// callbacks may be called asynchronously by the previous callback. // callbacks may be called asynchronously by the previous callback.
RegistrationCallback finish_registration(base::Bind( RegistrationCallback finish_registration(base::Bind(
...@@ -27,21 +55,17 @@ void ServiceWorkerRegisterJob::StartRegister(const GURL& pattern, ...@@ -27,21 +55,17 @@ void ServiceWorkerRegisterJob::StartRegister(const GURL& pattern,
UnregistrationCallback register_new( UnregistrationCallback register_new(
base::Bind(&ServiceWorkerRegisterJob::RegisterPatternAndContinue, base::Bind(&ServiceWorkerRegisterJob::RegisterPatternAndContinue,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
pattern,
script_url,
finish_registration)); finish_registration));
ServiceWorkerStorage::FindRegistrationCallback unregister_old( ServiceWorkerStorage::FindRegistrationCallback unregister_old(
base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue, base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
pattern,
script_url,
register_new)); register_new));
storage_->FindRegistrationForPattern(pattern, unregister_old); storage_->FindRegistrationForPattern(pattern_, unregister_old);
} }
void ServiceWorkerRegisterJob::StartUnregister(const GURL& pattern) { void ServiceWorkerRegisterJob::StartUnregister() {
// Set up a chain of callbacks, in reverse order. Each of these // Set up a chain of callbacks, in reverse order. Each of these
// callbacks may be called asynchronously by the previous callback. // callbacks may be called asynchronously by the previous callback.
UnregistrationCallback finish_unregistration( UnregistrationCallback finish_unregistration(
...@@ -51,16 +75,12 @@ void ServiceWorkerRegisterJob::StartUnregister(const GURL& pattern) { ...@@ -51,16 +75,12 @@ void ServiceWorkerRegisterJob::StartUnregister(const GURL& pattern) {
ServiceWorkerStorage::FindRegistrationCallback unregister( ServiceWorkerStorage::FindRegistrationCallback unregister(
base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue, base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
pattern,
GURL(),
finish_unregistration)); finish_unregistration));
storage_->FindRegistrationForPattern(pattern, unregister); storage_->FindRegistrationForPattern(pattern_, unregister);
} }
void ServiceWorkerRegisterJob::RegisterPatternAndContinue( void ServiceWorkerRegisterJob::RegisterPatternAndContinue(
const GURL& pattern,
const GURL& script_url,
const RegistrationCallback& callback, const RegistrationCallback& callback,
ServiceWorkerRegistrationStatus previous_status) { ServiceWorkerRegistrationStatus previous_status) {
if (previous_status != REGISTRATION_OK) { if (previous_status != REGISTRATION_OK) {
...@@ -76,15 +96,13 @@ void ServiceWorkerRegisterJob::RegisterPatternAndContinue( ...@@ -76,15 +96,13 @@ void ServiceWorkerRegisterJob::RegisterPatternAndContinue(
// TODO: Eventually RegisterInternal will be replaced by an asynchronous // TODO: Eventually RegisterInternal will be replaced by an asynchronous
// operation. Pass its resulting status through 'callback'. // operation. Pass its resulting status through 'callback'.
scoped_refptr<ServiceWorkerRegistration> registration = scoped_refptr<ServiceWorkerRegistration> registration =
storage_->RegisterInternal(pattern, script_url); storage_->RegisterInternal(pattern_, script_url_);
BrowserThread::PostTask(BrowserThread::IO, BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE, FROM_HERE,
base::Bind(callback, REGISTRATION_OK, registration)); base::Bind(callback, REGISTRATION_OK, registration));
} }
void ServiceWorkerRegisterJob::UnregisterPatternAndContinue( void ServiceWorkerRegisterJob::UnregisterPatternAndContinue(
const GURL& pattern,
const GURL& new_script_url,
const UnregistrationCallback& callback, const UnregistrationCallback& callback,
bool found, bool found,
ServiceWorkerRegistrationStatus previous_status, ServiceWorkerRegistrationStatus previous_status,
...@@ -92,26 +110,38 @@ void ServiceWorkerRegisterJob::UnregisterPatternAndContinue( ...@@ -92,26 +110,38 @@ void ServiceWorkerRegisterJob::UnregisterPatternAndContinue(
// The previous registration may not exist, which is ok. // The previous registration may not exist, which is ok.
if (previous_status == REGISTRATION_OK && found && if (previous_status == REGISTRATION_OK && found &&
(new_script_url.is_empty() || (script_url_.is_empty() ||
previous_registration->script_url() != new_script_url)) { previous_registration->script_url() != script_url_)) {
// TODO: Eventually UnregisterInternal will be replaced by an // TODO: Eventually UnregisterInternal will be replaced by an
// asynchronous operation. Pass its resulting status though // asynchronous operation. Pass its resulting status though
// 'callback'. // 'callback'.
storage_->UnregisterInternal(pattern); storage_->UnregisterInternal(pattern_);
DCHECK(previous_registration->is_shutdown());
} }
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, base::Bind(callback, previous_status)); BrowserThread::IO, FROM_HERE, base::Bind(callback, previous_status));
} }
void ServiceWorkerRegisterJob::RunCallbacks(
ServiceWorkerRegistrationStatus status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
it->Run(status, registration);
}
}
void ServiceWorkerRegisterJob::RegisterComplete( void ServiceWorkerRegisterJob::RegisterComplete(
ServiceWorkerRegistrationStatus status, ServiceWorkerRegistrationStatus status,
const scoped_refptr<ServiceWorkerRegistration>& registration) { const scoped_refptr<ServiceWorkerRegistration>& registration) {
callback_.Run(this, status, registration); RunCallbacks(status, registration);
coordinator_->FinishJob(pattern_, this);
} }
void ServiceWorkerRegisterJob::UnregisterComplete( void ServiceWorkerRegisterJob::UnregisterComplete(
ServiceWorkerRegistrationStatus status) { ServiceWorkerRegistrationStatus status) {
callback_.Run(this, status, NULL); RunCallbacks(status, NULL);
coordinator_->FinishJob(pattern_, this);
} }
} // namespace content } // namespace content
...@@ -5,33 +5,47 @@ ...@@ -5,33 +5,47 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_ #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_ #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_
#include <vector>
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_registration_status.h" #include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_storage.h" #include "content/browser/service_worker/service_worker_storage.h"
namespace content { namespace content {
class ServiceWorkerJobCoordinator;
// A ServiceWorkerRegisterJob lives only for the lifetime of a single // A ServiceWorkerRegisterJob lives only for the lifetime of a single
// registration or unregistration. // registration or unregistration.
class ServiceWorkerRegisterJob { class ServiceWorkerRegisterJob {
public: public:
enum RegistrationType {
REGISTER,
UNREGISTER,
};
typedef base::Callback<void(ServiceWorkerRegistrationStatus status, typedef base::Callback<void(ServiceWorkerRegistrationStatus status,
const scoped_refptr<ServiceWorkerRegistration>& const scoped_refptr<ServiceWorkerRegistration>&
registration)> RegistrationCallback; registration)> RegistrationCallback;
typedef base::Callback<void(ServiceWorkerRegistrationStatus status)> typedef base::Callback<void(ServiceWorkerRegistrationStatus status)>
UnregistrationCallback; UnregistrationCallback;
typedef base::Callback<void(
ServiceWorkerRegisterJob* job,
ServiceWorkerRegistrationStatus status,
ServiceWorkerRegistration* registration)> RegistrationCompleteCallback;
// All type of jobs (Register and Unregister) complete through a // All type of jobs (Register and Unregister) complete through a
// single call to this callback on the IO thread. // single call to this callback on the IO thread.
ServiceWorkerRegisterJob(ServiceWorkerStorage* storage, ServiceWorkerRegisterJob(ServiceWorkerStorage* storage,
const RegistrationCompleteCallback& callback); ServiceWorkerJobCoordinator* coordinator,
const GURL& pattern,
const GURL& script_url,
RegistrationType type);
~ServiceWorkerRegisterJob(); ~ServiceWorkerRegisterJob();
void AddCallback(const RegistrationCallback& callback);
void Start();
bool Equals(ServiceWorkerRegisterJob* job);
private:
// The Registration flow includes most or all of the following, // The Registration flow includes most or all of the following,
// depending on what is already registered: // depending on what is already registered:
// - creating a ServiceWorkerRegistration instance if there isn't // - creating a ServiceWorkerRegistration instance if there isn't
...@@ -44,25 +58,20 @@ class ServiceWorkerRegisterJob { ...@@ -44,25 +58,20 @@ class ServiceWorkerRegisterJob {
// - Waiting for older ServiceWorkerVersions to deactivate // - Waiting for older ServiceWorkerVersions to deactivate
// - designating the new version to be the 'active' version // - designating the new version to be the 'active' version
// This method should be called once and only once per job. // This method should be called once and only once per job.
void StartRegister(const GURL& pattern, const GURL& script_url); void StartRegister();
// The Unregistration process is primarily cleanup, removing // The Unregistration process is primarily cleanup, removing
// everything that was created during the Registration process, // everything that was created during the Registration process,
// including the ServiceWorkerRegistration itself. // including the ServiceWorkerRegistration itself.
// This method should be called once and only once per job. // This method should be called once and only once per job.
void StartUnregister(const GURL& pattern); void StartUnregister();
private:
// These are all steps in the registration and unregistration pipeline. // These are all steps in the registration and unregistration pipeline.
void RegisterPatternAndContinue( void RegisterPatternAndContinue(
const GURL& pattern,
const GURL& script_url,
const RegistrationCallback& callback, const RegistrationCallback& callback,
ServiceWorkerRegistrationStatus previous_status); ServiceWorkerRegistrationStatus previous_status);
void UnregisterPatternAndContinue( void UnregisterPatternAndContinue(
const GURL& pattern,
const GURL& script_url,
const UnregistrationCallback& callback, const UnregistrationCallback& callback,
bool found, bool found,
ServiceWorkerRegistrationStatus previous_status, ServiceWorkerRegistrationStatus previous_status,
...@@ -75,6 +84,10 @@ class ServiceWorkerRegisterJob { ...@@ -75,6 +84,10 @@ class ServiceWorkerRegisterJob {
ServiceWorkerRegistrationStatus status, ServiceWorkerRegistrationStatus status,
const scoped_refptr<ServiceWorkerRegistration>& registration); const scoped_refptr<ServiceWorkerRegistration>& registration);
void RunCallbacks(
ServiceWorkerRegistrationStatus status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
// The ServiceWorkerStorage object should always outlive // The ServiceWorkerStorage object should always outlive
// this. // this.
...@@ -83,7 +96,11 @@ class ServiceWorkerRegisterJob { ...@@ -83,7 +96,11 @@ class ServiceWorkerRegisterJob {
// because we may be cancelling while there are outstanding // because we may be cancelling while there are outstanding
// callbacks that expect access to storage_. // callbacks that expect access to storage_.
ServiceWorkerStorage* storage_; ServiceWorkerStorage* storage_;
const RegistrationCompleteCallback callback_; ServiceWorkerJobCoordinator* coordinator_;
const GURL pattern_;
const GURL script_url_;
const RegistrationType type_;
std::vector<RegistrationCallback> callbacks_;
base::WeakPtrFactory<ServiceWorkerRegisterJob> weak_factory_; base::WeakPtrFactory<ServiceWorkerRegisterJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegisterJob); DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegisterJob);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment