| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "sync/internal_api/public/model_type_store_backend.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/files/file_path.h" | |
| 10 #include "base/memory/ptr_util.h" | |
| 11 #include "third_party/leveldatabase/env_chromium.h" | |
| 12 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" | |
| 13 #include "third_party/leveldatabase/src/include/leveldb/db.h" | |
| 14 #include "third_party/leveldatabase/src/include/leveldb/env.h" | |
| 15 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | |
| 16 #include "third_party/leveldatabase/src/include/leveldb/options.h" | |
| 17 #include "third_party/leveldatabase/src/include/leveldb/slice.h" | |
| 18 #include "third_party/leveldatabase/src/include/leveldb/status.h" | |
| 19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | |
| 20 | |
| 21 namespace syncer_v2 { | |
| 22 | |
| 23 // static | |
| 24 base::LazyInstance<ModelTypeStoreBackend::BackendMap> | |
| 25 ModelTypeStoreBackend::backend_map_ = LAZY_INSTANCE_INITIALIZER; | |
| 26 | |
| 27 ModelTypeStoreBackend::ModelTypeStoreBackend(const std::string& path) | |
| 28 : path_(path) {} | |
| 29 | |
| 30 ModelTypeStoreBackend::~ModelTypeStoreBackend() { | |
| 31 backend_map_.Get().erase(path_); | |
| 32 } | |
| 33 | |
| 34 std::unique_ptr<leveldb::Env> ModelTypeStoreBackend::CreateInMemoryEnv() { | |
| 35 return base::WrapUnique(leveldb::NewMemEnv(leveldb::Env::Default())); | |
| 36 } | |
| 37 | |
| 38 // static | |
| 39 scoped_refptr<ModelTypeStoreBackend> ModelTypeStoreBackend::GetOrCreateBackend( | |
| 40 const std::string& path, | |
| 41 std::unique_ptr<leveldb::Env> env, | |
| 42 ModelTypeStore::Result* result) { | |
| 43 if (backend_map_.Get().find(path) != backend_map_.Get().end()) { | |
| 44 *result = ModelTypeStore::Result::SUCCESS; | |
| 45 return make_scoped_refptr(backend_map_.Get()[path]); | |
| 46 } | |
| 47 | |
| 48 scoped_refptr<ModelTypeStoreBackend> backend = | |
| 49 new ModelTypeStoreBackend(path); | |
| 50 | |
| 51 *result = backend->Init(path, std::move(env)); | |
| 52 | |
| 53 if (*result == ModelTypeStore::Result::SUCCESS) { | |
| 54 backend_map_.Get()[path] = backend.get(); | |
| 55 } else { | |
| 56 backend = nullptr; | |
| 57 } | |
| 58 | |
| 59 return backend; | |
| 60 } | |
| 61 | |
| 62 ModelTypeStore::Result ModelTypeStoreBackend::Init( | |
| 63 const std::string& path, | |
| 64 std::unique_ptr<leveldb::Env> env) { | |
| 65 DFAKE_SCOPED_LOCK(push_pop_); | |
| 66 leveldb::DB* db_raw = nullptr; | |
| 67 | |
| 68 leveldb::Options options; | |
| 69 options.create_if_missing = true; | |
| 70 options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue; | |
| 71 options.paranoid_checks = true; | |
| 72 if (env.get()) { | |
| 73 options.env = env.get(); | |
| 74 env_ = std::move(env); | |
| 75 } | |
| 76 | |
| 77 leveldb::Status status = leveldb::DB::Open(options, path, &db_raw); | |
| 78 if (!status.ok()) { | |
| 79 DCHECK(db_raw == nullptr); | |
| 80 return ModelTypeStore::Result::UNSPECIFIED_ERROR; | |
| 81 } | |
| 82 db_.reset(db_raw); | |
| 83 return ModelTypeStore::Result::SUCCESS; | |
| 84 } | |
| 85 | |
| 86 ModelTypeStore::Result ModelTypeStoreBackend::ReadRecordsWithPrefix( | |
| 87 const std::string& prefix, | |
| 88 const ModelTypeStore::IdList& id_list, | |
| 89 ModelTypeStore::RecordList* record_list, | |
| 90 ModelTypeStore::IdList* missing_id_list) { | |
| 91 DFAKE_SCOPED_LOCK(push_pop_); | |
| 92 DCHECK(db_); | |
| 93 record_list->reserve(id_list.size()); | |
| 94 leveldb::ReadOptions read_options; | |
| 95 read_options.verify_checksums = true; | |
| 96 std::string key; | |
| 97 std::string value; | |
| 98 for (const std::string& id : id_list) { | |
| 99 key = prefix + id; | |
| 100 leveldb::Status status = db_->Get(read_options, key, &value); | |
| 101 if (status.ok()) { | |
| 102 // TODO(pavely): Use emplace_back instead of push_back once it is allowed. | |
| 103 record_list->push_back(ModelTypeStore::Record(id, value)); | |
| 104 } else if (status.IsNotFound()) { | |
| 105 missing_id_list->push_back(id); | |
| 106 } else { | |
| 107 return ModelTypeStore::Result::UNSPECIFIED_ERROR; | |
| 108 } | |
| 109 } | |
| 110 return ModelTypeStore::Result::SUCCESS; | |
| 111 } | |
| 112 | |
| 113 ModelTypeStore::Result ModelTypeStoreBackend::ReadAllRecordsWithPrefix( | |
| 114 const std::string& prefix, | |
| 115 ModelTypeStore::RecordList* record_list) { | |
| 116 DFAKE_SCOPED_LOCK(push_pop_); | |
| 117 DCHECK(db_); | |
| 118 leveldb::ReadOptions read_options; | |
| 119 read_options.verify_checksums = true; | |
| 120 std::unique_ptr<leveldb::Iterator> iter(db_->NewIterator(read_options)); | |
| 121 const leveldb::Slice prefix_slice(prefix); | |
| 122 for (iter->Seek(prefix_slice); iter->Valid(); iter->Next()) { | |
| 123 leveldb::Slice key = iter->key(); | |
| 124 if (!key.starts_with(prefix_slice)) | |
| 125 break; | |
| 126 key.remove_prefix(prefix_slice.size()); | |
| 127 // TODO(pavely): Use emplace_back instead of push_back once it is allowed. | |
| 128 record_list->push_back( | |
| 129 ModelTypeStore::Record(key.ToString(), iter->value().ToString())); | |
| 130 } | |
| 131 return iter->status().ok() ? ModelTypeStore::Result::SUCCESS | |
| 132 : ModelTypeStore::Result::UNSPECIFIED_ERROR; | |
| 133 } | |
| 134 | |
| 135 ModelTypeStore::Result ModelTypeStoreBackend::WriteModifications( | |
| 136 std::unique_ptr<leveldb::WriteBatch> write_batch) { | |
| 137 DFAKE_SCOPED_LOCK(push_pop_); | |
| 138 DCHECK(db_); | |
| 139 leveldb::Status status = | |
| 140 db_->Write(leveldb::WriteOptions(), write_batch.get()); | |
| 141 return status.ok() ? ModelTypeStore::Result::SUCCESS | |
| 142 : ModelTypeStore::Result::UNSPECIFIED_ERROR; | |
| 143 } | |
| 144 | |
| 145 } // namespace syncer_v2 | |
| OLD | NEW |