Skip to content

Commit

Permalink
[power bookmarks] Add database class for sync metadata
Browse files Browse the repository at this point in the history
Change-Id: I7d2185d61ae92f79b321610212f2c11608e1152b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4014852
Commit-Queue: Brandon Wylie <wylieb@chromium.org>
Reviewed-by: bttk - <bttk@chromium.org>
Reviewed-by: Rushan Suleymanov <rushans@google.com>
Reviewed-by: Yuheng Huang <yuhengh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1078411}
  • Loading branch information
Brandon Wylie authored and Chromium LUCI CQ committed Dec 2, 2022
1 parent a43252c commit ab058af
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 11 deletions.
11 changes: 10 additions & 1 deletion components/power_bookmarks/storage/BUILD.gn
Expand Up @@ -11,11 +11,15 @@ static_library("storage") {
"power_bookmark_database.h",
"power_bookmark_database_impl.cc",
"power_bookmark_database_impl.h",
"power_bookmark_sync_metadata_database.cc",
"power_bookmark_sync_metadata_database.h",
]

deps = [
"//base",
"//components/power_bookmarks/core:powers",
"//components/sync/model",
"//components/sync/protocol",
"//sql",
"//third_party/sqlite",
"//url",
Expand All @@ -25,12 +29,17 @@ static_library("storage") {
source_set("unit_tests") {
testonly = true

sources = [ "power_bookmark_database_impl_unittest.cc" ]
sources = [
"power_bookmark_database_impl_unittest.cc",
"power_bookmark_sync_metadata_database_unittest.cc",
]

deps = [
":storage",
"//base",
"//components/power_bookmarks/core:powers",
"//components/sync/model",
"//components/sync/protocol",
"//sql",
"//sql:test_support",
"//testing/gtest",
Expand Down
1 change: 1 addition & 0 deletions components/power_bookmarks/storage/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+components/sync",
"+sql",
]
27 changes: 19 additions & 8 deletions components/power_bookmarks/storage/power_bookmark_database_impl.cc
Expand Up @@ -10,8 +10,8 @@
#include "base/strings/strcat.h"
#include "components/power_bookmarks/core/powers/search_params.h"
#include "components/power_bookmarks/core/proto/power_bookmark_specifics.pb.h"
#include "components/power_bookmarks/storage/power_bookmark_sync_metadata_database.h"
#include "sql/error_delegate_util.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "url/origin.h"
Expand Down Expand Up @@ -94,7 +94,10 @@ PowerBookmarkDatabaseImpl::PowerBookmarkDatabaseImpl(
: db_(sql::DatabaseOptions{.exclusive_locking = true,
.page_size = 4096,
.cache_size = 128}),
database_path_(database_dir.Append(kDatabaseName)) {}
database_path_(database_dir.Append(kDatabaseName)) {
sync_db_ =
std::make_unique<PowerBookmarkSyncMetadataDatabase>(&db_, &meta_table_);
}

PowerBookmarkDatabaseImpl::~PowerBookmarkDatabaseImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Expand Down Expand Up @@ -133,6 +136,14 @@ bool PowerBookmarkDatabaseImpl::Init() {
db_.Close();
return false;
}

if (!sync_db_->Init()) {
DLOG(ERROR) << "Failed to initialize sync metadata db: "
<< db_.GetErrorMessage();
db_.Close();
return false;
}

return true;
}

Expand All @@ -158,8 +169,7 @@ void PowerBookmarkDatabaseImpl::DatabaseErrorCallback(int error,
bool PowerBookmarkDatabaseImpl::InitSchema() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

sql::MetaTable meta_table;
bool has_metatable = meta_table.DoesTableExist(&db_);
bool has_metatable = meta_table_.DoesTableExist(&db_);
bool has_schema =
db_.DoesTableExist(kSaveTableName) && db_.DoesTableExist(kBlobTableName);

Expand All @@ -169,21 +179,22 @@ bool PowerBookmarkDatabaseImpl::InitSchema() {
}

// Create the meta table if it doesn't exist.
if (!meta_table.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber)) {
if (!meta_table_.Init(&db_, kCurrentVersionNumber,
kCompatibleVersionNumber)) {
return false;
}

// If DB and meta table already existed and current version is not compatible
// with DB then it should fail.
if (meta_table.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
return false;
}
if (!has_schema && !CreateSchema()) {
return false;
}

meta_table.SetVersionNumber(kCurrentVersionNumber);
meta_table.SetCompatibleVersionNumber(kCompatibleVersionNumber);
meta_table_.SetVersionNumber(kCurrentVersionNumber);
meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
return true;
}

Expand Down
Expand Up @@ -10,11 +10,13 @@
#include "components/power_bookmarks/core/powers/power_overview.h"
#include "components/power_bookmarks/storage/power_bookmark_database.h"
#include "sql/database.h"
#include "sql/meta_table.h"
#include "url/gurl.h"

namespace power_bookmarks {

struct SearchParams;
class PowerBookmarkSyncMetadataDatabase;

constexpr base::FilePath::CharType kDatabaseName[] =
FILE_PATH_LITERAL("PowerBookmarks.db");
Expand Down Expand Up @@ -45,6 +47,10 @@ class PowerBookmarkDatabaseImpl : public PowerBookmarkDatabase {
bool DeletePowersForURL(const GURL& url,
const PowerType& power_type) override;

PowerBookmarkSyncMetadataDatabase* GetSyncMetadataDatabase() {
return sync_db_.get();
}

private:
FRIEND_TEST_ALL_PREFIXES(PowerBookmarkDatabaseImplTest,
InitDatabaseWithErrorCallback);
Expand All @@ -61,6 +67,8 @@ class PowerBookmarkDatabaseImpl : public PowerBookmarkDatabase {
const base::GUID& id);

sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_);
sql::MetaTable meta_table_ GUARDED_BY_CONTEXT(sequence_checker_);
std::unique_ptr<PowerBookmarkSyncMetadataDatabase> sync_db_;

const base::FilePath database_path_;

Expand Down
Expand Up @@ -147,8 +147,8 @@ TEST_F(PowerBookmarkDatabaseImplTest, InitDatabaseError) {
sql::Database db;
EXPECT_TRUE(db.Open(db_file_path()));

// Database should have 2 tables: meta, saves.
EXPECT_EQ(3u, sql::test::CountSQLTables(&db));
// Database should have 4 tables: meta, saves, blobs and sync_meta.
EXPECT_EQ(4u, sql::test::CountSQLTables(&db));
}
}

Expand Down
@@ -0,0 +1,135 @@
// Copyright 2022 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/power_bookmarks/storage/power_bookmark_sync_metadata_database.h"

#include <memory>

#include "base/big_endian.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/protocol/entity_metadata.pb.h"
#include "sql/statement.h"

namespace power_bookmarks {

namespace {

// Key in sql::MetaTable, the value is a serialization of syner::ModelTypeState,
// which tracks the overall sync state of the power bookmark datatype.
const char kPowerBookmarkModelTypeStateKey[] = "power_bookmark_type_state";

} // namespace

// Description of database table:
//
// sync_metadata
// storage_key The guid of an entry in the saves table.
// value Serialized sync EntityMetadata, which tracks the sync
// state of each power bookmark entity.
PowerBookmarkSyncMetadataDatabase::PowerBookmarkSyncMetadataDatabase(
sql::Database* db,
sql::MetaTable* meta_table)
: db_(db), meta_table_(meta_table) {}

PowerBookmarkSyncMetadataDatabase::~PowerBookmarkSyncMetadataDatabase() =
default;

bool PowerBookmarkSyncMetadataDatabase::Init() {
if (!db_->DoesTableExist("sync_metadata")) {
static constexpr char kInitSql[] =
// clang-format off
"CREATE TABLE sync_metadata "
"(storage_key TEXT PRIMARY KEY NOT NULL, value BLOB)";
// clang-format on
DCHECK(db_->IsSQLValid(kInitSql));

if (!db_->Execute(kInitSql)) {
return false;
}
}
return true;
}

bool PowerBookmarkSyncMetadataDatabase::UpdateEntityMetadata(
syncer::ModelType model_type,
const std::string& storage_key,
const sync_pb::EntityMetadata& metadata) {
DCHECK(!storage_key.empty());

static constexpr char kUpdateSyncMetadataSql[] =
// clang-format off
"INSERT OR REPLACE INTO sync_metadata "
"(storage_key, value) VALUES(?, ?)";
// clang-format on
DCHECK(db_->IsSQLValid(kUpdateSyncMetadataSql));

sql::Statement s(db_->GetUniqueStatement(kUpdateSyncMetadataSql));
s.BindString(0, storage_key);
s.BindString(1, metadata.SerializeAsString());

return s.Run();
}

bool PowerBookmarkSyncMetadataDatabase::ClearEntityMetadata(
syncer::ModelType model_type,
const std::string& storage_key) {
DCHECK(!storage_key.empty());

static constexpr char kClearSyncMetadataSql[] =
// clang-format off
"DELETE FROM sync_metadata WHERE storage_key=?";
// clang-format on
DCHECK(db_->IsSQLValid(kClearSyncMetadataSql));

sql::Statement s(db_->GetUniqueStatement(kClearSyncMetadataSql));
s.BindString(0, storage_key);

return s.Run();
}

bool PowerBookmarkSyncMetadataDatabase::UpdateModelTypeState(
syncer::ModelType model_type,
const sync_pb::ModelTypeState& model_type_state) {
DCHECK_GT(meta_table_->GetVersionNumber(), 0);

std::string serialized_state = model_type_state.SerializeAsString();
return meta_table_->SetValue(kPowerBookmarkModelTypeStateKey,
serialized_state);
}

bool PowerBookmarkSyncMetadataDatabase::ClearModelTypeState(
syncer::ModelType model_type) {
DCHECK_GT(meta_table_->GetVersionNumber(), 0);
return meta_table_->DeleteKey(kPowerBookmarkModelTypeStateKey);
}

bool PowerBookmarkSyncMetadataDatabase::GetAllEntityMetadata(
syncer::MetadataBatch* metadata_batch) {
DCHECK(metadata_batch);

static constexpr char kGetAllEntityMetadataSql[] =
// clang-format off
"SELECT storage_key, value FROM sync_metadata";
// clang-format on
DCHECK(db_->IsSQLValid(kGetAllEntityMetadataSql));

sql::Statement s(db_->GetUniqueStatement(kGetAllEntityMetadataSql));

while (s.Step()) {
std::string storage_key = s.ColumnString(0);
std::string serialized_metadata = s.ColumnString(1);
auto entity_metadata = std::make_unique<sync_pb::EntityMetadata>();
if (!entity_metadata->ParseFromString(serialized_metadata)) {
DLOG(WARNING) << "Failed to deserialize POWER_BOOKMARK model type "
"sync_pb::EntityMetadata.";
return false;
}
metadata_batch->AddMetadata(storage_key, std::move(entity_metadata));
}
return true;
}

} // namespace power_bookmarks
@@ -0,0 +1,74 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_POWER_BOOKMARKS_STORAGE_POWER_BOOKMARK_SYNC_METADATA_DATABASE_H_
#define COMPONENTS_POWER_BOOKMARKS_STORAGE_POWER_BOOKMARK_SYNC_METADATA_DATABASE_H_

#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "components/sync/base/model_type.h"
#include "components/sync/model/sync_metadata_store.h"
#include "sql/meta_table.h"

namespace sql {
class Database;
class MetaTable;
} // namespace sql

namespace syncer {
class MetadataBatch;
} // namespace syncer

namespace power_bookmarks {

class PowerBookmarkSyncMetadataDatabaseTest;

// A sync metadata database maintains two things: the entity metadata table and
// the datatype state, stored in the MetaTable. The entity metadata table
// contains metadata (sync states) for each entity. The datatype state is the
// overall state of the power bookmarks datatype.
class PowerBookmarkSyncMetadataDatabase : public syncer::SyncMetadataStore {
public:
// After construction, Init() must be called before doing anything else to
// make sure the database is initialized.
PowerBookmarkSyncMetadataDatabase(sql::Database* db,
sql::MetaTable* meta_table);

PowerBookmarkSyncMetadataDatabase(const PowerBookmarkSyncMetadataDatabase&) =
delete;
PowerBookmarkSyncMetadataDatabase& operator=(
const PowerBookmarkSyncMetadataDatabase&) = delete;

~PowerBookmarkSyncMetadataDatabase() override;

// Makes sure the tables and indices are properly set up. Must be called
// before anything else.
bool Init();

// syncer::SyncMetadataStore implementation.
bool UpdateEntityMetadata(syncer::ModelType model_type,
const std::string& storage_key,
const sync_pb::EntityMetadata& metadata) override;
bool ClearEntityMetadata(syncer::ModelType model_type,
const std::string& storage_key) override;
bool UpdateModelTypeState(
syncer::ModelType model_type,
const sync_pb::ModelTypeState& model_type_state) override;
bool ClearModelTypeState(syncer::ModelType model_type) override;

// Reads all sync_pb::EntityMetadata and fills `metadata_batch` with it.
bool GetAllEntityMetadata(syncer::MetadataBatch* metadata_batch);

private:
friend class PowerBookmarkSyncMetadataDatabaseTest;

const raw_ptr<sql::Database> db_;
const raw_ptr<sql::MetaTable> meta_table_;
};

} // namespace power_bookmarks

#endif // COMPONENTS_POWER_BOOKMARKS_STORAGE_POWER_BOOKMARK_SYNC_METADATA_DATABASE_H_

0 comments on commit ab058af

Please sign in to comment.