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

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

Issue 1019073002: The notification database should be able to read or delete multiple items. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
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/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"
11 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
12 #include "content/browser/notifications/notification_database_data_conversions.h " 13 #include "content/browser/notifications/notification_database_data_conversions.h "
13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_database_data.h"
14 #include "storage/common/database/database_identifier.h" 16 #include "storage/common/database/database_identifier.h"
15 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 17 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
16 #include "third_party/leveldatabase/src/include/leveldb/db.h" 18 #include "third_party/leveldatabase/src/include/leveldb/db.h"
17 #include "third_party/leveldatabase/src/include/leveldb/env.h" 19 #include "third_party/leveldatabase/src/include/leveldb/env.h"
18 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 20 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
19 #include "url/gurl.h" 21 #include "url/gurl.h"
20 22
21 // Notification LevelDB database schema (in alphabetized order) 23 // Notification LevelDB database schema (in alphabetized order)
22 // ======================= 24 // =======================
23 // 25 //
24 // key: "DATA:" <origin identifier> '\x00' <notification_id> 26 // key: "DATA:" <origin identifier> ':' <notification_id>
25 // value: String containing the NotificationDatabaseDataProto protocol buffer 27 // value: String containing the NotificationDatabaseDataProto protocol buffer
26 // in serialized form. 28 // in serialized form.
27 // 29 //
28 // key: "NEXT_NOTIFICATION_ID" 30 // key: "NEXT_NOTIFICATION_ID"
29 // value: Decimal string which fits into an int64_t. 31 // value: Decimal string which fits into an int64_t.
30 // 32 //
31 33
32 namespace content { 34 namespace content {
33 namespace { 35 namespace {
34 36
35 // Keys of the fields defined in the database. 37 // Keys of the fields defined in the database.
36 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID"; 38 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
37 const char kDataKeyPrefix[] = "DATA:"; 39 const char kDataKeyPrefix[] = "DATA:";
38 40
39 // Separates the components of compound keys. 41 // Separates the components of compound keys.
40 const char kKeySeparator = '\x00'; 42 const char kKeySeparator = ':';
41 43
42 // The first notification id which to be handed out by the database. 44 // The first notification id which to be handed out by the database.
43 const int64_t kFirstNotificationId = 1; 45 const int64_t kFirstNotificationId = 1;
44 46
47 // The id used internally to represent an invalid Service Worker registration.
48 const int64_t kInvalidServiceWorkerRegistrationId = -1;
49
45 // Converts the LevelDB |status| to one of the notification database's values. 50 // Converts the LevelDB |status| to one of the notification database's values.
46 NotificationDatabase::Status LevelDBStatusToStatus( 51 NotificationDatabase::Status LevelDBStatusToStatus(
47 const leveldb::Status& status) { 52 const leveldb::Status& status) {
48 if (status.ok()) 53 if (status.ok())
49 return NotificationDatabase::STATUS_OK; 54 return NotificationDatabase::STATUS_OK;
50 else if (status.IsNotFound()) 55 else if (status.IsNotFound())
51 return NotificationDatabase::STATUS_ERROR_NOT_FOUND; 56 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
52 else if (status.IsCorruption()) 57 else if (status.IsCorruption())
53 return NotificationDatabase::STATUS_ERROR_CORRUPTED; 58 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
54 59
55 return NotificationDatabase::STATUS_ERROR_FAILED; 60 return NotificationDatabase::STATUS_ERROR_FAILED;
56 } 61 }
57 62
58 // Creates the compound data key in which notification data is stored. 63 // Creates a prefix for the data entries based on |origin|.
59 std::string CreateDataKey(int64_t notification_id, const GURL& origin) { 64 std::string CreateDataPrefix(const GURL& origin) {
60 return base::StringPrintf("%s%s%c%s", 65 if (!origin.is_valid())
66 return kDataKeyPrefix;
67
68 return base::StringPrintf("%s%s%c",
61 kDataKeyPrefix, 69 kDataKeyPrefix,
62 storage::GetIdentifierFromOrigin(origin).c_str(), 70 storage::GetIdentifierFromOrigin(origin).c_str(),
63 kKeySeparator, 71 kKeySeparator);
72 }
73
74 // Creates the compound data key in which notification data is stored.
75 std::string CreateDataKey(const GURL& origin, int64_t notification_id) {
76 DCHECK(origin.is_valid());
77
78 return base::StringPrintf("%s%s",
cmumford 2015/03/18 22:41:21 Can simplify to: return CreateDataPrefix(origin)
Peter Beverloo 2015/03/19 14:35:51 Done.
79 CreateDataPrefix(origin).c_str(),
64 base::Int64ToString(notification_id).c_str()); 80 base::Int64ToString(notification_id).c_str());
65 } 81 }
66 82
83 // Removes the |prefix| from the |key| and writes the remainder to |output|.
84 // Returns whether the |key| started with |prefix|.
85 bool RemovePrefix(const std::string& key,
cmumford 2015/03/18 22:41:20 Not sure this function really adds much. It does t
Peter Beverloo 2015/03/19 14:35:51 All done, that's awesome and much cleaner! This al
86 const std::string& prefix,
87 std::string* output) {
88 DCHECK(output);
89
90 if (!StartsWithASCII(key, prefix, true))
91 return false;
92
93 *output = key.substr(prefix.size());
94 return true;
95 }
96
97 // Deserializes data in |serialized_data| to |notification_database_data|.
98 // Will return if the deserialization was successful.
99 NotificationDatabase::Status DeserializedNotificationData(
100 const std::string& serialized_data,
101 NotificationDatabaseData* notification_database_data) {
102 DCHECK(notification_database_data);
103 if (DeserializeNotificationDatabaseData(serialized_data,
104 notification_database_data)) {
105 return NotificationDatabase::STATUS_OK;
106 }
107
108 DLOG(ERROR) << "Unable to deserialize a notification's data.";
109 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
110 }
111
67 } // namespace 112 } // namespace
68 113
69 NotificationDatabase::NotificationDatabase(const base::FilePath& path) 114 NotificationDatabase::NotificationDatabase(const base::FilePath& path)
70 : path_(path) { 115 : path_(path) {
71 } 116 }
72 117
73 NotificationDatabase::~NotificationDatabase() { 118 NotificationDatabase::~NotificationDatabase() {
74 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 119 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
75 } 120 }
76 121
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 NotificationDatabase::Status NotificationDatabase::ReadNotificationData( 155 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
111 int64_t notification_id, 156 int64_t notification_id,
112 const GURL& origin, 157 const GURL& origin,
113 NotificationDatabaseData* notification_database_data) const { 158 NotificationDatabaseData* notification_database_data) const {
114 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 159 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
115 DCHECK_EQ(STATE_INITIALIZED, state_); 160 DCHECK_EQ(STATE_INITIALIZED, state_);
116 DCHECK_GE(notification_id, kFirstNotificationId); 161 DCHECK_GE(notification_id, kFirstNotificationId);
117 DCHECK(origin.is_valid()); 162 DCHECK(origin.is_valid());
118 DCHECK(notification_database_data); 163 DCHECK(notification_database_data);
119 164
120 std::string key = CreateDataKey(notification_id, origin); 165 std::string key = CreateDataKey(origin, notification_id);
121 std::string serialized_data; 166 std::string serialized_data;
122 167
123 Status status = LevelDBStatusToStatus( 168 Status status = LevelDBStatusToStatus(
124 db_->Get(leveldb::ReadOptions(), key, &serialized_data)); 169 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
125 if (status != STATUS_OK) 170 if (status != STATUS_OK)
126 return status; 171 return status;
127 172
128 if (DeserializeNotificationDatabaseData(serialized_data, 173 return DeserializedNotificationData(serialized_data,
129 notification_database_data)) { 174 notification_database_data);
130 return STATUS_OK; 175 }
131 }
132 176
133 DLOG(ERROR) << "Unable to deserialize data for notification " 177 NotificationDatabase::Status
134 << notification_id << " belonging to " << origin << "."; 178 NotificationDatabase::ReadAllNotificationData(
135 return STATUS_ERROR_CORRUPTED; 179 std::vector<NotificationDatabaseData>* notification_data_vector) const {
180 return ReadAllNotificationDataInternal(GURL() /* origin */,
181 kInvalidServiceWorkerRegistrationId,
182 notification_data_vector);
183 }
184
185 NotificationDatabase::Status
186 NotificationDatabase::ReadAllNotificationDataForOrigin(
187 const GURL& origin,
188 std::vector<NotificationDatabaseData>* notification_data_vector) const {
189 return ReadAllNotificationDataInternal(origin,
190 kInvalidServiceWorkerRegistrationId,
191 notification_data_vector);
192 }
193
194 NotificationDatabase::Status
195 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration(
196 const GURL& origin,
197 int64_t service_worker_registration_id,
198 std::vector<NotificationDatabaseData>* notification_data_vector) const {
199 return ReadAllNotificationDataInternal(origin,
200 service_worker_registration_id,
201 notification_data_vector);
136 } 202 }
137 203
138 NotificationDatabase::Status NotificationDatabase::WriteNotificationData( 204 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
139 const GURL& origin, 205 const GURL& origin,
140 const NotificationDatabaseData& notification_database_data, 206 const NotificationDatabaseData& notification_database_data,
141 int64_t* notification_id) { 207 int64_t* notification_id) {
142 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 208 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
143 DCHECK_EQ(STATE_INITIALIZED, state_); 209 DCHECK_EQ(STATE_INITIALIZED, state_);
144 DCHECK(notification_id); 210 DCHECK(notification_id);
145 DCHECK(origin.is_valid()); 211 DCHECK(origin.is_valid());
146 212
147 std::string serialized_data; 213 std::string serialized_data;
148 if (!SerializeNotificationDatabaseData(notification_database_data, 214 if (!SerializeNotificationDatabaseData(notification_database_data,
149 &serialized_data)) { 215 &serialized_data)) {
150 DLOG(ERROR) << "Unable to serialize data for a notification belonging " 216 DLOG(ERROR) << "Unable to serialize data for a notification belonging "
151 << "to: " << origin; 217 << "to: " << origin;
152 return STATUS_ERROR_FAILED; 218 return STATUS_ERROR_FAILED;
153 } 219 }
154 220
155 DCHECK_GE(next_notification_id_, kFirstNotificationId); 221 DCHECK_GE(next_notification_id_, kFirstNotificationId);
156 222
157 leveldb::WriteBatch batch; 223 leveldb::WriteBatch batch;
158 batch.Put(CreateDataKey(next_notification_id_, origin), serialized_data); 224 batch.Put(CreateDataKey(origin, next_notification_id_), serialized_data);
159 batch.Put(kNextNotificationIdKey, 225 batch.Put(kNextNotificationIdKey,
160 base::Int64ToString(next_notification_id_ + 1)); 226 base::Int64ToString(next_notification_id_ + 1));
161 227
162 Status status = LevelDBStatusToStatus( 228 Status status = LevelDBStatusToStatus(
163 db_->Write(leveldb::WriteOptions(), &batch)); 229 db_->Write(leveldb::WriteOptions(), &batch));
164 if (status != STATUS_OK) 230 if (status != STATUS_OK)
165 return status; 231 return status;
166 232
167 *notification_id = next_notification_id_++; 233 *notification_id = next_notification_id_++;
168 return STATUS_OK; 234 return STATUS_OK;
169 } 235 }
170 236
171 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData( 237 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
172 int64_t notification_id, 238 int64_t notification_id,
173 const GURL& origin) { 239 const GURL& origin) {
174 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 240 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
175 DCHECK_EQ(STATE_INITIALIZED, state_); 241 DCHECK_EQ(STATE_INITIALIZED, state_);
176 DCHECK_GE(notification_id, kFirstNotificationId); 242 DCHECK_GE(notification_id, kFirstNotificationId);
177 DCHECK(origin.is_valid()); 243 DCHECK(origin.is_valid());
178 244
179 std::string key = CreateDataKey(notification_id, origin); 245 std::string key = CreateDataKey(origin, notification_id);
180 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key)); 246 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
181 } 247 }
182 248
249 NotificationDatabase::Status
250 NotificationDatabase::DeleteAllNotificationDataForOrigin(
251 const GURL& origin,
252 std::set<int64_t>* deleted_notification_ids) {
253 return DeleteAllNotificationDataInternal(origin,
254 kInvalidServiceWorkerRegistrationId,
255 deleted_notification_ids);
256 }
257
258 NotificationDatabase::Status
259 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration(
260 const GURL& origin,
261 int64_t service_worker_registration_id,
262 std::set<int64_t>* deleted_notification_ids) {
263 return DeleteAllNotificationDataInternal(origin,
264 service_worker_registration_id,
265 deleted_notification_ids);
266 }
267
183 NotificationDatabase::Status NotificationDatabase::Destroy() { 268 NotificationDatabase::Status NotificationDatabase::Destroy() {
184 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 269 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
185 270
186 leveldb::Options options; 271 leveldb::Options options;
187 if (IsInMemoryDatabase()) { 272 if (IsInMemoryDatabase()) {
188 if (!env_) 273 if (!env_)
189 return STATUS_OK; // The database has not been initialized. 274 return STATUS_OK; // The database has not been initialized.
190 275
191 options.env = env_.get(); 276 options.env = env_.get();
192 } 277 }
(...skipping 19 matching lines...) Expand all
212 return status; 297 return status;
213 298
214 if (!base::StringToInt64(value, &next_notification_id_) || 299 if (!base::StringToInt64(value, &next_notification_id_) ||
215 next_notification_id_ < kFirstNotificationId) { 300 next_notification_id_ < kFirstNotificationId) {
216 return STATUS_ERROR_CORRUPTED; 301 return STATUS_ERROR_CORRUPTED;
217 } 302 }
218 303
219 return STATUS_OK; 304 return STATUS_OK;
220 } 305 }
221 306
307 NotificationDatabase::Status
308 NotificationDatabase::ReadAllNotificationDataInternal(
309 const GURL& origin,
310 int64_t service_worker_registration_id,
311 std::vector<NotificationDatabaseData>* notification_data_vector) const {
312 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
313 DCHECK(notification_data_vector);
314
315 std::string prefix = CreateDataPrefix(origin);
316
317 NotificationDatabaseData notification_database_data;
318 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
319 for (iter->Seek(prefix); iter->Valid(); iter->Next()) {
320 Status status = LevelDBStatusToStatus(iter->status());
cmumford 2015/03/18 22:41:21 I don't think you'll ever get here (status will al
Peter Beverloo 2015/03/19 14:35:51 Done.
321 if (status != STATUS_OK)
322 return status;
323
324 if (!StartsWithASCII(iter->key().ToString(), prefix, true))
cmumford 2015/03/18 22:41:20 This works, but I recommend creating a prefix_slic
Peter Beverloo 2015/03/19 14:35:51 Done.
325 break;
326
327 status = DeserializedNotificationData(iter->value().ToString(),
328 &notification_database_data);
329 if (status != STATUS_OK)
330 return status;
331
332 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
333 notification_database_data.service_worker_registration_id !=
334 service_worker_registration_id) {
335 continue;
336 }
337
338 notification_data_vector->push_back(notification_database_data);
339 }
340
341 return STATUS_OK;
cmumford 2015/03/18 22:41:21 I think that moving LevelDBStatusToStatus(iter->st
Peter Beverloo 2015/03/19 14:35:51 Done.
342 }
343
344 NotificationDatabase::Status
345 NotificationDatabase::DeleteAllNotificationDataInternal(
346 const GURL& origin,
347 int64_t service_worker_registration_id,
348 std::set<int64_t>* deleted_notification_ids) {
349 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
350 DCHECK(deleted_notification_ids);
351 DCHECK(origin.is_valid());
352
353 std::string prefix = CreateDataPrefix(origin);
354 leveldb::WriteBatch batch;
355
356 NotificationDatabaseData notification_database_data;
357 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
358 for (iter->Seek(prefix); iter->Valid(); iter->Next()) {
359 Status status = LevelDBStatusToStatus(iter->status());
cmumford 2015/03/18 22:41:20 Same comment on status check as above.
Peter Beverloo 2015/03/19 14:35:51 Done.
360 if (status != STATUS_OK)
361 return status;
362
363 std::string value;
364 if (!RemovePrefix(iter->key().ToString(), prefix, &value))
cmumford 2015/03/18 22:41:21 leveldb::Slice::remove_prefix()
Peter Beverloo 2015/03/19 14:35:51 Done.
365 break;
366
367 int64_t notification_id = 0;
368 if (!base::StringToInt64(value, &notification_id))
cmumford 2015/03/18 22:41:21 Nit: notification_id isn't used until line 383 bel
Peter Beverloo 2015/03/19 14:35:51 Done.
369 return STATUS_ERROR_CORRUPTED;
370
371 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId) {
372 status = DeserializedNotificationData(iter->value().ToString(),
373 &notification_database_data);
374 if (status != STATUS_OK)
375 return status;
376
377 if (notification_database_data.service_worker_registration_id !=
378 service_worker_registration_id) {
379 continue;
380 }
381 }
382
383 deleted_notification_ids->insert(notification_id);
384 batch.Delete(iter->key());
385 }
386
387 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
cmumford 2015/03/18 22:41:21 Nit: Not sure if would get called much with no mat
Peter Beverloo 2015/03/19 14:35:51 Done.
388 }
389
222 } // namespace content 390 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698