blob: 5f88c93553b7f38c9581c18f7d132573d8697677 [file] [log] [blame]
// 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