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

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