Chromium Code Reviews| Index: components/sync/model_impl/model_type_store_backend.cc |
| diff --git a/components/sync/model_impl/model_type_store_backend.cc b/components/sync/model_impl/model_type_store_backend.cc |
| index afc6fe8f3d7c7f0c37eb2e3ff2ce29b38625a2f9..6a19fd1075dbb12c0ee5a67886d8e36053e6e978 100644 |
| --- a/components/sync/model_impl/model_type_store_backend.cc |
| +++ b/components/sync/model_impl/model_type_store_backend.cc |
| @@ -7,8 +7,10 @@ |
| #include <utility> |
| #include "base/files/file_path.h" |
| +#include "base/lazy_instance.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros.h" |
| +#include "base/synchronization/lock.h" |
| #include "components/sync/protocol/model_type_store_schema_descriptor.pb.h" |
| #include "third_party/leveldatabase/env_chromium.h" |
| #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" |
| @@ -31,10 +33,6 @@ const char ModelTypeStoreBackend::kDBSchemaDescriptorRecordId[] = |
| const char ModelTypeStoreBackend::kStoreInitResultHistogramName[] = |
| "Sync.ModelTypeStoreInitResult"; |
| -// static |
| -base::LazyInstance<ModelTypeStoreBackend::BackendMap>::DestructorAtExit |
| - ModelTypeStoreBackend::backend_map_ = LAZY_INSTANCE_INITIALIZER; |
| - |
| namespace { |
| StoreInitResultForHistogram LevelDbStatusToStoreInitResult( |
| @@ -54,13 +52,61 @@ StoreInitResultForHistogram LevelDbStatusToStoreInitResult( |
| return STORE_INIT_RESULT_UNKNOWN; |
| } |
| +// BackendMap tracks created ModelTypeStoreBackends ensuring at most one backend |
| +// exists for a given path. BackendMap keeps non-owning pointer to backend |
| +// allowing backend lifetime to be controlled by consumers. Since backends can |
| +// run concurrently on different threads all map operations are guarded by lock. |
| +class BackendMap { |
| + public: |
| + BackendMap() = default; |
| + |
| + // Returns backend reference or nullptr if backend for |path| is not in the |
| + // map. |
| + scoped_refptr<ModelTypeStoreBackend> GetBackend( |
| + const std::string& path) const; |
| + // Adds backend into the map ensuring it wasn't added before. |
| + void SetBackend(const std::string& path, ModelTypeStoreBackend* backend); |
| + void EraseBackend(const std::string& path); |
| + |
| + private: |
| + mutable base::Lock lock_; |
| + |
| + std::unordered_map<std::string, ModelTypeStoreBackend*> backends_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(BackendMap); |
| +}; |
| + |
| +base::LazyInstance<BackendMap>::DestructorAtExit backend_map = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +scoped_refptr<ModelTypeStoreBackend> BackendMap::GetBackend( |
| + const std::string& path) const { |
| + base::AutoLock scoped_lock(lock_); |
| + auto it = backends_.find(path); |
| + if (it == backends_.end()) |
|
skym
2017/03/08 19:28:15
a ternary would probably still be a single line, j
pavely
2017/03/08 20:41:12
Done.
|
| + return nullptr; |
| + return it->second; |
| +} |
| + |
| +void BackendMap::SetBackend(const std::string& path, |
| + ModelTypeStoreBackend* backend) { |
| + base::AutoLock scoped_lock(lock_); |
| + DCHECK(backends_.find(path) == backends_.end()); |
| + backends_[path] = backend; |
| +} |
| + |
| +void BackendMap::EraseBackend(const std::string& path) { |
| + base::AutoLock scoped_lock(lock_); |
| + backends_.erase(path); |
| +} |
| + |
| } // namespace |
| ModelTypeStoreBackend::ModelTypeStoreBackend(const std::string& path) |
| : path_(path) {} |
| ModelTypeStoreBackend::~ModelTypeStoreBackend() { |
| - backend_map_.Get().erase(path_); |
| + backend_map.Get().EraseBackend(path_); |
| } |
| std::unique_ptr<leveldb::Env> ModelTypeStoreBackend::CreateInMemoryEnv() { |
| @@ -72,18 +118,19 @@ scoped_refptr<ModelTypeStoreBackend> ModelTypeStoreBackend::GetOrCreateBackend( |
| const std::string& path, |
| std::unique_ptr<leveldb::Env> env, |
| ModelTypeStore::Result* result) { |
| - if (backend_map_.Get().find(path) != backend_map_.Get().end()) { |
| + scoped_refptr<ModelTypeStoreBackend> backend = |
| + backend_map.Get().GetBackend(path); |
| + if (backend) { |
| *result = ModelTypeStore::Result::SUCCESS; |
| - return make_scoped_refptr(backend_map_.Get()[path]); |
| + return backend; |
| } |
| - scoped_refptr<ModelTypeStoreBackend> backend = |
| - new ModelTypeStoreBackend(path); |
| + backend = new ModelTypeStoreBackend(path); |
| *result = backend->Init(path, std::move(env)); |
| if (*result == ModelTypeStore::Result::SUCCESS) { |
| - backend_map_.Get()[path] = backend.get(); |
| + backend_map.Get().SetBackend(path, backend.get()); |
| } else { |
| backend = nullptr; |
| } |
| @@ -94,7 +141,7 @@ scoped_refptr<ModelTypeStoreBackend> ModelTypeStoreBackend::GetOrCreateBackend( |
| ModelTypeStore::Result ModelTypeStoreBackend::Init( |
| const std::string& path, |
| std::unique_ptr<leveldb::Env> env) { |
| - DFAKE_SCOPED_LOCK(push_pop_); |
| + DCHECK(sequence_checker_.CalledOnValidSequence()); |
| env_ = std::move(env); |
| @@ -162,7 +209,7 @@ ModelTypeStore::Result ModelTypeStoreBackend::ReadRecordsWithPrefix( |
| const ModelTypeStore::IdList& id_list, |
| ModelTypeStore::RecordList* record_list, |
| ModelTypeStore::IdList* missing_id_list) { |
| - DFAKE_SCOPED_LOCK(push_pop_); |
| + DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(db_); |
| record_list->reserve(id_list.size()); |
| leveldb::ReadOptions read_options; |
| @@ -186,7 +233,7 @@ ModelTypeStore::Result ModelTypeStoreBackend::ReadRecordsWithPrefix( |
| ModelTypeStore::Result ModelTypeStoreBackend::ReadAllRecordsWithPrefix( |
| const std::string& prefix, |
| ModelTypeStore::RecordList* record_list) { |
| - DFAKE_SCOPED_LOCK(push_pop_); |
| + DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(db_); |
| leveldb::ReadOptions read_options; |
| read_options.verify_checksums = true; |
| @@ -205,7 +252,7 @@ ModelTypeStore::Result ModelTypeStoreBackend::ReadAllRecordsWithPrefix( |
| ModelTypeStore::Result ModelTypeStoreBackend::WriteModifications( |
| std::unique_ptr<leveldb::WriteBatch> write_batch) { |
| - DFAKE_SCOPED_LOCK(push_pop_); |
| + DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(db_); |
| leveldb::Status status = |
| db_->Write(leveldb::WriteOptions(), write_batch.get()); |
| @@ -263,4 +310,9 @@ void ModelTypeStoreBackend::RecordStoreInitResultHistogram( |
| STORE_INIT_RESULT_COUNT); |
| } |
| +// static |
| +bool ModelTypeStoreBackend::BackendExistsForTest(const std::string& path) { |
| + return backend_map.Get().GetBackend(path) != nullptr; |
| +} |
| + |
| } // namespace syncer |