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"
7 #include "base/bind_helpers.h"
8 #include "base/files/file_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/task_runner_util.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/trace_event/trace_event.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_disk_cache_migrator.h"
18 #include "content/browser/service_worker/service_worker_info.h"
19 #include "content/browser/service_worker/service_worker_registration.h"
20 #include "content/browser/service_worker/service_worker_version.h"
21 #include "content/common/service_worker/service_worker_types.h"
22 #include "content/common/service_worker/service_worker_utils.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 "storage/browser/quota/quota_manager_proxy.h"
28 #include "storage/browser/quota/special_storage_policy.h"
34 void RunSoon(const tracked_objects::Location
& from_here
,
35 const base::Closure
& closure
) {
36 base::ThreadTaskRunnerHandle::Get()->PostTask(from_here
, closure
);
40 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
41 ServiceWorkerStatusCode status
,
42 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
43 if (registration
&& registration
->is_deleted()) {
44 // It's past the point of no return and no longer findable.
45 callback
.Run(SERVICE_WORKER_ERROR_NOT_FOUND
, nullptr);
48 callback
.Run(status
, registration
);
51 void CompleteFindSoon(
52 const tracked_objects::Location
& from_here
,
53 const scoped_refptr
<ServiceWorkerRegistration
>& registration
,
54 ServiceWorkerStatusCode status
,
55 const ServiceWorkerStorage::FindRegistrationCallback
& callback
) {
57 base::Bind(&CompleteFindNow
, registration
, status
, callback
));
60 const base::FilePath::CharType kDatabaseName
[] =
61 FILE_PATH_LITERAL("Database");
62 const base::FilePath::CharType kDiskCacheName
[] =
63 FILE_PATH_LITERAL("ScriptCache");
64 const base::FilePath::CharType kOldDiskCacheName
[] = FILE_PATH_LITERAL("Cache");
66 const int kMaxMemDiskCacheSize
= 10 * 1024 * 1024;
67 const int kMaxDiskCacheSize
= 250 * 1024 * 1024;
69 ServiceWorkerStatusCode
DatabaseStatusToStatusCode(
70 ServiceWorkerDatabase::Status status
) {
72 case ServiceWorkerDatabase::STATUS_OK
:
73 return SERVICE_WORKER_OK
;
74 case ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
:
75 return SERVICE_WORKER_ERROR_NOT_FOUND
;
76 case ServiceWorkerDatabase::STATUS_ERROR_MAX
:
79 return SERVICE_WORKER_ERROR_FAILED
;
85 ServiceWorkerStorage::InitialData::InitialData()
86 : next_registration_id(kInvalidServiceWorkerRegistrationId
),
87 next_version_id(kInvalidServiceWorkerVersionId
),
88 next_resource_id(kInvalidServiceWorkerResourceId
),
89 disk_cache_migration_needed(false),
90 old_disk_cache_deletion_needed(false) {
93 ServiceWorkerStorage::InitialData::~InitialData() {
96 ServiceWorkerStorage::
97 DidDeleteRegistrationParams::DidDeleteRegistrationParams()
98 : registration_id(kInvalidServiceWorkerRegistrationId
) {
101 ServiceWorkerStorage::
102 DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
105 ServiceWorkerStorage::~ServiceWorkerStorage() {
106 ClearSessionOnlyOrigins();
107 weak_factory_
.InvalidateWeakPtrs();
108 database_task_manager_
->GetTaskRunner()->DeleteSoon(FROM_HERE
,
109 database_
.release());
113 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
114 const base::FilePath
& path
,
115 const base::WeakPtr
<ServiceWorkerContextCore
>& context
,
116 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager
,
117 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
118 storage::QuotaManagerProxy
* quota_manager_proxy
,
119 storage::SpecialStoragePolicy
* special_storage_policy
) {
120 return make_scoped_ptr(new ServiceWorkerStorage(path
,
122 database_task_manager
.Pass(),
125 special_storage_policy
));
129 scoped_ptr
<ServiceWorkerStorage
> ServiceWorkerStorage::Create(
130 const base::WeakPtr
<ServiceWorkerContextCore
>& context
,
131 ServiceWorkerStorage
* old_storage
) {
132 return make_scoped_ptr(
133 new ServiceWorkerStorage(old_storage
->path_
,
135 old_storage
->database_task_manager_
->Clone(),
136 old_storage
->disk_cache_thread_
,
137 old_storage
->quota_manager_proxy_
.get(),
138 old_storage
->special_storage_policy_
.get()));
141 void ServiceWorkerStorage::FindRegistrationForDocument(
142 const GURL
& document_url
,
143 const FindRegistrationCallback
& callback
) {
144 DCHECK(!document_url
.has_ref());
145 if (!LazyInitialize(base::Bind(
146 &ServiceWorkerStorage::FindRegistrationForDocument
,
147 weak_factory_
.GetWeakPtr(), document_url
, callback
))) {
148 if (state_
!= INITIALIZING
) {
149 CompleteFindNow(scoped_refptr
<ServiceWorkerRegistration
>(),
150 SERVICE_WORKER_ERROR_FAILED
, callback
);
152 TRACE_EVENT_INSTANT1(
154 "ServiceWorkerStorage::FindRegistrationForDocument:LazyInitialize",
155 TRACE_EVENT_SCOPE_THREAD
,
156 "URL", document_url
.spec());
159 DCHECK_EQ(INITIALIZED
, state_
);
161 // See if there are any stored registrations for the origin.
162 if (!ContainsKey(registered_origins_
, document_url
.GetOrigin())) {
163 // Look for something currently being installed.
164 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
165 FindInstallingRegistrationForDocument(document_url
);
166 ServiceWorkerStatusCode status
= installing_registration
168 : SERVICE_WORKER_ERROR_NOT_FOUND
;
169 TRACE_EVENT_INSTANT2(
171 "ServiceWorkerStorage::FindRegistrationForDocument:CheckInstalling",
172 TRACE_EVENT_SCOPE_THREAD
,
173 "URL", document_url
.spec(),
174 "Status", ServiceWorkerStatusToString(status
));
175 CompleteFindNow(installing_registration
,
181 // To connect this TRACE_EVENT with the callback, TimeTicks is used for
183 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
184 TRACE_EVENT_ASYNC_BEGIN1(
186 "ServiceWorkerStorage::FindRegistrationForDocument",
188 "URL", document_url
.spec());
189 database_task_manager_
->GetTaskRunner()->PostTask(
192 &FindForDocumentInDB
,
194 base::ThreadTaskRunnerHandle::Get(),
196 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument
,
197 weak_factory_
.GetWeakPtr(),
203 void ServiceWorkerStorage::FindRegistrationForPattern(
205 const FindRegistrationCallback
& callback
) {
206 if (!LazyInitialize(base::Bind(
207 &ServiceWorkerStorage::FindRegistrationForPattern
,
208 weak_factory_
.GetWeakPtr(), scope
, callback
))) {
209 if (state_
!= INITIALIZING
) {
210 CompleteFindSoon(FROM_HERE
, scoped_refptr
<ServiceWorkerRegistration
>(),
211 SERVICE_WORKER_ERROR_FAILED
, callback
);
215 DCHECK_EQ(INITIALIZED
, state_
);
217 // See if there are any stored registrations for the origin.
218 if (!ContainsKey(registered_origins_
, scope
.GetOrigin())) {
219 // Look for something currently being installed.
220 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
221 FindInstallingRegistrationForPattern(scope
);
222 CompleteFindSoon(FROM_HERE
, installing_registration
,
223 installing_registration
? SERVICE_WORKER_OK
224 : SERVICE_WORKER_ERROR_NOT_FOUND
,
229 database_task_manager_
->GetTaskRunner()->PostTask(
234 base::ThreadTaskRunnerHandle::Get(),
236 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForPattern
,
237 weak_factory_
.GetWeakPtr(),
242 ServiceWorkerRegistration
* ServiceWorkerStorage::GetUninstallingRegistration(
244 if (state_
!= INITIALIZED
)
246 for (const auto& registration
: uninstalling_registrations_
) {
247 if (registration
.second
->pattern() == scope
) {
248 DCHECK(registration
.second
->is_uninstalling());
249 return registration
.second
.get();
255 void ServiceWorkerStorage::FindRegistrationForId(
256 int64 registration_id
,
258 const FindRegistrationCallback
& callback
) {
259 if (!LazyInitialize(base::Bind(
260 &ServiceWorkerStorage::FindRegistrationForId
,
261 weak_factory_
.GetWeakPtr(), registration_id
, origin
, callback
))) {
262 if (state_
!= INITIALIZING
) {
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_
, origin
)) {
272 // Look for something currently being installed.
273 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
274 FindInstallingRegistrationForId(registration_id
);
275 CompleteFindNow(installing_registration
,
276 installing_registration
? SERVICE_WORKER_OK
277 : SERVICE_WORKER_ERROR_NOT_FOUND
,
282 scoped_refptr
<ServiceWorkerRegistration
> registration
=
283 context_
->GetLiveRegistration(registration_id
);
285 CompleteFindNow(registration
, SERVICE_WORKER_OK
, callback
);
289 database_task_manager_
->GetTaskRunner()->PostTask(
291 base::Bind(&FindForIdInDB
,
293 base::ThreadTaskRunnerHandle::Get(),
296 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId
,
297 weak_factory_
.GetWeakPtr(),
301 void ServiceWorkerStorage::FindRegistrationForIdOnly(
302 int64 registration_id
,
303 const FindRegistrationCallback
& callback
) {
305 base::Bind(&ServiceWorkerStorage::FindRegistrationForIdOnly
,
306 weak_factory_
.GetWeakPtr(), registration_id
, callback
))) {
307 if (state_
!= INITIALIZING
) {
308 CompleteFindNow(nullptr, SERVICE_WORKER_ERROR_FAILED
, callback
);
312 DCHECK_EQ(INITIALIZED
, state_
);
314 scoped_refptr
<ServiceWorkerRegistration
> registration
=
315 context_
->GetLiveRegistration(registration_id
);
317 // Delegate to FindRegistrationForId to make sure the same subset of live
318 // registrations is returned.
319 // TODO(mek): CompleteFindNow should really do all the required checks, so
320 // calling that directly here should be enough.
321 FindRegistrationForId(registration_id
, registration
->pattern().GetOrigin(),
326 database_task_manager_
->GetTaskRunner()->PostTask(
328 base::Bind(&FindForIdOnlyInDB
,
330 base::ThreadTaskRunnerHandle::Get(),
332 base::Bind(&ServiceWorkerStorage::DidFindRegistrationForId
,
333 weak_factory_
.GetWeakPtr(),
337 void ServiceWorkerStorage::GetRegistrationsForOrigin(
339 const GetRegistrationsCallback
& callback
) {
340 if (!LazyInitialize(base::Bind(
341 &ServiceWorkerStorage::GetRegistrationsForOrigin
,
342 weak_factory_
.GetWeakPtr(), origin
, callback
))) {
343 if (state_
!= INITIALIZING
) {
347 std::vector
<scoped_refptr
<ServiceWorkerRegistration
>>()));
351 DCHECK_EQ(INITIALIZED
, state_
);
353 RegistrationList
* registrations
= new RegistrationList
;
354 std::vector
<ResourceList
>* resource_lists
= new std::vector
<ResourceList
>;
355 PostTaskAndReplyWithResult(
356 database_task_manager_
->GetTaskRunner(), FROM_HERE
,
357 base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin
,
358 base::Unretained(database_
.get()), origin
, registrations
,
360 base::Bind(&ServiceWorkerStorage::DidGetRegistrations
,
361 weak_factory_
.GetWeakPtr(), callback
,
362 base::Owned(registrations
), base::Owned(resource_lists
),
366 void ServiceWorkerStorage::GetAllRegistrationsInfos(
367 const GetRegistrationsInfosCallback
& callback
) {
369 base::Bind(&ServiceWorkerStorage::GetAllRegistrationsInfos
,
370 weak_factory_
.GetWeakPtr(), callback
))) {
371 if (state_
!= INITIALIZING
) {
372 RunSoon(FROM_HERE
, base::Bind(
373 callback
, std::vector
<ServiceWorkerRegistrationInfo
>()));
377 DCHECK_EQ(INITIALIZED
, state_
);
379 RegistrationList
* registrations
= new RegistrationList
;
380 PostTaskAndReplyWithResult(
381 database_task_manager_
->GetTaskRunner(), FROM_HERE
,
382 base::Bind(&ServiceWorkerDatabase::GetAllRegistrations
,
383 base::Unretained(database_
.get()), registrations
),
384 base::Bind(&ServiceWorkerStorage::DidGetRegistrationsInfos
,
385 weak_factory_
.GetWeakPtr(), callback
,
386 base::Owned(registrations
), GURL()));
389 void ServiceWorkerStorage::StoreRegistration(
390 ServiceWorkerRegistration
* registration
,
391 ServiceWorkerVersion
* version
,
392 const StatusCallback
& callback
) {
393 DCHECK(registration
);
396 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
398 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
402 ServiceWorkerDatabase::RegistrationData data
;
403 data
.registration_id
= registration
->id();
404 data
.scope
= registration
->pattern();
405 data
.script
= version
->script_url();
406 data
.has_fetch_handler
= true;
407 data
.version_id
= version
->version_id();
408 data
.last_update_check
= registration
->last_update_check();
409 data
.is_active
= (version
== registration
->active_version());
411 ResourceList resources
;
412 version
->script_cache_map()->GetResources(&resources
);
414 if (resources
.empty()) {
415 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
419 uint64 resources_total_size_bytes
= 0;
420 for (const auto& resource
: resources
) {
421 resources_total_size_bytes
+= resource
.size_bytes
;
423 data
.resources_total_size_bytes
= resources_total_size_bytes
;
425 if (!has_checked_for_stale_resources_
)
426 DeleteStaleResources();
428 database_task_manager_
->GetTaskRunner()->PostTask(
430 base::Bind(&WriteRegistrationInDB
,
432 base::ThreadTaskRunnerHandle::Get(),
435 base::Bind(&ServiceWorkerStorage::DidStoreRegistration
,
436 weak_factory_
.GetWeakPtr(),
440 registration
->set_is_deleted(false);
443 void ServiceWorkerStorage::UpdateToActiveState(
444 ServiceWorkerRegistration
* registration
,
445 const StatusCallback
& callback
) {
446 DCHECK(registration
);
448 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
450 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
454 PostTaskAndReplyWithResult(
455 database_task_manager_
->GetTaskRunner(),
457 base::Bind(&ServiceWorkerDatabase::UpdateVersionToActive
,
458 base::Unretained(database_
.get()),
460 registration
->pattern().GetOrigin()),
461 base::Bind(&ServiceWorkerStorage::DidUpdateToActiveState
,
462 weak_factory_
.GetWeakPtr(),
466 void ServiceWorkerStorage::UpdateLastUpdateCheckTime(
467 ServiceWorkerRegistration
* registration
) {
468 DCHECK(registration
);
470 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
474 database_task_manager_
->GetTaskRunner()->PostTask(
477 base::IgnoreResult(&ServiceWorkerDatabase::UpdateLastCheckTime
),
478 base::Unretained(database_
.get()),
480 registration
->pattern().GetOrigin(),
481 registration
->last_update_check()));
484 void ServiceWorkerStorage::DeleteRegistration(
485 int64 registration_id
,
487 const StatusCallback
& callback
) {
488 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
490 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
494 if (!has_checked_for_stale_resources_
)
495 DeleteStaleResources();
497 DidDeleteRegistrationParams params
;
498 params
.registration_id
= registration_id
;
499 params
.origin
= origin
;
500 params
.callback
= callback
;
502 database_task_manager_
->GetTaskRunner()->PostTask(
504 base::Bind(&DeleteRegistrationFromDB
,
506 base::ThreadTaskRunnerHandle::Get(),
509 base::Bind(&ServiceWorkerStorage::DidDeleteRegistration
,
510 weak_factory_
.GetWeakPtr(),
513 // The registration should no longer be findable.
514 pending_deletions_
.insert(registration_id
);
515 ServiceWorkerRegistration
* registration
=
516 context_
->GetLiveRegistration(registration_id
);
518 registration
->set_is_deleted(true);
521 scoped_ptr
<ServiceWorkerResponseReader
>
522 ServiceWorkerStorage::CreateResponseReader(int64 response_id
) {
523 return make_scoped_ptr(
524 new ServiceWorkerResponseReader(response_id
, disk_cache()));
527 scoped_ptr
<ServiceWorkerResponseWriter
>
528 ServiceWorkerStorage::CreateResponseWriter(int64 response_id
) {
529 return make_scoped_ptr(
530 new ServiceWorkerResponseWriter(response_id
, disk_cache()));
533 scoped_ptr
<ServiceWorkerResponseMetadataWriter
>
534 ServiceWorkerStorage::CreateResponseMetadataWriter(int64 response_id
) {
535 return make_scoped_ptr(
536 new ServiceWorkerResponseMetadataWriter(response_id
, disk_cache()));
539 void ServiceWorkerStorage::StoreUncommittedResponseId(int64 id
) {
540 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
541 DCHECK_EQ(INITIALIZED
, state_
);
543 if (!has_checked_for_stale_resources_
)
544 DeleteStaleResources();
546 database_task_manager_
->GetTaskRunner()->PostTask(
548 base::Bind(base::IgnoreResult(
549 &ServiceWorkerDatabase::WriteUncommittedResourceIds
),
550 base::Unretained(database_
.get()),
551 std::set
<int64
>(&id
, &id
+ 1)));
554 void ServiceWorkerStorage::DoomUncommittedResponse(int64 id
) {
555 DCHECK_NE(kInvalidServiceWorkerResponseId
, id
);
556 database_task_manager_
->GetTaskRunner()->PostTask(
558 base::Bind(base::IgnoreResult(
559 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
560 base::Unretained(database_
.get()),
561 std::set
<int64
>(&id
, &id
+ 1)));
562 StartPurgingResources(std::vector
<int64
>(1, id
));
565 void ServiceWorkerStorage::StoreUserData(
566 int64 registration_id
,
568 const std::string
& key
,
569 const std::string
& data
,
570 const StatusCallback
& callback
) {
571 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
573 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
577 if (registration_id
== kInvalidServiceWorkerRegistrationId
|| key
.empty()) {
578 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
582 PostTaskAndReplyWithResult(
583 database_task_manager_
->GetTaskRunner(),
585 base::Bind(&ServiceWorkerDatabase::WriteUserData
,
586 base::Unretained(database_
.get()),
587 registration_id
, origin
, key
, data
),
588 base::Bind(&ServiceWorkerStorage::DidStoreUserData
,
589 weak_factory_
.GetWeakPtr(),
593 void ServiceWorkerStorage::GetUserData(
594 int64 registration_id
,
595 const std::string
& key
,
596 const GetUserDataCallback
& callback
) {
597 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
600 base::Bind(callback
, std::string(), SERVICE_WORKER_ERROR_FAILED
));
604 if (registration_id
== kInvalidServiceWorkerRegistrationId
|| key
.empty()) {
606 base::Bind(callback
, std::string(), SERVICE_WORKER_ERROR_FAILED
));
610 database_task_manager_
->GetTaskRunner()->PostTask(
612 base::Bind(&ServiceWorkerStorage::GetUserDataInDB
,
614 base::ThreadTaskRunnerHandle::Get(),
617 base::Bind(&ServiceWorkerStorage::DidGetUserData
,
618 weak_factory_
.GetWeakPtr(),
622 void ServiceWorkerStorage::ClearUserData(
623 int64 registration_id
,
624 const std::string
& key
,
625 const StatusCallback
& callback
) {
626 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
628 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
632 if (registration_id
== kInvalidServiceWorkerRegistrationId
|| key
.empty()) {
633 RunSoon(FROM_HERE
, base::Bind(callback
, SERVICE_WORKER_ERROR_FAILED
));
637 PostTaskAndReplyWithResult(
638 database_task_manager_
->GetTaskRunner(),
640 base::Bind(&ServiceWorkerDatabase::DeleteUserData
,
641 base::Unretained(database_
.get()),
642 registration_id
, key
),
643 base::Bind(&ServiceWorkerStorage::DidDeleteUserData
,
644 weak_factory_
.GetWeakPtr(),
648 void ServiceWorkerStorage::GetUserDataForAllRegistrations(
649 const std::string
& key
,
650 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback
&
653 base::Bind(&ServiceWorkerStorage::GetUserDataForAllRegistrations
,
654 weak_factory_
.GetWeakPtr(), key
, callback
))) {
655 if (state_
!= INITIALIZING
) {
657 base::Bind(callback
, std::vector
<std::pair
<int64
, std::string
>>(),
658 SERVICE_WORKER_ERROR_FAILED
));
662 DCHECK_EQ(INITIALIZED
, state_
);
666 base::Bind(callback
, std::vector
<std::pair
<int64
, std::string
>>(),
667 SERVICE_WORKER_ERROR_FAILED
));
671 database_task_manager_
->GetTaskRunner()->PostTask(
674 &ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB
,
676 base::ThreadTaskRunnerHandle::Get(),
678 base::Bind(&ServiceWorkerStorage::DidGetUserDataForAllRegistrations
,
679 weak_factory_
.GetWeakPtr(),
683 void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback
& callback
) {
686 // Delete the database on the database thread.
687 PostTaskAndReplyWithResult(
688 database_task_manager_
->GetTaskRunner(), FROM_HERE
,
689 base::Bind(&ServiceWorkerDatabase::DestroyDatabase
,
690 base::Unretained(database_
.get())),
691 base::Bind(&ServiceWorkerStorage::DidDeleteDatabase
,
692 weak_factory_
.GetWeakPtr(), callback
));
695 int64
ServiceWorkerStorage::NewRegistrationId() {
696 if (state_
== DISABLED
)
697 return kInvalidServiceWorkerRegistrationId
;
698 DCHECK_EQ(INITIALIZED
, state_
);
699 return next_registration_id_
++;
702 int64
ServiceWorkerStorage::NewVersionId() {
703 if (state_
== DISABLED
)
704 return kInvalidServiceWorkerVersionId
;
705 DCHECK_EQ(INITIALIZED
, state_
);
706 return next_version_id_
++;
709 int64
ServiceWorkerStorage::NewResourceId() {
710 if (state_
== DISABLED
)
711 return kInvalidServiceWorkerResourceId
;
712 DCHECK_EQ(INITIALIZED
, state_
);
713 return next_resource_id_
++;
716 void ServiceWorkerStorage::NotifyInstallingRegistration(
717 ServiceWorkerRegistration
* registration
) {
718 DCHECK(installing_registrations_
.find(registration
->id()) ==
719 installing_registrations_
.end());
720 installing_registrations_
[registration
->id()] = registration
;
723 void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
724 ServiceWorkerRegistration
* registration
,
725 ServiceWorkerVersion
* version
,
726 ServiceWorkerStatusCode status
) {
727 installing_registrations_
.erase(registration
->id());
728 if (status
!= SERVICE_WORKER_OK
&& version
) {
729 ResourceList resources
;
730 version
->script_cache_map()->GetResources(&resources
);
733 for (const auto& resource
: resources
)
734 ids
.insert(resource
.resource_id
);
736 database_task_manager_
->GetTaskRunner()->PostTask(
738 base::Bind(base::IgnoreResult(
739 &ServiceWorkerDatabase::PurgeUncommittedResourceIds
),
740 base::Unretained(database_
.get()),
745 void ServiceWorkerStorage::NotifyUninstallingRegistration(
746 ServiceWorkerRegistration
* registration
) {
747 DCHECK(uninstalling_registrations_
.find(registration
->id()) ==
748 uninstalling_registrations_
.end());
749 uninstalling_registrations_
[registration
->id()] = registration
;
752 void ServiceWorkerStorage::NotifyDoneUninstallingRegistration(
753 ServiceWorkerRegistration
* registration
) {
754 uninstalling_registrations_
.erase(registration
->id());
757 void ServiceWorkerStorage::Disable() {
760 disk_cache_
->Disable();
763 bool ServiceWorkerStorage::IsDisabled() const {
764 return state_
== DISABLED
;
767 void ServiceWorkerStorage::PurgeResources(const ResourceList
& resources
) {
768 if (!has_checked_for_stale_resources_
)
769 DeleteStaleResources();
770 StartPurgingResources(resources
);
773 ServiceWorkerStorage::ServiceWorkerStorage(
774 const base::FilePath
& path
,
775 base::WeakPtr
<ServiceWorkerContextCore
> context
,
776 scoped_ptr
<ServiceWorkerDatabaseTaskManager
> database_task_manager
,
777 const scoped_refptr
<base::SingleThreadTaskRunner
>& disk_cache_thread
,
778 storage::QuotaManagerProxy
* quota_manager_proxy
,
779 storage::SpecialStoragePolicy
* special_storage_policy
)
780 : next_registration_id_(kInvalidServiceWorkerRegistrationId
),
781 next_version_id_(kInvalidServiceWorkerVersionId
),
782 next_resource_id_(kInvalidServiceWorkerResourceId
),
783 state_(UNINITIALIZED
),
786 database_task_manager_(database_task_manager
.Pass()),
787 disk_cache_thread_(disk_cache_thread
),
788 quota_manager_proxy_(quota_manager_proxy
),
789 special_storage_policy_(special_storage_policy
),
790 disk_cache_migration_needed_(false),
791 old_disk_cache_deletion_needed_(false),
792 is_purge_pending_(false),
793 has_checked_for_stale_resources_(false),
794 weak_factory_(this) {
796 database_
.reset(new ServiceWorkerDatabase(GetDatabasePath()));
799 base::FilePath
ServiceWorkerStorage::GetDatabasePath() {
801 return base::FilePath();
802 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
803 .Append(kDatabaseName
);
806 base::FilePath
ServiceWorkerStorage::GetDiskCachePath() {
808 return base::FilePath();
809 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
810 .Append(kDiskCacheName
);
813 base::FilePath
ServiceWorkerStorage::GetOldDiskCachePath() {
815 return base::FilePath();
816 return path_
.Append(ServiceWorkerContextCore::kServiceWorkerDirectory
)
817 .Append(kOldDiskCacheName
);
820 bool ServiceWorkerStorage::LazyInitialize(const base::Closure
& callback
) {
827 pending_tasks_
.push_back(callback
);
830 pending_tasks_
.push_back(callback
);
834 state_
= INITIALIZING
;
835 database_task_manager_
->GetTaskRunner()->PostTask(
837 base::Bind(&ReadInitialDataFromDB
,
839 base::ThreadTaskRunnerHandle::Get(),
840 base::Bind(&ServiceWorkerStorage::DidReadInitialData
,
841 weak_factory_
.GetWeakPtr())));
845 void ServiceWorkerStorage::DidReadInitialData(
846 scoped_ptr
<InitialData
> data
,
847 ServiceWorkerDatabase::Status status
) {
849 DCHECK_EQ(INITIALIZING
, state_
);
851 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
852 next_registration_id_
= data
->next_registration_id
;
853 next_version_id_
= data
->next_version_id
;
854 next_resource_id_
= data
->next_resource_id
;
855 registered_origins_
.swap(data
->origins
);
856 disk_cache_migration_needed_
= data
->disk_cache_migration_needed
;
857 old_disk_cache_deletion_needed_
= data
->old_disk_cache_deletion_needed
;
858 state_
= INITIALIZED
;
860 DVLOG(2) << "Failed to initialize: "
861 << ServiceWorkerDatabase::StatusToString(status
);
862 ScheduleDeleteAndStartOver();
865 for (const auto& task
: pending_tasks_
)
866 RunSoon(FROM_HERE
, task
);
867 pending_tasks_
.clear();
870 void ServiceWorkerStorage::DidFindRegistrationForDocument(
871 const GURL
& document_url
,
872 const FindRegistrationCallback
& callback
,
874 const ServiceWorkerDatabase::RegistrationData
& data
,
875 const ResourceList
& resources
,
876 ServiceWorkerDatabase::Status status
) {
877 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
878 ReturnFoundRegistration(callback
, data
, resources
);
879 TRACE_EVENT_ASYNC_END1(
881 "ServiceWorkerStorage::FindRegistrationForDocument",
883 "Status", ServiceWorkerDatabase::StatusToString(status
));
887 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
888 // Look for something currently being installed.
889 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
890 FindInstallingRegistrationForDocument(document_url
);
891 ServiceWorkerStatusCode installing_status
=
892 installing_registration
? SERVICE_WORKER_OK
893 : SERVICE_WORKER_ERROR_NOT_FOUND
;
894 callback
.Run(installing_status
, installing_registration
);
895 TRACE_EVENT_ASYNC_END2(
897 "ServiceWorkerStorage::FindRegistrationForDocument",
899 "Status", ServiceWorkerDatabase::StatusToString(status
),
901 (installing_status
== SERVICE_WORKER_OK
) ?
902 "Installing registration is found" :
903 "Any registrations are not found");
907 ScheduleDeleteAndStartOver();
908 callback
.Run(DatabaseStatusToStatusCode(status
),
909 scoped_refptr
<ServiceWorkerRegistration
>());
910 TRACE_EVENT_ASYNC_END1(
912 "ServiceWorkerStorage::FindRegistrationForDocument",
914 "Status", ServiceWorkerDatabase::StatusToString(status
));
917 void ServiceWorkerStorage::DidFindRegistrationForPattern(
919 const FindRegistrationCallback
& callback
,
920 const ServiceWorkerDatabase::RegistrationData
& data
,
921 const ResourceList
& resources
,
922 ServiceWorkerDatabase::Status status
) {
923 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
924 ReturnFoundRegistration(callback
, data
, resources
);
928 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
929 scoped_refptr
<ServiceWorkerRegistration
> installing_registration
=
930 FindInstallingRegistrationForPattern(scope
);
931 callback
.Run(installing_registration
? SERVICE_WORKER_OK
932 : SERVICE_WORKER_ERROR_NOT_FOUND
,
933 installing_registration
);
937 ScheduleDeleteAndStartOver();
938 callback
.Run(DatabaseStatusToStatusCode(status
),
939 scoped_refptr
<ServiceWorkerRegistration
>());
942 void ServiceWorkerStorage::DidFindRegistrationForId(
943 const FindRegistrationCallback
& callback
,
944 const ServiceWorkerDatabase::RegistrationData
& data
,
945 const ResourceList
& resources
,
946 ServiceWorkerDatabase::Status status
) {
947 if (status
== ServiceWorkerDatabase::STATUS_OK
) {
948 ReturnFoundRegistration(callback
, data
, resources
);
952 if (status
== ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
953 // TODO(nhiroki): Find a registration in |installing_registrations_|.
954 callback
.Run(DatabaseStatusToStatusCode(status
),
955 scoped_refptr
<ServiceWorkerRegistration
>());
959 ScheduleDeleteAndStartOver();
960 callback
.Run(DatabaseStatusToStatusCode(status
),
961 scoped_refptr
<ServiceWorkerRegistration
>());
964 void ServiceWorkerStorage::ReturnFoundRegistration(
965 const FindRegistrationCallback
& callback
,
966 const ServiceWorkerDatabase::RegistrationData
& data
,
967 const ResourceList
& resources
) {
968 DCHECK(!resources
.empty());
969 scoped_refptr
<ServiceWorkerRegistration
> registration
=
970 GetOrCreateRegistration(data
, resources
);
971 CompleteFindNow(registration
, SERVICE_WORKER_OK
, callback
);
974 void ServiceWorkerStorage::DidGetRegistrations(
975 const GetRegistrationsCallback
& callback
,
976 RegistrationList
* registration_data_list
,
977 std::vector
<ResourceList
>* resources_list
,
978 const GURL
& origin_filter
,
979 ServiceWorkerDatabase::Status status
) {
980 DCHECK(registration_data_list
);
981 DCHECK(resources_list
);
983 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
984 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
985 ScheduleDeleteAndStartOver();
986 callback
.Run(std::vector
<scoped_refptr
<ServiceWorkerRegistration
>>());
990 // Add all stored registrations.
991 std::set
<int64
> registration_ids
;
992 std::vector
<scoped_refptr
<ServiceWorkerRegistration
>> registrations
;
994 for (const auto& registration_data
: *registration_data_list
) {
995 registration_ids
.insert(registration_data
.registration_id
);
996 registrations
.push_back(GetOrCreateRegistration(
997 registration_data
, resources_list
->at(index
++)));
1000 // Add unstored registrations that are being installed.
1001 for (const auto& registration
: installing_registrations_
) {
1002 if ((!origin_filter
.is_valid() ||
1003 registration
.second
->pattern().GetOrigin() == origin_filter
) &&
1004 registration_ids
.insert(registration
.first
).second
) {
1005 registrations
.push_back(registration
.second
);
1009 callback
.Run(registrations
);
1012 void ServiceWorkerStorage::DidGetRegistrationsInfos(
1013 const GetRegistrationsInfosCallback
& callback
,
1014 RegistrationList
* registration_data_list
,
1015 const GURL
& origin_filter
,
1016 ServiceWorkerDatabase::Status status
) {
1017 DCHECK(registration_data_list
);
1018 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1019 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1020 ScheduleDeleteAndStartOver();
1021 callback
.Run(std::vector
<ServiceWorkerRegistrationInfo
>());
1025 // Add all stored registrations.
1026 std::set
<int64
> pushed_registrations
;
1027 std::vector
<ServiceWorkerRegistrationInfo
> infos
;
1028 for (const auto& registration_data
: *registration_data_list
) {
1029 const bool inserted
=
1030 pushed_registrations
.insert(registration_data
.registration_id
).second
;
1033 ServiceWorkerRegistration
* registration
=
1034 context_
->GetLiveRegistration(registration_data
.registration_id
);
1036 infos
.push_back(registration
->GetInfo());
1040 ServiceWorkerRegistrationInfo info
;
1041 info
.pattern
= registration_data
.scope
;
1042 info
.registration_id
= registration_data
.registration_id
;
1043 info
.stored_version_size_bytes
=
1044 registration_data
.resources_total_size_bytes
;
1045 if (ServiceWorkerVersion
* version
=
1046 context_
->GetLiveVersion(registration_data
.version_id
)) {
1047 if (registration_data
.is_active
)
1048 info
.active_version
= version
->GetInfo();
1050 info
.waiting_version
= version
->GetInfo();
1051 infos
.push_back(info
);
1055 if (registration_data
.is_active
) {
1056 info
.active_version
.status
= ServiceWorkerVersion::ACTIVATED
;
1057 info
.active_version
.script_url
= registration_data
.script
;
1058 info
.active_version
.version_id
= registration_data
.version_id
;
1059 info
.active_version
.registration_id
= registration_data
.registration_id
;
1061 info
.waiting_version
.status
= ServiceWorkerVersion::INSTALLED
;
1062 info
.waiting_version
.script_url
= registration_data
.script
;
1063 info
.waiting_version
.version_id
= registration_data
.version_id
;
1064 info
.waiting_version
.registration_id
= registration_data
.registration_id
;
1066 infos
.push_back(info
);
1069 // Add unstored registrations that are being installed.
1070 for (const auto& registration
: installing_registrations_
) {
1071 if ((!origin_filter
.is_valid() ||
1072 registration
.second
->pattern().GetOrigin() == origin_filter
) &&
1073 pushed_registrations
.insert(registration
.first
).second
) {
1074 infos
.push_back(registration
.second
->GetInfo());
1078 callback
.Run(infos
);
1081 void ServiceWorkerStorage::DidStoreRegistration(
1082 const StatusCallback
& callback
,
1083 const ServiceWorkerDatabase::RegistrationData
& new_version
,
1085 const ServiceWorkerDatabase::RegistrationData
& deleted_version
,
1086 const std::vector
<int64
>& newly_purgeable_resources
,
1087 ServiceWorkerDatabase::Status status
) {
1088 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1089 ScheduleDeleteAndStartOver();
1090 callback
.Run(DatabaseStatusToStatusCode(status
));
1093 registered_origins_
.insert(origin
);
1095 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1096 context_
->GetLiveRegistration(new_version
.registration_id
);
1098 registration
->set_resources_total_size_bytes(
1099 new_version
.resources_total_size_bytes
);
1101 if (quota_manager_proxy_
) {
1102 // Can be nullptr in tests.
1103 quota_manager_proxy_
->NotifyStorageModified(
1104 storage::QuotaClient::kServiceWorker
,
1106 storage::StorageType::kStorageTypeTemporary
,
1107 new_version
.resources_total_size_bytes
-
1108 deleted_version
.resources_total_size_bytes
);
1111 callback
.Run(SERVICE_WORKER_OK
);
1113 if (!context_
->GetLiveVersion(deleted_version
.version_id
))
1114 StartPurgingResources(newly_purgeable_resources
);
1117 void ServiceWorkerStorage::DidUpdateToActiveState(
1118 const StatusCallback
& callback
,
1119 ServiceWorkerDatabase::Status status
) {
1120 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1121 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1122 ScheduleDeleteAndStartOver();
1124 callback
.Run(DatabaseStatusToStatusCode(status
));
1127 void ServiceWorkerStorage::DidDeleteRegistration(
1128 const DidDeleteRegistrationParams
& params
,
1129 bool origin_is_deletable
,
1130 const ServiceWorkerDatabase::RegistrationData
& deleted_version
,
1131 const std::vector
<int64
>& newly_purgeable_resources
,
1132 ServiceWorkerDatabase::Status status
) {
1133 pending_deletions_
.erase(params
.registration_id
);
1134 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1135 ScheduleDeleteAndStartOver();
1136 params
.callback
.Run(DatabaseStatusToStatusCode(status
));
1139 if (quota_manager_proxy_
) {
1140 // Can be nullptr in tests.
1141 quota_manager_proxy_
->NotifyStorageModified(
1142 storage::QuotaClient::kServiceWorker
,
1144 storage::StorageType::kStorageTypeTemporary
,
1145 -deleted_version
.resources_total_size_bytes
);
1147 if (origin_is_deletable
)
1148 registered_origins_
.erase(params
.origin
);
1149 params
.callback
.Run(SERVICE_WORKER_OK
);
1151 if (!context_
->GetLiveVersion(deleted_version
.version_id
))
1152 StartPurgingResources(newly_purgeable_resources
);
1155 void ServiceWorkerStorage::DidStoreUserData(
1156 const StatusCallback
& callback
,
1157 ServiceWorkerDatabase::Status status
) {
1158 // |status| can be NOT_FOUND when the associated registration did not exist in
1159 // the database. In the case, we don't have to schedule the corruption
1161 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1162 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1163 ScheduleDeleteAndStartOver();
1165 callback
.Run(DatabaseStatusToStatusCode(status
));
1168 void ServiceWorkerStorage::DidGetUserData(
1169 const GetUserDataCallback
& callback
,
1170 const std::string
& data
,
1171 ServiceWorkerDatabase::Status status
) {
1172 if (status
!= ServiceWorkerDatabase::STATUS_OK
&&
1173 status
!= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
) {
1174 ScheduleDeleteAndStartOver();
1176 callback
.Run(data
, DatabaseStatusToStatusCode(status
));
1179 void ServiceWorkerStorage::DidDeleteUserData(
1180 const StatusCallback
& callback
,
1181 ServiceWorkerDatabase::Status status
) {
1182 if (status
!= ServiceWorkerDatabase::STATUS_OK
)
1183 ScheduleDeleteAndStartOver();
1184 callback
.Run(DatabaseStatusToStatusCode(status
));
1187 void ServiceWorkerStorage::DidGetUserDataForAllRegistrations(
1188 const GetUserDataForAllRegistrationsCallback
& callback
,
1189 const std::vector
<std::pair
<int64
, std::string
>>& user_data
,
1190 ServiceWorkerDatabase::Status status
) {
1191 if (status
!= ServiceWorkerDatabase::STATUS_OK
)
1192 ScheduleDeleteAndStartOver();
1193 callback
.Run(user_data
, DatabaseStatusToStatusCode(status
));
1196 scoped_refptr
<ServiceWorkerRegistration
>
1197 ServiceWorkerStorage::GetOrCreateRegistration(
1198 const ServiceWorkerDatabase::RegistrationData
& data
,
1199 const ResourceList
& resources
) {
1200 scoped_refptr
<ServiceWorkerRegistration
> registration
=
1201 context_
->GetLiveRegistration(data
.registration_id
);
1203 return registration
;
1205 registration
= new ServiceWorkerRegistration(
1206 data
.scope
, data
.registration_id
, context_
);
1207 registration
->set_resources_total_size_bytes(data
.resources_total_size_bytes
);
1208 registration
->set_last_update_check(data
.last_update_check
);
1209 if (pending_deletions_
.find(data
.registration_id
) !=
1210 pending_deletions_
.end()) {
1211 registration
->set_is_deleted(true);
1213 scoped_refptr
<ServiceWorkerVersion
> version
=
1214 context_
->GetLiveVersion(data
.version_id
);
1216 version
= new ServiceWorkerVersion(
1217 registration
.get(), data
.script
, data
.version_id
, context_
);
1218 version
->SetStatus(data
.is_active
?
1219 ServiceWorkerVersion::ACTIVATED
: ServiceWorkerVersion::INSTALLED
);
1220 version
->script_cache_map()->SetResources(resources
);
1223 if (version
->status() == ServiceWorkerVersion::ACTIVATED
)
1224 registration
->SetActiveVersion(version
);
1225 else if (version
->status() == ServiceWorkerVersion::INSTALLED
)
1226 registration
->SetWaitingVersion(version
);
1230 return registration
;
1233 ServiceWorkerRegistration
*
1234 ServiceWorkerStorage::FindInstallingRegistrationForDocument(
1235 const GURL
& document_url
) {
1236 DCHECK(!document_url
.has_ref());
1238 LongestScopeMatcher
matcher(document_url
);
1239 ServiceWorkerRegistration
* match
= nullptr;
1241 // TODO(nhiroki): This searches over installing registrations linearly and it
1242 // couldn't be scalable. Maybe the regs should be partitioned by origin.
1243 for (const auto& registration
: installing_registrations_
)
1244 if (matcher
.MatchLongest(registration
.second
->pattern()))
1245 match
= registration
.second
.get();
1249 ServiceWorkerRegistration
*
1250 ServiceWorkerStorage::FindInstallingRegistrationForPattern(const GURL
& scope
) {
1251 for (const auto& registration
: installing_registrations_
)
1252 if (registration
.second
->pattern() == scope
)
1253 return registration
.second
.get();
1257 ServiceWorkerRegistration
*
1258 ServiceWorkerStorage::FindInstallingRegistrationForId(int64 registration_id
) {
1259 RegistrationRefsById::const_iterator found
=
1260 installing_registrations_
.find(registration_id
);
1261 if (found
== installing_registrations_
.end())
1263 return found
->second
.get();
1266 ServiceWorkerDiskCache
* ServiceWorkerStorage::disk_cache() {
1267 DCHECK_EQ(INITIALIZED
, state_
);
1269 return disk_cache_
.get();
1271 disk_cache_
= ServiceWorkerDiskCache::CreateWithSimpleBackend();
1273 base::FilePath path
= GetDiskCachePath();
1275 int rv
= disk_cache_
->InitWithMemBackend(kMaxMemDiskCacheSize
,
1276 net::CompletionCallback());
1277 DCHECK_EQ(net::OK
, rv
);
1278 return disk_cache_
.get();
1281 if (disk_cache_migration_needed_
) {
1282 // Defer the start of initialization until a migration is complete.
1283 disk_cache_
->set_is_waiting_to_initialize(true);
1284 DCHECK(!disk_cache_migrator_
);
1285 disk_cache_migrator_
.reset(new ServiceWorkerDiskCacheMigrator(
1286 GetOldDiskCachePath(), GetDiskCachePath(), kMaxDiskCacheSize
,
1287 disk_cache_thread_
));
1288 disk_cache_migrator_
->Start(
1289 base::Bind(&ServiceWorkerStorage::DidMigrateDiskCache
,
1290 weak_factory_
.GetWeakPtr()));
1291 return disk_cache_
.get();
1294 if (old_disk_cache_deletion_needed_
) {
1295 // Lazily delete the old diskcache.
1296 BrowserThread::PostAfterStartupTask(
1297 FROM_HERE
, base::ThreadTaskRunnerHandle::Get(),
1298 base::Bind(&ServiceWorkerStorage::DeleteOldDiskCache
,
1299 weak_factory_
.GetWeakPtr()));
1302 ServiceWorkerMetrics::RecordDiskCacheMigrationResult(
1303 ServiceWorkerMetrics::MIGRATION_NOT_NECESSARY
);
1305 InitializeDiskCache();
1306 return disk_cache_
.get();
1309 void ServiceWorkerStorage::DidMigrateDiskCache(ServiceWorkerStatusCode status
) {
1310 disk_cache_migrator_
.reset();
1311 if (status
!= SERVICE_WORKER_OK
) {
1312 OnDiskCacheMigrationFailed(
1313 ServiceWorkerMetrics::MIGRATION_ERROR_MIGRATION_FAILED
);
1317 PostTaskAndReplyWithResult(
1318 database_task_manager_
->GetTaskRunner(), FROM_HERE
,
1319 base::Bind(&ServiceWorkerDatabase::SetDiskCacheMigrationNotNeeded
,
1320 base::Unretained(database_
.get())),
1321 base::Bind(&ServiceWorkerStorage::DidSetDiskCacheMigrationNotNeeded
,
1322 weak_factory_
.GetWeakPtr()));
1325 void ServiceWorkerStorage::DidSetDiskCacheMigrationNotNeeded(
1326 ServiceWorkerDatabase::Status status
) {
1327 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1328 OnDiskCacheMigrationFailed(
1329 ServiceWorkerMetrics::MIGRATION_ERROR_UPDATE_DATABASE
);
1333 // Lazily delete the old diskcache and update the database.
1334 BrowserThread::PostAfterStartupTask(
1335 FROM_HERE
, base::ThreadTaskRunnerHandle::Get(),
1336 base::Bind(&ServiceWorkerStorage::DeleteOldDiskCache
,
1337 weak_factory_
.GetWeakPtr()));
1339 ServiceWorkerMetrics::RecordDiskCacheMigrationResult(
1340 ServiceWorkerMetrics::MIGRATION_OK
);
1341 InitializeDiskCache();
1344 void ServiceWorkerStorage::OnDiskCacheMigrationFailed(
1345 ServiceWorkerMetrics::DiskCacheMigrationResult result
) {
1346 DCHECK(ServiceWorkerMetrics::MIGRATION_ERROR_MIGRATION_FAILED
== result
||
1347 ServiceWorkerMetrics::MIGRATION_ERROR_UPDATE_DATABASE
== result
)
1349 ServiceWorkerMetrics::RecordDiskCacheMigrationResult(result
);
1351 // Give up migration and recreate the whole storage.
1352 ScheduleDeleteAndStartOver();
1354 // Lazily delete the old diskcache. Don't have to update the database
1355 // because it will be deleted by DeleteAndStartOver.
1356 BrowserThread::PostAfterStartupTask(
1357 FROM_HERE
, disk_cache_thread_
.get(),
1358 base::Bind(base::IgnoreResult(&base::DeleteFile
), GetOldDiskCachePath(),
1362 void ServiceWorkerStorage::InitializeDiskCache() {
1363 disk_cache_
->set_is_waiting_to_initialize(false);
1364 int rv
= disk_cache_
->InitWithDiskBackend(
1365 GetDiskCachePath(), kMaxDiskCacheSize
, false, disk_cache_thread_
,
1366 base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized
,
1367 weak_factory_
.GetWeakPtr()));
1368 if (rv
!= net::ERR_IO_PENDING
)
1369 OnDiskCacheInitialized(rv
);
1372 void ServiceWorkerStorage::OnDiskCacheInitialized(int rv
) {
1373 if (rv
!= net::OK
) {
1374 LOG(ERROR
) << "Failed to open the serviceworker diskcache: "
1375 << net::ErrorToString(rv
);
1376 ScheduleDeleteAndStartOver();
1378 ServiceWorkerMetrics::CountInitDiskCacheResult(rv
== net::OK
);
1381 void ServiceWorkerStorage::DeleteOldDiskCache() {
1382 DCHECK(state_
== INITIALIZED
|| state_
== DISABLED
) << state_
;
1385 database_task_manager_
->GetTaskRunner()->PostTask(
1386 FROM_HERE
, base::Bind(&ServiceWorkerStorage::DeleteOldDiskCacheInDB
,
1387 database_
.get(), GetOldDiskCachePath()));
1390 void ServiceWorkerStorage::StartPurgingResources(
1391 const std::vector
<int64
>& ids
) {
1392 DCHECK(has_checked_for_stale_resources_
);
1393 for (const auto& id
: ids
)
1394 purgeable_resource_ids_
.push_back(id
);
1395 ContinuePurgingResources();
1398 void ServiceWorkerStorage::StartPurgingResources(
1399 const ResourceList
& resources
) {
1400 DCHECK(has_checked_for_stale_resources_
);
1401 for (const auto& resource
: resources
)
1402 purgeable_resource_ids_
.push_back(resource
.resource_id
);
1403 ContinuePurgingResources();
1406 void ServiceWorkerStorage::ContinuePurgingResources() {
1407 if (purgeable_resource_ids_
.empty() || is_purge_pending_
)
1410 // Do one at a time until we're done, use RunSoon to avoid recursion when
1411 // DoomEntry returns immediately.
1412 is_purge_pending_
= true;
1413 int64 id
= purgeable_resource_ids_
.front();
1414 purgeable_resource_ids_
.pop_front();
1416 base::Bind(&ServiceWorkerStorage::PurgeResource
,
1417 weak_factory_
.GetWeakPtr(), id
));
1420 void ServiceWorkerStorage::PurgeResource(int64 id
) {
1421 DCHECK(is_purge_pending_
);
1422 int rv
= disk_cache()->DoomEntry(
1423 id
, base::Bind(&ServiceWorkerStorage::OnResourcePurged
,
1424 weak_factory_
.GetWeakPtr(), id
));
1425 if (rv
!= net::ERR_IO_PENDING
)
1426 OnResourcePurged(id
, rv
);
1429 void ServiceWorkerStorage::OnResourcePurged(int64 id
, int rv
) {
1430 DCHECK(is_purge_pending_
);
1431 is_purge_pending_
= false;
1433 ServiceWorkerMetrics::RecordPurgeResourceResult(rv
);
1435 database_task_manager_
->GetTaskRunner()->PostTask(
1437 base::Bind(base::IgnoreResult(
1438 &ServiceWorkerDatabase::ClearPurgeableResourceIds
),
1439 base::Unretained(database_
.get()),
1440 std::set
<int64
>(&id
, &id
+ 1)));
1442 // Continue purging resources regardless of the previous result.
1443 ContinuePurgingResources();
1446 void ServiceWorkerStorage::DeleteStaleResources() {
1447 DCHECK(!has_checked_for_stale_resources_
);
1448 has_checked_for_stale_resources_
= true;
1449 database_task_manager_
->GetTaskRunner()->PostTask(
1451 base::Bind(&ServiceWorkerStorage::CollectStaleResourcesFromDB
,
1453 base::ThreadTaskRunnerHandle::Get(),
1454 base::Bind(&ServiceWorkerStorage::DidCollectStaleResources
,
1455 weak_factory_
.GetWeakPtr())));
1458 void ServiceWorkerStorage::DidCollectStaleResources(
1459 const std::vector
<int64
>& stale_resource_ids
,
1460 ServiceWorkerDatabase::Status status
) {
1461 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1462 DCHECK_NE(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
, status
);
1463 ScheduleDeleteAndStartOver();
1466 StartPurgingResources(stale_resource_ids
);
1469 void ServiceWorkerStorage::ClearSessionOnlyOrigins() {
1470 // Can be null in tests.
1471 if (!special_storage_policy_
)
1474 if (!special_storage_policy_
->HasSessionOnlyOrigins())
1477 std::set
<GURL
> session_only_origins
;
1478 for (const GURL
& origin
: registered_origins_
) {
1479 if (special_storage_policy_
->IsStorageSessionOnly(origin
))
1480 session_only_origins
.insert(origin
);
1483 database_task_manager_
->GetShutdownBlockingTaskRunner()->PostTask(
1485 base::Bind(&DeleteAllDataForOriginsFromDB
,
1487 session_only_origins
));
1490 void ServiceWorkerStorage::CollectStaleResourcesFromDB(
1491 ServiceWorkerDatabase
* database
,
1492 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1493 const GetResourcesCallback
& callback
) {
1494 std::set
<int64
> ids
;
1495 ServiceWorkerDatabase::Status status
=
1496 database
->GetUncommittedResourceIds(&ids
);
1497 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1498 original_task_runner
->PostTask(
1501 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1505 status
= database
->PurgeUncommittedResourceIds(ids
);
1506 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1507 original_task_runner
->PostTask(
1510 callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1515 status
= database
->GetPurgeableResourceIds(&ids
);
1516 original_task_runner
->PostTask(
1518 base::Bind(callback
, std::vector
<int64
>(ids
.begin(), ids
.end()), status
));
1521 void ServiceWorkerStorage::ReadInitialDataFromDB(
1522 ServiceWorkerDatabase
* database
,
1523 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1524 const InitializeCallback
& callback
) {
1526 scoped_ptr
<ServiceWorkerStorage::InitialData
> data(
1527 new ServiceWorkerStorage::InitialData());
1529 ServiceWorkerDatabase::Status status
=
1530 database
->GetNextAvailableIds(&data
->next_registration_id
,
1531 &data
->next_version_id
,
1532 &data
->next_resource_id
);
1533 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1534 original_task_runner
->PostTask(
1535 FROM_HERE
, base::Bind(callback
, base::Passed(data
.Pass()), status
));
1540 database
->IsDiskCacheMigrationNeeded(&data
->disk_cache_migration_needed
);
1541 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1542 original_task_runner
->PostTask(
1543 FROM_HERE
, base::Bind(callback
, base::Passed(data
.Pass()), status
));
1547 status
= database
->IsOldDiskCacheDeletionNeeded(
1548 &data
->old_disk_cache_deletion_needed
);
1549 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1550 original_task_runner
->PostTask(
1551 FROM_HERE
, base::Bind(callback
, base::Passed(data
.Pass()), status
));
1555 status
= database
->GetOriginsWithRegistrations(&data
->origins
);
1556 original_task_runner
->PostTask(
1557 FROM_HERE
, base::Bind(callback
, base::Passed(data
.Pass()), status
));
1560 void ServiceWorkerStorage::DeleteOldDiskCacheInDB(
1561 ServiceWorkerDatabase
* database
,
1562 const base::FilePath
& disk_cache_path
) {
1563 // Ignore a failure. A retry will happen on the next initialization.
1564 if (!base::DeleteFile(disk_cache_path
, true))
1566 database
->SetOldDiskCacheDeletionNotNeeded();
1569 void ServiceWorkerStorage::DeleteRegistrationFromDB(
1570 ServiceWorkerDatabase
* database
,
1571 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1572 int64 registration_id
,
1574 const DeleteRegistrationCallback
& callback
) {
1577 ServiceWorkerDatabase::RegistrationData deleted_version
;
1578 std::vector
<int64
> newly_purgeable_resources
;
1579 ServiceWorkerDatabase::Status status
= database
->DeleteRegistration(
1580 registration_id
, origin
, &deleted_version
, &newly_purgeable_resources
);
1581 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1582 original_task_runner
->PostTask(
1585 callback
, false, deleted_version
, std::vector
<int64
>(), status
));
1589 // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
1590 // unique origin list.
1591 RegistrationList registrations
;
1592 status
= database
->GetRegistrationsForOrigin(origin
, ®istrations
, nullptr);
1593 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1594 original_task_runner
->PostTask(
1597 callback
, false, deleted_version
, std::vector
<int64
>(), status
));
1601 bool deletable
= registrations
.empty();
1602 original_task_runner
->PostTask(FROM_HERE
,
1603 base::Bind(callback
,
1606 newly_purgeable_resources
,
1610 void ServiceWorkerStorage::WriteRegistrationInDB(
1611 ServiceWorkerDatabase
* database
,
1612 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1613 const ServiceWorkerDatabase::RegistrationData
& data
,
1614 const ResourceList
& resources
,
1615 const WriteRegistrationCallback
& callback
) {
1617 ServiceWorkerDatabase::RegistrationData deleted_version
;
1618 std::vector
<int64
> newly_purgeable_resources
;
1619 ServiceWorkerDatabase::Status status
= database
->WriteRegistration(
1620 data
, resources
, &deleted_version
, &newly_purgeable_resources
);
1621 original_task_runner
->PostTask(FROM_HERE
,
1622 base::Bind(callback
,
1623 data
.script
.GetOrigin(),
1625 newly_purgeable_resources
,
1629 void ServiceWorkerStorage::FindForDocumentInDB(
1630 ServiceWorkerDatabase
* database
,
1631 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1632 const GURL
& document_url
,
1633 const FindInDBCallback
& callback
) {
1634 GURL origin
= document_url
.GetOrigin();
1635 RegistrationList registration_data_list
;
1636 ServiceWorkerDatabase::Status status
= database
->GetRegistrationsForOrigin(
1637 origin
, ®istration_data_list
, nullptr);
1638 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1639 original_task_runner
->PostTask(
1641 base::Bind(callback
,
1642 ServiceWorkerDatabase::RegistrationData(),
1648 ServiceWorkerDatabase::RegistrationData data
;
1649 ResourceList resources
;
1650 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1652 // Find one with a pattern match.
1653 LongestScopeMatcher
matcher(document_url
);
1654 int64 match
= kInvalidServiceWorkerRegistrationId
;
1655 for (const auto& registration_data
: registration_data_list
)
1656 if (matcher
.MatchLongest(registration_data
.scope
))
1657 match
= registration_data
.registration_id
;
1658 if (match
!= kInvalidServiceWorkerRegistrationId
)
1659 status
= database
->ReadRegistration(match
, origin
, &data
, &resources
);
1661 original_task_runner
->PostTask(
1663 base::Bind(callback
, data
, resources
, status
));
1666 void ServiceWorkerStorage::FindForPatternInDB(
1667 ServiceWorkerDatabase
* database
,
1668 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1670 const FindInDBCallback
& callback
) {
1671 GURL origin
= scope
.GetOrigin();
1672 RegistrationList registration_data_list
;
1673 ServiceWorkerDatabase::Status status
= database
->GetRegistrationsForOrigin(
1674 origin
, ®istration_data_list
, nullptr);
1675 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1676 original_task_runner
->PostTask(
1678 base::Bind(callback
,
1679 ServiceWorkerDatabase::RegistrationData(),
1685 // Find one with an exact matching scope.
1686 ServiceWorkerDatabase::RegistrationData data
;
1687 ResourceList resources
;
1688 status
= ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND
;
1689 for (const auto& registration_data
: registration_data_list
) {
1690 if (scope
!= registration_data
.scope
)
1692 status
= database
->ReadRegistration(registration_data
.registration_id
,
1693 origin
, &data
, &resources
);
1694 break; // We're done looping.
1697 original_task_runner
->PostTask(
1699 base::Bind(callback
, data
, resources
, status
));
1702 void ServiceWorkerStorage::FindForIdInDB(
1703 ServiceWorkerDatabase
* database
,
1704 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1705 int64 registration_id
,
1707 const FindInDBCallback
& callback
) {
1708 ServiceWorkerDatabase::RegistrationData data
;
1709 ResourceList resources
;
1710 ServiceWorkerDatabase::Status status
=
1711 database
->ReadRegistration(registration_id
, origin
, &data
, &resources
);
1712 original_task_runner
->PostTask(
1713 FROM_HERE
, base::Bind(callback
, data
, resources
, status
));
1716 void ServiceWorkerStorage::FindForIdOnlyInDB(
1717 ServiceWorkerDatabase
* database
,
1718 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1719 int64 registration_id
,
1720 const FindInDBCallback
& callback
) {
1722 ServiceWorkerDatabase::Status status
=
1723 database
->ReadRegistrationOrigin(registration_id
, &origin
);
1724 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1725 original_task_runner
->PostTask(
1727 base::Bind(callback
, ServiceWorkerDatabase::RegistrationData(),
1728 ResourceList(), status
));
1731 FindForIdInDB(database
, original_task_runner
, registration_id
, origin
,
1735 void ServiceWorkerStorage::GetUserDataInDB(
1736 ServiceWorkerDatabase
* database
,
1737 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1738 int64 registration_id
,
1739 const std::string
& key
,
1740 const GetUserDataInDBCallback
& callback
) {
1742 ServiceWorkerDatabase::Status status
=
1743 database
->ReadUserData(registration_id
, key
, &data
);
1744 original_task_runner
->PostTask(
1745 FROM_HERE
, base::Bind(callback
, data
, status
));
1748 void ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB(
1749 ServiceWorkerDatabase
* database
,
1750 scoped_refptr
<base::SequencedTaskRunner
> original_task_runner
,
1751 const std::string
& key
,
1752 const GetUserDataForAllRegistrationsInDBCallback
& callback
) {
1753 std::vector
<std::pair
<int64
, std::string
>> user_data
;
1754 ServiceWorkerDatabase::Status status
=
1755 database
->ReadUserDataForAllRegistrations(key
, &user_data
);
1756 original_task_runner
->PostTask(FROM_HERE
,
1757 base::Bind(callback
, user_data
, status
));
1760 void ServiceWorkerStorage::DeleteAllDataForOriginsFromDB(
1761 ServiceWorkerDatabase
* database
,
1762 const std::set
<GURL
>& origins
) {
1765 std::vector
<int64
> newly_purgeable_resources
;
1766 database
->DeleteAllDataForOrigins(origins
, &newly_purgeable_resources
);
1769 // TODO(nhiroki): The corruption recovery should not be scheduled if the error
1770 // is transient and it can get healed soon (e.g. IO error). To do that, the
1771 // database should not disable itself when an error occurs and the storage
1772 // controls it instead.
1773 void ServiceWorkerStorage::ScheduleDeleteAndStartOver() {
1774 // TODO(dmurph): Notify the quota manager somehow that all of our data is now
1776 if (state_
== DISABLED
) {
1777 // Recovery process has already been scheduled.
1782 DVLOG(1) << "Schedule to delete the context and start over.";
1783 context_
->ScheduleDeleteAndStartOver();
1786 void ServiceWorkerStorage::DidDeleteDatabase(
1787 const StatusCallback
& callback
,
1788 ServiceWorkerDatabase::Status status
) {
1789 DCHECK_EQ(DISABLED
, state_
);
1790 if (status
!= ServiceWorkerDatabase::STATUS_OK
) {
1791 // Give up the corruption recovery until the browser restarts.
1792 LOG(ERROR
) << "Failed to delete the database: "
1793 << ServiceWorkerDatabase::StatusToString(status
);
1794 ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
1795 ServiceWorkerMetrics::DELETE_DATABASE_ERROR
);
1796 callback
.Run(DatabaseStatusToStatusCode(status
));
1799 DVLOG(1) << "Deleted ServiceWorkerDatabase successfully.";
1801 // Delete the disk cache on the cache thread.
1802 // TODO(nhiroki): What if there is a bunch of files in the cache directory?
1803 // Deleting the directory could take a long time and restart could be delayed.
1804 // We should probably rename the directory and delete it later.
1805 PostTaskAndReplyWithResult(
1806 disk_cache_thread_
.get(), FROM_HERE
,
1807 base::Bind(&base::DeleteFile
, GetDiskCachePath(), true),
1808 base::Bind(&ServiceWorkerStorage::DidDeleteDiskCache
,
1809 weak_factory_
.GetWeakPtr(), callback
));
1812 void ServiceWorkerStorage::DidDeleteDiskCache(
1813 const StatusCallback
& callback
, bool result
) {
1814 DCHECK_EQ(DISABLED
, state_
);
1816 // Give up the corruption recovery until the browser restarts.
1817 LOG(ERROR
) << "Failed to delete the diskcache.";
1818 ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
1819 ServiceWorkerMetrics::DELETE_DISK_CACHE_ERROR
);
1820 callback
.Run(SERVICE_WORKER_ERROR_FAILED
);
1823 DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully.";
1824 ServiceWorkerMetrics::RecordDeleteAndStartOverResult(
1825 ServiceWorkerMetrics::DELETE_OK
);
1826 callback
.Run(SERVICE_WORKER_OK
);
1829 } // namespace content