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

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

Issue 999933002: Store the actual notification data in the notification database. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@n-db-GetNextNotificationId
Patch Set: comments 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"
12 #include "content/browser/notifications/notification_database_data.h"
11 #include "content/public/browser/browser_thread.h" 13 #include "content/public/browser/browser_thread.h"
14 #include "storage/common/database/database_identifier.h"
12 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 15 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
13 #include "third_party/leveldatabase/src/include/leveldb/db.h" 16 #include "third_party/leveldatabase/src/include/leveldb/db.h"
14 #include "third_party/leveldatabase/src/include/leveldb/env.h" 17 #include "third_party/leveldatabase/src/include/leveldb/env.h"
15 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 18 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
19 #include "url/gurl.h"
16 20
17 // Notification LevelDB database schema (in alphabetized order) 21 // Notification LevelDB database schema (in alphabetized order)
18 // ======================= 22 // =======================
19 // 23 //
24 // key: "DATA:" <origin identifier> '\x00' <notification_id>
25 // value: String containing the NotificationDatabaseDataProto protocol buffer
26 // in serialized form.
27 //
20 // key: "NEXT_NOTIFICATION_ID" 28 // key: "NEXT_NOTIFICATION_ID"
21 // value: Decimal string which fits into an int64_t. 29 // value: Decimal string which fits into an int64_t.
22 // 30 //
31 //
23 32
24 namespace content { 33 namespace content {
25 namespace { 34 namespace {
26 35
27 // Keys of the fields defined in the database. 36 // Keys of the fields defined in the database.
28 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID"; 37 const char kNextNotificationIdKey[] = "NEXT_NOTIFICATION_ID";
38 const char kDataKeyPrefix[] = "DATA:";
39
40 // Separates the components of compound keys.
41 const char kKeySeparator = '\x00';
29 42
30 // 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.
31 const int64_t kFirstNotificationId = 1; 44 const int64_t kFirstNotificationId = 1;
32 45
33 // 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.
34 NotificationDatabase::Status LevelDBStatusToStatus( 47 NotificationDatabase::Status LevelDBStatusToStatus(
35 const leveldb::Status& status) { 48 const leveldb::Status& status) {
36 if (status.ok()) 49 if (status.ok())
37 return NotificationDatabase::STATUS_OK; 50 return NotificationDatabase::STATUS_OK;
38 else if (status.IsNotFound()) 51 else if (status.IsNotFound())
39 return NotificationDatabase::STATUS_ERROR_NOT_FOUND; 52 return NotificationDatabase::STATUS_ERROR_NOT_FOUND;
40 else if (status.IsCorruption()) 53 else if (status.IsCorruption())
41 return NotificationDatabase::STATUS_ERROR_CORRUPTED; 54 return NotificationDatabase::STATUS_ERROR_CORRUPTED;
42 55
43 return NotificationDatabase::STATUS_ERROR_FAILED; 56 return NotificationDatabase::STATUS_ERROR_FAILED;
44 } 57 }
45 58
59 // Creates the compound data key in which notification data is stored.
60 std::string CreateDataKey(int64_t notification_id, const GURL& origin) {
61 return base::StringPrintf("%s%s%c%s",
62 kDataKeyPrefix,
63 storage::GetIdentifierFromOrigin(origin).c_str(),
64 kKeySeparator,
65 base::Int64ToString(notification_id).c_str());
66 }
67
46 } // namespace 68 } // namespace
47 69
48 NotificationDatabase::NotificationDatabase(const base::FilePath& path) 70 NotificationDatabase::NotificationDatabase(const base::FilePath& path)
49 : path_(path), 71 : path_(path),
50 state_(STATE_UNINITIALIZED) { 72 state_(STATE_UNINITIALIZED) {
51 sequence_checker_.DetachFromSequence(); 73 sequence_checker_.DetachFromSequence();
52 } 74 }
53 75
54 NotificationDatabase::~NotificationDatabase() { 76 NotificationDatabase::~NotificationDatabase() {
55 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 77 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
(...skipping 25 matching lines...) Expand all
81 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db)); 103 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
82 if (status != STATUS_OK) 104 if (status != STATUS_OK)
83 return status; 105 return status;
84 106
85 state_ = STATE_INITIALIZED; 107 state_ = STATE_INITIALIZED;
86 db_.reset(db); 108 db_.reset(db);
87 109
88 return STATUS_OK; 110 return STATUS_OK;
89 } 111 }
90 112
91 NotificationDatabase::Status NotificationDatabase::GetNextNotificationId( 113 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
92 int64_t* notification_id) const { 114 int64_t notification_id,
115 const GURL& origin,
116 NotificationDatabaseData* notification_database_data) const {
93 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 117 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
94 DCHECK_EQ(state_, STATE_INITIALIZED); 118 DCHECK_EQ(STATE_INITIALIZED, state_);
119 DCHECK_GE(notification_id, kFirstNotificationId);
120 DCHECK(origin.is_valid());
121 DCHECK(notification_database_data);
122
123 std::string key = CreateDataKey(notification_id, origin);
124 std::string serialized_data;
125
126 Status status = LevelDBStatusToStatus(
127 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
128 if (status != STATUS_OK)
129 return status;
130
131 if (notification_database_data->ParseFromString(serialized_data))
132 return STATUS_OK;
133
134 DLOG(ERROR) << "Unable to deserialize data for notification "
135 << notification_id << " belonging to " << origin << ".";
136 return STATUS_ERROR_CORRUPTED;
137 }
138
139 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
140 const GURL& origin,
141 const NotificationDatabaseData& notification_database_data,
142 int64_t* notification_id) {
143 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
144 DCHECK_EQ(STATE_INITIALIZED, state_);
95 DCHECK(notification_id); 145 DCHECK(notification_id);
146 DCHECK(origin.is_valid());
147
148 std::string serialized_data;
149 if (!notification_database_data.SerializeToString(&serialized_data)) {
150 DLOG(ERROR) << "Unable to serialize data for notification "
151 << notification_id << " belonging to " << origin << ".";
152 return STATUS_ERROR_FAILED;
153 }
154
155 leveldb::WriteBatch batch;
156 Status status = GetAndIncrementNextNotificationId(&batch, notification_id);
cmumford 2015/03/13 21:03:40 What about just getting the next notification ID o
Peter Beverloo 2015/03/16 11:56:45 Awesome, even better :) Thanks for the suggestion
157 if (status != STATUS_OK)
158 return status;
159
160 batch.Put(CreateDataKey(*notification_id, origin), serialized_data);
161
162 return LevelDBStatusToStatus(db_->Write(leveldb::WriteOptions(), &batch));
163 }
164
165 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
166 int64_t notification_id,
167 const GURL& origin) {
168 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
169 DCHECK_EQ(STATE_INITIALIZED, state_);
170 DCHECK_GE(notification_id, kFirstNotificationId);
171 DCHECK(origin.is_valid());
172
173 std::string key = CreateDataKey(notification_id, origin);
174
175 // TODO(peter): Instead of validating the existence of the data by reading the
176 // notification data, the notification list for |origin| should be considered
177 // instead. That list hasn't been implemented yet, however.
96 178
97 std::string value; 179 std::string value;
98 Status status = LevelDBStatusToStatus( 180 Status status = LevelDBStatusToStatus(
99 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value)); 181 db_->Get(leveldb::ReadOptions(), key, &value));
100
101 if (status == STATUS_ERROR_NOT_FOUND) {
102 *notification_id = kFirstNotificationId;
103 return STATUS_OK;
104 }
105
106 if (status != STATUS_OK) 182 if (status != STATUS_OK)
107 return status; 183 return status;
108 184
109 int64_t next_notification_id; 185 return LevelDBStatusToStatus(db_->Delete(leveldb::WriteOptions(), key));
110 if (!base::StringToInt64(value, &next_notification_id) ||
111 next_notification_id < kFirstNotificationId) {
112 return STATUS_ERROR_CORRUPTED;
113 }
114
115 *notification_id = next_notification_id;
116 return STATUS_OK;
117 } 186 }
118 187
119 NotificationDatabase::Status NotificationDatabase::Destroy() { 188 NotificationDatabase::Status NotificationDatabase::Destroy() {
120 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 189 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
121 190
122 leveldb::Options options; 191 leveldb::Options options;
123 if (IsInMemoryDatabase()) { 192 if (IsInMemoryDatabase()) {
124 if (!env_) 193 if (!env_)
125 return STATUS_OK; // The database has not been initialized. 194 return STATUS_OK; // The database has not been initialized.
126 195
127 options.env = env_.get(); 196 options.env = env_.get();
128 } 197 }
129 198
130 state_ = STATE_DISABLED; 199 state_ = STATE_DISABLED;
131 db_.reset(); 200 db_.reset();
132 201
133 return LevelDBStatusToStatus( 202 return LevelDBStatusToStatus(
134 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options)); 203 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
135 } 204 }
136 205
137 void NotificationDatabase::WriteNextNotificationId( 206 NotificationDatabase::Status
207 NotificationDatabase::GetAndIncrementNextNotificationId(
138 leveldb::WriteBatch* batch, 208 leveldb::WriteBatch* batch,
139 int64_t next_notification_id) const { 209 int64_t* notification_id) const {
140 DCHECK_GE(next_notification_id, kFirstNotificationId);
141 DCHECK(batch); 210 DCHECK(batch);
211 DCHECK(notification_id);
142 212
143 batch->Put(kNextNotificationIdKey, base::Int64ToString(next_notification_id)); 213 std::string value;
214 Status status = LevelDBStatusToStatus(
215 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value));
216
217 if (status == STATUS_ERROR_NOT_FOUND) {
218 *notification_id = kFirstNotificationId;
219
220 } else if (status == STATUS_OK) {
221 int64_t next_notification_id;
222 if (!base::StringToInt64(value, &next_notification_id) ||
223 next_notification_id < kFirstNotificationId) {
224 return STATUS_ERROR_CORRUPTED;
225 }
226
227 *notification_id = next_notification_id;
228 } else {
229 return status;
230 }
231
232 batch->Put(kNextNotificationIdKey,
233 base::Int64ToString(1 + *notification_id));
234
235 return STATUS_OK;
144 } 236 }
145 237
146 } // namespace content 238 } // 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