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

Side by Side Diff: chrome/browser/value_store/leveldb_value_store.cc

Issue 24021002: Propagate more information about ValueStore errors to callers, notably an (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add Pass*() Created 7 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/value_store/leveldb_value_store.h" 5 #include "chrome/browser/value_store/leveldb_value_store.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "base/strings/sys_string_conversions.h" 13 #include "base/strings/sys_string_conversions.h"
14 #include "chrome/browser/value_store/value_store_util.h"
14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
15 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" 16 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
16 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 17 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
17 18
19 namespace util = value_store_util;
18 using content::BrowserThread; 20 using content::BrowserThread;
19 21
20 namespace { 22 namespace {
21 23
22 const char* kInvalidJson = "Invalid JSON"; 24 const char kInvalidJson[] = "Invalid JSON";
23
24 ValueStore::ReadResult ReadFailure(const std::string& action,
25 const std::string& reason) {
26 CHECK_NE("", reason);
27 return ValueStore::MakeReadResult(base::StringPrintf(
28 "Failure to %s: %s", action.c_str(), reason.c_str()));
29 }
30
31 ValueStore::ReadResult ReadFailureForKey(const std::string& action,
32 const std::string& key,
33 const std::string& reason) {
34 CHECK_NE("", reason);
35 return ValueStore::MakeReadResult(base::StringPrintf(
36 "Failure to %s for key %s: %s",
37 action.c_str(), key.c_str(), reason.c_str()));
38 }
39
40 ValueStore::WriteResult WriteFailure(const std::string& action,
41 const std::string& reason) {
42 CHECK_NE("", reason);
43 return ValueStore::MakeWriteResult(base::StringPrintf(
44 "Failure to %s: %s", action.c_str(), reason.c_str()));
45 }
46
47 ValueStore::WriteResult WriteFailureForKey(const std::string& action,
48 const std::string& key,
49 const std::string& reason) {
50 CHECK_NE("", reason);
51 return ValueStore::MakeWriteResult(base::StringPrintf(
52 "Failure to %s for key %s: %s",
53 action.c_str(), key.c_str(), reason.c_str()));
54 }
55 25
56 // Scoped leveldb snapshot which releases the snapshot on destruction. 26 // Scoped leveldb snapshot which releases the snapshot on destruction.
57 class ScopedSnapshot { 27 class ScopedSnapshot {
58 public: 28 public:
59 explicit ScopedSnapshot(leveldb::DB* db) 29 explicit ScopedSnapshot(leveldb::DB* db)
60 : db_(db), snapshot_(db->GetSnapshot()) {} 30 : db_(db), snapshot_(db->GetSnapshot()) {}
61 31
62 ~ScopedSnapshot() { 32 ~ScopedSnapshot() {
63 db_->ReleaseSnapshot(snapshot_); 33 db_->ReleaseSnapshot(snapshot_);
64 } 34 }
65 35
66 const leveldb::Snapshot* get() { 36 const leveldb::Snapshot* get() {
67 return snapshot_; 37 return snapshot_;
68 } 38 }
69 39
70 private: 40 private:
71 leveldb::DB* db_; 41 leveldb::DB* db_;
72 const leveldb::Snapshot* snapshot_; 42 const leveldb::Snapshot* snapshot_;
73 43
74 DISALLOW_COPY_AND_ASSIGN(ScopedSnapshot); 44 DISALLOW_COPY_AND_ASSIGN(ScopedSnapshot);
75 }; 45 };
76 46
77 } // namespace 47 } // namespace
78 48
79 LeveldbValueStore::LeveldbValueStore(const base::FilePath& db_path) 49 LeveldbValueStore::LeveldbValueStore(const base::FilePath& db_path)
80 : db_path_(db_path) { 50 : db_path_(db_path) {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
82 52
83 std::string error = EnsureDbIsOpen(); 53 scoped_ptr<Error> open_error = EnsureDbIsOpen();
84 if (!error.empty()) 54 if (open_error)
85 LOG(WARNING) << error; 55 LOG(WARNING) << open_error->message;
86 } 56 }
87 57
88 LeveldbValueStore::~LeveldbValueStore() { 58 LeveldbValueStore::~LeveldbValueStore() {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
90 60
91 // Delete the database from disk if it's empty (but only if we managed to 61 // Delete the database from disk if it's empty (but only if we managed to
92 // open it!). This is safe on destruction, assuming that we have exclusive 62 // open it!). This is safe on destruction, assuming that we have exclusive
93 // access to the database. 63 // access to the database.
94 if (db_ && IsEmpty()) { 64 if (db_ && IsEmpty())
95 // Close |db_| now to release any lock on the directory. 65 DeleteDbFile();
96 db_.reset();
97 if (!base::DeleteFile(db_path_, true)) {
98 LOG(WARNING) << "Failed to delete LeveldbValueStore database " <<
99 db_path_.value();
100 }
101 }
102 } 66 }
103 67
104 size_t LeveldbValueStore::GetBytesInUse(const std::string& key) { 68 size_t LeveldbValueStore::GetBytesInUse(const std::string& key) {
105 // Let SettingsStorageQuotaEnforcer implement this. 69 // Let SettingsStorageQuotaEnforcer implement this.
106 NOTREACHED() << "Not implemented"; 70 NOTREACHED() << "Not implemented";
107 return 0; 71 return 0;
108 } 72 }
109 73
110 size_t LeveldbValueStore::GetBytesInUse( 74 size_t LeveldbValueStore::GetBytesInUse(
111 const std::vector<std::string>& keys) { 75 const std::vector<std::string>& keys) {
112 // Let SettingsStorageQuotaEnforcer implement this. 76 // Let SettingsStorageQuotaEnforcer implement this.
113 NOTREACHED() << "Not implemented"; 77 NOTREACHED() << "Not implemented";
114 return 0; 78 return 0;
115 } 79 }
116 80
117 size_t LeveldbValueStore::GetBytesInUse() { 81 size_t LeveldbValueStore::GetBytesInUse() {
118 // Let SettingsStorageQuotaEnforcer implement this. 82 // Let SettingsStorageQuotaEnforcer implement this.
119 NOTREACHED() << "Not implemented"; 83 NOTREACHED() << "Not implemented";
120 return 0; 84 return 0;
121 } 85 }
122 86
123 ValueStore::ReadResult LeveldbValueStore::Get(const std::string& key) { 87 ValueStore::ReadResult LeveldbValueStore::Get(const std::string& key) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
125 89
126 std::string error = EnsureDbIsOpen(); 90 scoped_ptr<Error> open_error = EnsureDbIsOpen();
127 if (!error.empty()) 91 if (open_error)
128 return ValueStore::MakeReadResult(error); 92 return MakeReadResult(open_error.Pass());
129 93
130 scoped_ptr<Value> setting; 94 scoped_ptr<Value> setting;
131 error = ReadFromDb(leveldb::ReadOptions(), key, &setting); 95 scoped_ptr<Error> error = ReadFromDb(leveldb::ReadOptions(), key, &setting);
132 if (!error.empty()) 96 if (error)
133 return ReadFailureForKey("get", key, error); 97 return MakeReadResult(error.Pass());
134 98
135 DictionaryValue* settings = new DictionaryValue(); 99 DictionaryValue* settings = new DictionaryValue();
136 if (setting.get()) 100 if (setting)
137 settings->SetWithoutPathExpansion(key, setting.release()); 101 settings->SetWithoutPathExpansion(key, setting.release());
138 return MakeReadResult(settings); 102 return MakeReadResult(make_scoped_ptr(settings));
139 } 103 }
140 104
141 ValueStore::ReadResult LeveldbValueStore::Get( 105 ValueStore::ReadResult LeveldbValueStore::Get(
142 const std::vector<std::string>& keys) { 106 const std::vector<std::string>& keys) {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
144 108
145 std::string error = EnsureDbIsOpen(); 109 scoped_ptr<Error> open_error = EnsureDbIsOpen();
146 if (!error.empty()) 110 if (open_error)
147 return ValueStore::MakeReadResult(error); 111 return MakeReadResult(open_error.Pass());
148 112
149 leveldb::ReadOptions options; 113 leveldb::ReadOptions options;
150 scoped_ptr<DictionaryValue> settings(new DictionaryValue()); 114 scoped_ptr<DictionaryValue> settings(new DictionaryValue());
151 115
152 // All interaction with the db is done on the same thread, so snapshotting 116 // All interaction with the db is done on the same thread, so snapshotting
153 // isn't strictly necessary. This is just defensive. 117 // isn't strictly necessary. This is just defensive.
154 ScopedSnapshot snapshot(db_.get()); 118 ScopedSnapshot snapshot(db_.get());
155 options.snapshot = snapshot.get(); 119 options.snapshot = snapshot.get();
156 for (std::vector<std::string>::const_iterator it = keys.begin(); 120 for (std::vector<std::string>::const_iterator it = keys.begin();
157 it != keys.end(); ++it) { 121 it != keys.end(); ++it) {
158 scoped_ptr<Value> setting; 122 scoped_ptr<Value> setting;
159 error = ReadFromDb(options, *it, &setting); 123 scoped_ptr<Error> error = ReadFromDb(options, *it, &setting);
160 if (!error.empty()) 124 if (error)
161 return ReadFailureForKey("get multiple items", *it, error); 125 return MakeReadResult(error.Pass());
162 if (setting.get()) 126 if (setting)
163 settings->SetWithoutPathExpansion(*it, setting.release()); 127 settings->SetWithoutPathExpansion(*it, setting.release());
164 } 128 }
165 129
166 return MakeReadResult(settings.release()); 130 return MakeReadResult(settings.Pass());
167 } 131 }
168 132
169 ValueStore::ReadResult LeveldbValueStore::Get() { 133 ValueStore::ReadResult LeveldbValueStore::Get() {
170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
171 135
172 std::string error = EnsureDbIsOpen(); 136 scoped_ptr<Error> open_error = EnsureDbIsOpen();
173 if (!error.empty()) 137 if (open_error)
174 return ValueStore::MakeReadResult(error); 138 return MakeReadResult(open_error.Pass());
175 139
176 base::JSONReader json_reader; 140 base::JSONReader json_reader;
177 leveldb::ReadOptions options = leveldb::ReadOptions(); 141 leveldb::ReadOptions options = leveldb::ReadOptions();
178 // All interaction with the db is done on the same thread, so snapshotting 142 // All interaction with the db is done on the same thread, so snapshotting
179 // isn't strictly necessary. This is just defensive. 143 // isn't strictly necessary. This is just defensive.
180 scoped_ptr<DictionaryValue> settings(new DictionaryValue()); 144 scoped_ptr<DictionaryValue> settings(new DictionaryValue());
181 145
182 ScopedSnapshot snapshot(db_.get()); 146 ScopedSnapshot snapshot(db_.get());
183 options.snapshot = snapshot.get(); 147 options.snapshot = snapshot.get();
184 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); 148 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
185 for (it->SeekToFirst(); it->Valid(); it->Next()) { 149 for (it->SeekToFirst(); it->Valid(); it->Next()) {
186 std::string key = it->key().ToString(); 150 std::string key = it->key().ToString();
187 Value* value = json_reader.ReadToValue(it->value().ToString()); 151 Value* value = json_reader.ReadToValue(it->value().ToString());
188 if (value == NULL) { 152 if (!value) {
189 // TODO(kalman): clear the offending non-JSON value from the database. 153 return MakeReadResult(
190 return ReadFailureForKey("get all", key, kInvalidJson); 154 Error::Create(CORRUPTION, kInvalidJson, util::NewKey(key)));
191 } 155 }
192 settings->SetWithoutPathExpansion(key, value); 156 settings->SetWithoutPathExpansion(key, value);
193 } 157 }
194 158
195 if (it->status().IsNotFound()) { 159 if (it->status().IsNotFound()) {
196 NOTREACHED() << "IsNotFound() but iterating over all keys?!"; 160 NOTREACHED() << "IsNotFound() but iterating over all keys?!";
197 return MakeReadResult(settings.release()); 161 return MakeReadResult(settings.Pass());
198 } 162 }
199 163
200 if (!it->status().ok()) 164 if (!it->status().ok())
201 return ReadFailure("get all items", it->status().ToString()); 165 return MakeReadResult(ToValueStoreError(it->status(), util::NoKey()));
202 166
203 return MakeReadResult(settings.release()); 167 return MakeReadResult(settings.Pass());
204 } 168 }
205 169
206 ValueStore::WriteResult LeveldbValueStore::Set( 170 ValueStore::WriteResult LeveldbValueStore::Set(
207 WriteOptions options, const std::string& key, const Value& value) { 171 WriteOptions options, const std::string& key, const Value& value) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
209 173
210 std::string error = EnsureDbIsOpen(); 174 scoped_ptr<Error> open_error = EnsureDbIsOpen();
211 if (!error.empty()) 175 if (open_error)
212 return ValueStore::MakeWriteResult(error); 176 return MakeWriteResult(open_error.Pass());
213 177
214 leveldb::WriteBatch batch; 178 leveldb::WriteBatch batch;
215 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList()); 179 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
216 error = AddToBatch(options, key, value, &batch, changes.get()); 180 scoped_ptr<Error> batch_error =
217 if (!error.empty()) 181 AddToBatch(options, key, value, &batch, changes.get());
218 return WriteFailureForKey("find changes to set", key, error); 182 if (batch_error)
183 return MakeWriteResult(batch_error.Pass());
219 184
220 error = WriteToDb(&batch); 185 scoped_ptr<Error> write_error = WriteToDb(&batch);
221 if (!error.empty()) 186 return write_error ? MakeWriteResult(write_error.Pass())
222 return WriteFailureForKey("set", key, error); 187 : MakeWriteResult(changes.Pass());
223 return MakeWriteResult(changes.release());
224 } 188 }
225 189
226 ValueStore::WriteResult LeveldbValueStore::Set( 190 ValueStore::WriteResult LeveldbValueStore::Set(
227 WriteOptions options, const DictionaryValue& settings) { 191 WriteOptions options, const DictionaryValue& settings) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
229 193
230 std::string error = EnsureDbIsOpen(); 194 scoped_ptr<Error> open_error = EnsureDbIsOpen();
231 if (!error.empty()) 195 if (open_error)
232 return ValueStore::MakeWriteResult(error); 196 return MakeWriteResult(open_error.Pass());
233 197
234 leveldb::WriteBatch batch; 198 leveldb::WriteBatch batch;
235 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList()); 199 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
236 200
237 for (DictionaryValue::Iterator it(settings); !it.IsAtEnd(); it.Advance()) { 201 for (DictionaryValue::Iterator it(settings); !it.IsAtEnd(); it.Advance()) {
238 error = AddToBatch(options, it.key(), it.value(), &batch, changes.get()); 202 scoped_ptr<Error> batch_error =
239 if (!error.empty()) { 203 AddToBatch(options, it.key(), it.value(), &batch, changes.get());
240 return WriteFailureForKey("find changes to set multiple items", 204 if (batch_error)
241 it.key(), 205 return MakeWriteResult(batch_error.Pass());
242 error);
243 }
244 } 206 }
245 207
246 error = WriteToDb(&batch); 208 scoped_ptr<Error> write_error = WriteToDb(&batch);
247 if (!error.empty()) 209 return write_error ? MakeWriteResult(write_error.Pass())
248 return WriteFailure("set multiple items", error); 210 : MakeWriteResult(changes.Pass());
249 return MakeWriteResult(changes.release());
250 } 211 }
251 212
252 ValueStore::WriteResult LeveldbValueStore::Remove(const std::string& key) { 213 ValueStore::WriteResult LeveldbValueStore::Remove(const std::string& key) {
253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
254 return Remove(std::vector<std::string>(1, key)); 215 return Remove(std::vector<std::string>(1, key));
255 } 216 }
256 217
257 ValueStore::WriteResult LeveldbValueStore::Remove( 218 ValueStore::WriteResult LeveldbValueStore::Remove(
258 const std::vector<std::string>& keys) { 219 const std::vector<std::string>& keys) {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
260 221
261 std::string error = EnsureDbIsOpen(); 222 scoped_ptr<Error> open_error = EnsureDbIsOpen();
262 if (!error.empty()) 223 if (open_error)
263 return ValueStore::MakeWriteResult(error); 224 return MakeWriteResult(open_error.Pass());
264 225
265 leveldb::WriteBatch batch; 226 leveldb::WriteBatch batch;
266 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList()); 227 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
267 228
268 for (std::vector<std::string>::const_iterator it = keys.begin(); 229 for (std::vector<std::string>::const_iterator it = keys.begin();
269 it != keys.end(); ++it) { 230 it != keys.end(); ++it) {
270 scoped_ptr<Value> old_value; 231 scoped_ptr<Value> old_value;
271 error = ReadFromDb(leveldb::ReadOptions(), *it, &old_value); 232 scoped_ptr<Error> read_error =
272 if (!error.empty()) { 233 ReadFromDb(leveldb::ReadOptions(), *it, &old_value);
273 return WriteFailureForKey("find changes to remove multiple items", 234 if (read_error)
274 *it, 235 return MakeWriteResult(read_error.Pass());
275 error);
276 }
277 236
278 if (old_value.get()) { 237 if (old_value) {
279 changes->push_back(ValueStoreChange(*it, old_value.release(), NULL)); 238 changes->push_back(ValueStoreChange(*it, old_value.release(), NULL));
280 batch.Delete(*it); 239 batch.Delete(*it);
281 } 240 }
282 } 241 }
283 242
284 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); 243 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch);
285 if (!status.ok() && !status.IsNotFound()) 244 if (!status.ok() && !status.IsNotFound())
286 return WriteFailure("remove multiple items", status.ToString()); 245 return MakeWriteResult(ToValueStoreError(status, util::NoKey()));
287 return MakeWriteResult(changes.release()); 246 return MakeWriteResult(changes.Pass());
288 } 247 }
289 248
290 ValueStore::WriteResult LeveldbValueStore::Clear() { 249 ValueStore::WriteResult LeveldbValueStore::Clear() {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
292 251
293 std::string error = EnsureDbIsOpen();
294 if (!error.empty())
295 return ValueStore::MakeWriteResult(error);
296
297 leveldb::ReadOptions read_options;
298 // All interaction with the db is done on the same thread, so snapshotting
299 // isn't strictly necessary. This is just defensive.
300 leveldb::WriteBatch batch;
301 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList()); 252 scoped_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
302 253
303 ScopedSnapshot snapshot(db_.get()); 254 ReadResult read_result = Get();
304 read_options.snapshot = snapshot.get(); 255 if (read_result->HasError())
305 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(read_options)); 256 return MakeWriteResult(read_result->PassError());
306 for (it->SeekToFirst(); it->Valid(); it->Next()) { 257
307 const std::string key = it->key().ToString(); 258 base::DictionaryValue& whole_db = read_result->settings();
308 const std::string old_value_json = it->value().ToString(); 259 while (!whole_db.empty()) {
309 Value* old_value = base::JSONReader().ReadToValue(old_value_json); 260 std::string next_key = DictionaryValue::Iterator(whole_db).key();
310 if (!old_value) { 261 scoped_ptr<base::Value> next_value;
311 // TODO: delete the bad JSON. 262 whole_db.RemoveWithoutPathExpansion(next_key, &next_value);
312 return WriteFailureForKey("find changes to clear", key, kInvalidJson); 263 changes->push_back(
313 } 264 ValueStoreChange(next_key, next_value.release(), NULL));
314 changes->push_back(ValueStoreChange(key, old_value, NULL));
315 batch.Delete(key);
316 } 265 }
317 266
318 if (it->status().IsNotFound()) 267 DeleteDbFile();
319 NOTREACHED() << "IsNotFound() but clearing?!"; 268 return MakeWriteResult(changes.Pass());
320 else if (!it->status().ok())
321 return WriteFailure("find changes to clear", it->status().ToString());
322
323 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch);
324 if (status.IsNotFound()) {
325 NOTREACHED() << "IsNotFound() but clearing?!";
326 return MakeWriteResult(changes.release());
327 }
328 if (!status.ok())
329 return WriteFailure("clear", status.ToString());
330 return MakeWriteResult(changes.release());
331 } 269 }
332 270
333 std::string LeveldbValueStore::EnsureDbIsOpen() { 271 scoped_ptr<ValueStore::Error> LeveldbValueStore::EnsureDbIsOpen() {
334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
335 273
336 if (db_.get()) 274 if (db_)
337 return std::string(); 275 return util::NoError();
338
339 #if defined(OS_POSIX)
340 std::string os_path(db_path_.value());
341 #elif defined(OS_WIN)
342 std::string os_path = base::SysWideToUTF8(db_path_.value());
343 #endif
344 276
345 leveldb::Options options; 277 leveldb::Options options;
346 options.max_open_files = 0; // Use minimum. 278 options.max_open_files = 0; // Use minimum.
347 options.create_if_missing = true; 279 options.create_if_missing = true;
348 leveldb::DB* db;
349 leveldb::Status status = leveldb::DB::Open(options, os_path, &db);
350 if (!status.ok()) {
351 // |os_path| may contain sensitive data, and these strings are passed
352 // through to the extension, so strip that out.
353 std::string status_string = status.ToString();
354 ReplaceSubstringsAfterOffset(&status_string, 0u, os_path, "...");
355 return base::StringPrintf("Failed to open database: %s",
356 status_string.c_str());
357 }
358 280
281 leveldb::DB* db = NULL;
282 leveldb::Status status =
283 leveldb::DB::Open(options, db_path_.AsUTF8Unsafe(), &db);
284 if (!status.ok())
285 return ToValueStoreError(status, util::NoKey());
286
287 CHECK(db);
359 db_.reset(db); 288 db_.reset(db);
360 return std::string(); 289 return util::NoError();
361 } 290 }
362 291
363 std::string LeveldbValueStore::ReadFromDb( 292 scoped_ptr<ValueStore::Error> LeveldbValueStore::ReadFromDb(
364 leveldb::ReadOptions options, 293 leveldb::ReadOptions options,
365 const std::string& key, 294 const std::string& key,
366 scoped_ptr<Value>* setting) { 295 scoped_ptr<Value>* setting) {
367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
368 DCHECK(setting != NULL); 297 DCHECK(setting);
298
369 std::string value_as_json; 299 std::string value_as_json;
370 leveldb::Status s = db_->Get(options, key, &value_as_json); 300 leveldb::Status s = db_->Get(options, key, &value_as_json);
371 301
372 if (s.IsNotFound()) { 302 if (s.IsNotFound()) {
373 // Despite there being no value, it was still a success. 303 // Despite there being no value, it was still a success. Check this first
374 // Check this first because ok() is false on IsNotFound. 304 // because ok() is false on IsNotFound.
375 return std::string(); 305 return util::NoError();
376 } 306 }
377 307
378 if (!s.ok()) 308 if (!s.ok())
379 return s.ToString(); 309 return ToValueStoreError(s, util::NewKey(key));
380 310
381 Value* value = base::JSONReader().ReadToValue(value_as_json); 311 Value* value = base::JSONReader().ReadToValue(value_as_json);
382 if (value == NULL) { 312 if (!value)
383 // TODO(kalman): clear the offending non-JSON value from the database. 313 return Error::Create(CORRUPTION, kInvalidJson, util::NewKey(key));
384 return kInvalidJson;
385 }
386 314
387 setting->reset(value); 315 setting->reset(value);
388 return std::string(); 316 return util::NoError();
389 } 317 }
390 318
391 std::string LeveldbValueStore::AddToBatch( 319 scoped_ptr<ValueStore::Error> LeveldbValueStore::AddToBatch(
392 ValueStore::WriteOptions options, 320 ValueStore::WriteOptions options,
393 const std::string& key, 321 const std::string& key,
394 const base::Value& value, 322 const base::Value& value,
395 leveldb::WriteBatch* batch, 323 leveldb::WriteBatch* batch,
396 ValueStoreChangeList* changes) { 324 ValueStoreChangeList* changes) {
397 scoped_ptr<Value> old_value; 325 bool write_new_value = true;
398 if (!(options & NO_CHECK_OLD_VALUE)) { 326
399 std::string error = ReadFromDb(leveldb::ReadOptions(), key, &old_value); 327 if (!(options & NO_GENERATE_CHANGES)) {
400 if (!error.empty()) 328 scoped_ptr<Value> old_value;
401 return error; 329 scoped_ptr<Error> read_error =
330 ReadFromDb(leveldb::ReadOptions(), key, &old_value);
331 if (read_error)
332 return read_error.Pass();
333 if (!old_value || !old_value->Equals(&value)) {
334 changes->push_back(
335 ValueStoreChange(key, old_value.release(), value.DeepCopy()));
336 } else {
337 write_new_value = false;
338 }
402 } 339 }
403 340
404 if (!old_value.get() || !old_value->Equals(&value)) { 341 if (write_new_value) {
405 if (!(options & NO_GENERATE_CHANGES)) {
406 changes->push_back(
407 ValueStoreChange(key, old_value.release(), value.DeepCopy()));
408 }
409 std::string value_as_json; 342 std::string value_as_json;
410 base::JSONWriter::Write(&value, &value_as_json); 343 base::JSONWriter::Write(&value, &value_as_json);
411 batch->Put(key, value_as_json); 344 batch->Put(key, value_as_json);
412 } 345 }
413 346
414 return std::string(); 347 return util::NoError();
415 } 348 }
416 349
417 std::string LeveldbValueStore::WriteToDb(leveldb::WriteBatch* batch) { 350 scoped_ptr<ValueStore::Error> LeveldbValueStore::WriteToDb(
351 leveldb::WriteBatch* batch) {
418 leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch); 352 leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch);
419 if (status.IsNotFound()) { 353 return status.ok() ? util::NoError()
420 NOTREACHED() << "IsNotFound() but writing?!"; 354 : ToValueStoreError(status, util::NoKey());
421 return std::string();
422 }
423 return status.ok() ? std::string() : status.ToString();
424 } 355 }
425 356
426 bool LeveldbValueStore::IsEmpty() { 357 bool LeveldbValueStore::IsEmpty() {
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
428 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions())); 359 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));
429 360
430 it->SeekToFirst(); 361 it->SeekToFirst();
431 bool is_empty = !it->Valid(); 362 bool is_empty = !it->Valid();
432 if (!it->status().ok()) { 363 if (!it->status().ok()) {
433 LOG(ERROR) << "Checking DB emptiness failed: " << it->status().ToString(); 364 LOG(ERROR) << "Checking DB emptiness failed: " << it->status().ToString();
434 return false; 365 return false;
435 } 366 }
436 return is_empty; 367 return is_empty;
437 } 368 }
369
370 void LeveldbValueStore::DeleteDbFile() {
371 db_.reset(); // release any lock on the directory
372 if (!base::DeleteFile(db_path_, true /* recursive */)) {
373 LOG(WARNING) << "Failed to delete LeveldbValueStore database at " <<
374 db_path_.value();
375 }
376 }
377
378 scoped_ptr<ValueStore::Error> LeveldbValueStore::ToValueStoreError(
379 const leveldb::Status& status,
380 scoped_ptr<std::string> key) {
381 CHECK(!status.ok());
382 CHECK(!status.IsNotFound()); // not an error
383
384 std::string message = status.ToString();
385 // The message may contain |db_path_|, which may be considered sensitive
386 // data, and those strings are passed to the extension, so strip it out.
387 ReplaceSubstringsAfterOffset(&message, 0u, db_path_.AsUTF8Unsafe(), "...");
388
389 return Error::Create(CORRUPTION, message, key.Pass());
390 }
OLDNEW
« no previous file with comments | « chrome/browser/value_store/leveldb_value_store.h ('k') | chrome/browser/value_store/testing_value_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698