Commit fb74da9c authored by falken's avatar falken Committed by Commit bot

ServiceWorker: More accurate StartWorker result and UMA

This adds SERVICE_WORKER_ERROR_DISK_CACHE to indicate
failure to read from the disk cache. It also re-enables
logging of StartWorker for redundant workers. This was
previously disabled because we got a lot of "failed" spam
for updates that get aborted when there is no script change,
so I've changed StartWorker to fail with SW_ERROR_EXISTS in
that case.

This patch is a step in the direction of evicting a SW
that can't be read from disk cache.

BUG=448003

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

Cr-Commit-Position: refs/heads/master@{#326923}
parent 2e7db0a2
...@@ -51,6 +51,7 @@ void NotificationClickEventFinished( ...@@ -51,6 +51,7 @@ void NotificationClickEventFinished(
case SERVICE_WORKER_ERROR_STATE: case SERVICE_WORKER_ERROR_STATE:
case SERVICE_WORKER_ERROR_TIMEOUT: case SERVICE_WORKER_ERROR_TIMEOUT:
case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
case SERVICE_WORKER_ERROR_DISK_CACHE:
case SERVICE_WORKER_ERROR_MAX_VALUE: case SERVICE_WORKER_ERROR_MAX_VALUE:
status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR; status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
break; break;
...@@ -103,6 +104,7 @@ void DispatchNotificationClickEventOnRegistration( ...@@ -103,6 +104,7 @@ void DispatchNotificationClickEventOnRegistration(
case SERVICE_WORKER_ERROR_STATE: case SERVICE_WORKER_ERROR_STATE:
case SERVICE_WORKER_ERROR_TIMEOUT: case SERVICE_WORKER_ERROR_TIMEOUT:
case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
case SERVICE_WORKER_ERROR_DISK_CACHE:
case SERVICE_WORKER_ERROR_MAX_VALUE: case SERVICE_WORKER_ERROR_MAX_VALUE:
status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR; status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
break; break;
......
...@@ -559,6 +559,7 @@ void PushMessagingMessageFilter::UnregisterHavingGottenSenderId( ...@@ -559,6 +559,7 @@ void PushMessagingMessageFilter::UnregisterHavingGottenSenderId(
case SERVICE_WORKER_ERROR_STATE: case SERVICE_WORKER_ERROR_STATE:
case SERVICE_WORKER_ERROR_TIMEOUT: case SERVICE_WORKER_ERROR_TIMEOUT:
case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
case SERVICE_WORKER_ERROR_DISK_CACHE:
case SERVICE_WORKER_ERROR_MAX_VALUE: case SERVICE_WORKER_ERROR_MAX_VALUE:
NOTREACHED() << "Got unexpected error code: " << service_worker_status NOTREACHED() << "Got unexpected error code: " << service_worker_status
<< " " << ServiceWorkerStatusToString(service_worker_status); << " " << ServiceWorkerStatusToString(service_worker_status);
...@@ -734,6 +735,7 @@ void PushMessagingMessageFilter::DidGetRegistration( ...@@ -734,6 +735,7 @@ void PushMessagingMessageFilter::DidGetRegistration(
case SERVICE_WORKER_ERROR_STATE: case SERVICE_WORKER_ERROR_STATE:
case SERVICE_WORKER_ERROR_TIMEOUT: case SERVICE_WORKER_ERROR_TIMEOUT:
case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
case SERVICE_WORKER_ERROR_DISK_CACHE:
case SERVICE_WORKER_ERROR_MAX_VALUE: case SERVICE_WORKER_ERROR_MAX_VALUE:
NOTREACHED() << "Got unexpected error code: " << service_worker_status NOTREACHED() << "Got unexpected error code: " << service_worker_status
<< " " << ServiceWorkerStatusToString(service_worker_status); << " " << ServiceWorkerStatusToString(service_worker_status);
......
...@@ -109,6 +109,7 @@ void PushMessagingRouter::DeliverMessageEnd( ...@@ -109,6 +109,7 @@ void PushMessagingRouter::DeliverMessageEnd(
case SERVICE_WORKER_ERROR_IPC_FAILED: case SERVICE_WORKER_ERROR_IPC_FAILED:
case SERVICE_WORKER_ERROR_TIMEOUT: case SERVICE_WORKER_ERROR_TIMEOUT:
case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
case SERVICE_WORKER_ERROR_DISK_CACHE:
delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR; delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
break; break;
case SERVICE_WORKER_ERROR_EXISTS: case SERVICE_WORKER_ERROR_EXISTS:
......
...@@ -151,7 +151,7 @@ void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) { ...@@ -151,7 +151,7 @@ void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
DCHECK_LT(result, 0); DCHECK_LT(result, 0);
ServiceWorkerMetrics::CountReadResponseResult( ServiceWorkerMetrics::CountReadResponseResult(
ServiceWorkerMetrics::READ_HEADERS_ERROR); ServiceWorkerMetrics::READ_HEADERS_ERROR);
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); Done(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
return; return;
} }
DCHECK_GE(result, 0); DCHECK_GE(result, 0);
...@@ -192,14 +192,22 @@ void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) { ...@@ -192,14 +192,22 @@ void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) {
range_requested_, resource_size, true /* replace status line */); range_requested_, resource_size, true /* replace status line */);
} }
void ServiceWorkerReadFromCacheJob::Done(const net::URLRequestStatus& status) {
if (!status.is_success()) {
version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_DISK_CACHE);
// TODO(falken): Retry and evict the SW if it fails again.
}
NotifyDone(status);
}
void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) { void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) {
ServiceWorkerMetrics::ReadResponseResult check_result; ServiceWorkerMetrics::ReadResponseResult check_result;
if (result == 0) { if (result == 0) {
check_result = ServiceWorkerMetrics::READ_OK; check_result = ServiceWorkerMetrics::READ_OK;
NotifyDone(net::URLRequestStatus()); Done(net::URLRequestStatus());
} else if (result < 0) { } else if (result < 0) {
check_result = ServiceWorkerMetrics::READ_DATA_ERROR; check_result = ServiceWorkerMetrics::READ_DATA_ERROR;
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); Done(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
} else { } else {
check_result = ServiceWorkerMetrics::READ_OK; check_result = ServiceWorkerMetrics::READ_OK;
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
......
...@@ -55,6 +55,7 @@ class CONTENT_EXPORT ServiceWorkerReadFromCacheJob ...@@ -55,6 +55,7 @@ class CONTENT_EXPORT ServiceWorkerReadFromCacheJob
const net::HttpResponseInfo* http_info() const; const net::HttpResponseInfo* http_info() const;
bool is_range_request() const { return range_requested_.IsValid(); } bool is_range_request() const { return range_requested_.IsValid(); }
void SetupRangeResponse(int response_data_size); void SetupRangeResponse(int response_data_size);
void Done(const net::URLRequestStatus& status);
base::WeakPtr<ServiceWorkerContextCore> context_; base::WeakPtr<ServiceWorkerContextCore> context_;
scoped_refptr<ServiceWorkerVersion> version_; scoped_refptr<ServiceWorkerVersion> version_;
......
...@@ -450,7 +450,9 @@ void ServiceWorkerRegisterJob::CompleteInternal( ...@@ -450,7 +450,9 @@ void ServiceWorkerRegisterJob::CompleteInternal(
if (should_uninstall_on_failure_) if (should_uninstall_on_failure_)
registration()->ClearWhenReady(); registration()->ClearWhenReady();
if (new_version()) { if (new_version()) {
if (status != SERVICE_WORKER_ERROR_EXISTS) if (status == SERVICE_WORKER_ERROR_EXISTS)
new_version()->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
else
new_version()->ReportError(status, status_message); new_version()->ReportError(status, status_message);
registration()->UnsetVersion(new_version()); registration()->UnsetVersion(new_version());
new_version()->Doom(); new_version()->Doom();
......
...@@ -59,6 +59,7 @@ void GetServiceWorkerRegistrationStatusResponse( ...@@ -59,6 +59,7 @@ void GetServiceWorkerRegistrationStatusResponse(
case SERVICE_WORKER_ERROR_EXISTS: case SERVICE_WORKER_ERROR_EXISTS:
case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED: case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
case SERVICE_WORKER_ERROR_STATE: case SERVICE_WORKER_ERROR_STATE:
case SERVICE_WORKER_ERROR_DISK_CACHE:
case SERVICE_WORKER_ERROR_MAX_VALUE: case SERVICE_WORKER_ERROR_MAX_VALUE:
// Unexpected, or should have bailed out before calling this, or we don't // Unexpected, or should have bailed out before calling this, or we don't
// have a corresponding blink error code yet. // have a corresponding blink error code yet.
......
...@@ -348,12 +348,14 @@ bool IsInstalled(ServiceWorkerVersion::Status status) { ...@@ -348,12 +348,14 @@ bool IsInstalled(ServiceWorkerVersion::Status status) {
switch (status) { switch (status) {
case ServiceWorkerVersion::NEW: case ServiceWorkerVersion::NEW:
case ServiceWorkerVersion::INSTALLING: case ServiceWorkerVersion::INSTALLING:
case ServiceWorkerVersion::REDUNDANT:
return false; return false;
case ServiceWorkerVersion::INSTALLED: case ServiceWorkerVersion::INSTALLED:
case ServiceWorkerVersion::ACTIVATING: case ServiceWorkerVersion::ACTIVATING:
case ServiceWorkerVersion::ACTIVATED: case ServiceWorkerVersion::ACTIVATED:
return true; return true;
case ServiceWorkerVersion::REDUNDANT:
NOTREACHED() << "Cannot use REDUNDANT here.";
return false;
} }
NOTREACHED() << "Unexpected status: " << status; NOTREACHED() << "Unexpected status: " << status;
return false; return false;
...@@ -452,6 +454,11 @@ void ServiceWorkerVersion::StartWorker( ...@@ -452,6 +454,11 @@ void ServiceWorkerVersion::StartWorker(
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT)); RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
return; return;
} }
if (status_ == REDUNDANT) {
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
return;
}
prestart_status_ = status_;
// Ensure the live registration during starting worker so that the worker can // Ensure the live registration during starting worker so that the worker can
// get associated with it in SWDispatcherHost::OnSetHostedVersionId(). // get associated with it in SWDispatcherHost::OnSetHostedVersionId().
...@@ -837,6 +844,11 @@ void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status, ...@@ -837,6 +844,11 @@ void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status,
} }
} }
void ServiceWorkerVersion::SetStartWorkerStatusCode(
ServiceWorkerStatusCode status) {
start_worker_status_ = status;
}
void ServiceWorkerVersion::Doom() { void ServiceWorkerVersion::Doom() {
DCHECK(!HasControllee()); DCHECK(!HasControllee());
SetStatus(REDUNDANT); SetStatus(REDUNDANT);
...@@ -1514,11 +1526,16 @@ void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker( ...@@ -1514,11 +1526,16 @@ void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
const StatusCallback& callback, const StatusCallback& callback,
ServiceWorkerStatusCode status, ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& protect) { const scoped_refptr<ServiceWorkerRegistration>& protect) {
if (status != SERVICE_WORKER_OK || is_redundant()) { if (status != SERVICE_WORKER_OK) {
RecordStartWorkerResult(status); RecordStartWorkerResult(status);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED)); RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
return; return;
} }
if (is_redundant()) {
RecordStartWorkerResult(SERVICE_WORKER_ERROR_NOT_FOUND);
RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
return;
}
switch (running_status()) { switch (running_status()) {
case RUNNING: case RUNNING:
...@@ -1742,17 +1759,13 @@ void ServiceWorkerVersion::RecordStartWorkerResult( ...@@ -1742,17 +1759,13 @@ void ServiceWorkerVersion::RecordStartWorkerResult(
base::TimeTicks start_time = start_time_; base::TimeTicks start_time = start_time_;
ClearTick(&start_time_); ClearTick(&start_time_);
// Failing to start a redundant worker isn't interesting and very common when ServiceWorkerMetrics::RecordStartWorkerStatus(status,
// update dooms because the script is byte-to-byte identical. IsInstalled(prestart_status_));
if (is_redundant())
return;
ServiceWorkerMetrics::RecordStartWorkerStatus(status, IsInstalled(status_));
if (status == SERVICE_WORKER_OK && !start_time.is_null() && if (status == SERVICE_WORKER_OK && !start_time.is_null() &&
!skip_recording_startup_time_) { !skip_recording_startup_time_) {
ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time), ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time),
IsInstalled(status_)); IsInstalled(prestart_status_));
} }
if (status != SERVICE_WORKER_ERROR_TIMEOUT) if (status != SERVICE_WORKER_ERROR_TIMEOUT)
...@@ -1851,6 +1864,9 @@ ServiceWorkerStatusCode ServiceWorkerVersion::DeduceStartWorkerFailureReason( ...@@ -1851,6 +1864,9 @@ ServiceWorkerStatusCode ServiceWorkerVersion::DeduceStartWorkerFailureReason(
if (ping_state_ == PING_TIMED_OUT) if (ping_state_ == PING_TIMED_OUT)
return SERVICE_WORKER_ERROR_TIMEOUT; return SERVICE_WORKER_ERROR_TIMEOUT;
if (start_worker_status_ != SERVICE_WORKER_OK)
return start_worker_status_;
const net::URLRequestStatus& main_script_status = const net::URLRequestStatus& main_script_status =
script_cache_map()->main_script_status(); script_cache_map()->main_script_status();
if (main_script_status.status() != net::URLRequestStatus::SUCCESS) { if (main_script_status.status() != net::URLRequestStatus::SUCCESS) {
......
...@@ -286,6 +286,9 @@ class CONTENT_EXPORT ServiceWorkerVersion ...@@ -286,6 +286,9 @@ class CONTENT_EXPORT ServiceWorkerVersion
void ReportError(ServiceWorkerStatusCode status, void ReportError(ServiceWorkerStatusCode status,
const std::string& status_message); const std::string& status_message);
// Sets the status code to pass to StartWorker callbacks if start fails.
void SetStartWorkerStatusCode(ServiceWorkerStatusCode status);
// Sets this version's status to REDUNDANT and deletes its resources. // Sets this version's status to REDUNDANT and deletes its resources.
// The version must not have controllees. // The version must not have controllees.
void Doom(); void Doom();
...@@ -543,6 +546,12 @@ class CONTENT_EXPORT ServiceWorkerVersion ...@@ -543,6 +546,12 @@ class CONTENT_EXPORT ServiceWorkerVersion
std::vector<int> pending_skip_waiting_requests_; std::vector<int> pending_skip_waiting_requests_;
scoped_ptr<net::HttpResponseInfo> main_script_http_info_; scoped_ptr<net::HttpResponseInfo> main_script_http_info_;
// The status when StartWorker was invoked. Used for UMA.
Status prestart_status_ = NEW;
// If not OK, the reason that StartWorker failed. Used for
// running |start_callbacks_|.
ServiceWorkerStatusCode start_worker_status_ = SERVICE_WORKER_OK;
base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_; base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion); DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion);
......
...@@ -43,6 +43,8 @@ const char* ServiceWorkerStatusToString(ServiceWorkerStatusCode status) { ...@@ -43,6 +43,8 @@ const char* ServiceWorkerStatusToString(ServiceWorkerStatusCode status) {
return "The ServiceWorker timed out"; return "The ServiceWorker timed out";
case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED: case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
return "ServiceWorker script evaluation failed"; return "ServiceWorker script evaluation failed";
case SERVICE_WORKER_ERROR_DISK_CACHE:
return "Disk cache error";
case SERVICE_WORKER_ERROR_MAX_VALUE: case SERVICE_WORKER_ERROR_MAX_VALUE:
NOTREACHED(); NOTREACHED();
} }
......
...@@ -63,6 +63,9 @@ enum ServiceWorkerStatusCode { ...@@ -63,6 +63,9 @@ enum ServiceWorkerStatusCode {
// An error occurred during initial script evaluation. // An error occurred during initial script evaluation.
SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED, SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED,
// Generic error to indicate failure to read/write the disk cache.
SERVICE_WORKER_ERROR_DISK_CACHE,
SERVICE_WORKER_ERROR_MAX_VALUE SERVICE_WORKER_ERROR_MAX_VALUE
}; };
......
...@@ -61370,6 +61370,7 @@ To add a new entry, add it with any value and run test to compute valid value. ...@@ -61370,6 +61370,7 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="13" label="SERVICE_WORKER_ERROR_STATE"/> <int value="13" label="SERVICE_WORKER_ERROR_STATE"/>
<int value="14" label="SERVICE_WORKER_ERROR_TIMEOUT"/> <int value="14" label="SERVICE_WORKER_ERROR_TIMEOUT"/>
<int value="15" label="SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED"/> <int value="15" label="SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED"/>
<int value="16" label="SERVICE_WORKER_ERROR_DISK_CACHE"/>
</enum> </enum>
<enum name="ServiceWorkerWriteResponseResult" type="int"> <enum name="ServiceWorkerWriteResponseResult" type="int">
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