| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/value_store/value_store_frontend.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/files/file_path.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/trace_event/trace_event.h" |
| #include "components/value_store/leveldb_value_store.h" |
| #include "components/value_store/value_store.h" |
| #include "components/value_store/value_store_factory.h" |
| |
| namespace value_store { |
| |
| class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> { |
| public: |
| Backend(const scoped_refptr<ValueStoreFactory>& store_factory, |
| const base::FilePath& directory, |
| const std::string& uma_client_name, |
| const scoped_refptr<base::SequencedTaskRunner>& origin_task_runner, |
| const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) |
| : store_factory_(store_factory), |
| directory_(directory), |
| uma_client_name_(uma_client_name), |
| origin_task_runner_(origin_task_runner), |
| file_task_runner_(file_task_runner) {} |
| Backend(const Backend&) = delete; |
| Backend& operator=(const Backend&) = delete; |
| |
| void Get(const std::string& key, ValueStoreFrontend::ReadCallback callback) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| LazyInit(); |
| ValueStore::ReadResult result = storage_->Get(key); |
| |
| // Extract the value from the ReadResult and pass ownership of it to the |
| // callback. |
| absl::optional<base::Value> value; |
| if (result.status().ok()) { |
| value = result.settings().Extract(key); |
| } else { |
| LOG(WARNING) << "Reading " << key << " from " << db_path_.value() |
| << " failed: " << result.status().message; |
| } |
| |
| origin_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&ValueStoreFrontend::Backend::RunCallback, |
| this, std::move(callback), std::move(value))); |
| } |
| |
| void Set(const std::string& key, base::Value value) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| LazyInit(); |
| // We don't need the old value, so skip generating changes. |
| ValueStore::WriteResult result = storage_->Set( |
| ValueStore::IGNORE_QUOTA | ValueStore::NO_GENERATE_CHANGES, key, value); |
| LOG_IF(ERROR, !result.status().ok()) |
| << "Error while writing " << key << " to " << db_path_.value(); |
| } |
| |
| void Remove(const std::string& key) { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| LazyInit(); |
| storage_->Remove(key); |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<Backend>; |
| |
| virtual ~Backend() { |
| if (storage_ && !file_task_runner_->RunsTasksInCurrentSequence()) |
| file_task_runner_->DeleteSoon(FROM_HERE, storage_.release()); |
| } |
| |
| void LazyInit() { |
| DCHECK(file_task_runner_->RunsTasksInCurrentSequence()); |
| if (storage_) |
| return; |
| TRACE_EVENT0("ValueStoreFrontend::Backend", "LazyInit"); |
| storage_ = store_factory_->CreateValueStore(directory_, uma_client_name_); |
| } |
| |
| void RunCallback(ValueStoreFrontend::ReadCallback callback, |
| absl::optional<base::Value> value) { |
| DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); |
| std::move(callback).Run(std::move(value)); |
| } |
| |
| // The factory which will be used to lazily create the ValueStore when needed. |
| // Used exclusively on the backend sequence. |
| scoped_refptr<ValueStoreFactory> store_factory_; |
| const base::FilePath directory_; |
| const std::string uma_client_name_; |
| |
| scoped_refptr<base::SequencedTaskRunner> origin_task_runner_; |
| scoped_refptr<base::SequencedTaskRunner> file_task_runner_; |
| |
| // The actual ValueStore that handles persisting the data to disk. Used |
| // exclusively on the backend sequence. |
| std::unique_ptr<ValueStore> storage_; |
| |
| base::FilePath db_path_; |
| }; |
| |
| ValueStoreFrontend::ValueStoreFrontend( |
| const scoped_refptr<ValueStoreFactory>& store_factory, |
| const base::FilePath& directory, |
| const std::string& uma_client_name, |
| const scoped_refptr<base::SequencedTaskRunner>& origin_task_runner, |
| const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) |
| : backend_(base::MakeRefCounted<Backend>(store_factory, |
| directory, |
| uma_client_name, |
| origin_task_runner, |
| file_task_runner)), |
| origin_task_runner_(origin_task_runner), |
| file_task_runner_(file_task_runner) { |
| DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); |
| } |
| |
| ValueStoreFrontend::~ValueStoreFrontend() { |
| DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); |
| } |
| |
| void ValueStoreFrontend::Get(const std::string& key, ReadCallback callback) { |
| DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); |
| |
| file_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&ValueStoreFrontend::Backend::Get, backend_, |
| key, std::move(callback))); |
| } |
| |
| void ValueStoreFrontend::Set(const std::string& key, base::Value value) { |
| DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); |
| |
| file_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&ValueStoreFrontend::Backend::Set, backend_, |
| key, std::move(value))); |
| } |
| |
| void ValueStoreFrontend::Remove(const std::string& key) { |
| DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); |
| |
| file_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&ValueStoreFrontend::Backend::Remove, backend_, key)); |
| } |
| |
| } // namespace value_store |