1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/service_worker/service_worker_storage.h"
9 #include "base/bind_helpers.h"
10 #include "base/file_util.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/task_runner_util.h"
14 #include "content/browser/service_worker/service_worker_context_core.h"
15 #include "content/browser/service_worker/service_worker_disk_cache.h"
16 #include "content/browser/service_worker/service_worker_info.h"
17 #include "content/browser/service_worker/service_worker_metrics.h"
18 #include "content/browser/service_worker/service_worker_registration.h"
19 #include "content/browser/service_worker/service_worker_utils.h"
20 #include "content/browser/service_worker/service_worker_version.h"
21 #include "content/common/service_worker/service_worker_types.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "net/base/completion_callback.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/net_errors.h"
26 #include "webkit/browser/quota/quota_manager_proxy.h"
32 void RunSoon(const tracked_objects::Location
& from_here
,
33 const base::Closure
& closure
) {
34 base::MessageLoop::current()->PostTask(from_here
, closure
);
38 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
39 ServiceWorkerStatusCode status
,
40 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
41 callback
.Run(status
, registration
);
44 void CompleteFindSoon(
45 const tracked_objects::Location
& from_here
,
46 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
47 ServiceWorkerStatusCode status
,
48 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
49 RunSoon(from_here
, base::Bind(callback
, status
, registration
));
52 const base::FilePath::CharType kServiceWorkerDirectory
[] =
53 FILE_PATH_LITERAL("Service Worker");
54 const base::FilePath::CharType kDatabaseName
[] =
55 FILE_PATH_LITERAL("Database");
56 const base::FilePath::CharType kDiskCacheName
[] =
57 FILE_PATH_LITERAL("Cache");
59 const int kMaxMemDiskCacheSize
= 10 * 1024 * 1024;
60 const int kMaxDiskCacheSize
= 250 * 1024 * 1024;
62 ServiceWorkerStatusCode
DatabaseStatusToStatusCode(
63 ServiceWorkerDatabase::Status status
) {
65 case ServiceWorkerDatabase::STATUS_OK
:
66 return SERVICE_WORKER_OK
;
67 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
:
68 return SERVICE_WORKER_ERROR_NOT_FOUND
;
69 case ServiceWorkerDatabase::STATUS_ERROR_MAX
:
72 return SERVICE_WORKER_ERROR_FAILED
;
76 class ResponseComparer
: public base::RefCounted
<ResponseComparer
> {
79 base::WeakPtr
<ServiceWorkerStorage
> owner
,
80 scoped_ptr
<ServiceWorkerResponseReader
> lhs
,
81 scoped_ptr
<ServiceWorkerResponseReader
> rhs
,
82 const ServiceWorkerStorage::CompareCallback
& callback
)
84 completion_callback_(callback
),
85 lhs_reader_(lhs
.release()),
86 rhs_reader_(rhs
.release()),
94 friend class base::RefCounted
<ResponseComparer
>;
96 static const int kBufferSize
= 16 * 1024;
98 ~ResponseComparer() {}
100 void OnReadInfoComplete(int result
);
102 void OnReadDataComplete(int result
);
104 base::WeakPtr
<ServiceWorkerStorage
> owner_
;
105 ServiceWorkerStorage::CompareCallback completion_callback_
;
106 scoped_ptr
<ServiceWorkerResponseReader
> lhs_reader_
;
107 scoped_refptr
<HttpResponseInfoIOBuffer
> lhs_info_
;
108 scoped_refptr
<net::IOBuffer
> lhs_buffer_
;
109 scoped_ptr
<ServiceWorkerResponseReader
> rhs_reader_
;
110 scoped_refptr
<HttpResponseInfoIOBuffer
> rhs_info_
;
111 scoped_refptr
<net::IOBuffer
> rhs_buffer_
;
112 int completion_count_
;
113 int previous_result_
;
114 DISALLOW_COPY_AND_ASSIGN(ResponseComparer
);
117 void ResponseComparer::Start() {
118 lhs_buffer_
= new net::IOBuffer(kBufferSize
);
119 lhs_info_
= new HttpResponseInfoIOBuffer();
120 rhs_buffer_
= new net::IOBuffer(kBufferSize
);
121 rhs_info_
= new HttpResponseInfoIOBuffer();
126 void ResponseComparer::ReadInfos() {
127 lhs_reader_
->ReadInfo(
129 base::Bind(&ResponseComparer::OnReadInfoComplete
,
131 rhs_reader_
->ReadInfo(
133 base::Bind(&ResponseComparer::OnReadInfoComplete
,
137 void ResponseComparer::OnReadInfoComplete(int result
) {
138 if (completion_callback_
.is_null() || !owner_
)
141 completion_callback_
.Run(SERVICE_WORKER_ERROR_FAILED
, false);
142 completion_callback_
.Reset();
145 if (++completion_count_
!= 2)
148 if (lhs_info_
->response_data_size
!= rhs_info_
->response_data_size
) {
149 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
155 void ResponseComparer::ReadSomeData() {
156 completion_count_
= 0;
157 lhs_reader_
->ReadData(
160 base::Bind(&ResponseComparer::OnReadDataComplete
, this));
161 rhs_reader_
->ReadData(
164 base::Bind(&ResponseComparer::OnReadDataComplete
, this));
167 void ResponseComparer::OnReadDataComplete(int result
) {
168 if (completion_callback_
.is_null() || !owner_
)
171 completion_callback_
.Run(SERVICE_WORKER_ERROR_FAILED
, false);
172 completion_callback_
.Reset();
175 if (++completion_count_
!= 2) {
176 previous_result_
= result
;
180 // TODO(michaeln): Probably shouldn't assume that the amounts read from
181 // each reader will always be the same. This would wrongly signal false
183 if (result
!= previous_result_
) {
184 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
189 completion_callback_
.Run(SERVICE_WORKER_OK
, true);
194 memcmp(lhs_buffer_
->data(), rhs_buffer_
->data(), result
);
195 if (compare_result
!= 0) {
196 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
205 ServiceWorkerStorage::InitialData::InitialData()
206 : next_registration_id(kInvalidServiceWorkerRegistrationId
),
207 next_version_id(kInvalidServiceWorkerVersionId
),
208 next_resource_id(kInvalidServiceWorkerResourceId
) {
211 ServiceWorkerStorage::InitialData::~InitialData() {
214 ServiceWorkerStorage::
215 DidDeleteRegistrationParams::DidDeleteRegistrationParams()
216 : registration_id(kInvalidServiceWorkerRegistrationId
) {
219 ServiceWorkerStorage::
220 DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
223 ServiceWorkerStorage::~ServiceWorkerStorage() {
224 weak_factory_
.InvalidateWeakPtrs();
225 database_task_runner_
->DeleteSoon(FROM_HERE
, database_
.release());
229 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
230 const base::FilePath
& path
,
231 base::WeakPtr
<ServiceWorkerContextCore
> context
,
232 base::SequencedTaskRunner
* database_task_runner
,
233 base::MessageLoopProxy
* disk_cache_thread
,
234 quota::QuotaManagerProxy
* quota_manager_proxy
) {
235 return make_scoped_ptr(
236 new ServiceWorkerStorage(path
,
238 database_task_runner
,
240 quota_manager_proxy
));
244 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
245 base::WeakPtr
<ServiceWorkerContextCore
> context
,
246 ServiceWorkerStorage
* old_storage
) {
247 return make_scoped_ptr(
248 new ServiceWorkerStorage(old_storage
->path_
,
250 old_storage
->database_task_runner_
,
251 old_storage
->disk_cache_thread_
,
252 old_storage
->quota_manager_proxy_
));
255 void ServiceWorkerStorage::FindRegistrationForDocument(
256 const GURL
& document_url
,
257 const FindRegistrationCallback
& callback
) {
258 DCHECK(!document_url
.has_ref());
259 if (!LazyInitialize(base::Bind(
260 &ServiceWorkerStorage::FindRegistrationForDocument
,
261 weak_factory_
.GetWeakPtr(), document_url
, callback
))) {
262 if (state_
!= INITIALIZING
|| !context_
) {
263 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
264 SERVICE_WORKER_ERROR_FAILED
, callback
);
268 DCHECK_EQ(INITIALIZED
, state_
);
270 // See if there are any stored registrations for the origin.
271 if (!ContainsKey(registered_origins_
, document_url
.GetOrigin())) {
272 // Look for something currently being installed.
273 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
274 FindInstallingRegistrationForDocument(document_url
);
276 installing_registration
,
277 installing_registration
?
278 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
,
283 database_task_runner_
->PostTask(
286 &FindForDocumentInDB
,
288 base::MessageLoopProxy::current(),
290 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument
,
291 weak_factory_
.GetWeakPtr(), document_url
, callback
)));
294 void ServiceWorkerStorage::FindRegistrationForPattern(
296 const FindRegistrationCallback
& callback
) {
297 if (!LazyInitialize(base::Bind(
298 &ServiceWorkerStorage::FindRegistrationForPattern
,
299 weak_factory_
.GetWeakPtr(), scope
, callback
))) {
300 if (state_
!= INITIALIZING
|| !context_
) {
301 CompleteFindSoon(FROM_HERE
, scoped_refptr
<ServiceWorkerRegistration
>(),
302 SERVICE_WORKER_ERROR_FAILED
, callback
);
306 DCHECK_EQ(INITIALIZED
, state_
);
308 // See if there are any stored registrations for the origin.
309 if (!ContainsKey(registered_origins_
, scope
.GetOrigin())) {
310 // Look for something currently being installed.
311 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
312 FindInstallingRegistrationForPattern(scope
);
314 FROM_HERE
, installing_registration
,
315 installing_registration
?
316 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
,
321 database_task_runner_
->PostTask(
326 base::MessageLoopProxy::current(),
328 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForPattern
,
329 weak_factory_
.GetWeakPtr(), scope
, callback
)));
332 void ServiceWorkerStorage::FindRegistrationForId(
333 int64 registration_id
,
335 const FindRegistrationCallback
& callback
) {
336 if (!LazyInitialize(base::Bind(
337 &ServiceWorkerStorage::FindRegistrationForId
,
338 weak_factory_
.GetWeakPtr(), registration_id
, origin
, callback
))) {
339 if (state_
!= INITIALIZING
|| !context_
) {
340 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
341 SERVICE_WORKER_ERROR_FAILED
, callback
);
345 DCHECK_EQ(INITIALIZED
, state_
);
347 // See if there are any stored registrations for the origin.
348 if (!ContainsKey(registered_origins_
, origin
)) {
349 // Look for something currently being installed.
350 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
351 FindInstallingRegistrationForId(registration_id
);
353 installing_registration
,
354 installing_registration
?
355 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
,
360 scoped_refptr
<ServiceWorkerRegistration
> registration
=
361 context_
->GetLiveRegistration(registration_id
);
363 CompleteFindNow(registration
, SERVICE_WORKER_OK
, callback
);
367 database_task_runner_
->PostTask(
369 base::Bind(&FindForIdInDB
,
371 base::MessageLoopProxy::current(),
372 registration_id
, origin
,
373 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId
,
374 weak_factory_
.GetWeakPtr(), callback
)));
377 void ServiceWorkerStorage::GetAllRegistrations(
378 const GetAllRegistrationInfosCallback
& callback
) {
379 if (!LazyInitialize(base::Bind(
380 &ServiceWorkerStorage::GetAllRegistrations
,
381 weak_factory_
.GetWeakPtr(), callback
))) {
382 if (state_
!= INITIALIZING
|| !context_
) {
383 RunSoon(FROM_HERE
, base::Bind(
384 callback
, std::vector
<ServiceWorkerRegistrationInfo
>()));
388 DCHECK_EQ(INITIALIZED
, state_
);
390 RegistrationList
* registrations
= new RegistrationList
;
391 PostTaskAndReplyWithResult(
392 database_task_runner_
,
394 base::Bind(&ServiceWorkerDatabase::GetAllRegistrations
,
395 base::Unretained(database_
.get()),
396 base::Unretained(registrations
)),
397 base::Bind(&ServiceWorkerStorage::DidGetAllRegistrations
,
398 weak_factory_
.GetWeakPtr(),
400 base::Owned(registrations
)));
403 void ServiceWorkerStorage::StoreRegistration(
404 ServiceWorkerRegistration
* registration
,
405 ServiceWorkerVersion
* version
,
406 const StatusCallback
& callback
) {
407 DCHECK(registration
);
410 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
411 if (IsDisabled() || !context_
) {
412 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
416 ServiceWorkerDatabase::RegistrationData data
;
417 data
.registration_id
= registration
->id();
418 data
.scope
= registration
->pattern();
419 data
.script
= registration
->script_url();
420 data
.has_fetch_handler
= true;
421 data
.version_id
= version
->version_id();
422 data
.last_update_check
= base::Time::Now();
423 data
.is_active
= false; // initially stored in the waiting state
425 ResourceList resources
;
426 version
->script_cache_map()->GetResources(&resources
);
428 if (!has_checked_for_stale_resources_
)
429 DeleteStaleResources();
431 database_task_runner_
->PostTask(
433 base::Bind(&WriteRegistrationInDB
,
435 base::MessageLoopProxy::current(),
437 base::Bind(&ServiceWorkerStorage::DidStoreRegistration
,
438 weak_factory_
.GetWeakPtr(),
442 void ServiceWorkerStorage::UpdateToActiveState(
443 ServiceWorkerRegistration
* registration
,
444 const StatusCallback
& callback
) {
445 DCHECK(registration
);
447 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
448 if (IsDisabled() || !context_
) {
449 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
453 PostTaskAndReplyWithResult(
454 database_task_runner_
,
456 base::Bind(&ServiceWorkerDatabase::UpdateVersionToActive
,
457 base::Unretained(database_
.get()),
459 registration
->script_url().GetOrigin()),
460 base::Bind(&ServiceWorkerStorage::DidUpdateToActiveState
,
461 weak_factory_
.GetWeakPtr(),
465 void ServiceWorkerStorage::DeleteRegistration(
466 int64 registration_id
,
468 const StatusCallback
& callback
) {
469 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
470 if (IsDisabled() || !context_
) {
471 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
475 if (!has_checked_for_stale_resources_
)
476 DeleteStaleResources();
478 DidDeleteRegistrationParams params
;
479 params
.registration_id
= registration_id
;
480 params
.origin
= origin
;
481 params
.callback
= callback
;
483 database_task_runner_
->PostTask(
485 base::Bind(&DeleteRegistrationFromDB
,
487 base::MessageLoopProxy::current(),
488 registration_id
, origin
,
489 base::Bind(&ServiceWorkerStorage::DidDeleteRegistration
,
490 weak_factory_
.GetWeakPtr(), params
)));
492 // The registration should no longer be findable.
493 pending_deletions_
.insert(registration_id
);
494 ServiceWorkerRegistration
* registration
=
495 context_
->GetLiveRegistration(registration_id
);
497 registration
->set_is_deleted();
500 scoped_ptr
<ServiceWorkerResponseReader
>
501 ServiceWorkerStorage::CreateResponseReader(int64 response_id
) {
502 return make_scoped_ptr(
503 new ServiceWorkerResponseReader(response_id
, disk_cache()));
506 scoped_ptr
<ServiceWorkerResponseWriter
>
507 ServiceWorkerStorage::CreateResponseWriter(int64 response_id
) {
508 return make_scoped_ptr(
509 new ServiceWorkerResponseWriter(response_id
, disk_cache()));
512 void ServiceWorkerStorage::StoreUncommittedResponseId(int64 id
) {
513 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
514 DCHECK_EQ(INITIALIZED
, state_
);
516 if (!has_checked_for_stale_resources_
)
517 DeleteStaleResources();
519 database_task_runner_
->PostTask(
521 base::Bind(base::IgnoreResult(
522 &ServiceWorkerDatabase::WriteUncommittedResourceIds
),
523 base::Unretained(database_
.get()),
524 std::set
<int64
>(&id
, &id
+ 1)));
527 void ServiceWorkerStorage::DoomUncommittedResponse(int64 id
) {
528 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
529 database_task_runner_
->PostTask(
531 base::Bind(base::IgnoreResult(
532 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
533 base::Unretained(database_
.get()),
534 std::set
<int64
>(&id
, &id
+ 1)));
535 StartPurgingResources(std::vector
<int64
>(1, id
));
538 void ServiceWorkerStorage::CompareScriptResources(
539 int64 lhs_id
, int64 rhs_id
,
540 const CompareCallback
& callback
) {
541 DCHECK(!callback
.is_null());
542 scoped_refptr
<ResponseComparer
> comparer
=
543 new ResponseComparer(weak_factory_
.GetWeakPtr(),
544 CreateResponseReader(lhs_id
),
545 CreateResponseReader(rhs_id
),
547 comparer
->Start(); // It deletes itself when done.
550 void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback
& callback
) {
553 // Delete the database on the database thread.
554 PostTaskAndReplyWithResult(
555 database_task_runner_
,
557 base::Bind(&ServiceWorkerDatabase::DestroyDatabase
,
558 base::Unretained(database_
.get())),
559 base::Bind(&ServiceWorkerStorage::DidDeleteDatabase
,
560 weak_factory_
.GetWeakPtr(), callback
));
563 int64
ServiceWorkerStorage::NewRegistrationId() {
564 if (state_
== DISABLED
)
565 return kInvalidServiceWorkerRegistrationId
;
566 DCHECK_EQ(INITIALIZED
, state_
);
567 return next_registration_id_
++;
570 int64
ServiceWorkerStorage::NewVersionId() {
571 if (state_
== DISABLED
)
572 return kInvalidServiceWorkerVersionId
;
573 DCHECK_EQ(INITIALIZED
, state_
);
574 return next_version_id_
++;
577 int64
ServiceWorkerStorage::NewResourceId() {
578 if (state_
== DISABLED
)
579 return kInvalidServiceWorkerResourceId
;
580 DCHECK_EQ(INITIALIZED
, state_
);
581 return next_resource_id_
++;
584 void ServiceWorkerStorage::NotifyInstallingRegistration(
585 ServiceWorkerRegistration
* registration
) {
586 installing_registrations_
[registration
->id()] = registration
;
589 void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
590 ServiceWorkerRegistration
* registration
,
591 ServiceWorkerVersion
* version
,
592 ServiceWorkerStatusCode status
) {
593 installing_registrations_
.erase(registration
->id());
594 if (status
!= SERVICE_WORKER_OK
&& version
) {
595 ResourceList resources
;
596 version
->script_cache_map()->GetResources(&resources
);
599 for (size_t i
= 0; i
< resources
.size(); ++i
)
600 ids
.insert(resources
[i
].resource_id
);
602 database_task_runner_
->PostTask(
604 base::Bind(base::IgnoreResult(
605 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
606 base::Unretained(database_
.get()),
611 void ServiceWorkerStorage::Disable() {
614 disk_cache_
->Disable();
617 bool ServiceWorkerStorage::IsDisabled() const {
618 return state_
== DISABLED
;
621 void ServiceWorkerStorage::PurgeResources(const ResourceList
& resources
) {
622 if (!has_checked_for_stale_resources_
)
623 DeleteStaleResources();
624 StartPurgingResources(resources
);
627 ServiceWorkerStorage::ServiceWorkerStorage(
628 const base::FilePath
& path
,
629 base::WeakPtr
<ServiceWorkerContextCore
> context
,
630 base::SequencedTaskRunner
* database_task_runner
,
631 base::MessageLoopProxy
* disk_cache_thread
,
632 quota::QuotaManagerProxy
* quota_manager_proxy
)
633 : next_registration_id_(kInvalidServiceWorkerRegistrationId
),
634 next_version_id_(kInvalidServiceWorkerVersionId
),
635 next_resource_id_(kInvalidServiceWorkerResourceId
),
636 state_(UNINITIALIZED
),
639 database_task_runner_(database_task_runner
),
640 disk_cache_thread_(disk_cache_thread
),
641 quota_manager_proxy_(quota_manager_proxy
),
642 is_purge_pending_(false),
643 has_checked_for_stale_resources_(false),
644 weak_factory_(this) {
645 database_
.reset(new ServiceWorkerDatabase(GetDatabasePath()));
648 base::FilePath
ServiceWorkerStorage::GetDatabasePath() {
650 return base::FilePath();
651 return path_
.Append(kServiceWorkerDirectory
).Append(kDatabaseName
);
654 base::FilePath
ServiceWorkerStorage::GetDiskCachePath() {
656 return base::FilePath();
657 return path_
.Append(kServiceWorkerDirectory
).Append(kDiskCacheName
);
660 bool ServiceWorkerStorage::LazyInitialize(const base::Closure
& callback
) {
670 pending_tasks_
.push_back(callback
);
673 pending_tasks_
.push_back(callback
);
677 state_
= INITIALIZING
;
678 database_task_runner_
->PostTask(
680 base::Bind(&ReadInitialDataFromDB
,
682 base::MessageLoopProxy::current(),
683 base::Bind(&ServiceWorkerStorage::DidReadInitialData
,
684 weak_factory_
.GetWeakPtr())));
688 void ServiceWorkerStorage::DidReadInitialData(
690 ServiceWorkerDatabase::Status status
) {
692 DCHECK_EQ(INITIALIZING
, state_
);
694 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
695 next_registration_id_
= data
->next_registration_id
;
696 next_version_id_
= data
->next_version_id
;
697 next_resource_id_
= data
->next_resource_id
;
698 registered_origins_
.swap(data
->origins
);
699 state_
= INITIALIZED
;
701 // TODO(nhiroki): Stringify |status| using StatusToString() defined in
702 // service_worker_database.cc.
703 DVLOG(2) << "Failed to initialize: " << status
;
704 ScheduleDeleteAndStartOver();
707 for (std::vector
<base::Closure
>::const_iterator it
= pending_tasks_
.begin();
708 it
!= pending_tasks_
.end(); ++it
) {
709 RunSoon(FROM_HERE
, *it
);
711 pending_tasks_
.clear();
714 void ServiceWorkerStorage::DidFindRegistrationForDocument(
715 const GURL
& document_url
,
716 const FindRegistrationCallback
& callback
,
717 const ServiceWorkerDatabase::RegistrationData
& data
,
718 const ResourceList
& resources
,
719 ServiceWorkerDatabase::Status status
) {
720 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
721 ReturnFoundRegistration(callback
, data
, resources
);
725 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
726 // Look for something currently being installed.
727 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
728 FindInstallingRegistrationForDocument(document_url
);
729 callback
.Run(installing_registration
?
730 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
,
731 installing_registration
);
735 ScheduleDeleteAndStartOver();
736 callback
.Run(DatabaseStatusToStatusCode(status
),
737 scoped_refptr
<ServiceWorkerRegistration
>());
740 void ServiceWorkerStorage::DidFindRegistrationForPattern(
742 const FindRegistrationCallback
& callback
,
743 const ServiceWorkerDatabase::RegistrationData
& data
,
744 const ResourceList
& resources
,
745 ServiceWorkerDatabase::Status status
) {
746 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
747 ReturnFoundRegistration(callback
, data
, resources
);
751 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
752 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
753 FindInstallingRegistrationForPattern(scope
);
754 callback
.Run(installing_registration
?
755 SERVICE_WORKER_OK
: SERVICE_WORKER_ERROR_NOT_FOUND
,
756 installing_registration
);
760 ScheduleDeleteAndStartOver();
761 callback
.Run(DatabaseStatusToStatusCode(status
),
762 scoped_refptr
<ServiceWorkerRegistration
>());
765 void ServiceWorkerStorage::DidFindRegistrationForId(
766 const FindRegistrationCallback
& callback
,
767 const ServiceWorkerDatabase::RegistrationData
& data
,
768 const ResourceList
& resources
,
769 ServiceWorkerDatabase::Status status
) {
770 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
771 ReturnFoundRegistration(callback
, data
, resources
);
775 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
776 // TODO(nhiroki): Find a registration in |installing_registrations_|.
777 callback
.Run(DatabaseStatusToStatusCode(status
),
778 scoped_refptr
<ServiceWorkerRegistration
>());
782 ScheduleDeleteAndStartOver();
783 callback
.Run(DatabaseStatusToStatusCode(status
),
784 scoped_refptr
<ServiceWorkerRegistration
>());
787 void ServiceWorkerStorage::ReturnFoundRegistration(
788 const FindRegistrationCallback
& callback
,
789 const ServiceWorkerDatabase::RegistrationData
& data
,
790 const ResourceList
& resources
) {
791 scoped_refptr
<ServiceWorkerRegistration
> registration
=
792 GetOrCreateRegistration(data
, resources
);
793 if (registration
->is_deleted()) {
794 // It's past the point of no return and no longer findable.
795 callback
.Run(SERVICE_WORKER_ERROR_NOT_FOUND
, NULL
);
798 callback
.Run(SERVICE_WORKER_OK
, registration
);
801 void ServiceWorkerStorage::DidGetAllRegistrations(
802 const GetAllRegistrationInfosCallback
& callback
,
803 RegistrationList
* registrations
,
804 ServiceWorkerDatabase::Status status
) {
805 DCHECK(registrations
);
806 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
807 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
808 ScheduleDeleteAndStartOver();
809 callback
.Run(std::vector
<ServiceWorkerRegistrationInfo
>());
813 // Add all stored registrations.
814 std::set
<int64
> pushed_registrations
;
815 std::vector
<ServiceWorkerRegistrationInfo
> infos
;
816 for (RegistrationList::const_iterator it
= registrations
->begin();
817 it
!= registrations
->end(); ++it
) {
818 const bool inserted
=
819 pushed_registrations
.insert(it
->registration_id
).second
;
822 ServiceWorkerRegistration
* registration
=
823 context_
->GetLiveRegistration(it
->registration_id
);
825 infos
.push_back(registration
->GetInfo());
829 ServiceWorkerRegistrationInfo info
;
830 info
.pattern
= it
->scope
;
831 info
.script_url
= it
->script
;
832 info
.registration_id
= it
->registration_id
;
833 if (ServiceWorkerVersion
* version
=
834 context_
->GetLiveVersion(it
->version_id
)) {
836 info
.active_version
= version
->GetInfo();
838 info
.waiting_version
= version
->GetInfo();
839 infos
.push_back(info
);
844 info
.active_version
.is_null
= false;
845 info
.active_version
.status
= ServiceWorkerVersion::ACTIVATED
;
846 info
.active_version
.version_id
= it
->version_id
;
848 info
.waiting_version
.is_null
= false;
849 info
.waiting_version
.status
= ServiceWorkerVersion::INSTALLED
;
850 info
.waiting_version
.version_id
= it
->version_id
;
852 infos
.push_back(info
);
855 // Add unstored registrations that are being installed.
856 for (RegistrationRefsById::const_iterator it
=
857 installing_registrations_
.begin();
858 it
!= installing_registrations_
.end(); ++it
) {
859 if (pushed_registrations
.insert(it
->first
).second
)
860 infos
.push_back(it
->second
->GetInfo());
866 void ServiceWorkerStorage::DidStoreRegistration(
867 const StatusCallback
& callback
,
869 int64 deleted_version_id
,
870 const std::vector
<int64
>& newly_purgeable_resources
,
871 ServiceWorkerDatabase::Status status
) {
872 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
873 ScheduleDeleteAndStartOver();
874 callback
.Run(DatabaseStatusToStatusCode(status
));
877 registered_origins_
.insert(origin
);
878 callback
.Run(SERVICE_WORKER_OK
);
880 if (!context_
|| !context_
->GetLiveVersion(deleted_version_id
))
881 StartPurgingResources(newly_purgeable_resources
);
884 void ServiceWorkerStorage::DidUpdateToActiveState(
885 const StatusCallback
& callback
,
886 ServiceWorkerDatabase::Status status
) {
887 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
888 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
889 ScheduleDeleteAndStartOver();
891 callback
.Run(DatabaseStatusToStatusCode(status
));
894 void ServiceWorkerStorage::DidDeleteRegistration(
895 const DidDeleteRegistrationParams
& params
,
896 bool origin_is_deletable
,
898 const std::vector
<int64
>& newly_purgeable_resources
,
899 ServiceWorkerDatabase::Status status
) {
900 pending_deletions_
.erase(params
.registration_id
);
901 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
902 ScheduleDeleteAndStartOver();
903 params
.callback
.Run(DatabaseStatusToStatusCode(status
));
906 if (origin_is_deletable
)
907 registered_origins_
.erase(params
.origin
);
908 params
.callback
.Run(SERVICE_WORKER_OK
);
910 if (!context_
|| !context_
->GetLiveVersion(version_id
))
911 StartPurgingResources(newly_purgeable_resources
);
914 scoped_refptr
<ServiceWorkerRegistration
>
915 ServiceWorkerStorage::GetOrCreateRegistration(
916 const ServiceWorkerDatabase::RegistrationData
& data
,
917 const ResourceList
& resources
) {
918 scoped_refptr
<ServiceWorkerRegistration
> registration
=
919 context_
->GetLiveRegistration(data
.registration_id
);
923 registration
= new ServiceWorkerRegistration(
924 data
.scope
, data
.script
, data
.registration_id
, context_
);
925 if (pending_deletions_
.find(data
.registration_id
) !=
926 pending_deletions_
.end()) {
927 registration
->set_is_deleted();
929 scoped_refptr
<ServiceWorkerVersion
> version
=
930 context_
->GetLiveVersion(data
.version_id
);
932 version
= new ServiceWorkerVersion(registration
, data
.version_id
, context_
);
933 version
->SetStatus(data
.is_active
?
934 ServiceWorkerVersion::ACTIVATED
: ServiceWorkerVersion::INSTALLED
);
935 version
->script_cache_map()->SetResources(resources
);
938 if (version
->status() == ServiceWorkerVersion::ACTIVATED
)
939 registration
->SetActiveVersion(version
);
940 else if (version
->status() == ServiceWorkerVersion::INSTALLED
)
941 registration
->SetWaitingVersion(version
);
948 ServiceWorkerRegistration
*
949 ServiceWorkerStorage::FindInstallingRegistrationForDocument(
950 const GURL
& document_url
) {
951 DCHECK(!document_url
.has_ref());
953 LongestScopeMatcher
matcher(document_url
);
954 ServiceWorkerRegistration
* match
= NULL
;
956 // TODO(nhiroki): This searches over installing registrations linearly and it
957 // couldn't be scalable. Maybe the regs should be partitioned by origin.
958 for (RegistrationRefsById::const_iterator it
=
959 installing_registrations_
.begin();
960 it
!= installing_registrations_
.end(); ++it
) {
961 if (matcher
.MatchLongest(it
->second
->pattern()))
967 ServiceWorkerRegistration
*
968 ServiceWorkerStorage::FindInstallingRegistrationForPattern(
970 for (RegistrationRefsById::const_iterator it
=
971 installing_registrations_
.begin();
972 it
!= installing_registrations_
.end(); ++it
) {
973 if (it
->second
->pattern() == scope
)
979 ServiceWorkerRegistration
*
980 ServiceWorkerStorage::FindInstallingRegistrationForId(
981 int64 registration_id
) {
982 RegistrationRefsById::const_iterator found
=
983 installing_registrations_
.find(registration_id
);
984 if (found
== installing_registrations_
.end())
986 return found
->second
;
989 ServiceWorkerDiskCache
* ServiceWorkerStorage::disk_cache() {
991 return disk_cache_
.get();
993 disk_cache_
.reset(new ServiceWorkerDiskCache
);
995 base::FilePath path
= GetDiskCachePath();
997 int rv
= disk_cache_
->InitWithMemBackend(kMaxMemDiskCacheSize
,
998 net::CompletionCallback());
999 DCHECK_EQ(net::OK
, rv
);
1000 return disk_cache_
.get();
1003 int rv
= disk_cache_
->InitWithDiskBackend(
1004 path
, kMaxDiskCacheSize
, false,
1005 disk_cache_thread_
.get(),
1006 base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized
,
1007 weak_factory_
.GetWeakPtr()));
1008 if (rv
!= net::ERR_IO_PENDING
)
1009 OnDiskCacheInitialized(rv
);
1011 return disk_cache_
.get();
1014 void ServiceWorkerStorage::OnDiskCacheInitialized(int rv
) {
1015 if (rv
!= net::OK
) {
1016 LOG(ERROR
) << "Failed to open the serviceworker diskcache: "
1017 << net::ErrorToString(rv
);
1018 ScheduleDeleteAndStartOver();
1020 ServiceWorkerMetrics::CountInitDiskCacheResult(rv
== net::OK
);
1023 void ServiceWorkerStorage::StartPurgingResources(
1024 const std::vector
<int64
>& ids
) {
1025 DCHECK(has_checked_for_stale_resources_
);
1026 for (size_t i
= 0; i
< ids
.size(); ++i
)
1027 purgeable_resource_ids_
.push_back(ids
[i
]);
1028 ContinuePurgingResources();
1031 void ServiceWorkerStorage::StartPurgingResources(
1032 const ResourceList
& resources
) {
1033 DCHECK(has_checked_for_stale_resources_
);
1034 for (size_t i
= 0; i
< resources
.size(); ++i
)
1035 purgeable_resource_ids_
.push_back(resources
[i
].resource_id
);
1036 ContinuePurgingResources();
1039 void ServiceWorkerStorage::ContinuePurgingResources() {
1040 if (purgeable_resource_ids_
.empty() || is_purge_pending_
)
1043 // Do one at a time until we're done, use RunSoon to avoid recursion when
1044 // DoomEntry returns immediately.
1045 is_purge_pending_
= true;
1046 int64 id
= purgeable_resource_ids_
.front();
1047 purgeable_resource_ids_
.pop_front();
1049 base::Bind(&ServiceWorkerStorage::PurgeResource
,
1050 weak_factory_
.GetWeakPtr(), id
));
1053 void ServiceWorkerStorage::PurgeResource(int64 id
) {
1054 DCHECK(is_purge_pending_
);
1055 int rv
= disk_cache()->DoomEntry(
1056 id
, base::Bind(&ServiceWorkerStorage::OnResourcePurged
,
1057 weak_factory_
.GetWeakPtr(), id
));
1058 if (rv
!= net::ERR_IO_PENDING
)
1059 OnResourcePurged(id
, rv
);
1062 void ServiceWorkerStorage::OnResourcePurged(int64 id
, int rv
) {
1063 DCHECK(is_purge_pending_
);
1064 is_purge_pending_
= false;
1066 database_task_runner_
->PostTask(
1068 base::Bind(base::IgnoreResult(
1069 &ServiceWorkerDatabase::ClearPurgeableResourceIds
),
1070 base::Unretained(database_
.get()),
1071 std::set
<int64
>(&id
, &id
+ 1)));
1073 ContinuePurgingResources();
1076 void ServiceWorkerStorage::DeleteStaleResources() {
1077 DCHECK(!has_checked_for_stale_resources_
);
1078 has_checked_for_stale_resources_
= true;
1079 database_task_runner_
->PostTask(
1081 base::Bind(&ServiceWorkerStorage::CollectStaleResourcesFromDB
,
1083 base::MessageLoopProxy::current(),
1084 base::Bind(&ServiceWorkerStorage::DidCollectStaleResources
,
1085 weak_factory_
.GetWeakPtr())));
1088 void ServiceWorkerStorage::DidCollectStaleResources(
1089 const std::vector
<int64
>& stale_resource_ids
,
1090 ServiceWorkerDatabase::Status status
) {
1091 DCHECK_EQ(ServiceWorkerDatabase::STATUS_OK
, status
);
1092 if (status
!= ServiceWorkerDatabase::STATUS_OK
)
1094 StartPurgingResources(stale_resource_ids
);
1097 void ServiceWorkerStorage::CollectStaleResourcesFromDB(
1098 ServiceWorkerDatabase
* database
,
1099 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1100 const GetResourcesCallback
& callback
) {
1101 std::set
<int64
> ids
;
1102 ServiceWorkerDatabase::Status status
=
1103 database
->GetUncommittedResourceIds(&ids
);
1104 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1105 original_task_runner
->PostTask(
1108 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1112 status
= database
->PurgeUncommittedResourceIds(ids
);
1113 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1114 original_task_runner
->PostTask(
1117 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1122 status
= database
->GetPurgeableResourceIds(&ids
);
1123 original_task_runner
->PostTask(
1125 base::Bind(callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1128 void ServiceWorkerStorage::ReadInitialDataFromDB(
1129 ServiceWorkerDatabase
* database
,
1130 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1131 const InitializeCallback
& callback
) {
1133 scoped_ptr
<ServiceWorkerStorage::InitialData
> data(
1134 new ServiceWorkerStorage::InitialData());
1136 ServiceWorkerDatabase::Status status
=
1137 database
->GetNextAvailableIds(&data
->next_registration_id
,
1138 &data
->next_version_id
,
1139 &data
->next_resource_id
);
1140 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1141 original_task_runner
->PostTask(
1142 FROM_HERE
, base::Bind(callback
, base::Owned(data
.release()), status
));
1146 status
= database
->GetOriginsWithRegistrations(&data
->origins
);
1147 original_task_runner
->PostTask(
1148 FROM_HERE
, base::Bind(callback
, base::Owned(data
.release()), status
));
1151 void ServiceWorkerStorage::DeleteRegistrationFromDB(
1152 ServiceWorkerDatabase
* database
,
1153 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1154 int64 registration_id
,
1156 const DeleteRegistrationCallback
& callback
) {
1159 int64 version_id
= kInvalidServiceWorkerVersionId
;
1160 std::vector
<int64
> newly_purgeable_resources
;
1161 ServiceWorkerDatabase::Status status
= database
->DeleteRegistration(
1162 registration_id
, origin
, &version_id
, &newly_purgeable_resources
);
1163 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1164 original_task_runner
->PostTask(FROM_HERE
,
1165 base::Bind(callback
,
1167 kInvalidServiceWorkerVersionId
,
1168 std::vector
<int64
>(),
1173 // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
1174 // unique origin list.
1175 std::vector
<ServiceWorkerDatabase::RegistrationData
> registrations
;
1176 status
= database
->GetRegistrationsForOrigin(origin
, ®istrations
);
1177 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1178 original_task_runner
->PostTask(FROM_HERE
,
1179 base::Bind(callback
,
1181 kInvalidServiceWorkerVersionId
,
1182 std::vector
<int64
>(),
1187 bool deletable
= registrations
.empty();
1188 original_task_runner
->PostTask(
1191 callback
, deletable
, version_id
, newly_purgeable_resources
, status
));
1194 void ServiceWorkerStorage::WriteRegistrationInDB(
1195 ServiceWorkerDatabase
* database
,
1196 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1197 const ServiceWorkerDatabase::RegistrationData
& data
,
1198 const ResourceList
& resources
,
1199 const WriteRegistrationCallback
& callback
) {
1201 int64 deleted_version_id
= kInvalidServiceWorkerVersionId
;
1202 std::vector
<int64
> newly_purgeable_resources
;
1203 ServiceWorkerDatabase::Status status
= database
->WriteRegistration(
1204 data
, resources
, &deleted_version_id
, &newly_purgeable_resources
);
1205 original_task_runner
->PostTask(FROM_HERE
,
1206 base::Bind(callback
,
1207 data
.script
.GetOrigin(),
1209 newly_purgeable_resources
,
1213 void ServiceWorkerStorage::FindForDocumentInDB(
1214 ServiceWorkerDatabase
* database
,
1215 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1216 const GURL
& document_url
,
1217 const FindInDBCallback
& callback
) {
1218 GURL origin
= document_url
.GetOrigin();
1219 RegistrationList registrations
;
1220 ServiceWorkerDatabase::Status status
=
1221 database
->GetRegistrationsForOrigin(origin
, ®istrations
);
1222 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1223 original_task_runner
->PostTask(
1225 base::Bind(callback
,
1226 ServiceWorkerDatabase::RegistrationData(),
1232 ServiceWorkerDatabase::RegistrationData data
;
1233 ResourceList resources
;
1234 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1236 // Find one with a pattern match.
1237 LongestScopeMatcher
matcher(document_url
);
1238 int64 match
= kInvalidServiceWorkerRegistrationId
;
1239 for (size_t i
= 0; i
< registrations
.size(); ++i
) {
1240 if (matcher
.MatchLongest(registrations
[i
].scope
))
1241 match
= registrations
[i
].registration_id
;
1244 if (match
!= kInvalidServiceWorkerRegistrationId
)
1245 status
= database
->ReadRegistration(match
, origin
, &data
, &resources
);
1247 original_task_runner
->PostTask(
1249 base::Bind(callback
, data
, resources
, status
));
1252 void ServiceWorkerStorage::FindForPatternInDB(
1253 ServiceWorkerDatabase
* database
,
1254 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1256 const FindInDBCallback
& callback
) {
1257 GURL origin
= scope
.GetOrigin();
1258 std::vector
<ServiceWorkerDatabase::RegistrationData
> registrations
;
1259 ServiceWorkerDatabase::Status status
=
1260 database
->GetRegistrationsForOrigin(origin
, ®istrations
);
1261 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1262 original_task_runner
->PostTask(
1264 base::Bind(callback
,
1265 ServiceWorkerDatabase::RegistrationData(),
1271 // Find one with an exact matching scope.
1272 ServiceWorkerDatabase::RegistrationData data
;
1273 ResourceList resources
;
1274 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1275 for (RegistrationList::const_iterator it
= registrations
.begin();
1276 it
!= registrations
.end(); ++it
) {
1277 if (scope
!= it
->scope
)
1279 status
= database
->ReadRegistration(it
->registration_id
, origin
,
1281 break; // We're done looping.
1284 original_task_runner
->PostTask(
1286 base::Bind(callback
, data
, resources
, status
));
1289 void ServiceWorkerStorage::FindForIdInDB(
1290 ServiceWorkerDatabase
* database
,
1291 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1292 int64 registration_id
,
1294 const FindInDBCallback
& callback
) {
1295 ServiceWorkerDatabase::RegistrationData data
;
1296 ResourceList resources
;
1297 ServiceWorkerDatabase::Status status
=
1298 database
->ReadRegistration(registration_id
, origin
, &data
, &resources
);
1299 original_task_runner
->PostTask(
1300 FROM_HERE
, base::Bind(callback
, data
, resources
, status
));
1303 // TODO(nhiroki): The corruption recovery should not be scheduled if the error
1304 // is transient and it can get healed soon (e.g. IO error). To do that, the
1305 // database should not disable itself when an error occurs and the storage
1306 // controls it instead.
1307 void ServiceWorkerStorage::ScheduleDeleteAndStartOver() {
1308 if (state_
== DISABLED
) {
1309 // Recovery process has already been scheduled.
1314 DVLOG(1) << "Schedule to delete the context and start over.";
1315 context_
->ScheduleDeleteAndStartOver();
1318 void ServiceWorkerStorage::DidDeleteDatabase(
1319 const StatusCallback
& callback
,
1320 ServiceWorkerDatabase::Status status
) {
1321 DCHECK_EQ(DISABLED
, state_
);
1322 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1323 // Give up the corruption recovery until the browser restarts.
1324 LOG(ERROR
) << "Failed to delete the database: " << status
;
1325 callback
.Run(DatabaseStatusToStatusCode(status
));
1328 DVLOG(1) << "Deleted ServiceWorkerDatabase successfully.";
1330 // Delete the disk cache on the cache thread.
1331 // TODO(nhiroki): What if there is a bunch of files in the cache directory?
1332 // Deleting the directory could take a long time and restart could be delayed.
1333 // We should probably rename the directory and delete it later.
1334 PostTaskAndReplyWithResult(
1335 database_task_runner_
,
1337 base::Bind(&base::DeleteFile
, GetDiskCachePath(), true),
1338 base::Bind(&ServiceWorkerStorage::DidDeleteDiskCache
,
1339 weak_factory_
.GetWeakPtr(), callback
));
1342 void ServiceWorkerStorage::DidDeleteDiskCache(
1343 const StatusCallback
& callback
, bool result
) {
1344 DCHECK_EQ(DISABLED
, state_
);
1346 // Give up the corruption recovery until the browser restarts.
1347 LOG(ERROR
) << "Failed to delete the diskcache.";
1348 callback
.Run(SERVICE_WORKER_ERROR_FAILED
);
1351 DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully.";
1352 callback
.Run(SERVICE_WORKER_OK
);
1355 } // namespace content