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/single_thread_task_runner.h"
14 #include "base/task_runner_util.h"
15 #include "content/browser/service_worker/service_worker_context_core.h"
16 #include "content/browser/service_worker/service_worker_disk_cache.h"
17 #include "content/browser/service_worker/service_worker_info.h"
18 #include "content/browser/service_worker/service_worker_metrics.h"
19 #include "content/browser/service_worker/service_worker_registration.h"
20 #include "content/browser/service_worker/service_worker_utils.h"
21 #include "content/browser/service_worker/service_worker_version.h"
22 #include "content/common/service_worker/service_worker_types.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "net/base/completion_callback.h"
25 #include "net/base/io_buffer.h"
26 #include "net/base/net_errors.h"
27 #include "webkit/browser/quota/quota_manager_proxy.h"
33 void RunSoon(const tracked_objects::Location
& from_here
,
34 const base::Closure
& closure
) {
35 base::MessageLoop::current()->PostTask(from_here
, closure
);
39 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
40 ServiceWorkerStatusCode status
,
41 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
42 callback
.Run(status
, registration
);
45 void CompleteFindSoon(
46 const tracked_objects::Location
& from_here
,
47 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
48 ServiceWorkerStatusCode status
,
49 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
50 RunSoon(from_here
, base::Bind(callback
, status
, registration
));
53 const base::FilePath::CharType kDatabaseName
[] =
54 FILE_PATH_LITERAL("Database");
55 const base::FilePath::CharType kDiskCacheName
[] =
56 FILE_PATH_LITERAL("Cache");
58 const int kMaxMemDiskCacheSize
= 10 * 1024 * 1024;
59 const int kMaxDiskCacheSize
= 250 * 1024 * 1024;
61 ServiceWorkerStatusCode
DatabaseStatusToStatusCode(
62 ServiceWorkerDatabase::Status status
) {
64 case ServiceWorkerDatabase::STATUS_OK
:
65 return SERVICE_WORKER_OK
;
66 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
:
67 return SERVICE_WORKER_ERROR_NOT_FOUND
;
68 case ServiceWorkerDatabase::STATUS_ERROR_MAX
:
71 return SERVICE_WORKER_ERROR_FAILED
;
75 class ResponseComparer
: public base::RefCounted
<ResponseComparer
> {
78 base::WeakPtr
<ServiceWorkerStorage
> owner
,
79 scoped_ptr
<ServiceWorkerResponseReader
> lhs
,
80 scoped_ptr
<ServiceWorkerResponseReader
> rhs
,
81 const ServiceWorkerStorage::CompareCallback
& callback
)
83 completion_callback_(callback
),
84 lhs_reader_(lhs
.release()),
85 rhs_reader_(rhs
.release()),
93 friend class base::RefCounted
<ResponseComparer
>;
95 static const int kBufferSize
= 16 * 1024;
97 ~ResponseComparer() {}
99 void OnReadInfoComplete(int result
);
101 void OnReadDataComplete(int result
);
103 base::WeakPtr
<ServiceWorkerStorage
> owner_
;
104 ServiceWorkerStorage::CompareCallback completion_callback_
;
105 scoped_ptr
<ServiceWorkerResponseReader
> lhs_reader_
;
106 scoped_refptr
<HttpResponseInfoIOBuffer
> lhs_info_
;
107 scoped_refptr
<net::IOBuffer
> lhs_buffer_
;
108 scoped_ptr
<ServiceWorkerResponseReader
> rhs_reader_
;
109 scoped_refptr
<HttpResponseInfoIOBuffer
> rhs_info_
;
110 scoped_refptr
<net::IOBuffer
> rhs_buffer_
;
111 int completion_count_
;
112 int previous_result_
;
113 DISALLOW_COPY_AND_ASSIGN(ResponseComparer
);
116 void ResponseComparer::Start() {
117 lhs_buffer_
= new net::IOBuffer(kBufferSize
);
118 lhs_info_
= new HttpResponseInfoIOBuffer();
119 rhs_buffer_
= new net::IOBuffer(kBufferSize
);
120 rhs_info_
= new HttpResponseInfoIOBuffer();
125 void ResponseComparer::ReadInfos() {
126 lhs_reader_
->ReadInfo(
127 lhs_info_
.get(), base::Bind(&ResponseComparer::OnReadInfoComplete
, this));
128 rhs_reader_
->ReadInfo(
129 rhs_info_
.get(), base::Bind(&ResponseComparer::OnReadInfoComplete
, this));
132 void ResponseComparer::OnReadInfoComplete(int result
) {
133 if (completion_callback_
.is_null() || !owner_
)
136 completion_callback_
.Run(SERVICE_WORKER_ERROR_FAILED
, false);
137 completion_callback_
.Reset();
140 if (++completion_count_
!= 2)
143 if (lhs_info_
->response_data_size
!= rhs_info_
->response_data_size
) {
144 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
150 void ResponseComparer::ReadSomeData() {
151 completion_count_
= 0;
152 lhs_reader_
->ReadData(
155 base::Bind(&ResponseComparer::OnReadDataComplete
, this));
156 rhs_reader_
->ReadData(
159 base::Bind(&ResponseComparer::OnReadDataComplete
, this));
162 void ResponseComparer::OnReadDataComplete(int result
) {
163 if (completion_callback_
.is_null() || !owner_
)
166 completion_callback_
.Run(SERVICE_WORKER_ERROR_FAILED
, false);
167 completion_callback_
.Reset();
170 if (++completion_count_
!= 2) {
171 previous_result_
= result
;
175 // TODO(michaeln): Probably shouldn't assume that the amounts read from
176 // each reader will always be the same. This would wrongly signal false
178 if (result
!= previous_result_
) {
179 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
184 completion_callback_
.Run(SERVICE_WORKER_OK
, true);
189 memcmp(lhs_buffer_
->data(), rhs_buffer_
->data(), result
);
190 if (compare_result
!= 0) {
191 completion_callback_
.Run(SERVICE_WORKER_OK
, false);
200 ServiceWorkerStorage::InitialData::InitialData()
201 : next_registration_id(kInvalidServiceWorkerRegistrationId
),
202 next_version_id(kInvalidServiceWorkerVersionId
),
203 next_resource_id(kInvalidServiceWorkerResourceId
) {
206 ServiceWorkerStorage::InitialData::~InitialData() {
209 ServiceWorkerStorage::
210 DidDeleteRegistrationParams::DidDeleteRegistrationParams()
211 : registration_id(kInvalidServiceWorkerRegistrationId
) {
214 ServiceWorkerStorage::
215 DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
218 ServiceWorkerStorage::~ServiceWorkerStorage() {
219 weak_factory_
.InvalidateWeakPtrs();
220 database_task_runner_
->DeleteSoon(FROM_HERE
, database_
.release());
224 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
225 const base::FilePath
& path
,
226 base::WeakPtr
<ServiceWorkerContextCore
> context
,
227 const scoped_refptr
<base::SequencedTaskRunner
>& database_task_runner
,
228 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
229 storage::QuotaManagerProxy
* quota_manager_proxy
) {
230 return make_scoped_ptr(new ServiceWorkerStorage(path
,
232 database_task_runner
,
234 quota_manager_proxy
));
238 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
239 base::WeakPtr
<ServiceWorkerContextCore
> context
,
240 ServiceWorkerStorage
* old_storage
) {
241 return make_scoped_ptr(
242 new ServiceWorkerStorage(old_storage
->path_
,
244 old_storage
->database_task_runner_
,
245 old_storage
->disk_cache_thread_
,
246 old_storage
->quota_manager_proxy_
.get()));
249 void ServiceWorkerStorage::FindRegistrationForDocument(
250 const GURL
& document_url
,
251 const FindRegistrationCallback
& callback
) {
252 DCHECK(!document_url
.has_ref());
253 if (!LazyInitialize(base::Bind(
254 &ServiceWorkerStorage::FindRegistrationForDocument
,
255 weak_factory_
.GetWeakPtr(), document_url
, callback
))) {
256 if (state_
!= INITIALIZING
|| !context_
) {
257 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
258 SERVICE_WORKER_ERROR_FAILED
, callback
);
262 DCHECK_EQ(INITIALIZED
, state_
);
264 // See if there are any stored registrations for the origin.
265 if (!ContainsKey(registered_origins_
, document_url
.GetOrigin())) {
266 // Look for something currently being installed.
267 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
268 FindInstallingRegistrationForDocument(document_url
);
269 CompleteFindNow(installing_registration
,
270 installing_registration
.get()
272 : SERVICE_WORKER_ERROR_NOT_FOUND
,
277 database_task_runner_
->PostTask(
280 &FindForDocumentInDB
,
282 base::MessageLoopProxy::current(),
284 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument
,
285 weak_factory_
.GetWeakPtr(), document_url
, callback
)));
288 void ServiceWorkerStorage::FindRegistrationForPattern(
290 const FindRegistrationCallback
& callback
) {
291 if (!LazyInitialize(base::Bind(
292 &ServiceWorkerStorage::FindRegistrationForPattern
,
293 weak_factory_
.GetWeakPtr(), scope
, callback
))) {
294 if (state_
!= INITIALIZING
|| !context_
) {
295 CompleteFindSoon(FROM_HERE
, scoped_refptr
<ServiceWorkerRegistration
>(),
296 SERVICE_WORKER_ERROR_FAILED
, callback
);
300 DCHECK_EQ(INITIALIZED
, state_
);
302 // See if there are any stored registrations for the origin.
303 if (!ContainsKey(registered_origins_
, scope
.GetOrigin())) {
304 // Look for something currently being installed.
305 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
306 FindInstallingRegistrationForPattern(scope
);
307 CompleteFindSoon(FROM_HERE
,
308 installing_registration
,
309 installing_registration
.get()
311 : SERVICE_WORKER_ERROR_NOT_FOUND
,
316 database_task_runner_
->PostTask(
321 base::MessageLoopProxy::current(),
323 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForPattern
,
324 weak_factory_
.GetWeakPtr(), scope
, callback
)));
327 ServiceWorkerRegistration
* ServiceWorkerStorage::GetUninstallingRegistration(
329 if (state_
!= INITIALIZED
|| !context_
)
331 for (RegistrationRefsById::const_iterator it
=
332 uninstalling_registrations_
.begin();
333 it
!= uninstalling_registrations_
.end();
335 if (it
->second
->pattern() == scope
) {
336 DCHECK(it
->second
->is_uninstalling());
337 return it
->second
.get();
343 void ServiceWorkerStorage::FindRegistrationForId(
344 int64 registration_id
,
346 const FindRegistrationCallback
& callback
) {
347 if (!LazyInitialize(base::Bind(
348 &ServiceWorkerStorage::FindRegistrationForId
,
349 weak_factory_
.GetWeakPtr(), registration_id
, origin
, callback
))) {
350 if (state_
!= INITIALIZING
|| !context_
) {
351 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
352 SERVICE_WORKER_ERROR_FAILED
, callback
);
356 DCHECK_EQ(INITIALIZED
, state_
);
358 // See if there are any stored registrations for the origin.
359 if (!ContainsKey(registered_origins_
, origin
)) {
360 // Look for something currently being installed.
361 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
362 FindInstallingRegistrationForId(registration_id
);
363 CompleteFindNow(installing_registration
,
364 installing_registration
.get()
366 : SERVICE_WORKER_ERROR_NOT_FOUND
,
371 scoped_refptr
<ServiceWorkerRegistration
> registration
=
372 context_
->GetLiveRegistration(registration_id
);
373 if (registration
.get()) {
374 CompleteFindNow(registration
, SERVICE_WORKER_OK
, callback
);
378 database_task_runner_
->PostTask(
380 base::Bind(&FindForIdInDB
,
382 base::MessageLoopProxy::current(),
383 registration_id
, origin
,
384 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId
,
385 weak_factory_
.GetWeakPtr(), callback
)));
388 void ServiceWorkerStorage::GetAllRegistrations(
389 const GetAllRegistrationInfosCallback
& callback
) {
390 if (!LazyInitialize(base::Bind(
391 &ServiceWorkerStorage::GetAllRegistrations
,
392 weak_factory_
.GetWeakPtr(), callback
))) {
393 if (state_
!= INITIALIZING
|| !context_
) {
394 RunSoon(FROM_HERE
, base::Bind(
395 callback
, std::vector
<ServiceWorkerRegistrationInfo
>()));
399 DCHECK_EQ(INITIALIZED
, state_
);
401 RegistrationList
* registrations
= new RegistrationList
;
402 PostTaskAndReplyWithResult(
403 database_task_runner_
.get(),
405 base::Bind(&ServiceWorkerDatabase::GetAllRegistrations
,
406 base::Unretained(database_
.get()),
407 base::Unretained(registrations
)),
408 base::Bind(&ServiceWorkerStorage::DidGetAllRegistrations
,
409 weak_factory_
.GetWeakPtr(),
411 base::Owned(registrations
)));
414 void ServiceWorkerStorage::StoreRegistration(
415 ServiceWorkerRegistration
* registration
,
416 ServiceWorkerVersion
* version
,
417 const StatusCallback
& callback
) {
418 DCHECK(registration
);
421 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
422 if (IsDisabled() || !context_
) {
423 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
427 ServiceWorkerDatabase::RegistrationData data
;
428 data
.registration_id
= registration
->id();
429 data
.scope
= registration
->pattern();
430 data
.script
= version
->script_url();
431 data
.has_fetch_handler
= true;
432 data
.version_id
= version
->version_id();
433 data
.last_update_check
= registration
->last_update_check();
434 data
.is_active
= (version
== registration
->active_version());
436 ResourceList resources
;
437 version
->script_cache_map()->GetResources(&resources
);
439 if (!has_checked_for_stale_resources_
)
440 DeleteStaleResources();
442 database_task_runner_
->PostTask(
444 base::Bind(&WriteRegistrationInDB
,
446 base::MessageLoopProxy::current(),
448 base::Bind(&ServiceWorkerStorage::DidStoreRegistration
,
449 weak_factory_
.GetWeakPtr(),
452 registration
->set_is_deleted(false);
455 void ServiceWorkerStorage::UpdateToActiveState(
456 ServiceWorkerRegistration
* registration
,
457 const StatusCallback
& callback
) {
458 DCHECK(registration
);
460 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
461 if (IsDisabled() || !context_
) {
462 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
466 PostTaskAndReplyWithResult(
467 database_task_runner_
.get(),
469 base::Bind(&ServiceWorkerDatabase::UpdateVersionToActive
,
470 base::Unretained(database_
.get()),
472 registration
->pattern().GetOrigin()),
473 base::Bind(&ServiceWorkerStorage::DidUpdateToActiveState
,
474 weak_factory_
.GetWeakPtr(),
478 void ServiceWorkerStorage::UpdateLastUpdateCheckTime(
479 ServiceWorkerRegistration
* registration
) {
480 DCHECK(registration
);
482 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
483 if (IsDisabled() || !context_
)
486 database_task_runner_
->PostTask(
489 base::IgnoreResult(&ServiceWorkerDatabase::UpdateLastCheckTime
),
490 base::Unretained(database_
.get()),
492 registration
->pattern().GetOrigin(),
493 registration
->last_update_check()));
496 void ServiceWorkerStorage::DeleteRegistration(
497 int64 registration_id
,
499 const StatusCallback
& callback
) {
500 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
501 if (IsDisabled() || !context_
) {
502 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
506 if (!has_checked_for_stale_resources_
)
507 DeleteStaleResources();
509 DidDeleteRegistrationParams params
;
510 params
.registration_id
= registration_id
;
511 params
.origin
= origin
;
512 params
.callback
= callback
;
514 database_task_runner_
->PostTask(
516 base::Bind(&DeleteRegistrationFromDB
,
518 base::MessageLoopProxy::current(),
519 registration_id
, origin
,
520 base::Bind(&ServiceWorkerStorage::DidDeleteRegistration
,
521 weak_factory_
.GetWeakPtr(), params
)));
523 // The registration should no longer be findable.
524 pending_deletions_
.insert(registration_id
);
525 ServiceWorkerRegistration
* registration
=
526 context_
->GetLiveRegistration(registration_id
);
528 registration
->set_is_deleted(true);
531 scoped_ptr
<ServiceWorkerResponseReader
>
532 ServiceWorkerStorage::CreateResponseReader(int64 response_id
) {
533 return make_scoped_ptr(
534 new ServiceWorkerResponseReader(response_id
, disk_cache()));
537 scoped_ptr
<ServiceWorkerResponseWriter
>
538 ServiceWorkerStorage::CreateResponseWriter(int64 response_id
) {
539 return make_scoped_ptr(
540 new ServiceWorkerResponseWriter(response_id
, disk_cache()));
543 void ServiceWorkerStorage::StoreUncommittedResponseId(int64 id
) {
544 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
545 DCHECK_EQ(INITIALIZED
, state_
);
547 if (!has_checked_for_stale_resources_
)
548 DeleteStaleResources();
550 database_task_runner_
->PostTask(
552 base::Bind(base::IgnoreResult(
553 &ServiceWorkerDatabase::WriteUncommittedResourceIds
),
554 base::Unretained(database_
.get()),
555 std::set
<int64
>(&id
, &id
+ 1)));
558 void ServiceWorkerStorage::DoomUncommittedResponse(int64 id
) {
559 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
560 database_task_runner_
->PostTask(
562 base::Bind(base::IgnoreResult(
563 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
564 base::Unretained(database_
.get()),
565 std::set
<int64
>(&id
, &id
+ 1)));
566 StartPurgingResources(std::vector
<int64
>(1, id
));
569 void ServiceWorkerStorage::CompareScriptResources(
570 int64 lhs_id
, int64 rhs_id
,
571 const CompareCallback
& callback
) {
572 DCHECK(!callback
.is_null());
573 scoped_refptr
<ResponseComparer
> comparer
=
574 new ResponseComparer(weak_factory_
.GetWeakPtr(),
575 CreateResponseReader(lhs_id
),
576 CreateResponseReader(rhs_id
),
578 comparer
->Start(); // It deletes itself when done.
581 void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback
& callback
) {
584 // Delete the database on the database thread.
585 PostTaskAndReplyWithResult(
586 database_task_runner_
.get(),
588 base::Bind(&ServiceWorkerDatabase::DestroyDatabase
,
589 base::Unretained(database_
.get())),
590 base::Bind(&ServiceWorkerStorage::DidDeleteDatabase
,
591 weak_factory_
.GetWeakPtr(),
595 int64
ServiceWorkerStorage::NewRegistrationId() {
596 if (state_
== DISABLED
)
597 return kInvalidServiceWorkerRegistrationId
;
598 DCHECK_EQ(INITIALIZED
, state_
);
599 return next_registration_id_
++;
602 int64
ServiceWorkerStorage::NewVersionId() {
603 if (state_
== DISABLED
)
604 return kInvalidServiceWorkerVersionId
;
605 DCHECK_EQ(INITIALIZED
, state_
);
606 return next_version_id_
++;
609 int64
ServiceWorkerStorage::NewResourceId() {
610 if (state_
== DISABLED
)
611 return kInvalidServiceWorkerResourceId
;
612 DCHECK_EQ(INITIALIZED
, state_
);
613 return next_resource_id_
++;
616 void ServiceWorkerStorage::NotifyInstallingRegistration(
617 ServiceWorkerRegistration
* registration
) {
618 DCHECK(installing_registrations_
.find(registration
->id()) ==
619 installing_registrations_
.end());
620 installing_registrations_
[registration
->id()] = registration
;
623 void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
624 ServiceWorkerRegistration
* registration
,
625 ServiceWorkerVersion
* version
,
626 ServiceWorkerStatusCode status
) {
627 installing_registrations_
.erase(registration
->id());
628 if (status
!= SERVICE_WORKER_OK
&& version
) {
629 ResourceList resources
;
630 version
->script_cache_map()->GetResources(&resources
);
633 for (size_t i
= 0; i
< resources
.size(); ++i
)
634 ids
.insert(resources
[i
].resource_id
);
636 database_task_runner_
->PostTask(
638 base::Bind(base::IgnoreResult(
639 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
640 base::Unretained(database_
.get()),
645 void ServiceWorkerStorage::NotifyUninstallingRegistration(
646 ServiceWorkerRegistration
* registration
) {
647 DCHECK(uninstalling_registrations_
.find(registration
->id()) ==
648 uninstalling_registrations_
.end());
649 uninstalling_registrations_
[registration
->id()] = registration
;
652 void ServiceWorkerStorage::NotifyDoneUninstallingRegistration(
653 ServiceWorkerRegistration
* registration
) {
654 uninstalling_registrations_
.erase(registration
->id());
657 void ServiceWorkerStorage::Disable() {
660 disk_cache_
->Disable();
663 bool ServiceWorkerStorage::IsDisabled() const {
664 return state_
== DISABLED
;
667 void ServiceWorkerStorage::PurgeResources(const ResourceList
& resources
) {
668 if (!has_checked_for_stale_resources_
)
669 DeleteStaleResources();
670 StartPurgingResources(resources
);
673 ServiceWorkerStorage::ServiceWorkerStorage(
674 const base::FilePath
& path
,
675 base::WeakPtr
<ServiceWorkerContextCore
> context
,
676 const scoped_refptr
<base::SequencedTaskRunner
>& database_task_runner
,
677 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
678 storage::QuotaManagerProxy
* quota_manager_proxy
)
679 : next_registration_id_(kInvalidServiceWorkerRegistrationId
),
680 next_version_id_(kInvalidServiceWorkerVersionId
),
681 next_resource_id_(kInvalidServiceWorkerResourceId
),
682 state_(UNINITIALIZED
),
685 database_task_runner_(database_task_runner
),
686 disk_cache_thread_(disk_cache_thread
),
687 quota_manager_proxy_(quota_manager_proxy
),
688 is_purge_pending_(false),
689 has_checked_for_stale_resources_(false),
690 weak_factory_(this) {
691 database_
.reset(new ServiceWorkerDatabase(GetDatabasePath()));
694 base::FilePath
ServiceWorkerStorage::GetDatabasePath() {
696 return base::FilePath();
697 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
698 .Append(kDatabaseName
);
701 base::FilePath
ServiceWorkerStorage::GetDiskCachePath() {
703 return base::FilePath();
704 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
705 .Append(kDiskCacheName
);
708 bool ServiceWorkerStorage::LazyInitialize(const base::Closure
& callback
) {
718 pending_tasks_
.push_back(callback
);
721 pending_tasks_
.push_back(callback
);
725 state_
= INITIALIZING
;
726 database_task_runner_
->PostTask(
728 base::Bind(&ReadInitialDataFromDB
,
730 base::MessageLoopProxy::current(),
731 base::Bind(&ServiceWorkerStorage::DidReadInitialData
,
732 weak_factory_
.GetWeakPtr())));
736 void ServiceWorkerStorage::DidReadInitialData(
738 ServiceWorkerDatabase::Status status
) {
740 DCHECK_EQ(INITIALIZING
, state_
);
742 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
743 next_registration_id_
= data
->next_registration_id
;
744 next_version_id_
= data
->next_version_id
;
745 next_resource_id_
= data
->next_resource_id
;
746 registered_origins_
.swap(data
->origins
);
747 state_
= INITIALIZED
;
749 // TODO(nhiroki): Stringify |status| using StatusToString() defined in
750 // service_worker_database.cc.
751 DVLOG(2) << "Failed to initialize: " << status
;
752 ScheduleDeleteAndStartOver();
755 for (std::vector
<base::Closure
>::const_iterator it
= pending_tasks_
.begin();
756 it
!= pending_tasks_
.end(); ++it
) {
757 RunSoon(FROM_HERE
, *it
);
759 pending_tasks_
.clear();
762 void ServiceWorkerStorage::DidFindRegistrationForDocument(
763 const GURL
& document_url
,
764 const FindRegistrationCallback
& callback
,
765 const ServiceWorkerDatabase::RegistrationData
& data
,
766 const ResourceList
& resources
,
767 ServiceWorkerDatabase::Status status
) {
768 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
769 ReturnFoundRegistration(callback
, data
, resources
);
773 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
774 // Look for something currently being installed.
775 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
776 FindInstallingRegistrationForDocument(document_url
);
777 callback
.Run(installing_registration
.get() ? SERVICE_WORKER_OK
778 : SERVICE_WORKER_ERROR_NOT_FOUND
,
779 installing_registration
);
783 ScheduleDeleteAndStartOver();
784 callback
.Run(DatabaseStatusToStatusCode(status
),
785 scoped_refptr
<ServiceWorkerRegistration
>());
788 void ServiceWorkerStorage::DidFindRegistrationForPattern(
790 const FindRegistrationCallback
& callback
,
791 const ServiceWorkerDatabase::RegistrationData
& data
,
792 const ResourceList
& resources
,
793 ServiceWorkerDatabase::Status status
) {
794 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
795 ReturnFoundRegistration(callback
, data
, resources
);
799 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
800 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
801 FindInstallingRegistrationForPattern(scope
);
802 callback
.Run(installing_registration
.get() ? SERVICE_WORKER_OK
803 : SERVICE_WORKER_ERROR_NOT_FOUND
,
804 installing_registration
);
808 ScheduleDeleteAndStartOver();
809 callback
.Run(DatabaseStatusToStatusCode(status
),
810 scoped_refptr
<ServiceWorkerRegistration
>());
813 void ServiceWorkerStorage::DidFindRegistrationForId(
814 const FindRegistrationCallback
& callback
,
815 const ServiceWorkerDatabase::RegistrationData
& data
,
816 const ResourceList
& resources
,
817 ServiceWorkerDatabase::Status status
) {
818 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
819 ReturnFoundRegistration(callback
, data
, resources
);
823 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
824 // TODO(nhiroki): Find a registration in |installing_registrations_|.
825 callback
.Run(DatabaseStatusToStatusCode(status
),
826 scoped_refptr
<ServiceWorkerRegistration
>());
830 ScheduleDeleteAndStartOver();
831 callback
.Run(DatabaseStatusToStatusCode(status
),
832 scoped_refptr
<ServiceWorkerRegistration
>());
835 void ServiceWorkerStorage::ReturnFoundRegistration(
836 const FindRegistrationCallback
& callback
,
837 const ServiceWorkerDatabase::RegistrationData
& data
,
838 const ResourceList
& resources
) {
839 scoped_refptr
<ServiceWorkerRegistration
> registration
=
840 GetOrCreateRegistration(data
, resources
);
841 if (registration
->is_deleted()) {
842 // It's past the point of no return and no longer findable.
843 callback
.Run(SERVICE_WORKER_ERROR_NOT_FOUND
, NULL
);
846 callback
.Run(SERVICE_WORKER_OK
, registration
);
849 void ServiceWorkerStorage::DidGetAllRegistrations(
850 const GetAllRegistrationInfosCallback
& callback
,
851 RegistrationList
* registrations
,
852 ServiceWorkerDatabase::Status status
) {
853 DCHECK(registrations
);
854 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
855 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
856 ScheduleDeleteAndStartOver();
857 callback
.Run(std::vector
<ServiceWorkerRegistrationInfo
>());
861 // Add all stored registrations.
862 std::set
<int64
> pushed_registrations
;
863 std::vector
<ServiceWorkerRegistrationInfo
> infos
;
864 for (RegistrationList::const_iterator it
= registrations
->begin();
865 it
!= registrations
->end(); ++it
) {
866 const bool inserted
=
867 pushed_registrations
.insert(it
->registration_id
).second
;
870 ServiceWorkerRegistration
* registration
=
871 context_
->GetLiveRegistration(it
->registration_id
);
873 infos
.push_back(registration
->GetInfo());
877 ServiceWorkerRegistrationInfo info
;
878 info
.pattern
= it
->scope
;
879 info
.registration_id
= it
->registration_id
;
880 if (ServiceWorkerVersion
* version
=
881 context_
->GetLiveVersion(it
->version_id
)) {
883 info
.active_version
= version
->GetInfo();
885 info
.waiting_version
= version
->GetInfo();
886 infos
.push_back(info
);
891 info
.active_version
.is_null
= false;
892 info
.active_version
.status
= ServiceWorkerVersion::ACTIVATED
;
893 info
.active_version
.version_id
= it
->version_id
;
895 info
.waiting_version
.is_null
= false;
896 info
.waiting_version
.status
= ServiceWorkerVersion::INSTALLED
;
897 info
.waiting_version
.version_id
= it
->version_id
;
899 infos
.push_back(info
);
902 // Add unstored registrations that are being installed.
903 for (RegistrationRefsById::const_iterator it
=
904 installing_registrations_
.begin();
905 it
!= installing_registrations_
.end(); ++it
) {
906 if (pushed_registrations
.insert(it
->first
).second
)
907 infos
.push_back(it
->second
->GetInfo());
913 void ServiceWorkerStorage::DidStoreRegistration(
914 const StatusCallback
& callback
,
916 int64 deleted_version_id
,
917 const std::vector
<int64
>& newly_purgeable_resources
,
918 ServiceWorkerDatabase::Status status
) {
919 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
920 ScheduleDeleteAndStartOver();
921 callback
.Run(DatabaseStatusToStatusCode(status
));
924 registered_origins_
.insert(origin
);
925 callback
.Run(SERVICE_WORKER_OK
);
927 if (!context_
|| !context_
->GetLiveVersion(deleted_version_id
))
928 StartPurgingResources(newly_purgeable_resources
);
931 void ServiceWorkerStorage::DidUpdateToActiveState(
932 const StatusCallback
& callback
,
933 ServiceWorkerDatabase::Status status
) {
934 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
935 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
936 ScheduleDeleteAndStartOver();
938 callback
.Run(DatabaseStatusToStatusCode(status
));
941 void ServiceWorkerStorage::DidDeleteRegistration(
942 const DidDeleteRegistrationParams
& params
,
943 bool origin_is_deletable
,
945 const std::vector
<int64
>& newly_purgeable_resources
,
946 ServiceWorkerDatabase::Status status
) {
947 pending_deletions_
.erase(params
.registration_id
);
948 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
949 ScheduleDeleteAndStartOver();
950 params
.callback
.Run(DatabaseStatusToStatusCode(status
));
953 if (origin_is_deletable
)
954 registered_origins_
.erase(params
.origin
);
955 params
.callback
.Run(SERVICE_WORKER_OK
);
957 if (!context_
|| !context_
->GetLiveVersion(version_id
))
958 StartPurgingResources(newly_purgeable_resources
);
961 scoped_refptr
<ServiceWorkerRegistration
>
962 ServiceWorkerStorage::GetOrCreateRegistration(
963 const ServiceWorkerDatabase::RegistrationData
& data
,
964 const ResourceList
& resources
) {
965 scoped_refptr
<ServiceWorkerRegistration
> registration
=
966 context_
->GetLiveRegistration(data
.registration_id
);
967 if (registration
.get())
970 registration
= new ServiceWorkerRegistration(
971 data
.scope
, data
.registration_id
, context_
);
972 registration
->set_last_update_check(data
.last_update_check
);
973 if (pending_deletions_
.find(data
.registration_id
) !=
974 pending_deletions_
.end()) {
975 registration
->set_is_deleted(true);
977 scoped_refptr
<ServiceWorkerVersion
> version
=
978 context_
->GetLiveVersion(data
.version_id
);
979 if (!version
.get()) {
980 version
= new ServiceWorkerVersion(
981 registration
.get(), data
.script
, data
.version_id
, context_
);
982 version
->SetStatus(data
.is_active
?
983 ServiceWorkerVersion::ACTIVATED
: ServiceWorkerVersion::INSTALLED
);
984 version
->script_cache_map()->SetResources(resources
);
987 if (version
->status() == ServiceWorkerVersion::ACTIVATED
)
988 registration
->SetActiveVersion(version
.get());
989 else if (version
->status() == ServiceWorkerVersion::INSTALLED
)
990 registration
->SetWaitingVersion(version
.get());
997 ServiceWorkerRegistration
*
998 ServiceWorkerStorage::FindInstallingRegistrationForDocument(
999 const GURL
& document_url
) {
1000 DCHECK(!document_url
.has_ref());
1002 LongestScopeMatcher
matcher(document_url
);
1003 ServiceWorkerRegistration
* match
= NULL
;
1005 // TODO(nhiroki): This searches over installing registrations linearly and it
1006 // couldn't be scalable. Maybe the regs should be partitioned by origin.
1007 for (RegistrationRefsById::const_iterator it
=
1008 installing_registrations_
.begin();
1009 it
!= installing_registrations_
.end(); ++it
) {
1010 if (matcher
.MatchLongest(it
->second
->pattern()))
1011 match
= it
->second
.get();
1016 ServiceWorkerRegistration
*
1017 ServiceWorkerStorage::FindInstallingRegistrationForPattern(
1018 const GURL
& scope
) {
1019 for (RegistrationRefsById::const_iterator it
=
1020 installing_registrations_
.begin();
1021 it
!= installing_registrations_
.end(); ++it
) {
1022 if (it
->second
->pattern() == scope
)
1023 return it
->second
.get();
1028 ServiceWorkerRegistration
*
1029 ServiceWorkerStorage::FindInstallingRegistrationForId(
1030 int64 registration_id
) {
1031 RegistrationRefsById::const_iterator found
=
1032 installing_registrations_
.find(registration_id
);
1033 if (found
== installing_registrations_
.end())
1035 return found
->second
.get();
1038 ServiceWorkerDiskCache
* ServiceWorkerStorage::disk_cache() {
1040 return disk_cache_
.get();
1042 disk_cache_
.reset(new ServiceWorkerDiskCache
);
1044 base::FilePath path
= GetDiskCachePath();
1046 int rv
= disk_cache_
->InitWithMemBackend(kMaxMemDiskCacheSize
,
1047 net::CompletionCallback());
1048 DCHECK_EQ(net::OK
, rv
);
1049 return disk_cache_
.get();
1052 int rv
= disk_cache_
->InitWithDiskBackend(
1057 base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized
,
1058 weak_factory_
.GetWeakPtr()));
1059 if (rv
!= net::ERR_IO_PENDING
)
1060 OnDiskCacheInitialized(rv
);
1062 return disk_cache_
.get();
1065 void ServiceWorkerStorage::OnDiskCacheInitialized(int rv
) {
1066 if (rv
!= net::OK
) {
1067 LOG(ERROR
) << "Failed to open the serviceworker diskcache: "
1068 << net::ErrorToString(rv
);
1069 ScheduleDeleteAndStartOver();
1071 ServiceWorkerMetrics::CountInitDiskCacheResult(rv
== net::OK
);
1074 void ServiceWorkerStorage::StartPurgingResources(
1075 const std::vector
<int64
>& ids
) {
1076 DCHECK(has_checked_for_stale_resources_
);
1077 for (size_t i
= 0; i
< ids
.size(); ++i
)
1078 purgeable_resource_ids_
.push_back(ids
[i
]);
1079 ContinuePurgingResources();
1082 void ServiceWorkerStorage::StartPurgingResources(
1083 const ResourceList
& resources
) {
1084 DCHECK(has_checked_for_stale_resources_
);
1085 for (size_t i
= 0; i
< resources
.size(); ++i
)
1086 purgeable_resource_ids_
.push_back(resources
[i
].resource_id
);
1087 ContinuePurgingResources();
1090 void ServiceWorkerStorage::ContinuePurgingResources() {
1091 if (purgeable_resource_ids_
.empty() || is_purge_pending_
)
1094 // Do one at a time until we're done, use RunSoon to avoid recursion when
1095 // DoomEntry returns immediately.
1096 is_purge_pending_
= true;
1097 int64 id
= purgeable_resource_ids_
.front();
1098 purgeable_resource_ids_
.pop_front();
1100 base::Bind(&ServiceWorkerStorage::PurgeResource
,
1101 weak_factory_
.GetWeakPtr(), id
));
1104 void ServiceWorkerStorage::PurgeResource(int64 id
) {
1105 DCHECK(is_purge_pending_
);
1106 int rv
= disk_cache()->DoomEntry(
1107 id
, base::Bind(&ServiceWorkerStorage::OnResourcePurged
,
1108 weak_factory_
.GetWeakPtr(), id
));
1109 if (rv
!= net::ERR_IO_PENDING
)
1110 OnResourcePurged(id
, rv
);
1113 void ServiceWorkerStorage::OnResourcePurged(int64 id
, int rv
) {
1114 DCHECK(is_purge_pending_
);
1115 is_purge_pending_
= false;
1117 database_task_runner_
->PostTask(
1119 base::Bind(base::IgnoreResult(
1120 &ServiceWorkerDatabase::ClearPurgeableResourceIds
),
1121 base::Unretained(database_
.get()),
1122 std::set
<int64
>(&id
, &id
+ 1)));
1124 ContinuePurgingResources();
1127 void ServiceWorkerStorage::DeleteStaleResources() {
1128 DCHECK(!has_checked_for_stale_resources_
);
1129 has_checked_for_stale_resources_
= true;
1130 database_task_runner_
->PostTask(
1132 base::Bind(&ServiceWorkerStorage::CollectStaleResourcesFromDB
,
1134 base::MessageLoopProxy::current(),
1135 base::Bind(&ServiceWorkerStorage::DidCollectStaleResources
,
1136 weak_factory_
.GetWeakPtr())));
1139 void ServiceWorkerStorage::DidCollectStaleResources(
1140 const std::vector
<int64
>& stale_resource_ids
,
1141 ServiceWorkerDatabase::Status status
) {
1142 DCHECK_EQ(ServiceWorkerDatabase::STATUS_OK
, status
);
1143 if (status
!= ServiceWorkerDatabase::STATUS_OK
)
1145 StartPurgingResources(stale_resource_ids
);
1148 void ServiceWorkerStorage::CollectStaleResourcesFromDB(
1149 ServiceWorkerDatabase
* database
,
1150 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1151 const GetResourcesCallback
& callback
) {
1152 std::set
<int64
> ids
;
1153 ServiceWorkerDatabase::Status status
=
1154 database
->GetUncommittedResourceIds(&ids
);
1155 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1156 original_task_runner
->PostTask(
1159 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1163 status
= database
->PurgeUncommittedResourceIds(ids
);
1164 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1165 original_task_runner
->PostTask(
1168 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1173 status
= database
->GetPurgeableResourceIds(&ids
);
1174 original_task_runner
->PostTask(
1176 base::Bind(callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1179 void ServiceWorkerStorage::ReadInitialDataFromDB(
1180 ServiceWorkerDatabase
* database
,
1181 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1182 const InitializeCallback
& callback
) {
1184 scoped_ptr
<ServiceWorkerStorage::InitialData
> data(
1185 new ServiceWorkerStorage::InitialData());
1187 ServiceWorkerDatabase::Status status
=
1188 database
->GetNextAvailableIds(&data
->next_registration_id
,
1189 &data
->next_version_id
,
1190 &data
->next_resource_id
);
1191 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1192 original_task_runner
->PostTask(
1193 FROM_HERE
, base::Bind(callback
, base::Owned(data
.release()), status
));
1197 status
= database
->GetOriginsWithRegistrations(&data
->origins
);
1198 original_task_runner
->PostTask(
1199 FROM_HERE
, base::Bind(callback
, base::Owned(data
.release()), status
));
1202 void ServiceWorkerStorage::DeleteRegistrationFromDB(
1203 ServiceWorkerDatabase
* database
,
1204 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1205 int64 registration_id
,
1207 const DeleteRegistrationCallback
& callback
) {
1210 int64 version_id
= kInvalidServiceWorkerVersionId
;
1211 std::vector
<int64
> newly_purgeable_resources
;
1212 ServiceWorkerDatabase::Status status
= database
->DeleteRegistration(
1213 registration_id
, origin
, &version_id
, &newly_purgeable_resources
);
1214 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1215 original_task_runner
->PostTask(FROM_HERE
,
1216 base::Bind(callback
,
1218 kInvalidServiceWorkerVersionId
,
1219 std::vector
<int64
>(),
1224 // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
1225 // unique origin list.
1226 std::vector
<ServiceWorkerDatabase::RegistrationData
> registrations
;
1227 status
= database
->GetRegistrationsForOrigin(origin
, ®istrations
);
1228 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1229 original_task_runner
->PostTask(FROM_HERE
,
1230 base::Bind(callback
,
1232 kInvalidServiceWorkerVersionId
,
1233 std::vector
<int64
>(),
1238 bool deletable
= registrations
.empty();
1239 original_task_runner
->PostTask(
1242 callback
, deletable
, version_id
, newly_purgeable_resources
, status
));
1245 void ServiceWorkerStorage::WriteRegistrationInDB(
1246 ServiceWorkerDatabase
* database
,
1247 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1248 const ServiceWorkerDatabase::RegistrationData
& data
,
1249 const ResourceList
& resources
,
1250 const WriteRegistrationCallback
& callback
) {
1252 int64 deleted_version_id
= kInvalidServiceWorkerVersionId
;
1253 std::vector
<int64
> newly_purgeable_resources
;
1254 ServiceWorkerDatabase::Status status
= database
->WriteRegistration(
1255 data
, resources
, &deleted_version_id
, &newly_purgeable_resources
);
1256 original_task_runner
->PostTask(FROM_HERE
,
1257 base::Bind(callback
,
1258 data
.script
.GetOrigin(),
1260 newly_purgeable_resources
,
1264 void ServiceWorkerStorage::FindForDocumentInDB(
1265 ServiceWorkerDatabase
* database
,
1266 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1267 const GURL
& document_url
,
1268 const FindInDBCallback
& callback
) {
1269 GURL origin
= document_url
.GetOrigin();
1270 RegistrationList registrations
;
1271 ServiceWorkerDatabase::Status status
=
1272 database
->GetRegistrationsForOrigin(origin
, ®istrations
);
1273 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1274 original_task_runner
->PostTask(
1276 base::Bind(callback
,
1277 ServiceWorkerDatabase::RegistrationData(),
1283 ServiceWorkerDatabase::RegistrationData data
;
1284 ResourceList resources
;
1285 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1287 // Find one with a pattern match.
1288 LongestScopeMatcher
matcher(document_url
);
1289 int64 match
= kInvalidServiceWorkerRegistrationId
;
1290 for (size_t i
= 0; i
< registrations
.size(); ++i
) {
1291 if (matcher
.MatchLongest(registrations
[i
].scope
))
1292 match
= registrations
[i
].registration_id
;
1295 if (match
!= kInvalidServiceWorkerRegistrationId
)
1296 status
= database
->ReadRegistration(match
, origin
, &data
, &resources
);
1298 original_task_runner
->PostTask(
1300 base::Bind(callback
, data
, resources
, status
));
1303 void ServiceWorkerStorage::FindForPatternInDB(
1304 ServiceWorkerDatabase
* database
,
1305 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1307 const FindInDBCallback
& callback
) {
1308 GURL origin
= scope
.GetOrigin();
1309 std::vector
<ServiceWorkerDatabase::RegistrationData
> registrations
;
1310 ServiceWorkerDatabase::Status status
=
1311 database
->GetRegistrationsForOrigin(origin
, ®istrations
);
1312 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1313 original_task_runner
->PostTask(
1315 base::Bind(callback
,
1316 ServiceWorkerDatabase::RegistrationData(),
1322 // Find one with an exact matching scope.
1323 ServiceWorkerDatabase::RegistrationData data
;
1324 ResourceList resources
;
1325 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1326 for (RegistrationList::const_iterator it
= registrations
.begin();
1327 it
!= registrations
.end(); ++it
) {
1328 if (scope
!= it
->scope
)
1330 status
= database
->ReadRegistration(it
->registration_id
, origin
,
1332 break; // We're done looping.
1335 original_task_runner
->PostTask(
1337 base::Bind(callback
, data
, resources
, status
));
1340 void ServiceWorkerStorage::FindForIdInDB(
1341 ServiceWorkerDatabase
* database
,
1342 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1343 int64 registration_id
,
1345 const FindInDBCallback
& callback
) {
1346 ServiceWorkerDatabase::RegistrationData data
;
1347 ResourceList resources
;
1348 ServiceWorkerDatabase::Status status
=
1349 database
->ReadRegistration(registration_id
, origin
, &data
, &resources
);
1350 original_task_runner
->PostTask(
1351 FROM_HERE
, base::Bind(callback
, data
, resources
, status
));
1354 // TODO(nhiroki): The corruption recovery should not be scheduled if the error
1355 // is transient and it can get healed soon (e.g. IO error). To do that, the
1356 // database should not disable itself when an error occurs and the storage
1357 // controls it instead.
1358 void ServiceWorkerStorage::ScheduleDeleteAndStartOver() {
1359 if (state_
== DISABLED
) {
1360 // Recovery process has already been scheduled.
1365 DVLOG(1) << "Schedule to delete the context and start over.";
1366 context_
->ScheduleDeleteAndStartOver();
1369 void ServiceWorkerStorage::DidDeleteDatabase(
1370 const StatusCallback
& callback
,
1371 ServiceWorkerDatabase::Status status
) {
1372 DCHECK_EQ(DISABLED
, state_
);
1373 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1374 // Give up the corruption recovery until the browser restarts.
1375 LOG(ERROR
) << "Failed to delete the database: " << status
;
1376 callback
.Run(DatabaseStatusToStatusCode(status
));
1379 DVLOG(1) << "Deleted ServiceWorkerDatabase successfully.";
1381 // Delete the disk cache on the cache thread.
1382 // TODO(nhiroki): What if there is a bunch of files in the cache directory?
1383 // Deleting the directory could take a long time and restart could be delayed.
1384 // We should probably rename the directory and delete it later.
1385 PostTaskAndReplyWithResult(
1386 database_task_runner_
.get(),
1388 base::Bind(&base::DeleteFile
, GetDiskCachePath(), true),
1389 base::Bind(&ServiceWorkerStorage::DidDeleteDiskCache
,
1390 weak_factory_
.GetWeakPtr(),
1394 void ServiceWorkerStorage::DidDeleteDiskCache(
1395 const StatusCallback
& callback
, bool result
) {
1396 DCHECK_EQ(DISABLED
, state_
);
1398 // Give up the corruption recovery until the browser restarts.
1399 LOG(ERROR
) << "Failed to delete the diskcache.";
1400 callback
.Run(SERVICE_WORKER_ERROR_FAILED
);
1403 DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully.";
1404 callback
.Run(SERVICE_WORKER_OK
);
1407 } // namespace content