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

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: 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),
72 next_notification_id_(0),
cmumford 2015/03/16 17:14:07 Could initialize this (and state_) in the header i
Peter Beverloo 2015/03/16 17:48:23 Cool, I didn't know we allowed that :). Changed!
50 state_(STATE_UNINITIALIZED) { 73 state_(STATE_UNINITIALIZED) {
51 sequence_checker_.DetachFromSequence(); 74 sequence_checker_.DetachFromSequence();
52 } 75 }
53 76
54 NotificationDatabase::~NotificationDatabase() { 77 NotificationDatabase::~NotificationDatabase() {
55 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 78 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
56 } 79 }
57 80
58 NotificationDatabase::Status NotificationDatabase::Open( 81 NotificationDatabase::Status NotificationDatabase::Open(
59 bool create_if_missing) { 82 bool create_if_missing) {
(...skipping 18 matching lines...) Expand all
78 101
79 leveldb::DB* db = nullptr; 102 leveldb::DB* db = nullptr;
80 Status status = LevelDBStatusToStatus( 103 Status status = LevelDBStatusToStatus(
81 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db)); 104 leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
82 if (status != STATUS_OK) 105 if (status != STATUS_OK)
83 return status; 106 return status;
84 107
85 state_ = STATE_INITIALIZED; 108 state_ = STATE_INITIALIZED;
86 db_.reset(db); 109 db_.reset(db);
87 110
111 return GetNextNotificationId(&next_notification_id_);
cmumford 2015/03/16 17:14:07 Now that GetNextNotificationId is private and is a
Peter Beverloo 2015/03/16 17:48:23 Done.
112 }
113
114 NotificationDatabase::Status NotificationDatabase::ReadNotificationData(
115 int64_t notification_id,
116 const GURL& origin,
117 NotificationDatabaseData* notification_database_data) const {
118 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
119 DCHECK_EQ(STATE_INITIALIZED, state_);
120 DCHECK_GE(notification_id, kFirstNotificationId);
cmumford 2015/03/16 17:14:07 Could you also add DCHECK_LT(notification_id, next
Peter Beverloo 2015/03/16 17:48:23 It would just return STATUS_NOT_FOUND, which in it
121 DCHECK(origin.is_valid());
122 DCHECK(notification_database_data);
123
124 std::string key = CreateDataKey(notification_id, origin);
125 std::string serialized_data;
126
127 Status status = LevelDBStatusToStatus(
128 db_->Get(leveldb::ReadOptions(), key, &serialized_data));
129 if (status != STATUS_OK)
130 return status;
131
132 if (notification_database_data->ParseFromString(serialized_data))
133 return STATUS_OK;
134
135 DLOG(ERROR) << "Unable to deserialize data for notification "
136 << notification_id << " belonging to " << origin << ".";
137 return STATUS_ERROR_CORRUPTED;
138 }
139
140 NotificationDatabase::Status NotificationDatabase::WriteNotificationData(
141 const GURL& origin,
142 const NotificationDatabaseData& notification_database_data,
143 int64_t* notification_id) {
144 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
145 DCHECK_EQ(STATE_INITIALIZED, state_);
146 DCHECK(notification_id);
147 DCHECK(origin.is_valid());
148
149 std::string serialized_data;
150 if (!notification_database_data.SerializeToString(&serialized_data)) {
151 DLOG(ERROR) << "Unable to serialize data for a notification belonging "
152 << "to: " << origin;
153 return STATUS_ERROR_FAILED;
154 }
155
156 DCHECK_GE(next_notification_id_, kFirstNotificationId);
157
158 leveldb::WriteBatch batch;
159 batch.Put(CreateDataKey(next_notification_id_, origin), serialized_data);
160 batch.Put(kNextNotificationIdKey,
161 base::Int64ToString(next_notification_id_ + 1));
162
163 Status status = LevelDBStatusToStatus(
164 db_->Write(leveldb::WriteOptions(), &batch));
165 if (status != STATUS_OK)
166 return status;
167
168 *notification_id = next_notification_id_++;
88 return STATUS_OK; 169 return STATUS_OK;
89 } 170 }
90 171
91 NotificationDatabase::Status NotificationDatabase::GetNextNotificationId( 172 NotificationDatabase::Status NotificationDatabase::DeleteNotificationData(
92 int64_t* notification_id) const { 173 int64_t notification_id,
174 const GURL& origin) {
93 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 175 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
94 DCHECK_EQ(state_, STATE_INITIALIZED); 176 DCHECK_EQ(STATE_INITIALIZED, state_);
95 DCHECK(notification_id); 177 DCHECK_GE(notification_id, kFirstNotificationId);
178 DCHECK(origin.is_valid());
179
180 std::string key = CreateDataKey(notification_id, origin);
181
182 // TODO(peter): Instead of validating the existence of the data by reading the
cmumford 2015/03/16 17:14:07 Regarding validation. I would suggest making this
Peter Beverloo 2015/03/16 17:48:23 Issue 409520 provides good context. I have been do
183 // notification data, the notification list for |origin| should be considered
184 // instead. That list hasn't been implemented yet, however.
96 185
97 std::string value; 186 std::string value;
98 Status status = LevelDBStatusToStatus( 187 Status status = LevelDBStatusToStatus(
99 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value)); 188 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) 189 if (status != STATUS_OK)
107 return status; 190 return status;
108 191
109 int64_t next_notification_id; 192 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 } 193 }
118 194
119 NotificationDatabase::Status NotificationDatabase::Destroy() { 195 NotificationDatabase::Status NotificationDatabase::Destroy() {
120 DCHECK(sequence_checker_.CalledOnValidSequencedThread()); 196 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
121 197
122 leveldb::Options options; 198 leveldb::Options options;
123 if (IsInMemoryDatabase()) { 199 if (IsInMemoryDatabase()) {
124 if (!env_) 200 if (!env_)
125 return STATUS_OK; // The database has not been initialized. 201 return STATUS_OK; // The database has not been initialized.
126 202
127 options.env = env_.get(); 203 options.env = env_.get();
128 } 204 }
129 205
130 state_ = STATE_DISABLED; 206 state_ = STATE_DISABLED;
131 db_.reset(); 207 db_.reset();
132 208
133 return LevelDBStatusToStatus( 209 return LevelDBStatusToStatus(
134 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options)); 210 leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
135 } 211 }
136 212
137 void NotificationDatabase::WriteNextNotificationId( 213 NotificationDatabase::Status NotificationDatabase::GetNextNotificationId(
138 leveldb::WriteBatch* batch, 214 int64_t* notification_id) const {
139 int64_t next_notification_id) const { 215 DCHECK(notification_id);
140 DCHECK_GE(next_notification_id, kFirstNotificationId);
141 DCHECK(batch);
142 216
143 batch->Put(kNextNotificationIdKey, base::Int64ToString(next_notification_id)); 217 std::string value;
218 Status status = LevelDBStatusToStatus(
219 db_->Get(leveldb::ReadOptions(), kNextNotificationIdKey, &value));
220
221 if (status == STATUS_ERROR_NOT_FOUND) {
222 *notification_id = kFirstNotificationId;
223 return STATUS_OK;
224 }
225
226 if (status != STATUS_OK)
227 return status;
228
229 int64_t next_notification_id;
cmumford 2015/03/16 17:14:07 No need for local next_notification_id variable, b
Peter Beverloo 2015/03/16 17:48:23 Done.
230 if (!base::StringToInt64(value, &next_notification_id) ||
231 next_notification_id < kFirstNotificationId) {
232 return STATUS_ERROR_CORRUPTED;
233 }
234
235 *notification_id = next_notification_id;
236 return STATUS_OK;
144 } 237 }
145 238
146 } // namespace content 239 } // 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