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

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

Powered by Google App Engine
This is Rietveld 408576698