910e62b5创建于 1月15日历史提交
// Copyright 2025 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/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;
// TODO(crbug.com/301390275): make this consistent with other places where
// amount of groups are limited once numbers are known.
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;
}

}  // namespace

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,
              /*flush_delay=*/base::TimeDelta())) {}

MigrationStateDatabaseImpl::~MigrationStateDatabaseImpl() {
  // Shutdown `proto_table_manager_` and delete it together with `db_` and
  // KeyValueTable on DB sequence, then deletes KeyValueData and runs
  // `shutdown_callback_` on the main sequence.
  // This ensures that DB objects outlive any other task posted to DB sequence,
  // since their deletion is the very last posted task.
  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_);
  // Unretained() for DB objects is safe here, because `this` destructor ensures
  // that these objects outlive any task posted to DB sequence.
  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);
}

}  // namespace data_sharing