Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: content/browser/background_sync/background_sync_manager.cc

Issue 1048053002: [BackgroundSync] Handle storage failure (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@background_sync
Patch Set: Rebase Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/background_sync/background_sync_manager.cc
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 7ea194f1af92dd463d56a59fbc1527c99842d81f..1075e39fa3261bbab20146c94fea6886aa394b29 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -46,6 +46,7 @@ scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
}
BackgroundSyncManager::~BackgroundSyncManager() {
+ service_worker_context_->RemoveObserver(this);
}
void BackgroundSyncManager::Register(
@@ -57,6 +58,13 @@ void BackgroundSyncManager::Register(
DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId,
sync_registration.id);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
StatusAndRegistrationCallback pending_callback =
base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback,
weak_ptr_factory_.GetWeakPtr(), callback);
@@ -74,6 +82,12 @@ void BackgroundSyncManager::Unregister(
const StatusCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
StatusCallback pending_callback =
base::Bind(&BackgroundSyncManager::PendingStatusCallback,
weak_ptr_factory_.GetWeakPtr(), callback);
@@ -91,6 +105,13 @@ void BackgroundSyncManager::GetRegistration(
const StatusAndRegistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
StatusAndRegistrationCallback pending_callback =
base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback,
weak_ptr_factory_.GetWeakPtr(), callback);
@@ -101,33 +122,81 @@ void BackgroundSyncManager::GetRegistration(
sync_registration_name, pending_callback));
}
+void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id,
+ const GURL& pattern) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ base::Closure pending_callback =
jsbell 2015/04/01 21:54:54 Can you add a comment that this do-nothing callbac
jkarlin 2015/04/02 17:57:56 Nice suggestion. I made such functions for all of
michaeln 2015/04/02 23:06:20 Nice, those helpers help a lot.
+ base::Bind(&BackgroundSyncManager::PendingClosure,
+ weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing));
+
+ // Operations already in the queue will either fail when they write to storage
+ // or return stale results based on registrations loaded in memory. This is
+ // inconsequential since the service worker is gone.
+ op_scheduler_.ScheduleOperation(base::Bind(
+ &BackgroundSyncManager::OnRegistrationDeletedImpl,
+ weak_ptr_factory_.GetWeakPtr(), registration_id, pending_callback));
+}
+
+void BackgroundSyncManager::OnStorageWiped() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ base::Closure pending_callback =
+ base::Bind(&BackgroundSyncManager::PendingClosure,
+ weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing));
+
+ // Operations already in the queue will either fail when they write to storage
+ // or return stale results based on registrations loaded in memory. This is
+ // inconsequential since the service workers are gone.
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::OnStorageWipedImpl,
+ weak_ptr_factory_.GetWeakPtr(), pending_callback));
+}
+
BackgroundSyncManager::BackgroundSyncManager(
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
- : service_worker_context_(service_worker_context), weak_ptr_factory_(this) {
+ : service_worker_context_(service_worker_context),
+ disabled_(false),
+ weak_ptr_factory_(this) {
+ service_worker_context_->AddObserver(this);
}
void BackgroundSyncManager::Init() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!op_scheduler_.ScheduledOperations());
+ DCHECK(!disabled_);
+
+ base::Closure pending_callback =
+ base::Bind(&BackgroundSyncManager::PendingClosure,
+ weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing));
op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(),
+ pending_callback));
}
-void BackgroundSyncManager::InitImpl() {
+void BackgroundSyncManager::InitImpl(const base::Closure& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
GetDataFromBackend(
kBackgroundSyncUserDataKey,
base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), callback));
}
void BackgroundSyncManager::InitDidGetDataFromBackend(
+ const base::Closure& callback,
const std::vector<std::pair<int64, std::string>>& user_data,
ServiceWorkerStatusCode status) {
- if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND)
- LOG(ERROR) << "Background Sync Failed to load from backend.";
+ if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
+ LOG(ERROR) << "BackgroundSync failed to init due to backend failure.";
+ DisableAndClearManager();
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
bool corruption_detected = false;
for (const std::pair<int64, std::string>& data : user_data) {
@@ -163,12 +232,12 @@ void BackgroundSyncManager::InitDidGetDataFromBackend(
if (corruption_detected) {
LOG(ERROR) << "Corruption detected in background sync backend";
- sw_to_registrations_map_.clear();
+ DisableAndClearManager();
}
// TODO(jkarlin): Call the scheduling algorithm here.
- op_scheduler_.CompleteOperationAndRunNext();
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
}
void BackgroundSyncManager::RegisterImpl(
@@ -176,6 +245,13 @@ void BackgroundSyncManager::RegisterImpl(
int64 sw_registration_id,
const BackgroundSyncRegistration& sync_registration,
const StatusAndRegistrationCallback& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
BackgroundSyncRegistration existing_registration;
if (LookupRegistration(sw_registration_id, sync_registration.name,
&existing_registration)) {
@@ -198,7 +274,60 @@ void BackgroundSyncManager::RegisterImpl(
origin, sw_registration_id,
base::Bind(&BackgroundSyncManager::RegisterDidStore,
weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
- new_registration, existing_registration, callback));
+ new_registration, callback));
+}
+
+void BackgroundSyncManager::DisableAndClearManager() {
+ disabled_ = true;
+ base::Closure pending_callback =
+ base::Bind(&BackgroundSyncManager::PendingClosure,
+ weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing));
+
+ op_scheduler_.ScheduleOperation(
+ base::Bind(&BackgroundSyncManager::DisableAndClearManagerImpl,
+ weak_ptr_factory_.GetWeakPtr(), pending_callback));
+}
+
+void BackgroundSyncManager::DisableAndClearManagerImpl(
jsbell 2015/04/01 21:54:54 Out of curiosity, are there any relevant "I'm runn
jkarlin 2015/04/02 17:57:56 There is a check that an operation is currently ru
jsbell 2015/04/02 20:25:13 sgtm
+ const base::Closure& callback) {
+ DCHECK(disabled_);
michaeln 2015/04/01 21:37:30 Can BackgroundSyncManager::OnStorageWipedImpl happ
jkarlin 2015/04/02 17:57:56 Yes, there is a race on disabled_ if DisableAndCle
michaeln 2015/04/02 23:06:20 yup, that works!
+
+ sw_to_registrations_map_.clear();
+
+ // Delete all backend entries. The memory representation of registered syncs
+ // may be corrupt so reload the registrations from storage again.
jsbell 2015/04/01 21:54:54 Maybe clarify in the comment why memory is "corrup
jkarlin 2015/04/02 17:57:56 Done.
+ GetDataFromBackend(
+ kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
+ const base::Closure& callback,
+ const std::vector<std::pair<int64, std::string>>& user_data,
+ ServiceWorkerStatusCode status) {
+ if (status != SERVICE_WORKER_OK || user_data.empty()) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+ return;
+ }
+
+ base::Closure barrier_closure =
+ base::BarrierClosure(user_data.size(), base::Bind(callback));
+
+ for (const auto& sw_id_and_regs : user_data) {
+ service_worker_context_->context()->storage()->ClearUserData(
+ sw_id_and_regs.first, kBackgroundSyncUserDataKey,
+ base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne,
+ weak_ptr_factory_.GetWeakPtr(), barrier_closure));
+ }
+}
+
+void BackgroundSyncManager::DisableAndClearManagerClearedOne(
+ const base::Closure& barrier_closure,
+ ServiceWorkerStatusCode status) {
+ // The status doesn't matter at this point, there is nothing else to be done.
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(barrier_closure));
}
bool BackgroundSyncManager::LookupRegistration(
@@ -255,18 +384,21 @@ void BackgroundSyncManager::StoreRegistrations(
void BackgroundSyncManager::RegisterDidStore(
int64 sw_registration_id,
const BackgroundSyncRegistration& new_registration,
- const BackgroundSyncRegistration& previous_registration,
const StatusAndRegistrationCallback& callback,
ServiceWorkerStatusCode status) {
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // The registration is gone.
+ sw_to_registrations_map_.erase(sw_registration_id);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
if (status != SERVICE_WORKER_OK) {
- // Restore the previous state.
- if (previous_registration.id !=
- BackgroundSyncRegistration::kInvalidRegistrationId) {
- AddRegistrationToMap(sw_registration_id, previous_registration);
- } else {
- RemoveRegistrationFromMap(sw_registration_id, new_registration.name,
- nullptr);
- }
+ LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
+ "failure.";
+ DisableAndClearManager();
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
@@ -334,6 +466,12 @@ void BackgroundSyncManager::UnregisterImpl(
const std::string& sync_registration_name,
BackgroundSyncRegistration::RegistrationId sync_registration_id,
const StatusCallback& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
BackgroundSyncRegistration existing_registration;
if (!LookupRegistration(sw_registration_id, sync_registration_name,
&existing_registration) ||
@@ -359,9 +497,17 @@ void BackgroundSyncManager::UnregisterDidStore(
const BackgroundSyncRegistration& old_sync_registration,
const StatusCallback& callback,
ServiceWorkerStatusCode status) {
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ // ServiceWorker was unregistered.
+ sw_to_registrations_map_.erase(sw_registration_id);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
+ return;
+ }
+
if (status != SERVICE_WORKER_OK) {
- // Restore the previous state.
- AddRegistrationToMap(sw_registration_id, old_sync_registration);
+ LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
+ DisableAndClearManager();
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
return;
@@ -377,6 +523,13 @@ void BackgroundSyncManager::GetRegistrationImpl(
int64 sw_registration_id,
const std::string sync_registration_name,
const StatusAndRegistrationCallback& callback) {
+ if (disabled_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
+ return;
+ }
+
BackgroundSyncRegistration out_registration;
if (!LookupRegistration(sw_registration_id, sync_registration_name,
&out_registration)) {
@@ -390,6 +543,21 @@ void BackgroundSyncManager::GetRegistrationImpl(
FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registration));
}
+void BackgroundSyncManager::OnRegistrationDeletedImpl(
+ int64 registration_id,
+ const base::Closure& callback) {
+ // The backend (ServiceWorkerStorage) will delete the data, so just delete the
+ // memory representation here.
+ sw_to_registrations_map_.erase(registration_id);
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+}
+
+void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
+ sw_to_registrations_map_.clear();
+ disabled_ = false;
michaeln 2015/04/01 21:37:30 would it make sense to schedule an op to reinit?
jkarlin 2015/04/02 17:57:56 Scheduling the op might allow some new requests to
+ InitImpl(callback);
+}
+
void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
const StatusAndRegistrationCallback& callback,
ErrorType error,
@@ -411,4 +579,12 @@ void BackgroundSyncManager::PendingStatusCallback(
op_scheduler_.CompleteOperationAndRunNext();
}
+void BackgroundSyncManager::PendingClosure(const base::Closure& callback) {
+ // The callback might delete this object, so hang onto a weak ptr to find out.
+ base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
+ callback.Run();
+ if (manager)
+ op_scheduler_.CompleteOperationAndRunNext();
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698