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

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/stringprintf.h" 11 #include "base/strings/stringprintf.h"
12 #include "content/browser/notifications/notification_database_data_conversions.h " 12 #include "content/browser/notifications/notification_database_data_conversions.h "
13 #include "content/public/browser/browser_thread.h" 13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/notification_database_data.h"
14 #include "storage/common/database/database_identifier.h" 15 #include "storage/common/database/database_identifier.h"
15 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 16 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
16 #include "third_party/leveldatabase/src/include/leveldb/db.h" 17 #include "third_party/leveldatabase/src/include/leveldb/db.h"
17 #include "third_party/leveldatabase/src/include/leveldb/env.h" 18 #include "third_party/leveldatabase/src/include/leveldb/env.h"
18 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
19 #include "url/gurl.h" 20 #include "url/gurl.h"
20 21
21 // Notification LevelDB database schema (in alphabetized order) 22 // Notification LevelDB database schema (in alphabetized order)
22 // ======================= 23 // =======================
23 // 24 //
24 // key: "DATA:" <origin identifier> '\x00' <notification_id> 25 // key: "DATA:" <origin identifier> '\x00' <notification_id>
25 // value: String containing the NotificationDatabaseDataProto protocol buffer 26 // value: String containing the NotificationDatabaseDataProto protocol buffer
26 // in serialized form. 27 // in serialized form.
27 // 28 //
28 // key: "NEXT_NOTIFICATION_ID" 29 // key: "NEXT_NOTIFICATION_ID"
29 // value: Decimal string which fits into an int64_t. 30 // value: Decimal string which fits into an int64_t.
30 //
31 31
32 namespace content { 32 namespace content {
33 namespace { 33 namespace {
34 34
35 // Keys of the fields defined in the database. 35 // Keys of the fields defined in the database.
36 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID"; 36 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
37 const char kDataKeyPrefix[] = "DATA:"; 37 const char kDataKeyPrefix[] = "DATA:";
38 38
39 // Separates the components of compound keys. 39 // Separates the components of compound keys.
40 const char kKeySeparator = '\x00'; 40 const char kKeySeparator = '\x00';
41 41
42 // The first notification id which to be handed out by the database. 42 // The first notification id which to be handed out by the database.
43 const int64_t kFirstNotificationId = 1; 43 const int64_t kFirstNotificationId = 1;
44 44
45 // The id used internally to represent an invalid Service Worker registration.
46 const int64_t kInvalidServiceWorkerRegistrationId = -1;
johnme 2015/03/19 16:17:10 Nit: Include content/common/service_worker/service
Peter Beverloo 2015/03/19 16:53:42 Done.
47
45 // 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.
46 NotificationDatabase::Status LevelDBStatusToStatus( 49 NotificationDatabase::Status LevelDBStatusToStatus(
47 const leveldb::Status& status) { 50 const leveldb::Status& status) {
48 if (status.ok()) 51 if (status.ok())
49 return NotificationDatabase::STATUS_OK; 52 return NotificationDatabase::STATUS_OK;
50 else if (status.IsNotFound()) 53 else if (status.IsNotFound())
51 return NotificationDatabase::STATUS_ERROR_NOT_FOUND; 54 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
52 else if (status.IsCorruption()) 55 else if (status.IsCorruption())
53 return NotificationDatabase::STATUS_ERROR_CORRUPTED; 56 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
54 57
55 return NotificationDatabase::STATUS_ERROR_FAILED; 58 return NotificationDatabase::STATUS_ERROR_FAILED;
56 } 59 }
57 60
58 // Creates the compound data key in which notification data is stored. 61 // Creates a prefix for the data entries based on |origin|.
59 std::string CreateDataKey(int64_t notification_id, const GURL& origin) { 62 std::string CreateDataPrefix(const GURL& origin) {
johnme 2015/03/19 16:17:10 Optional alternative: Why not include the service_
Peter Beverloo 2015/03/19 16:53:42 I considered this, and actually implemented a few
60 return base::StringPrintf("%s%s%c%s", 63 if (!origin.is_valid())
64 return kDataKeyPrefix;
65
66 return base::StringPrintf("%s%s%c",
61 kDataKeyPrefix, 67 kDataKeyPrefix,
62 storage::GetIdentifierFromOrigin(origin).c_str(), 68 storage::GetIdentifierFromOrigin(origin).c_str(),
63 kKeySeparator, 69 kKeySeparator);
64 base::Int64ToString(notification_id).c_str()); 70 }
71
72 // Creates the compound data key in which notification data is stored.
73 std::string CreateDataKey(const GURL& origin, int64_t notification_id) {
74 DCHECK(origin.is_valid());
75 return CreateDataPrefix(origin) + base::Int64ToString(notification_id);
76 }
77
78 // Deserializes data in |serialized_data| to |notification_database_data|.
79 // Will return if the deserialization was successful.
80 NotificationDatabase::Status DeserializedNotificationData(
81 const std::string& serialized_data,
82 NotificationDatabaseData* notification_database_data) {
83 DCHECK(notification_database_data);
84 if (DeserializeNotificationDatabaseData(serialized_data,
85 notification_database_data)) {
86 return NotificationDatabase::STATUS_OK;
87 }
88
89 DLOG(ERROR) << "Unable to deserialize a notification's data.";
90 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
65 } 91 }
66 92
67 } // namespace 93 } // namespace
68 94
69 NotificationDatabase::NotificationDatabase(const base::FilePath& path) 95 NotificationDatabase::NotificationDatabase(const base::FilePath& path)
70 : path_(path) { 96 : path_(path) {
71 } 97 }
72 98
73 NotificationDatabase::~NotificationDatabase() { 99 NotificationDatabase::~NotificationDatabase() {
74 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 100 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 NotificationDatabase::Status NotificationDatabase::ReadNotificationData( 136 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
111 int64_t notification_id, 137 int64_t notification_id,
112 const GURL& origin, 138 const GURL& origin,
113 NotificationDatabaseData* notification_database_data) const { 139 NotificationDatabaseData* notification_database_data) const {
114 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 140 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
115 DCHECK_EQ(STATE_INITIALIZED, state_); 141 DCHECK_EQ(STATE_INITIALIZED, state_);
116 DCHECK_GE(notification_id, kFirstNotificationId); 142 DCHECK_GE(notification_id, kFirstNotificationId);
117 DCHECK(origin.is_valid()); 143 DCHECK(origin.is_valid());
118 DCHECK(notification_database_data); 144 DCHECK(notification_database_data);
119 145
120 std::string key = CreateDataKey(notification_id, origin); 146 std::string key = CreateDataKey(origin, notification_id);
121 std::string serialized_data; 147 std::string serialized_data;
122 148
123 Status status = LevelDBStatusToStatus( 149 Status status = LevelDBStatusToStatus(
124 db_->Get(leveldb::ReadOptions(), key, &serialized_data)); 150 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
125 if (status != STATUS_OK) 151 if (status != STATUS_OK)
126 return status; 152 return status;
127 153
128 if (DeserializeNotificationDatabaseData(serialized_data, 154 return DeserializedNotificationData(serialized_data,
129 notification_database_data)) { 155 notification_database_data);
130 return STATUS_OK; 156 }
131 }
132 157
133 DLOG(ERROR) << "Unable to deserialize data for notification " 158 NotificationDatabase::Status
134 << notification_id << " belonging to " << origin << "."; 159 NotificationDatabase::ReadAllNotificationData(
135 return STATUS_ERROR_CORRUPTED; 160 std::vector<NotificationDatabaseData>* notification_data_vector) const {
161 return ReadAllNotificationDataInternal(GURL() /* origin */,
162 kInvalidServiceWorkerRegistrationId,
163 notification_data_vector);
164 }
165
166 NotificationDatabase::Status
167 NotificationDatabase::ReadAllNotificationDataForOrigin(
168 const GURL& origin,
169 std::vector<NotificationDatabaseData>* notification_data_vector) const {
170 return ReadAllNotificationDataInternal(origin,
171 kInvalidServiceWorkerRegistrationId,
172 notification_data_vector);
173 }
174
175 NotificationDatabase::Status
176 NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration(
177 const GURL& origin,
178 int64_t service_worker_registration_id,
179 std::vector<NotificationDatabaseData>* notification_data_vector) const {
180 return ReadAllNotificationDataInternal(origin,
181 service_worker_registration_id,
182 notification_data_vector);
136 } 183 }
137 184
138 NotificationDatabase::Status NotificationDatabase::WriteNotificationData( 185 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
139 const GURL& origin, 186 const GURL& origin,
140 const NotificationDatabaseData& notification_database_data, 187 const NotificationDatabaseData& notification_database_data,
141 int64_t* notification_id) { 188 int64_t* notification_id) {
142 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 189 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
143 DCHECK_EQ(STATE_INITIALIZED, state_); 190 DCHECK_EQ(STATE_INITIALIZED, state_);
144 DCHECK(notification_id); 191 DCHECK(notification_id);
145 DCHECK(origin.is_valid()); 192 DCHECK(origin.is_valid());
146 193
147 std::string serialized_data; 194 std::string serialized_data;
148 if (!SerializeNotificationDatabaseData(notification_database_data, 195 if (!SerializeNotificationDatabaseData(notification_database_data,
149 &serialized_data)) { 196 &serialized_data)) {
150 DLOG(ERROR) << "Unable to serialize data for a notification belonging " 197 DLOG(ERROR) << "Unable to serialize data for a notification belonging "
151 << "to: " << origin; 198 << "to: " << origin;
152 return STATUS_ERROR_FAILED; 199 return STATUS_ERROR_FAILED;
153 } 200 }
154 201
155 DCHECK_GE(next_notification_id_, kFirstNotificationId); 202 DCHECK_GE(next_notification_id_, kFirstNotificationId);
156 203
157 leveldb::WriteBatch batch; 204 leveldb::WriteBatch batch;
158 batch.Put(CreateDataKey(next_notification_id_, origin), serialized_data); 205 batch.Put(CreateDataKey(origin, next_notification_id_), serialized_data);
159 batch.Put(kNextNotificationIdKey, 206 batch.Put(kNextNotificationIdKey,
160 base::Int64ToString(next_notification_id_ + 1)); 207 base::Int64ToString(next_notification_id_ + 1));
161 208
162 Status status = LevelDBStatusToStatus( 209 Status status = LevelDBStatusToStatus(
163 db_->Write(leveldb::WriteOptions(), &batch)); 210 db_->Write(leveldb::WriteOptions(), &batch));
164 if (status != STATUS_OK) 211 if (status != STATUS_OK)
165 return status; 212 return status;
166 213
167 *notification_id = next_notification_id_++; 214 *notification_id = next_notification_id_++;
168 return STATUS_OK; 215 return STATUS_OK;
169 } 216 }
170 217
171 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData( 218 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
172 int64_t notification_id, 219 int64_t notification_id,
173 const GURL& origin) { 220 const GURL& origin) {
174 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 221 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
175 DCHECK_EQ(STATE_INITIALIZED, state_); 222 DCHECK_EQ(STATE_INITIALIZED, state_);
176 DCHECK_GE(notification_id, kFirstNotificationId); 223 DCHECK_GE(notification_id, kFirstNotificationId);
177 DCHECK(origin.is_valid()); 224 DCHECK(origin.is_valid());
178 225
179 std::string key = CreateDataKey(notification_id, origin); 226 std::string key = CreateDataKey(origin, notification_id);
180 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key)); 227 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
181 } 228 }
182 229
230 NotificationDatabase::Status
231 NotificationDatabase::DeleteAllNotificationDataForOrigin(
232 const GURL& origin,
233 std::set<int64_t>* deleted_notification_set) {
234 return DeleteAllNotificationDataInternal(origin,
235 kInvalidServiceWorkerRegistrationId,
236 deleted_notification_set);
237 }
238
239 NotificationDatabase::Status
240 NotificationDatabase::DeleteAllNotificationDataForServiceWorkerRegistration(
241 const GURL& origin,
242 int64_t service_worker_registration_id,
243 std::set<int64_t>* deleted_notification_set) {
244 return DeleteAllNotificationDataInternal(origin,
245 service_worker_registration_id,
246 deleted_notification_set);
247 }
248
183 NotificationDatabase::Status NotificationDatabase::Destroy() { 249 NotificationDatabase::Status NotificationDatabase::Destroy() {
184 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 250 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
185 251
186 leveldb::Options options; 252 leveldb::Options options;
187 if (IsInMemoryDatabase()) { 253 if (IsInMemoryDatabase()) {
188 if (!env_) 254 if (!env_)
189 return STATUS_OK; // The database has not been initialized. 255 return STATUS_OK; // The database has not been initialized.
190 256
191 options.env = env_.get(); 257 options.env = env_.get();
192 } 258 }
(...skipping 19 matching lines...) Expand all
212 return status; 278 return status;
213 279
214 if (!base::StringToInt64(value, &next_notification_id_) || 280 if (!base::StringToInt64(value, &next_notification_id_) ||
215 next_notification_id_ < kFirstNotificationId) { 281 next_notification_id_ < kFirstNotificationId) {
216 return STATUS_ERROR_CORRUPTED; 282 return STATUS_ERROR_CORRUPTED;
217 } 283 }
218 284
219 return STATUS_OK; 285 return STATUS_OK;
220 } 286 }
221 287
288 NotificationDatabase::Status
289 NotificationDatabase::ReadAllNotificationDataInternal(
290 const GURL& origin,
291 int64_t service_worker_registration_id,
292 std::vector<NotificationDatabaseData>* notification_data_vector) const {
293 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
294 DCHECK(notification_data_vector);
295
296 const std::string prefix = CreateDataPrefix(origin);
297
298 leveldb::Slice prefix_slice(prefix);
299
300 NotificationDatabaseData notification_database_data;
301 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
302 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
303 if (!iter->key().starts_with(prefix_slice))
304 break;
305
306 Status status = DeserializedNotificationData(iter->value().ToString(),
307 &notification_database_data);
308 if (status != STATUS_OK)
309 return status;
310
311 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId &&
312 notification_database_data.service_worker_registration_id !=
313 service_worker_registration_id) {
314 continue;
315 }
316
317 notification_data_vector->push_back(notification_database_data);
318 }
319
320 return LevelDBStatusToStatus(iter->status());
321 }
322
323 NotificationDatabase::Status
324 NotificationDatabase::DeleteAllNotificationDataInternal(
325 const GURL& origin,
326 int64_t service_worker_registration_id,
327 std::set<int64_t>* deleted_notification_set) {
328 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
329 DCHECK(deleted_notification_set);
330 DCHECK(origin.is_valid());
331
332 const std::string prefix = CreateDataPrefix(origin);
333
334 leveldb::Slice prefix_slice(prefix);
335 leveldb::WriteBatch batch;
336
337 NotificationDatabaseData notification_database_data;
338 scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
339 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) {
340 if (!iter->key().starts_with(prefix_slice))
341 break;
342
343 if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId) {
344 Status status = DeserializedNotificationData(iter->value().ToString(),
345 &notification_database_data);
346 if (status != STATUS_OK)
347 return status;
348
349 if (notification_database_data.service_worker_registration_id !=
350 service_worker_registration_id) {
351 continue;
352 }
353 }
354
355 leveldb::Slice notification_id_slice = iter->key();
356 notification_id_slice.remove_prefix(prefix_slice.size());
357
358 int64_t notification_id = 0;
359 if (!base::StringToInt64(notification_id_slice.ToString(),
360 &notification_id)) {
361 return STATUS_ERROR_CORRUPTED;
362 }
363
364 deleted_notification_set->insert(notification_id);
365 batch.Delete(iter->key());
366 }
367
368 if (deleted_notification_set->empty())
369 return STATUS_OK;
370
371 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
372 }
373
222 } // namespace content 374 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/notifications/notification_database.h ('k') | content/browser/notifications/notification_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698