blob: 5a17141ab33d7c7ccb35d0a9ba51179fb42b0ede [file] [log] [blame]
// Copyright 2016 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/services/storage/dom_storage/async_dom_storage_database.h"
#include <inttypes.h>
#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include "base/optional.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
namespace storage {
// static
std::unique_ptr<AsyncDomStorageDatabase> AsyncDomStorageDatabase::OpenDirectory(
const leveldb_env::Options& options,
const base::FilePath& directory,
const std::string& dbname,
const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
StatusCallback callback) {
std::unique_ptr<AsyncDomStorageDatabase> db(new AsyncDomStorageDatabase);
DomStorageDatabase::OpenDirectory(
directory, dbname, options, memory_dump_id,
std::move(blocking_task_runner),
base::BindOnce(&AsyncDomStorageDatabase::OnDatabaseOpened,
db->weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
return db;
}
// static
std::unique_ptr<AsyncDomStorageDatabase> AsyncDomStorageDatabase::OpenInMemory(
const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
const std::string& tracking_name,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
StatusCallback callback) {
std::unique_ptr<AsyncDomStorageDatabase> db(new AsyncDomStorageDatabase);
DomStorageDatabase::OpenInMemory(
tracking_name, memory_dump_id, std::move(blocking_task_runner),
base::BindOnce(&AsyncDomStorageDatabase::OnDatabaseOpened,
db->weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
return db;
}
AsyncDomStorageDatabase::AsyncDomStorageDatabase() = default;
AsyncDomStorageDatabase::~AsyncDomStorageDatabase() = default;
void AsyncDomStorageDatabase::Put(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& value,
StatusCallback callback) {
RunDatabaseTask(
base::BindOnce(
[](const std::vector<uint8_t>& key, const std::vector<uint8_t>& value,
const DomStorageDatabase& db) { return db.Put(key, value); },
key, value),
std::move(callback));
}
void AsyncDomStorageDatabase::Delete(const std::vector<uint8_t>& key,
StatusCallback callback) {
RunDatabaseTask(
base::BindOnce(
[](const std::vector<uint8_t>& key, const DomStorageDatabase& db) {
return db.Delete(key);
},
key),
std::move(callback));
}
void AsyncDomStorageDatabase::DeletePrefixed(
const std::vector<uint8_t>& key_prefix,
StatusCallback callback) {
RunDatabaseTask(
base::BindOnce(
[](const std::vector<uint8_t>& prefix, const DomStorageDatabase& db) {
leveldb::WriteBatch batch;
leveldb::Status status = db.DeletePrefixed(prefix, &batch);
if (!status.ok())
return status;
return db.Commit(&batch);
},
key_prefix),
std::move(callback));
}
void AsyncDomStorageDatabase::RewriteDB(StatusCallback callback) {
DCHECK(database_);
database_.PostTaskWithThisObject(
FROM_HERE,
base::BindOnce(
[](StatusCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
DomStorageDatabase* db) {
callback_task_runner->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), db->RewriteDB()));
},
std::move(callback), base::SequencedTaskRunnerHandle::Get()));
}
void AsyncDomStorageDatabase::Get(const std::vector<uint8_t>& key,
GetCallback callback) {
struct GetResult {
leveldb::Status status;
DomStorageDatabase::Value value;
};
RunDatabaseTask(
base::BindOnce(
[](const std::vector<uint8_t>& key, const DomStorageDatabase& db) {
GetResult result;
result.status = db.Get(key, &result.value);
return result;
},
key),
base::BindOnce(
[](GetCallback callback, GetResult result) {
std::move(callback).Run(result.status, result.value);
},
std::move(callback)));
}
void AsyncDomStorageDatabase::CopyPrefixed(
const std::vector<uint8_t>& source_key_prefix,
const std::vector<uint8_t>& destination_key_prefix,
StatusCallback callback) {
RunDatabaseTask(base::BindOnce(
[](const std::vector<uint8_t>& prefix,
const std::vector<uint8_t>& new_prefix,
const DomStorageDatabase& db) {
leveldb::WriteBatch batch;
leveldb::Status status =
db.CopyPrefixed(prefix, new_prefix, &batch);
if (!status.ok())
return status;
return db.Commit(&batch);
},
source_key_prefix, destination_key_prefix),
std::move(callback));
}
void AsyncDomStorageDatabase::RunBatchDatabaseTasks(
std::vector<BatchDatabaseTask> tasks,
base::OnceCallback<void(leveldb::Status)> callback) {
RunDatabaseTask(base::BindOnce(
[](std::vector<BatchDatabaseTask> tasks,
const DomStorageDatabase& db) {
leveldb::WriteBatch batch;
for (auto& task : tasks)
std::move(task).Run(&batch, db);
return db.Commit(&batch);
},
std::move(tasks)),
std::move(callback));
}
void AsyncDomStorageDatabase::OnDatabaseOpened(
StatusCallback callback,
base::SequenceBound<DomStorageDatabase> database,
leveldb::Status status) {
database_ = std::move(database);
std::vector<BoundDatabaseTask> tasks;
std::swap(tasks, tasks_to_run_on_open_);
if (status.ok()) {
for (auto& task : tasks)
database_.PostTaskWithThisObject(FROM_HERE, std::move(task));
}
std::move(callback).Run(status);
}
} // namespace storage