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

Side by Side 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: 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/notifications/platform_notification_context_impl.h" 5 #include "content/browser/notifications/platform_notification_context_impl.h"
6 6
7 #include "base/bind_helpers.h" 7 #include "base/bind_helpers.h"
8 #include "base/files/file_util.h"
8 #include "base/threading/sequenced_worker_pool.h" 9 #include "base/threading/sequenced_worker_pool.h"
9 #include "content/browser/notifications/notification_database.h" 10 #include "content/browser/notifications/notification_database.h"
10 #include "content/browser/service_worker/service_worker_context_wrapper.h" 11 #include "content/browser/service_worker/service_worker_context_wrapper.h"
11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/notification_database_data.h" 13 #include "content/public/browser/notification_database_data.h"
13 14
14 using base::DoNothing; 15 using base::DoNothing;
15 16
16 namespace content { 17 namespace content {
17 18
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 const GURL& origin, 82 const GURL& origin,
82 const ReadResultCallback& callback) { 83 const ReadResultCallback& callback) {
83 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 84 DCHECK(task_runner_->RunsTasksOnCurrentThread());
84 85
85 NotificationDatabaseData database_data; 86 NotificationDatabaseData database_data;
86 NotificationDatabase::Status status = 87 NotificationDatabase::Status status =
87 database_->ReadNotificationData(notification_id, 88 database_->ReadNotificationData(notification_id,
88 origin, 89 origin,
89 &database_data); 90 &database_data);
90 91
92 // TODO(peter): Record UMA on |status| for reading from the database.
93
91 if (status == NotificationDatabase::STATUS_OK) { 94 if (status == NotificationDatabase::STATUS_OK) {
92 BrowserThread::PostTask(BrowserThread::IO, 95 BrowserThread::PostTask(BrowserThread::IO,
93 FROM_HERE, 96 FROM_HERE,
94 base::Bind(callback, 97 base::Bind(callback,
95 true /* success */, 98 true /* success */,
96 database_data)); 99 database_data));
97 return; 100 return;
98 } 101 }
99 102
100 // TODO(peter): Record UMA on |status| for reading from the database. 103 // Blow away the database if reading data failed due to corruption.
101 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. 104 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
105 DestroyDatabase();
102 106
103 BrowserThread::PostTask( 107 BrowserThread::PostTask(
104 BrowserThread::IO, 108 BrowserThread::IO,
105 FROM_HERE, 109 FROM_HERE,
106 base::Bind(callback, false /* success */, NotificationDatabaseData())); 110 base::Bind(callback, false /* success */, NotificationDatabaseData()));
107 } 111 }
108 112
109 void PlatformNotificationContextImpl::WriteNotificationData( 113 void PlatformNotificationContextImpl::WriteNotificationData(
110 const GURL& origin, 114 const GURL& origin,
111 const NotificationDatabaseData& database_data, 115 const NotificationDatabaseData& database_data,
(...skipping 10 matching lines...) Expand all
122 const NotificationDatabaseData& database_data, 126 const NotificationDatabaseData& database_data,
123 const WriteResultCallback& callback) { 127 const WriteResultCallback& callback) {
124 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 128 DCHECK(task_runner_->RunsTasksOnCurrentThread());
125 129
126 int64_t notification_id = 0; 130 int64_t notification_id = 0;
127 NotificationDatabase::Status status = 131 NotificationDatabase::Status status =
128 database_->WriteNotificationData(origin, 132 database_->WriteNotificationData(origin,
129 database_data, 133 database_data,
130 &notification_id); 134 &notification_id);
131 135
132 DCHECK_GT(notification_id, 0); 136 // TODO(peter): Record UMA on |status| for reading from the database.
133 137
134 if (status == NotificationDatabase::STATUS_OK) { 138 if (status == NotificationDatabase::STATUS_OK) {
139 DCHECK_GT(notification_id, 0);
135 BrowserThread::PostTask(BrowserThread::IO, 140 BrowserThread::PostTask(BrowserThread::IO,
136 FROM_HERE, 141 FROM_HERE,
137 base::Bind(callback, 142 base::Bind(callback,
138 true /* success */, 143 true /* success */,
139 notification_id)); 144 notification_id));
140 return; 145 return;
141 } 146 }
142 147
143 // TODO(peter): Record UMA on |status| for reading from the database. 148 // Blow away the database if writing data failed due to corruption.
144 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. 149 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
150 DestroyDatabase();
145 151
146 BrowserThread::PostTask( 152 BrowserThread::PostTask(
147 BrowserThread::IO, 153 BrowserThread::IO,
148 FROM_HERE, 154 FROM_HERE,
149 base::Bind(callback, false /* success */, 0 /* notification_id */)); 155 base::Bind(callback, false /* success */, 0 /* notification_id */));
150 } 156 }
151 157
152 void PlatformNotificationContextImpl::DeleteNotificationData( 158 void PlatformNotificationContextImpl::DeleteNotificationData(
153 int64_t notification_id, 159 int64_t notification_id,
154 const GURL& origin, 160 const GURL& origin,
155 const DeleteResultCallback& callback) { 161 const DeleteResultCallback& callback) {
156 DCHECK_CURRENTLY_ON(BrowserThread::IO); 162 DCHECK_CURRENTLY_ON(BrowserThread::IO);
157 LazyInitialize( 163 LazyInitialize(
158 base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData, 164 base::Bind(&PlatformNotificationContextImpl::DoDeleteNotificationData,
159 this, notification_id, origin, callback), 165 this, notification_id, origin, callback),
160 base::Bind(callback, false /* success */)); 166 base::Bind(callback, false /* success */));
161 } 167 }
162 168
163 void PlatformNotificationContextImpl::DoDeleteNotificationData( 169 void PlatformNotificationContextImpl::DoDeleteNotificationData(
164 int64_t notification_id, 170 int64_t notification_id,
165 const GURL& origin, 171 const GURL& origin,
166 const DeleteResultCallback& callback) { 172 const DeleteResultCallback& callback) {
167 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 173 DCHECK(task_runner_->RunsTasksOnCurrentThread());
168 174
169 NotificationDatabase::Status status = 175 NotificationDatabase::Status status =
170 database_->DeleteNotificationData(notification_id, origin); 176 database_->DeleteNotificationData(notification_id, origin);
171 177
172 const bool success = status == NotificationDatabase::STATUS_OK; 178 // TODO(peter): Record UMA on |status| for reading from the database.
173 179
174 // TODO(peter): Record UMA on |status| for reading from the database. 180 bool success = status == NotificationDatabase::STATUS_OK;
175 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED. 181
182 // Blow away the database if reading data failed due to corruption. Following
johnme 2015/03/20 15:29:06 s/reading/deleting/
Peter Beverloo 2015/03/20 18:55:37 Done.
183 // the contract of the delete methods, consider this to be a success as the
184 // caller's goal has been achieved: the data is gone.
185 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) {
186 DestroyDatabase();
cmumford 2015/03/20 17:36:52 Well I guess you will have times where DestroyData
187 success = true;
188 }
176 189
177 BrowserThread::PostTask(BrowserThread::IO, 190 BrowserThread::PostTask(BrowserThread::IO,
178 FROM_HERE, 191 FROM_HERE,
179 base::Bind(callback, success)); 192 base::Bind(callback, success));
180 } 193 }
181 194
182 void PlatformNotificationContextImpl::OnRegistrationDeleted( 195 void PlatformNotificationContextImpl::OnRegistrationDeleted(
183 int64_t registration_id, 196 int64_t registration_id,
184 const GURL& pattern) { 197 const GURL& pattern) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO); 198 DCHECK_CURRENTLY_ON(BrowserThread::IO);
186 LazyInitialize( 199 LazyInitialize(
187 base::Bind(&PlatformNotificationContextImpl:: 200 base::Bind(&PlatformNotificationContextImpl::
188 DoDeleteNotificationsForServiceWorkerRegistration, 201 DoDeleteNotificationsForServiceWorkerRegistration,
189 this, pattern.GetOrigin(), registration_id), 202 this, pattern.GetOrigin(), registration_id),
190 base::Bind(&DoNothing)); 203 base::Bind(&DoNothing));
191 } 204 }
192 205
193 void PlatformNotificationContextImpl:: 206 void PlatformNotificationContextImpl::
194 DoDeleteNotificationsForServiceWorkerRegistration( 207 DoDeleteNotificationsForServiceWorkerRegistration(
195 const GURL& origin, 208 const GURL& origin,
196 int64_t service_worker_registration_id) { 209 int64_t service_worker_registration_id) {
197 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 210 DCHECK(task_runner_->RunsTasksOnCurrentThread());
198 211
199 std::set<int64_t> deleted_notifications_set; 212 std::set<int64_t> deleted_notifications_set;
200 database_->DeleteAllNotificationDataForServiceWorkerRegistration( 213 NotificationDatabase::Status status =
201 origin, service_worker_registration_id, &deleted_notifications_set); 214 database_->DeleteAllNotificationDataForServiceWorkerRegistration(
215 origin, service_worker_registration_id, &deleted_notifications_set);
202 216
203 // TODO(peter): Record UMA on status for deleting from the database. 217 // TODO(peter): Record UMA on status for deleting from the database.
218
219 // Blow away the database if a corruption error occurred during the deletion.
220 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED)
221 DestroyDatabase();
222
204 // TODO(peter): Close the notifications in |deleted_notifications_set|. 223 // TODO(peter): Close the notifications in |deleted_notifications_set|.
205 } 224 }
206 225
226 void PlatformNotificationContextImpl::OnStorageWiped() {
227 DCHECK_CURRENTLY_ON(BrowserThread::IO);
228 LazyInitialize(
229 base::Bind(&PlatformNotificationContextImpl::DestroyDatabase, this),
230 base::Bind(&DoNothing));
231 }
232
207 void PlatformNotificationContextImpl::LazyInitialize( 233 void PlatformNotificationContextImpl::LazyInitialize(
208 const base::Closure& success_closure, 234 const base::Closure& success_closure,
209 const base::Closure& failure_closure) { 235 const base::Closure& failure_closure) {
210 DCHECK_CURRENTLY_ON(BrowserThread::IO); 236 DCHECK_CURRENTLY_ON(BrowserThread::IO);
211 237
212 if (!task_runner_) { 238 if (!task_runner_) {
213 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); 239 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
214 base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken(); 240 base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken();
215 241
216 task_runner_ = pool->GetSequencedTaskRunner(token); 242 task_runner_ = pool->GetSequencedTaskRunner(token);
217 } 243 }
218 244
219 task_runner_->PostTask( 245 task_runner_->PostTask(
220 FROM_HERE, 246 FROM_HERE,
221 base::Bind(&PlatformNotificationContextImpl::OpenDatabase, 247 base::Bind(&PlatformNotificationContextImpl::OpenDatabase,
222 this, success_closure, failure_closure)); 248 this, success_closure, failure_closure,
249 true /* delete_on_corruption */));
223 } 250 }
224 251
225 void PlatformNotificationContextImpl::OpenDatabase( 252 void PlatformNotificationContextImpl::OpenDatabase(
226 const base::Closure& success_closure, 253 const base::Closure& success_closure,
227 const base::Closure& failure_closure) { 254 const base::Closure& failure_closure,
255 bool delete_on_corruption) {
228 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 256 DCHECK(task_runner_->RunsTasksOnCurrentThread());
229 257
230 if (database_) { 258 if (database_) {
231 success_closure.Run(); 259 success_closure.Run();
232 return; 260 return;
233 } 261 }
234 262
235 database_.reset(new NotificationDatabase(GetDatabasePath())); 263 database_.reset(new NotificationDatabase(GetDatabasePath()));
264 NotificationDatabase::Status status =
265 database_->Open(true /* create_if_missing */);
236 266
237 // TODO(peter): Record UMA on |status| for opening the database. 267 // TODO(peter): Record UMA on |status| for opening the database.
238 // TODO(peter): Do the DeleteAndStartOver dance for STATUS_ERROR_CORRUPTED.
239
240 NotificationDatabase::Status status =
241 database_->Open(true /* create_if_missing */);
242 268
243 if (status == NotificationDatabase::STATUS_OK) { 269 if (status == NotificationDatabase::STATUS_OK) {
244 success_closure.Run(); 270 success_closure.Run();
245 return; 271 return;
246 } 272 }
247 273
248 // TODO(peter): Properly handle failures when opening the database. 274 // When the database could not be opened due to corruption, and the
275 // |delete_on_corruption| parameter is true, blow it away and retry.
276 if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED &&
277 delete_on_corruption) {
278 DestroyDatabase();
279 OpenDatabase(success_closure,
280 failure_closure,
281 false /* delete_on_corruption */);
cmumford 2015/03/20 17:36:52 I see your point about booleans - I prefer the rel
Peter Beverloo 2015/03/20 18:55:37 That's a great suggestion - thank you once again!
282 return;
283 }
284
249 database_.reset(); 285 database_.reset();
250 286
251 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure); 287 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_closure);
252 } 288 }
253 289
290 void PlatformNotificationContextImpl::DestroyDatabase() {
291 DCHECK(task_runner_->RunsTasksOnCurrentThread());
292 DCHECK(database_);
293
294 // TODO(peter): Record UMA on the status code of the Destroy() call.
295 database_->Destroy();
296 database_.reset();
297
298 // Remove all files in the directory that the database was previously located
299 // in, to make sure that any left-over files are gone as well.
300 base::FilePath database_path = GetDatabasePath();
301 if (!database_path.empty())
302 base::DeleteFile(database_path, true);
303
304 // TODO(peter): Close any existing persistent notifications on the platform.
305 }
306
254 base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const { 307 base::FilePath PlatformNotificationContextImpl::GetDatabasePath() const {
255 if (path_.empty()) 308 if (path_.empty())
256 return path_; 309 return path_;
257 310
258 return path_.Append(kPlatformNotificationsDirectory); 311 return path_.Append(kPlatformNotificationsDirectory);
259 } 312 }
260 313
261 void PlatformNotificationContextImpl::SetTaskRunnerForTesting( 314 void PlatformNotificationContextImpl::SetTaskRunnerForTesting(
262 const scoped_refptr<base::SequencedTaskRunner>& task_runner) { 315 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
263 task_runner_ = task_runner; 316 task_runner_ = task_runner;
264 } 317 }
265 318
266 } // namespace content 319 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698