OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "extensions/browser/value_store/lazy_leveldb.h" | 5 #include "extensions/browser/value_store/lazy_leveldb.h" |
6 | 6 |
7 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| 11 #include "base/threading/sequenced_task_runner_handle.h" |
| 12 #include "base/threading/thread_restrictions.h" |
11 #include "content/public/browser/browser_thread.h" | 13 #include "content/public/browser/browser_thread.h" |
12 #include "third_party/leveldatabase/env_chromium.h" | 14 #include "third_party/leveldatabase/env_chromium.h" |
13 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | 15 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" |
14 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 16 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
15 | 17 |
16 using base::StringPiece; | 18 using base::StringPiece; |
17 using content::BrowserThread; | 19 using content::BrowserThread; |
18 | 20 |
19 namespace { | 21 namespace { |
20 | 22 |
(...skipping 22 matching lines...) Expand all Loading... |
43 ValueStore::StatusCode LevelDbToValueStoreStatusCode( | 45 ValueStore::StatusCode LevelDbToValueStoreStatusCode( |
44 const leveldb::Status& status) { | 46 const leveldb::Status& status) { |
45 if (status.ok()) | 47 if (status.ok()) |
46 return ValueStore::OK; | 48 return ValueStore::OK; |
47 if (status.IsCorruption()) | 49 if (status.IsCorruption()) |
48 return ValueStore::CORRUPTION; | 50 return ValueStore::CORRUPTION; |
49 return ValueStore::OTHER_ERROR; | 51 return ValueStore::OTHER_ERROR; |
50 } | 52 } |
51 | 53 |
52 leveldb::Status DeleteValue(leveldb::DB* db, const std::string& key) { | 54 leveldb::Status DeleteValue(leveldb::DB* db, const std::string& key) { |
53 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 55 base::ThreadRestrictions::AssertIOAllowed(); |
54 | 56 |
55 leveldb::WriteBatch batch; | 57 leveldb::WriteBatch batch; |
56 batch.Delete(key); | 58 batch.Delete(key); |
57 | 59 |
58 return db->Write(leveldb::WriteOptions(), &batch); | 60 return db->Write(leveldb::WriteOptions(), &batch); |
59 } | 61 } |
60 | 62 |
61 } // namespace | 63 } // namespace |
62 | 64 |
63 LazyLevelDb::LazyLevelDb(const std::string& uma_client_name, | 65 LazyLevelDb::LazyLevelDb(const std::string& uma_client_name, |
(...skipping 15 matching lines...) Expand all Loading... |
79 "Extensions.Database.Database.Restore." + uma_client_name, 1, | 81 "Extensions.Database.Database.Restore." + uma_client_name, 1, |
80 LEVELDB_DB_RESTORE_MAX, LEVELDB_DB_RESTORE_MAX + 1, | 82 LEVELDB_DB_RESTORE_MAX, LEVELDB_DB_RESTORE_MAX + 1, |
81 base::Histogram::kUmaTargetedHistogramFlag); | 83 base::Histogram::kUmaTargetedHistogramFlag); |
82 value_restore_histogram_ = base::LinearHistogram::FactoryGet( | 84 value_restore_histogram_ = base::LinearHistogram::FactoryGet( |
83 "Extensions.Database.Value.Restore." + uma_client_name, 1, | 85 "Extensions.Database.Value.Restore." + uma_client_name, 1, |
84 LEVELDB_VALUE_RESTORE_MAX, LEVELDB_VALUE_RESTORE_MAX + 1, | 86 LEVELDB_VALUE_RESTORE_MAX, LEVELDB_VALUE_RESTORE_MAX + 1, |
85 base::Histogram::kUmaTargetedHistogramFlag); | 87 base::Histogram::kUmaTargetedHistogramFlag); |
86 } | 88 } |
87 | 89 |
88 LazyLevelDb::~LazyLevelDb() { | 90 LazyLevelDb::~LazyLevelDb() { |
89 if (db_ && !BrowserThread::CurrentlyOn(BrowserThread::FILE)) | 91 base::ThreadRestrictions::AssertIOAllowed(); |
90 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, db_.release()); | |
91 } | 92 } |
92 | 93 |
93 ValueStore::Status LazyLevelDb::Read(const std::string& key, | 94 ValueStore::Status LazyLevelDb::Read(const std::string& key, |
94 std::unique_ptr<base::Value>* value) { | 95 std::unique_ptr<base::Value>* value) { |
95 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 96 base::ThreadRestrictions::AssertIOAllowed(); |
96 DCHECK(value); | 97 DCHECK(value); |
97 | 98 |
98 std::string value_as_json; | 99 std::string value_as_json; |
99 leveldb::Status s = db_->Get(read_options_, key, &value_as_json); | 100 leveldb::Status s = db_->Get(read_options_, key, &value_as_json); |
100 | 101 |
101 if (s.IsNotFound()) { | 102 if (s.IsNotFound()) { |
102 // Despite there being no value, it was still a success. Check this first | 103 // Despite there being no value, it was still a success. Check this first |
103 // because ok() is false on IsNotFound. | 104 // because ok() is false on IsNotFound. |
104 return ValueStore::Status(); | 105 return ValueStore::Status(); |
105 } | 106 } |
106 | 107 |
107 if (!s.ok()) | 108 if (!s.ok()) |
108 return ToValueStoreError(s); | 109 return ToValueStoreError(s); |
109 | 110 |
110 std::unique_ptr<base::Value> val = | 111 std::unique_ptr<base::Value> val = |
111 base::JSONReader().ReadToValue(value_as_json); | 112 base::JSONReader().ReadToValue(value_as_json); |
112 if (!val) | 113 if (!val) |
113 return ValueStore::Status(ValueStore::CORRUPTION, FixCorruption(&key), | 114 return ValueStore::Status(ValueStore::CORRUPTION, FixCorruption(&key), |
114 kInvalidJson); | 115 kInvalidJson); |
115 | 116 |
116 *value = std::move(val); | 117 *value = std::move(val); |
117 return ValueStore::Status(); | 118 return ValueStore::Status(); |
118 } | 119 } |
119 | 120 |
120 ValueStore::Status LazyLevelDb::Delete(const std::string& key) { | 121 ValueStore::Status LazyLevelDb::Delete(const std::string& key) { |
121 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 122 base::ThreadRestrictions::AssertIOAllowed(); |
122 | 123 |
123 ValueStore::Status status = EnsureDbIsOpen(); | 124 ValueStore::Status status = EnsureDbIsOpen(); |
124 if (!status.ok()) | 125 if (!status.ok()) |
125 return status; | 126 return status; |
126 | 127 |
127 return ToValueStoreError(DeleteValue(db_.get(), key)); | 128 return ToValueStoreError(DeleteValue(db_.get(), key)); |
128 } | 129 } |
129 | 130 |
130 ValueStore::BackingStoreRestoreStatus LazyLevelDb::LogRestoreStatus( | 131 ValueStore::BackingStoreRestoreStatus LazyLevelDb::LogRestoreStatus( |
131 ValueStore::BackingStoreRestoreStatus restore_status) const { | 132 ValueStore::BackingStoreRestoreStatus restore_status) const { |
(...skipping 15 matching lines...) Expand all Loading... |
147 break; | 148 break; |
148 case ValueStore::VALUE_RESTORE_DELETE_FAILURE: | 149 case ValueStore::VALUE_RESTORE_DELETE_FAILURE: |
149 value_restore_histogram_->Add(LEVELDB_VALUE_RESTORE_DELETE_FAILURE); | 150 value_restore_histogram_->Add(LEVELDB_VALUE_RESTORE_DELETE_FAILURE); |
150 break; | 151 break; |
151 } | 152 } |
152 return restore_status; | 153 return restore_status; |
153 } | 154 } |
154 | 155 |
155 ValueStore::BackingStoreRestoreStatus LazyLevelDb::FixCorruption( | 156 ValueStore::BackingStoreRestoreStatus LazyLevelDb::FixCorruption( |
156 const std::string* key) { | 157 const std::string* key) { |
157 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 158 base::ThreadRestrictions::AssertIOAllowed(); |
158 leveldb::Status s; | 159 leveldb::Status s; |
159 if (key && db_) { | 160 if (key && db_) { |
160 s = DeleteValue(db_.get(), *key); | 161 s = DeleteValue(db_.get(), *key); |
161 // Deleting involves writing to the log, so it's possible to have a | 162 // Deleting involves writing to the log, so it's possible to have a |
162 // perfectly OK database but still have a delete fail. | 163 // perfectly OK database but still have a delete fail. |
163 if (s.ok()) | 164 if (s.ok()) |
164 return LogRestoreStatus(ValueStore::VALUE_RESTORE_DELETE_SUCCESS); | 165 return LogRestoreStatus(ValueStore::VALUE_RESTORE_DELETE_SUCCESS); |
165 else if (s.IsIOError()) | 166 else if (s.IsIOError()) |
166 return LogRestoreStatus(ValueStore::VALUE_RESTORE_DELETE_FAILURE); | 167 return LogRestoreStatus(ValueStore::VALUE_RESTORE_DELETE_FAILURE); |
167 // Any other kind of failure triggers a db repair. | 168 // Any other kind of failure triggers a db repair. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 } | 216 } |
216 } | 217 } |
217 | 218 |
218 // Only log for the final and most extreme form of database restoration. | 219 // Only log for the final and most extreme form of database restoration. |
219 LogRestoreStatus(restore_status); | 220 LogRestoreStatus(restore_status); |
220 | 221 |
221 return restore_status; | 222 return restore_status; |
222 } | 223 } |
223 | 224 |
224 ValueStore::Status LazyLevelDb::EnsureDbIsOpen() { | 225 ValueStore::Status LazyLevelDb::EnsureDbIsOpen() { |
225 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 226 base::ThreadRestrictions::AssertIOAllowed(); |
226 | 227 |
227 if (db_) | 228 if (db_) |
228 return ValueStore::Status(); | 229 return ValueStore::Status(); |
229 | 230 |
230 if (db_unrecoverable_) { | 231 if (db_unrecoverable_) { |
231 return ValueStore::Status(ValueStore::CORRUPTION, | 232 return ValueStore::Status(ValueStore::CORRUPTION, |
232 ValueStore::DB_RESTORE_DELETE_FAILURE, | 233 ValueStore::DB_RESTORE_DELETE_FAILURE, |
233 "Database corrupted"); | 234 "Database corrupted"); |
234 } | 235 } |
235 | 236 |
(...skipping 25 matching lines...) Expand all Loading... |
261 std::string message = status.ToString(); | 262 std::string message = status.ToString(); |
262 // The message may contain |db_path_|, which may be considered sensitive | 263 // The message may contain |db_path_|, which may be considered sensitive |
263 // data, and those strings are passed to the extension, so strip it out. | 264 // data, and those strings are passed to the extension, so strip it out. |
264 base::ReplaceSubstringsAfterOffset(&message, 0u, db_path_.AsUTF8Unsafe(), | 265 base::ReplaceSubstringsAfterOffset(&message, 0u, db_path_.AsUTF8Unsafe(), |
265 "..."); | 266 "..."); |
266 | 267 |
267 return ValueStore::Status(LevelDbToValueStoreStatusCode(status), message); | 268 return ValueStore::Status(LevelDbToValueStoreStatusCode(status), message); |
268 } | 269 } |
269 | 270 |
270 bool LazyLevelDb::DeleteDbFile() { | 271 bool LazyLevelDb::DeleteDbFile() { |
271 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 272 base::ThreadRestrictions::AssertIOAllowed(); |
272 db_.reset(); // release any lock on the directory | 273 db_.reset(); // release any lock on the directory |
273 if (!base::DeleteFile(db_path_, true /* recursive */)) { | 274 if (!base::DeleteFile(db_path_, true /* recursive */)) { |
274 LOG(WARNING) << "Failed to delete leveldb database at " << db_path_.value(); | 275 LOG(WARNING) << "Failed to delete leveldb database at " << db_path_.value(); |
275 return false; | 276 return false; |
276 } | 277 } |
277 return true; | 278 return true; |
278 } | 279 } |
279 | 280 |
280 ValueStore::Status LazyLevelDb::CreateIterator( | 281 ValueStore::Status LazyLevelDb::CreateIterator( |
281 const leveldb::ReadOptions& read_options, | 282 const leveldb::ReadOptions& read_options, |
282 std::unique_ptr<leveldb::Iterator>* iterator) { | 283 std::unique_ptr<leveldb::Iterator>* iterator) { |
283 ValueStore::Status status = EnsureDbIsOpen(); | 284 ValueStore::Status status = EnsureDbIsOpen(); |
284 if (!status.ok()) | 285 if (!status.ok()) |
285 return status; | 286 return status; |
286 *iterator = base::WrapUnique(db_->NewIterator(read_options)); | 287 *iterator = base::WrapUnique(db_->NewIterator(read_options)); |
287 return ValueStore::Status(); | 288 return ValueStore::Status(); |
288 } | 289 } |
OLD | NEW |