Commit 0e476caf authored by falken's avatar falken Committed by Commit bot

(Reland) Evict Service Worker when reading it from disk cache fails.

If reading the SW resources from the disk cache fails, we should evict
the worker or else we will keep getting the same failure.

This patch unsets the worker from the live registration, and then
deletes the registration if the SW was the stored version.

This relands the original commit (64e3ffb1), and fixes a problem where
the test terminated before the eviction, which starts on the IO thread,
then hops to the database task runner, finishes. Now the test ends by
looking up the registration in storage, which hops to the database task
runner, so it can only finish once eviction finishes.

Original patch: https://codereview.chromium.org/1098083003/

BUG=448003

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

Cr-Commit-Position: refs/heads/master@{#327260}
parent b4a0d73b
......@@ -11,6 +11,7 @@
#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_metrics.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
......@@ -193,9 +194,15 @@ void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) {
}
void ServiceWorkerReadFromCacheJob::Done(const net::URLRequestStatus& status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!status.is_success()) {
version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_DISK_CACHE);
// TODO(falken): Retry and evict the SW if it fails again.
// TODO(falken): Retry before evicting.
if (context_) {
ServiceWorkerRegistration* registration =
context_->GetLiveRegistration(version_->registration_id());
registration->DeleteVersion(version_);
}
}
NotifyDone(status);
}
......
......@@ -253,6 +253,8 @@ void ServiceWorkerRegistration::ClearUserData(
}
void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
if (!context_)
return;
DCHECK_EQ(active_version(), version);
if (is_uninstalling_)
Clear();
......@@ -302,6 +304,45 @@ void ServiceWorkerRegistration::ActivateWaitingVersion() {
this, activating_version));
}
void ServiceWorkerRegistration::DeleteVersion(
const scoped_refptr<ServiceWorkerVersion>& version) {
DCHECK_EQ(id(), version->registration_id());
// "Set registration's active worker to null." (The spec's step order may
// differ. It's OK because the other steps queue a task.)
UnsetVersion(version.get());
// "Run the Update State algorithm passing registration's active worker and
// 'redundant' as the arguments."
version->SetStatus(ServiceWorkerVersion::REDUNDANT);
// "For each service worker client client whose active worker is
// registration's active worker..." set the active worker to null.
for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
context_->GetProviderHostIterator();
!it->IsAtEnd(); it->Advance()) {
ServiceWorkerProviderHost* host = it->GetProviderHost();
if (host->controlling_version() == version)
host->NotifyControllerActivationFailed();
}
version->Doom();
if (!active_version() && !waiting_version()) {
// Delete the records from the db.
context_->storage()->DeleteRegistration(
id(), pattern().GetOrigin(),
base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
// But not from memory if there is a version in the pipeline.
if (installing_version()) {
is_deleted_ = false;
} else {
is_uninstalled_ = true;
FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
}
}
}
void ServiceWorkerRegistration::OnActivateEventFinished(
ServiceWorkerVersion* activating_version,
ServiceWorkerStatusCode status) {
......@@ -311,38 +352,7 @@ void ServiceWorkerRegistration::OnActivateEventFinished(
// "If activateFailed is true, then:..."
if (status != SERVICE_WORKER_OK) {
// "Set registration's active worker to null." (The spec's step order may
// differ. It's OK because the other steps queue a task.)
UnsetVersion(activating_version);
// "Run the Update State algorithm passing registration's active worker and
// 'redundant' as the arguments."
activating_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
// "For each service worker client client whose active worker is
// registration's active worker..." set the active worker to null.
for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
context_->GetProviderHostIterator();
!it->IsAtEnd(); it->Advance()) {
ServiceWorkerProviderHost* host = it->GetProviderHost();
if (host->controlling_version() == activating_version)
host->NotifyControllerActivationFailed();
}
activating_version->Doom();
if (!waiting_version()) {
// Delete the records from the db.
context_->storage()->DeleteRegistration(
id(), pattern().GetOrigin(),
base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
// But not from memory if there is a version in the pipeline.
if (installing_version()) {
is_deleted_ = false;
} else {
is_uninstalled_ = true;
FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
}
}
DeleteVersion(make_scoped_refptr(activating_version));
return;
}
......
......@@ -137,6 +137,10 @@ class CONTENT_EXPORT ServiceWorkerRegistration
void ClearUserData(const std::string& key,
const StatusCallback& callback);
// Unsets the version and deletes its resources. Also deletes this
// registration from storage if there is no longer a stored version.
void DeleteVersion(const scoped_refptr<ServiceWorkerVersion>& version);
private:
friend class base::RefCounted<ServiceWorkerRegistration>;
......
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