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

Unified Diff: content/browser/notifications/platform_notification_context_impl.cc

Issue 1024463006: Destroy the notification database when corruption occurs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@n-db-SWContextObserver
Patch Set: another test 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/notifications/platform_notification_context_impl.cc
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc
index df744ea6b839c8d6d72cdb955dc6b9430df25aec..f891ca63c4633f21eda37f11ab247cfddfb66082 100644
--- a/content/browser/notifications/platform_notification_context_impl.cc
+++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -4,6 +4,7 @@
#include "content/browser/notifications/platform_notification_context_impl.h"
+#include "base/files/file_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/browser/notifications/notification_database.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -18,6 +19,15 @@ void EmptyFailureCallback() {}
} // namespace
+// Defines the behavior to apply when a corrupt database is being opened.
+enum class PlatformNotificationContextImpl::CorruptionBehavior {
+ // Destroy the entire database and start over with an empty one.
+ DESTROY_AND_START_OVER,
+
+ // Abort the operation and invoke the failure callback.
+ FAIL_OPERATION,
cmumford 2015/03/19 22:12:27 I can't really think of a time where you'd want to
Peter Beverloo 2015/03/20 14:31:26 Done. Note that this CL used this to avoid gettin
+};
+
// Name of the directory in the user's profile directory where the notification
// database files should be stored.
const base::FilePath::CharType kPlatformNotificationsDirectory[] =
@@ -91,6 +101,8 @@ void PlatformNotificationContextImpl::DoReadNotificationData(
origin,
&database_data);
+ // TODO(peter): Record UMA on |status| for reading from the database.
+
if (status == NotificationDatabase::STATUS_OK) {
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
@@ -100,8 +112,9 @@ void PlatformNotificationContextImpl::DoReadNotificationData(
return;
}
- // TODO(peter): Record UMA on |status| for reading from the database.
- // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
+ // Blow away the database if reading data failed due to corruption.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
BrowserThread::PostTask(
BrowserThread::IO,
@@ -132,9 +145,10 @@ void PlatformNotificationContextImpl::DoWriteNotificationData(
database_data,
&notification_id);
- DCHECK_GT(notification_id, 0);
+ // TODO(peter): Record UMA on |status| for reading from the database.
if (status == NotificationDatabase::STATUS_OK) {
+ DCHECK_GT(notification_id, 0);
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(callback,
@@ -143,8 +157,9 @@ void PlatformNotificationContextImpl::DoWriteNotificationData(
return;
}
- // TODO(peter): Record UMA on |status| for reading from the database.
- // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
+ // Blow away the database if writing data failed due to corruption.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
BrowserThread::PostTask(
BrowserThread::IO,
@@ -172,10 +187,17 @@ void PlatformNotificationContextImpl::DoDeleteNotificationData(
NotificationDatabase::Status status =
database_->DeleteNotificationData(notification_id, origin);
- const bool success = status == NotificationDatabase::STATUS_OK;
-
// TODO(peter): Record UMA on |status| for reading from the database.
- // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
+
+ bool success = status == NotificationDatabase::STATUS_OK;
+
+ // Blow away the database if reading data failed due to corruption. Following
+ // the contract of the delete methods, consider this to be a success as the
+ // caller's goal has been achieved: the data is gone.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
+ DestroyDatabase();
+ success = true;
+ }
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
@@ -200,13 +222,26 @@ void PlatformNotificationContextImpl::
DCHECK(task_runner_->RunsTasksOnCurrentThread());
std::set<int64_t> deleted_notifications_set;
- database_->DeleteAllNotificationDataForServiceWorkerRegistration(
- origin, service_worker_registration_id, &deleted_notifications_set);
+ NotificationDatabase::Status status =
+ database_->DeleteAllNotificationDataForServiceWorkerRegistration(
+ origin, service_worker_registration_id, &deleted_notifications_set);
// TODO(peter): Record UMA on status for deleting from the database.
+
+ // Blow away the database if a corruption error occurred during the deletion.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
+ DestroyDatabase();
+
// TODO(peter): Close the notifications in |deleted_notifications_set|.
}
+void PlatformNotificationContextImpl::OnStorageWiped() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LazyInitialize(
+ base::Bind(&PlatformNotificationContextImpl::DestroyDatabase, this),
+ base::Bind(&EmptyFailureCallback));
+}
+
void PlatformNotificationContextImpl::LazyInitialize(
const base::Closure& success_closure,
const base::Closure& failure_closure) {
@@ -222,12 +257,14 @@ void PlatformNotificationContextImpl::LazyInitialize(
task_runner_->PostTask(
FROM_HERE,
base::Bind(&PlatformNotificationContextImpl::OpenDatabase,
- this, success_closure, failure_closure));
+ this, success_closure, failure_closure,
+ CorruptionBehavior::DESTROY_AND_START_OVER));
}
void PlatformNotificationContextImpl::OpenDatabase(
const base::Closure& success_closure,
- const base::Closure& failure_closure) {
+ const base::Closure& failure_closure,
+ CorruptionBehavior corruption_behavior) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
if (database_) {
@@ -236,24 +273,50 @@ void PlatformNotificationContextImpl::OpenDatabase(
}
database_.reset(new NotificationDatabase(GetDatabasePath()));
-
- // TODO(peter): Record UMA on |status| for opening the database.
- // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
-
NotificationDatabase::Status status =
database_->Open(true /* create_if_missing */);
+ // TODO(peter): Record UMA on |status| for opening the database.
+
if (status == NotificationDatabase::STATUS_OK) {
success_closure.Run();
return;
}
- // TODO(peter): Properly handle failures when opening the database.
+ // When the database could not be opened due to corruption and the corruption
+ // behavior is set to DESTROY_AND_START_OVER, blow away the database and retry
+ // opening it with the same success and failure callbacks.
+ if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED &&
+ corruption_behavior == CorruptionBehavior::DESTROY_AND_START_OVER) {
+ DestroyDatabase();
+ OpenDatabase(success_closure,
cmumford 2015/03/19 22:12:27 If I'm reading this correctly the user of this fun
Peter Beverloo 2015/03/20 14:31:26 Indeed. The TODO on line 317 covers this - when th
+ failure_closure,
+ CorruptionBehavior::FAIL_OPERATION);
+ return;
+ }
+
database_.reset();
cmumford 2015/03/19 22:12:27 Do you want to reset this ptr above before calling
Peter Beverloo 2015/03/20 14:31:26 Currently DestroyDatabase() calls NotificationData
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure);
}
+void PlatformNotificationContextImpl::DestroyDatabase() {
cmumford 2015/03/19 22:12:27 You should return a status code here, and check it
Peter Beverloo 2015/03/20 14:31:26 That's an interesting case, I hadn't considered th
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(database_);
+
+ // TODO(peter): Record UMA on the status code of the Destroy() call.
+ database_->Destroy();
+ database_.reset();
+
+ // Remove all files in the directory that the database was previously located
+ // in, to make sure that any left-over files are gone as well.
+ base::FilePath database_path = GetDatabasePath();
+ if (!database_path.empty())
+ base::DeleteFile(database_path, true);
+
+ // TODO(peter): Close any existing persistent notifications on the platform.
+}
+
base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const {
if (path_.empty())
return path_;

Powered by Google App Engine
This is Rietveld 408576698