| 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 |