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

Side by Side Diff: content/browser/notifications/notification_database.cc

Issue 2300093002: Make //content responsible for generating notification Ids (Closed)
Patch Set: rebase + comments Created 4 years, 3 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/notification_database.h" 5 #include "content/browser/notifications/notification_database.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 12 matching lines...) Expand all
23 #include "url/gurl.h" 23 #include "url/gurl.h"
24 24
25 // Notification LevelDB database schema (in alphabetized order) 25 // Notification LevelDB database schema (in alphabetized order)
26 // ======================= 26 // =======================
27 // 27 //
28 // key: "DATA:" <origin identifier> '\x00' <notification_id> 28 // key: "DATA:" <origin identifier> '\x00' <notification_id>
29 // value: String containing the NotificationDatabaseDataProto protocol buffer 29 // value: String containing the NotificationDatabaseDataProto protocol buffer
30 // in serialized form. 30 // in serialized form.
31 // 31 //
32 // key: "NEXT_NOTIFICATION_ID" 32 // key: "NEXT_NOTIFICATION_ID"
33 // value: Decimal string which fits into an int64_t. 33 // value: Decimal string which fits into an int64_t, containing the next
34 // persistent notification ID.
34 35
35 namespace content { 36 namespace content {
36 namespace { 37 namespace {
37 38
38 // Keys of the fields defined in the database. 39 // Keys of the fields defined in the database.
39 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID"; 40 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
40 const char kDataKeyPrefix[] = "DATA:"; 41 const char kDataKeyPrefix[] = "DATA:";
41 42
42 // Separates the components of compound keys. 43 // Separates the components of compound keys.
43 const char kKeySeparator = '\x00'; 44 const char kKeySeparator = '\x00';
44 45
45 // The first notification id which to be handed out by the database. 46 // The first notification id which to be handed out by the database.
46 const int64_t kFirstNotificationId = 1; 47 const int64_t kFirstPersistentNotificationId = 1;
47 48
48 // Converts the LevelDB |status| to one of the notification database's values. 49 // Converts the LevelDB |status| to one of the notification database's values.
49 NotificationDatabase::Status LevelDBStatusToStatus( 50 NotificationDatabase::Status LevelDBStatusToStatus(
50 const leveldb::Status& status) { 51 const leveldb::Status& status) {
51 if (status.ok()) 52 if (status.ok())
52 return NotificationDatabase::STATUS_OK; 53 return NotificationDatabase::STATUS_OK;
53 else if (status.IsNotFound()) 54 else if (status.IsNotFound())
54 return NotificationDatabase::STATUS_ERROR_NOT_FOUND; 55 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
55 else if (status.IsCorruption()) 56 else if (status.IsCorruption())
56 return NotificationDatabase::STATUS_ERROR_CORRUPTED; 57 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
(...skipping 11 matching lines...) Expand all
68 std::string CreateDataPrefix(const GURL& origin) { 69 std::string CreateDataPrefix(const GURL& origin) {
69 if (!origin.is_valid()) 70 if (!origin.is_valid())
70 return kDataKeyPrefix; 71 return kDataKeyPrefix;
71 72
72 return base::StringPrintf("%s%s%c", kDataKeyPrefix, 73 return base::StringPrintf("%s%s%c", kDataKeyPrefix,
73 storage::GetIdentifierFromOrigin(origin).c_str(), 74 storage::GetIdentifierFromOrigin(origin).c_str(),
74 kKeySeparator); 75 kKeySeparator);
75 } 76 }
76 77
77 // Creates the compound data key in which notification data is stored. 78 // Creates the compound data key in which notification data is stored.
78 std::string CreateDataKey(const GURL& origin, int64_t notification_id) { 79 std::string CreateDataKey(const GURL& origin,
80 const std::string& notification_id) {
79 DCHECK(origin.is_valid()); 81 DCHECK(origin.is_valid());
80 return CreateDataPrefix(origin) + base::Int64ToString(notification_id); 82 DCHECK(!notification_id.empty());
83
84 return CreateDataPrefix(origin) + notification_id;
81 } 85 }
82 86
83 // Deserializes data in |serialized_data| to |notification_database_data|. 87 // Deserializes data in |serialized_data| to |notification_database_data|.
84 // Will return if the deserialization was successful. 88 // Will return if the deserialization was successful.
85 NotificationDatabase::Status DeserializedNotificationData( 89 NotificationDatabase::Status DeserializedNotificationData(
86 const std::string& serialized_data, 90 const std::string& serialized_data,
87 NotificationDatabaseData* notification_database_data) { 91 NotificationDatabaseData* notification_database_data) {
88 DCHECK(notification_database_data); 92 DCHECK(notification_database_data);
89 if (DeserializeNotificationDatabaseData(serialized_data, 93 if (DeserializeNotificationDatabaseData(serialized_data,
90 notification_database_data)) { 94 notification_database_data)) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 134
131 leveldb::DB* db = nullptr; 135 leveldb::DB* db = nullptr;
132 Status status = LevelDBStatusToStatus( 136 Status status = LevelDBStatusToStatus(
133 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db)); 137 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
134 if (status != STATUS_OK) 138 if (status != STATUS_OK)
135 return status; 139 return status;
136 140
137 state_ = STATE_INITIALIZED; 141 state_ = STATE_INITIALIZED;
138 db_.reset(db); 142 db_.reset(db);
139 143
140 return ReadNextNotificationId(); 144 return ReadNextPersistentNotificationId();
145 }
146
147 int64_t NotificationDatabase::GetNextPersistentNotificationId() {
148 return next_persistent_notification_id_++;
141 } 149 }
142 150
143 NotificationDatabase::Status NotificationDatabase::ReadNotificationData( 151 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
144 int64_t notification_id, 152 const std::string& notification_id,
145 const GURL& origin, 153 const GURL& origin,
146 NotificationDatabaseData* notification_database_data) const { 154 NotificationDatabaseData* notification_database_data) const {
147 DCHECK(sequence_checker_.CalledOnValidSequence()); 155 DCHECK(sequence_checker_.CalledOnValidSequence());
148 DCHECK_EQ(STATE_INITIALIZED, state_); 156 DCHECK_EQ(STATE_INITIALIZED, state_);
149 DCHECK_GE(notification_id, kFirstNotificationId); 157 DCHECK(!notification_id.empty());
150 DCHECK(origin.is_valid()); 158 DCHECK(origin.is_valid());
151 DCHECK(notification_database_data); 159 DCHECK(notification_database_data);
152 160
153 std::string key = CreateDataKey(origin, notification_id); 161 std::string key = CreateDataKey(origin, notification_id);
154 std::string serialized_data; 162 std::string serialized_data;
155 163
156 Status status = LevelDBStatusToStatus( 164 Status status = LevelDBStatusToStatus(
157 db_->Get(leveldb::ReadOptions(), key, &serialized_data)); 165 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
158 if (status != STATUS_OK) 166 if (status != STATUS_OK)
159 return status; 167 return status;
(...skipping 21 matching lines...) Expand all
181 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration( 189 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration(
182 const GURL& origin, 190 const GURL& origin,
183 int64_t service_worker_registration_id, 191 int64_t service_worker_registration_id,
184 std::vector<NotificationDatabaseData>* notification_data_vector) const { 192 std::vector<NotificationDatabaseData>* notification_data_vector) const {
185 return ReadAllNotificationDataInternal(origin, service_worker_registration_id, 193 return ReadAllNotificationDataInternal(origin, service_worker_registration_id,
186 notification_data_vector); 194 notification_data_vector);
187 } 195 }
188 196
189 NotificationDatabase::Status NotificationDatabase::WriteNotificationData( 197 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
190 const GURL& origin, 198 const GURL& origin,
191 const NotificationDatabaseData& notification_database_data, 199 const NotificationDatabaseData& notification_data) {
192 int64_t* notification_id) {
193 DCHECK(sequence_checker_.CalledOnValidSequence()); 200 DCHECK(sequence_checker_.CalledOnValidSequence());
194 DCHECK_EQ(STATE_INITIALIZED, state_); 201 DCHECK_EQ(STATE_INITIALIZED, state_);
195 DCHECK(notification_id);
196 DCHECK(origin.is_valid()); 202 DCHECK(origin.is_valid());
197 203
198 DCHECK_GE(next_notification_id_, kFirstNotificationId); 204 const std::string& notification_id = notification_data.notification_id;
199 205 DCHECK(!notification_id.empty());
200 NotificationDatabaseData storage_data = notification_database_data;
201 storage_data.notification_id = next_notification_id_;
202 206
203 std::string serialized_data; 207 std::string serialized_data;
204 if (!SerializeNotificationDatabaseData(storage_data, &serialized_data)) { 208 if (!SerializeNotificationDatabaseData(notification_data, &serialized_data)) {
205 DLOG(ERROR) << "Unable to serialize data for a notification belonging " 209 DLOG(ERROR) << "Unable to serialize data for a notification belonging "
206 << "to: " << origin; 210 << "to: " << origin;
207 return STATUS_ERROR_FAILED; 211 return STATUS_ERROR_FAILED;
208 } 212 }
209 213
210 leveldb::WriteBatch batch; 214 leveldb::WriteBatch batch;
211 batch.Put(CreateDataKey(origin, next_notification_id_), serialized_data); 215 batch.Put(CreateDataKey(origin, notification_id), serialized_data);
212 batch.Put(kNextNotificationIdKey,
213 base::Int64ToString(next_notification_id_ + 1));
214 216
215 Status status = 217 if (written_persistent_notification_id_ != next_persistent_notification_id_) {
216 LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch)); 218 written_persistent_notification_id_ = next_persistent_notification_id_;
217 if (status != STATUS_OK) 219 batch.Put(kNextNotificationIdKey,
218 return status; 220 base::Int64ToString(next_persistent_notification_id_));
221 }
219 222
220 *notification_id = next_notification_id_++; 223 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
221 return STATUS_OK;
222 } 224 }
223 225
224 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData( 226 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
225 int64_t notification_id, 227 const std::string& notification_id,
226 const GURL& origin) { 228 const GURL& origin) {
227 DCHECK(sequence_checker_.CalledOnValidSequence()); 229 DCHECK(sequence_checker_.CalledOnValidSequence());
228 DCHECK_EQ(STATE_INITIALIZED, state_); 230 DCHECK_EQ(STATE_INITIALIZED, state_);
229 DCHECK_GE(notification_id, kFirstNotificationId); 231 DCHECK(!notification_id.empty());
230 DCHECK(origin.is_valid()); 232 DCHECK(origin.is_valid());
231 233
232 std::string key = CreateDataKey(origin, notification_id); 234 std::string key = CreateDataKey(origin, notification_id);
233 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key)); 235 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
234 } 236 }
235 237
236 NotificationDatabase::Status 238 NotificationDatabase::Status
237 NotificationDatabase::DeleteAllNotificationDataForOrigin( 239 NotificationDatabase::DeleteAllNotificationDataForOrigin(
238 const GURL& origin, 240 const GURL& origin,
239 const std::string& tag, 241 const std::string& tag,
240 std::set<int64_t>* deleted_notification_set) { 242 std::set<std::string>* deleted_notification_ids) {
241 return DeleteAllNotificationDataInternal(origin, tag, 243 return DeleteAllNotificationDataInternal(origin, tag,
242 kInvalidServiceWorkerRegistrationId, 244 kInvalidServiceWorkerRegistrationId,
243 deleted_notification_set); 245 deleted_notification_ids);
244 } 246 }
245 247
246 NotificationDatabase::Status 248 NotificationDatabase::Status
247 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration( 249 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration(
248 const GURL& origin, 250 const GURL& origin,
249 int64_t service_worker_registration_id, 251 int64_t service_worker_registration_id,
250 std::set<int64_t>* deleted_notification_set) { 252 std::set<std::string>* deleted_notification_ids) {
251 return DeleteAllNotificationDataInternal(origin, "" /* tag */, 253 return DeleteAllNotificationDataInternal(origin, "" /* tag */,
252 service_worker_registration_id, 254 service_worker_registration_id,
253 deleted_notification_set); 255 deleted_notification_ids);
254 } 256 }
255 257
256 NotificationDatabase::Status NotificationDatabase::Destroy() { 258 NotificationDatabase::Status NotificationDatabase::Destroy() {
257 DCHECK(sequence_checker_.CalledOnValidSequence()); 259 DCHECK(sequence_checker_.CalledOnValidSequence());
258 260
259 leveldb::Options options; 261 leveldb::Options options;
260 if (IsInMemoryDatabase()) { 262 if (IsInMemoryDatabase()) {
261 if (!env_) 263 if (!env_)
262 return STATUS_OK; // The database has not been initialized. 264 return STATUS_OK; // The database has not been initialized.
263 265
264 options.env = env_.get(); 266 options.env = env_.get();
265 } 267 }
266 268
267 state_ = STATE_DISABLED; 269 state_ = STATE_DISABLED;
268 db_.reset(); 270 db_.reset();
269 271
270 return LevelDBStatusToStatus( 272 return LevelDBStatusToStatus(
271 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options)); 273 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
272 } 274 }
273 275
274 NotificationDatabase::Status NotificationDatabase::ReadNextNotificationId() { 276 NotificationDatabase::Status
277 NotificationDatabase::ReadNextPersistentNotificationId() {
275 std::string value; 278 std::string value;
276 Status status = LevelDBStatusToStatus( 279 Status status = LevelDBStatusToStatus(
277 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value)); 280 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value));
278 281
279 if (status == STATUS_ERROR_NOT_FOUND) { 282 if (status == STATUS_ERROR_NOT_FOUND) {
280 next_notification_id_ = kFirstNotificationId; 283 next_persistent_notification_id_ = kFirstPersistentNotificationId;
284 written_persistent_notification_id_ = kFirstPersistentNotificationId;
281 return STATUS_OK; 285 return STATUS_OK;
282 } 286 }
283 287
284 if (status != STATUS_OK) 288 if (status != STATUS_OK)
285 return status; 289 return status;
286 290
287 if (!base::StringToInt64(value, &next_notification_id_) || 291 if (!base::StringToInt64(value, &next_persistent_notification_id_) ||
288 next_notification_id_ < kFirstNotificationId) { 292 next_persistent_notification_id_ < kFirstPersistentNotificationId) {
289 return STATUS_ERROR_CORRUPTED; 293 return STATUS_ERROR_CORRUPTED;
290 } 294 }
291 295
296 written_persistent_notification_id_ = next_persistent_notification_id_;
297
292 return STATUS_OK; 298 return STATUS_OK;
293 } 299 }
294 300
295 NotificationDatabase::Status 301 NotificationDatabase::Status
296 NotificationDatabase::ReadAllNotificationDataInternal( 302 NotificationDatabase::ReadAllNotificationDataInternal(
297 const GURL& origin, 303 const GURL& origin,
298 int64_t service_worker_registration_id, 304 int64_t service_worker_registration_id,
299 std::vector<NotificationDatabaseData>* notification_data_vector) const { 305 std::vector<NotificationDatabaseData>* notification_data_vector) const {
300 DCHECK(sequence_checker_.CalledOnValidSequence()); 306 DCHECK(sequence_checker_.CalledOnValidSequence());
301 DCHECK(notification_data_vector); 307 DCHECK(notification_data_vector);
302 308
303 const std::string prefix = CreateDataPrefix(origin); 309 const std::string prefix = CreateDataPrefix(origin);
304 310
305 leveldb::Slice prefix_slice(prefix); 311 leveldb::Slice prefix_slice(prefix);
306 312
307 NotificationDatabaseData notification_database_data; 313 NotificationDatabaseData notification_database_data;
308 std::unique_ptr<leveldb::Iterator> iter( 314 std::unique_ptr<leveldb::Iterator> iter(
309 db_->NewIterator(leveldb::ReadOptions())); 315 db_->NewIterator(leveldb::ReadOptions()));
310 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) { 316 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
311 if (!iter->key().starts_with(prefix_slice)) 317 if (!iter->key().starts_with(prefix_slice))
312 break; 318 break;
313 319
314 Status status = DeserializedNotificationData(iter->value().ToString(), 320 Status status = DeserializedNotificationData(iter->value().ToString(),
315 &notification_database_data); 321 &notification_database_data);
316 if (status != STATUS_OK) 322 if (status != STATUS_OK)
317 return status; 323 return status;
johnme 2016/09/08 15:21:50 I'm concerned that notifications that pre-date the
Peter Beverloo 2016/09/08 18:56:03 Why would it fail to deserialize? That'd work just
318 324
319 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId && 325 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
320 notification_database_data.service_worker_registration_id != 326 notification_database_data.service_worker_registration_id !=
321 service_worker_registration_id) { 327 service_worker_registration_id) {
322 continue; 328 continue;
323 } 329 }
324 330
325 notification_data_vector->push_back(notification_database_data); 331 notification_data_vector->push_back(notification_database_data);
326 } 332 }
327 333
328 return LevelDBStatusToStatus(iter->status()); 334 return LevelDBStatusToStatus(iter->status());
329 } 335 }
330 336
331 NotificationDatabase::Status 337 NotificationDatabase::Status
332 NotificationDatabase::DeleteAllNotificationDataInternal( 338 NotificationDatabase::DeleteAllNotificationDataInternal(
333 const GURL& origin, 339 const GURL& origin,
334 const std::string& tag, 340 const std::string& tag,
335 int64_t service_worker_registration_id, 341 int64_t service_worker_registration_id,
336 std::set<int64_t>* deleted_notification_set) { 342 std::set<std::string>* deleted_notification_ids) {
337 DCHECK(sequence_checker_.CalledOnValidSequence()); 343 DCHECK(sequence_checker_.CalledOnValidSequence());
338 DCHECK(deleted_notification_set); 344 DCHECK(deleted_notification_ids);
339 DCHECK(origin.is_valid()); 345 DCHECK(origin.is_valid());
340 346
341 const std::string prefix = CreateDataPrefix(origin); 347 const std::string prefix = CreateDataPrefix(origin);
342 const bool should_deserialize =
343 service_worker_registration_id != kInvalidServiceWorkerRegistrationId ||
344 !tag.empty();
345 348
346 leveldb::Slice prefix_slice(prefix); 349 leveldb::Slice prefix_slice(prefix);
347 leveldb::WriteBatch batch; 350 leveldb::WriteBatch batch;
348 351
349 NotificationDatabaseData notification_database_data; 352 NotificationDatabaseData notification_database_data;
350 std::unique_ptr<leveldb::Iterator> iter( 353 std::unique_ptr<leveldb::Iterator> iter(
351 db_->NewIterator(leveldb::ReadOptions())); 354 db_->NewIterator(leveldb::ReadOptions()));
352 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) { 355 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
353 if (!iter->key().starts_with(prefix_slice)) 356 if (!iter->key().starts_with(prefix_slice))
354 break; 357 break;
355 358
356 if (should_deserialize) { 359 Status status = DeserializedNotificationData(iter->value().ToString(),
357 Status status = DeserializedNotificationData(iter->value().ToString(), 360 &notification_database_data);
358 &notification_database_data); 361 if (status != STATUS_OK)
359 if (status != STATUS_OK) 362 return status;
360 return status;
361 363
362 if (!tag.empty() && 364 if (!tag.empty() &&
363 notification_database_data.notification_data.tag != tag) { 365 notification_database_data.notification_data.tag != tag) {
364 continue; 366 continue;
365 }
366
367 if (service_worker_registration_id !=
368 kInvalidServiceWorkerRegistrationId &&
369 notification_database_data.service_worker_registration_id !=
370 service_worker_registration_id) {
371 continue;
372 }
373 } 367 }
374 368
375 leveldb::Slice notification_id_slice = iter->key(); 369 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
376 notification_id_slice.remove_prefix(prefix_slice.size()); 370 notification_database_data.service_worker_registration_id !=
377 371 service_worker_registration_id) {
378 int64_t notification_id = 0; 372 continue;
379 if (!base::StringToInt64(notification_id_slice.ToString(),
380 &notification_id)) {
381 return STATUS_ERROR_CORRUPTED;
382 } 373 }
383 374
384 deleted_notification_set->insert(notification_id);
385 batch.Delete(iter->key()); 375 batch.Delete(iter->key());
376 deleted_notification_ids->insert(
377 notification_database_data.notification_id);
386 } 378 }
387 379
388 if (deleted_notification_set->empty()) 380 if (deleted_notification_ids->empty())
389 return STATUS_OK; 381 return STATUS_OK;
390 382
391 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch)); 383 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
392 } 384 }
393 385
394 } // namespace content 386 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698