// Copyright 2014 The Chromium Authors. All rights reserved. // 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 #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 { public: Backend(const scoped_refptr& store_factory, const base::FilePath& directory, const std::string& uma_client_name, const scoped_refptr& origin_task_runner, const scoped_refptr& 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 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), value.has_value() ? base::Value::ToUniquePtrValue(std::move(*value)) : nullptr)); } void Set(const std::string& key, std::unique_ptr 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; 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, std::unique_ptr 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 store_factory_; const base::FilePath directory_; const std::string uma_client_name_; scoped_refptr origin_task_runner_; scoped_refptr file_task_runner_; // The actual ValueStore that handles persisting the data to disk. Used // exclusively on the backend sequence. std::unique_ptr storage_; base::FilePath db_path_; }; ValueStoreFrontend::ValueStoreFrontend( const scoped_refptr& store_factory, const base::FilePath& directory, const std::string& uma_client_name, const scoped_refptr& origin_task_runner, const scoped_refptr& file_task_runner) : backend_(base::MakeRefCounted(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, std::unique_ptr 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