#include "components/data_sharing/migration/internal/migration_state_database_impl.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/task/thread_pool.h"
namespace data_sharing {
namespace {
constexpr char kMigrationStateTableName[] = "migration_state";
constexpr int kCurrentSchemaVersion = 1;
constexpr size_t kMaxNumEntriesInDB = 20000;
bool InitOnDBSequence(
base::FilePath profile_dir,
sql::Database* db,
sqlite_proto::ProtoTableManager* table_manager,
sqlite_proto::KeyValueData<data_sharing_pb::MigrationState>*
migration_state_data) {
CHECK(db);
CHECK(table_manager);
CHECK(migration_state_data);
base::FilePath db_dir = profile_dir.Append(FILE_PATH_LITERAL("DataSharing"));
if (!base::CreateDirectory(db_dir)) {
LOG(ERROR) << "Failed to create or open DB directory: " << db_dir.value();
return false;
}
const base::FilePath db_path =
db_dir.Append(FILE_PATH_LITERAL("MigrationStateDatabase"));
if (!db->Open(db_path)) {
LOG(ERROR) << "Failed to open DB " << db_path << ": "
<< db->GetErrorMessage();
return false;
}
table_manager->InitializeOnDbSequence(
db, std::vector<std::string>{kMigrationStateTableName},
kCurrentSchemaVersion);
migration_state_data->InitializeOnDBSequence();
return true;
}
}
MigrationStateDatabaseImpl::MigrationStateDatabaseImpl(
const base::FilePath& profile_dir)
: profile_path_(profile_dir),
db_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
db_(std::make_unique<sql::Database>(
sql::Database::Tag("DataSharingMigrationStateStorage"))),
proto_table_manager_(
base::MakeRefCounted<sqlite_proto::ProtoTableManager>(
db_task_runner_)),
migration_state_table_(
std::make_unique<
sqlite_proto::KeyValueTable<data_sharing_pb::MigrationState>>(
kMigrationStateTableName)),
migration_state_data_(
std::make_unique<
sqlite_proto::KeyValueData<data_sharing_pb::MigrationState>>(
proto_table_manager_,
migration_state_table_.get(),
kMaxNumEntriesInDB,
base::TimeDelta())) {}
MigrationStateDatabaseImpl::~MigrationStateDatabaseImpl() {
db_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
[](std::unique_ptr<sql::Database> db,
scoped_refptr<sqlite_proto::ProtoTableManager> table_manager,
auto migration_state_table) { table_manager->WillShutdown(); },
std::move(db_), std::move(proto_table_manager_),
std::move(migration_state_table_)));
}
void MigrationStateDatabaseImpl::Init(InitCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
db_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&InitOnDBSequence, profile_path_,
base::Unretained(db_.get()),
base::Unretained(proto_table_manager_.get()),
base::Unretained(migration_state_data_.get())),
base::BindOnce(&MigrationStateDatabaseImpl::OnInitialized,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
std::optional<data_sharing_pb::MigrationState>
MigrationStateDatabaseImpl::GetMigrationState(
const ContextId& context_id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(is_initialized_);
data_sharing_pb::MigrationState state;
if (!migration_state_data_->TryGetData(context_id.value(), &state)) {
return std::nullopt;
}
return state;
}
void MigrationStateDatabaseImpl::UpdateMigrationState(
const ContextId& context_id,
const data_sharing_pb::MigrationState& state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(is_initialized_);
migration_state_data_->UpdateData(context_id.value(), state);
}
void MigrationStateDatabaseImpl::DeleteMigrationState(
const ContextId& context_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CHECK(is_initialized_);
migration_state_data_->DeleteData({context_id.value()});
}
void MigrationStateDatabaseImpl::OnInitialized(InitCallback callback,
bool success) {
is_initialized_ = success;
std::move(callback).Run(success);
}
}