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

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

Issue 2300093002: Make //content responsible for generating notification Ids (Closed)
Patch Set: Make //content responsible for generating notification Ids 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.
johnme 2016/09/07 17:13:14 "Decimal string that fits into an int64_t, contain
Peter Beverloo 2016/09/08 13:18:56 Done.
34 34
35 namespace content { 35 namespace content {
36 namespace { 36 namespace {
37 37
38 // Keys of the fields defined in the database. 38 // Keys of the fields defined in the database.
39 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID"; 39 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
johnme 2016/09/07 17:13:13 kNextPersistentNotificationIdKey?
Peter Beverloo 2016/09/08 13:18:56 The name ideally should match the key. We shouldn'
40 const char kDataKeyPrefix[] = "DATA:"; 40 const char kDataKeyPrefix[] = "DATA:";
41 41
42 // Separates the components of compound keys. 42 // Separates the components of compound keys.
43 const char kKeySeparator = '\x00'; 43 const char kKeySeparator = '\x00';
44 44
45 // The first notification id which to be handed out by the database. 45 // The first notification id which to be handed out by the database.
46 const int64_t kFirstNotificationId = 1; 46 const int64_t kFirstPersistentNotificationId = 1;
47 47
48 // Converts the LevelDB |status| to one of the notification database's values. 48 // Converts the LevelDB |status| to one of the notification database's values.
49 NotificationDatabase::Status LevelDBStatusToStatus( 49 NotificationDatabase::Status LevelDBStatusToStatus(
50 const leveldb::Status& status) { 50 const leveldb::Status& status) {
51 if (status.ok()) 51 if (status.ok())
52 return NotificationDatabase::STATUS_OK; 52 return NotificationDatabase::STATUS_OK;
53 else if (status.IsNotFound()) 53 else if (status.IsNotFound())
54 return NotificationDatabase::STATUS_ERROR_NOT_FOUND; 54 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
55 else if (status.IsCorruption()) 55 else if (status.IsCorruption())
56 return NotificationDatabase::STATUS_ERROR_CORRUPTED; 56 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
57 else if (status.IsIOError()) 57 else if (status.IsIOError())
58 return NotificationDatabase::STATUS_IO_ERROR; 58 return NotificationDatabase::STATUS_IO_ERROR;
59 else if (status.IsNotSupportedError()) 59 else if (status.IsNotSupportedError())
60 return NotificationDatabase::STATUS_NOT_SUPPORTED; 60 return NotificationDatabase::STATUS_NOT_SUPPORTED;
61 else if (status.IsInvalidArgument()) 61 else if (status.IsInvalidArgument())
62 return NotificationDatabase::STATUS_INVALID_ARGUMENT; 62 return NotificationDatabase::STATUS_INVALID_ARGUMENT;
63 63
64 return NotificationDatabase::STATUS_ERROR_FAILED; 64 return NotificationDatabase::STATUS_ERROR_FAILED;
65 } 65 }
66 66
67 // Creates a prefix for the data entries based on |origin|. 67 // Creates a prefix for the data entries based on |origin|.
68 std::string CreateDataPrefix(const GURL& origin) { 68 std::string CreateDataPrefix(const GURL& origin) {
69 if (!origin.is_valid()) 69 if (!origin.is_valid())
70 return kDataKeyPrefix; 70 return kDataKeyPrefix;
71 71
72 return base::StringPrintf("%s%s%c", kDataKeyPrefix, 72 return base::StringPrintf("%s%s%c", kDataKeyPrefix,
73 storage::GetIdentifierFromOrigin(origin).c_str(), 73 storage::GetIdentifierFromOrigin(origin).c_str(),
johnme 2016/09/07 17:13:14 Drive-by: DatabaseIdentifier::CreateFromOrigin has
Peter Beverloo 2016/09/08 13:18:56 Yes.
74 kKeySeparator); 74 kKeySeparator);
75 } 75 }
76 76
77 // Creates the compound data key in which notification data is stored. 77 // Creates the compound data key in which notification data is stored.
78 std::string CreateDataKey(const GURL& origin, int64_t notification_id) { 78 std::string CreateDataKey(const GURL& origin,
79 const std::string& notification_id) {
79 DCHECK(origin.is_valid()); 80 DCHECK(origin.is_valid());
80 return CreateDataPrefix(origin) + base::Int64ToString(notification_id); 81 DCHECK(!notification_id.empty());
82
83 return CreateDataPrefix(origin) + notification_id;
81 } 84 }
82 85
83 // Deserializes data in |serialized_data| to |notification_database_data|. 86 // Deserializes data in |serialized_data| to |notification_database_data|.
84 // Will return if the deserialization was successful. 87 // Will return if the deserialization was successful.
85 NotificationDatabase::Status DeserializedNotificationData( 88 NotificationDatabase::Status DeserializedNotificationData(
86 const std::string& serialized_data, 89 const std::string& serialized_data,
87 NotificationDatabaseData* notification_database_data) { 90 NotificationDatabaseData* notification_database_data) {
88 DCHECK(notification_database_data); 91 DCHECK(notification_database_data);
89 if (DeserializeNotificationDatabaseData(serialized_data, 92 if (DeserializeNotificationDatabaseData(serialized_data,
90 notification_database_data)) { 93 notification_database_data)) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db)); 136 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
134 if (status != STATUS_OK) 137 if (status != STATUS_OK)
135 return status; 138 return status;
136 139
137 state_ = STATE_INITIALIZED; 140 state_ = STATE_INITIALIZED;
138 db_.reset(db); 141 db_.reset(db);
139 142
140 return ReadNextNotificationId(); 143 return ReadNextNotificationId();
141 } 144 }
142 145
146 int64_t NotificationDatabase::GetNextNotificationId() {
147 return next_persistent_notification_id_++;
148 }
149
143 NotificationDatabase::Status NotificationDatabase::ReadNotificationData( 150 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
144 int64_t notification_id, 151 const std::string& notification_id,
145 const GURL& origin, 152 const GURL& origin,
146 NotificationDatabaseData* notification_database_data) const { 153 NotificationDatabaseData* notification_database_data) const {
147 DCHECK(sequence_checker_.CalledOnValidSequence()); 154 DCHECK(sequence_checker_.CalledOnValidSequence());
148 DCHECK_EQ(STATE_INITIALIZED, state_); 155 DCHECK_EQ(STATE_INITIALIZED, state_);
149 DCHECK_GE(notification_id, kFirstNotificationId); 156 DCHECK(!notification_id.empty());
150 DCHECK(origin.is_valid()); 157 DCHECK(origin.is_valid());
151 DCHECK(notification_database_data); 158 DCHECK(notification_database_data);
152 159
153 std::string key = CreateDataKey(origin, notification_id); 160 std::string key = CreateDataKey(origin, notification_id);
154 std::string serialized_data; 161 std::string serialized_data;
155 162
156 Status status = LevelDBStatusToStatus( 163 Status status = LevelDBStatusToStatus(
157 db_->Get(leveldb::ReadOptions(), key, &serialized_data)); 164 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
158 if (status != STATUS_OK) 165 if (status != STATUS_OK)
159 return status; 166 return status;
(...skipping 21 matching lines...) Expand all
181 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration( 188 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration(
182 const GURL& origin, 189 const GURL& origin,
183 int64_t service_worker_registration_id, 190 int64_t service_worker_registration_id,
184 std::vector<NotificationDatabaseData>* notification_data_vector) const { 191 std::vector<NotificationDatabaseData>* notification_data_vector) const {
185 return ReadAllNotificationDataInternal(origin, service_worker_registration_id, 192 return ReadAllNotificationDataInternal(origin, service_worker_registration_id,
186 notification_data_vector); 193 notification_data_vector);
187 } 194 }
188 195
189 NotificationDatabase::Status NotificationDatabase::WriteNotificationData( 196 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
190 const GURL& origin, 197 const GURL& origin,
191 const NotificationDatabaseData& notification_database_data, 198 const NotificationDatabaseData& notification_data) {
192 int64_t* notification_id) {
193 DCHECK(sequence_checker_.CalledOnValidSequence()); 199 DCHECK(sequence_checker_.CalledOnValidSequence());
194 DCHECK_EQ(STATE_INITIALIZED, state_); 200 DCHECK_EQ(STATE_INITIALIZED, state_);
195 DCHECK(notification_id);
196 DCHECK(origin.is_valid()); 201 DCHECK(origin.is_valid());
197 202
198 DCHECK_GE(next_notification_id_, kFirstNotificationId); 203 const std::string& notification_id = notification_data.notification_id;
199 204 DCHECK(!notification_id.empty());
200 NotificationDatabaseData storage_data = notification_database_data;
201 storage_data.notification_id = next_notification_id_;
202 205
203 std::string serialized_data; 206 std::string serialized_data;
204 if (!SerializeNotificationDatabaseData(storage_data, &serialized_data)) { 207 if (!SerializeNotificationDatabaseData(notification_data, &serialized_data)) {
205 DLOG(ERROR) << "Unable to serialize data for a notification belonging " 208 DLOG(ERROR) << "Unable to serialize data for a notification belonging "
206 << "to: " << origin; 209 << "to: " << origin;
207 return STATUS_ERROR_FAILED; 210 return STATUS_ERROR_FAILED;
208 } 211 }
209 212
210 leveldb::WriteBatch batch; 213 leveldb::WriteBatch batch;
211 batch.Put(CreateDataKey(origin, next_notification_id_), serialized_data); 214 batch.Put(CreateDataKey(origin, notification_id), serialized_data);
212 batch.Put(kNextNotificationIdKey,
213 base::Int64ToString(next_notification_id_ + 1));
214 215
215 Status status = 216 if (written_persistent_notification_id_ != next_persistent_notification_id_) {
johnme 2016/09/07 17:13:13 I like that if you create two and successfully wri
Peter Beverloo 2016/09/08 13:18:56 That's fine. We have space for another 9,223,372,0
216 LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch)); 217 written_persistent_notification_id_ = next_persistent_notification_id_;
217 if (status != STATUS_OK) 218 batch.Put(kNextNotificationIdKey,
218 return status; 219 base::Int64ToString(next_persistent_notification_id_));
220 }
219 221
220 *notification_id = next_notification_id_++; 222 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
221 return STATUS_OK;
222 } 223 }
223 224
224 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData( 225 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
225 int64_t notification_id, 226 const std::string& notification_id,
226 const GURL& origin) { 227 const GURL& origin) {
227 DCHECK(sequence_checker_.CalledOnValidSequence()); 228 DCHECK(sequence_checker_.CalledOnValidSequence());
228 DCHECK_EQ(STATE_INITIALIZED, state_); 229 DCHECK_EQ(STATE_INITIALIZED, state_);
229 DCHECK_GE(notification_id, kFirstNotificationId); 230 DCHECK(!notification_id.empty());
230 DCHECK(origin.is_valid()); 231 DCHECK(origin.is_valid());
231 232
232 std::string key = CreateDataKey(origin, notification_id); 233 std::string key = CreateDataKey(origin, notification_id);
233 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key)); 234 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
234 } 235 }
235 236
236 NotificationDatabase::Status 237 NotificationDatabase::Status
237 NotificationDatabase::DeleteAllNotificationDataForOrigin( 238 NotificationDatabase::DeleteAllNotificationDataForOrigin(
238 const GURL& origin, 239 const GURL& origin,
239 const std::string& tag, 240 const std::string& tag,
240 std::set<int64_t>* deleted_notification_set) { 241 std::set<std::string>* deleted_notification_ids) {
241 return DeleteAllNotificationDataInternal(origin, tag, 242 return DeleteAllNotificationDataInternal(origin, tag,
242 kInvalidServiceWorkerRegistrationId, 243 kInvalidServiceWorkerRegistrationId,
243 deleted_notification_set); 244 deleted_notification_ids);
244 } 245 }
245 246
246 NotificationDatabase::Status 247 NotificationDatabase::Status
247 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration( 248 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration(
248 const GURL& origin, 249 const GURL& origin,
249 int64_t service_worker_registration_id, 250 int64_t service_worker_registration_id,
250 std::set<int64_t>* deleted_notification_set) { 251 std::set<std::string>* deleted_notification_ids) {
251 return DeleteAllNotificationDataInternal(origin, "" /* tag */, 252 return DeleteAllNotificationDataInternal(origin, "" /* tag */,
252 service_worker_registration_id, 253 service_worker_registration_id,
253 deleted_notification_set); 254 deleted_notification_ids);
254 } 255 }
255 256
256 NotificationDatabase::Status NotificationDatabase::Destroy() { 257 NotificationDatabase::Status NotificationDatabase::Destroy() {
257 DCHECK(sequence_checker_.CalledOnValidSequence()); 258 DCHECK(sequence_checker_.CalledOnValidSequence());
258 259
259 leveldb::Options options; 260 leveldb::Options options;
260 if (IsInMemoryDatabase()) { 261 if (IsInMemoryDatabase()) {
261 if (!env_) 262 if (!env_)
262 return STATUS_OK; // The database has not been initialized. 263 return STATUS_OK; // The database has not been initialized.
263 264
264 options.env = env_.get(); 265 options.env = env_.get();
265 } 266 }
266 267
267 state_ = STATE_DISABLED; 268 state_ = STATE_DISABLED;
268 db_.reset(); 269 db_.reset();
269 270
270 return LevelDBStatusToStatus( 271 return LevelDBStatusToStatus(
271 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options)); 272 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
272 } 273 }
273 274
274 NotificationDatabase::Status NotificationDatabase::ReadNextNotificationId() { 275 NotificationDatabase::Status NotificationDatabase::ReadNextNotificationId() {
275 std::string value; 276 std::string value;
276 Status status = LevelDBStatusToStatus( 277 Status status = LevelDBStatusToStatus(
277 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value)); 278 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value));
278 279
279 if (status == STATUS_ERROR_NOT_FOUND) { 280 if (status == STATUS_ERROR_NOT_FOUND) {
280 next_notification_id_ = kFirstNotificationId; 281 next_persistent_notification_id_ = kFirstPersistentNotificationId;
282 written_persistent_notification_id_ = kFirstPersistentNotificationId;
281 return STATUS_OK; 283 return STATUS_OK;
282 } 284 }
283 285
284 if (status != STATUS_OK) 286 if (status != STATUS_OK)
285 return status; 287 return status;
286 288
287 if (!base::StringToInt64(value, &next_notification_id_) || 289 if (!base::StringToInt64(value, &next_persistent_notification_id_) ||
288 next_notification_id_ < kFirstNotificationId) { 290 next_persistent_notification_id_ < kFirstPersistentNotificationId) {
289 return STATUS_ERROR_CORRUPTED; 291 return STATUS_ERROR_CORRUPTED;
290 } 292 }
291 293
294 written_persistent_notification_id_ = next_persistent_notification_id_;
295
292 return STATUS_OK; 296 return STATUS_OK;
293 } 297 }
294 298
295 NotificationDatabase::Status 299 NotificationDatabase::Status
296 NotificationDatabase::ReadAllNotificationDataInternal( 300 NotificationDatabase::ReadAllNotificationDataInternal(
297 const GURL& origin, 301 const GURL& origin,
298 int64_t service_worker_registration_id, 302 int64_t service_worker_registration_id,
299 std::vector<NotificationDatabaseData>* notification_data_vector) const { 303 std::vector<NotificationDatabaseData>* notification_data_vector) const {
300 DCHECK(sequence_checker_.CalledOnValidSequence()); 304 DCHECK(sequence_checker_.CalledOnValidSequence());
301 DCHECK(notification_data_vector); 305 DCHECK(notification_data_vector);
(...skipping 24 matching lines...) Expand all
326 } 330 }
327 331
328 return LevelDBStatusToStatus(iter->status()); 332 return LevelDBStatusToStatus(iter->status());
329 } 333 }
330 334
331 NotificationDatabase::Status 335 NotificationDatabase::Status
332 NotificationDatabase::DeleteAllNotificationDataInternal( 336 NotificationDatabase::DeleteAllNotificationDataInternal(
333 const GURL& origin, 337 const GURL& origin,
334 const std::string& tag, 338 const std::string& tag,
335 int64_t service_worker_registration_id, 339 int64_t service_worker_registration_id,
336 std::set<int64_t>* deleted_notification_set) { 340 std::set<std::string>* deleted_notification_ids) {
337 DCHECK(sequence_checker_.CalledOnValidSequence()); 341 DCHECK(sequence_checker_.CalledOnValidSequence());
338 DCHECK(deleted_notification_set); 342 DCHECK(deleted_notification_ids);
339 DCHECK(origin.is_valid()); 343 DCHECK(origin.is_valid());
340 344
341 const std::string prefix = CreateDataPrefix(origin); 345 const std::string prefix = CreateDataPrefix(origin);
342 const bool should_deserialize =
343 service_worker_registration_id != kInvalidServiceWorkerRegistrationId ||
344 !tag.empty();
345 346
346 leveldb::Slice prefix_slice(prefix); 347 leveldb::Slice prefix_slice(prefix);
347 leveldb::WriteBatch batch; 348 leveldb::WriteBatch batch;
348 349
349 NotificationDatabaseData notification_database_data; 350 NotificationDatabaseData notification_database_data;
350 std::unique_ptr<leveldb::Iterator> iter( 351 std::unique_ptr<leveldb::Iterator> iter(
351 db_->NewIterator(leveldb::ReadOptions())); 352 db_->NewIterator(leveldb::ReadOptions()));
352 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) { 353 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
353 if (!iter->key().starts_with(prefix_slice)) 354 if (!iter->key().starts_with(prefix_slice))
354 break; 355 break;
355 356
356 if (should_deserialize) { 357 Status status = DeserializedNotificationData(iter->value().ToString(),
357 Status status = DeserializedNotificationData(iter->value().ToString(), 358 &notification_database_data);
358 &notification_database_data); 359 if (status != STATUS_OK)
359 if (status != STATUS_OK) 360 return status;
360 return status;
361 361
362 if (!tag.empty() && 362 if (!tag.empty() &&
363 notification_database_data.notification_data.tag != tag) { 363 notification_database_data.notification_data.tag != tag) {
364 continue; 364 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 } 365 }
374 366
375 leveldb::Slice notification_id_slice = iter->key(); 367 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
376 notification_id_slice.remove_prefix(prefix_slice.size()); 368 notification_database_data.service_worker_registration_id !=
377 369 service_worker_registration_id) {
378 int64_t notification_id = 0; 370 continue;
379 if (!base::StringToInt64(notification_id_slice.ToString(),
380 &notification_id)) {
381 return STATUS_ERROR_CORRUPTED;
382 } 371 }
383 372
384 deleted_notification_set->insert(notification_id);
385 batch.Delete(iter->key()); 373 batch.Delete(iter->key());
374 deleted_notification_ids->insert(
375 notification_database_data.notification_id);
386 } 376 }
387 377
388 if (deleted_notification_set->empty()) 378 if (deleted_notification_ids->empty())
389 return STATUS_OK; 379 return STATUS_OK;
390 380
391 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch)); 381 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
392 } 382 }
393 383
394 } // namespace content 384 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698