Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ddl: Support FLASHBACK DATABASE #8424

Merged
merged 12 commits into from
Dec 7, 2023
24 changes: 22 additions & 2 deletions dbms/src/Databases/DatabaseTiFlash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <Storages/IManageableStorage.h>
#include <Storages/KVStore/TMTContext.h>
#include <Storages/KVStore/TMTStorages.h>
#include <TiDB/Schema/TiDB.h>
#include <common/logger_useful.h>

namespace DB
Expand Down Expand Up @@ -610,7 +611,7 @@ void DatabaseTiFlash::shutdown()
tables.clear();
}

void DatabaseTiFlash::alterTombstone(const Context & context, Timestamp tombstone_)
void DatabaseTiFlash::alterTombstone(const Context & context, Timestamp tombstone_, const TiDB::DBInfoPtr & new_db_info)
{
const auto database_metadata_path = getDatabaseMetadataPath(metadata_path);
const auto database_metadata_tmp_path = database_metadata_path + ".tmp";
Expand All @@ -622,7 +623,18 @@ void DatabaseTiFlash::alterTombstone(const Context & context, Timestamp tombston

{
// Alter the attach statement in metadata.
auto dbinfo_literal = std::make_shared<ASTLiteral>(Field(db_info == nullptr ? "" : (db_info->serialize())));
std::shared_ptr<ASTLiteral> dbinfo_literal = [&]() {
String seri_info;
if (new_db_info != nullptr)
{
seri_info = new_db_info->serialize();
}
else if (db_info != nullptr)
{
seri_info = db_info->serialize();
}
return std::make_shared<ASTLiteral>(Field(seri_info));
}();
Field format_version_field(static_cast<UInt64>(DatabaseTiFlash::CURRENT_VERSION));
auto version_literal = std::make_shared<ASTLiteral>(format_version_field);
auto tombstone_literal = std::make_shared<ASTLiteral>(Field(tombstone_));
Expand Down Expand Up @@ -651,6 +663,9 @@ void DatabaseTiFlash::alterTombstone(const Context & context, Timestamp tombston
}
else
{
// update the seri dbinfo
args.children[0] = dbinfo_literal;
args.children[1] = version_literal;
// udpate the tombstone mark
args.children[2] = tombstone_literal;
}
Expand Down Expand Up @@ -704,6 +719,11 @@ void DatabaseTiFlash::alterTombstone(const Context & context, Timestamp tombston

// After all done, set the tombstone
tombstone = tombstone_;
// Overwrite db_info if not null
if (new_db_info)
{
db_info = new_db_info;
}
}

void DatabaseTiFlash::drop(const Context & context)
Expand Down
2 changes: 1 addition & 1 deletion dbms/src/Databases/DatabaseTiFlash.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class DatabaseTiFlash : public DatabaseWithOwnTablesBase

bool isTombstone() const override { return tombstone != 0; }
Timestamp getTombstone() const override { return tombstone; }
void alterTombstone(const Context & context, Timestamp tombstone_) override;
void alterTombstone(const Context & context, Timestamp tombstone_, const TiDB::DBInfoPtr & new_db_info) override;

void drop(const Context & context) override;

Expand Down
11 changes: 10 additions & 1 deletion dbms/src/Databases/IDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
#include <functional>
#include <memory>

namespace TiDB
{
struct DBInfo;
using DBInfoPtr = std::shared_ptr<DBInfo>;
} // namespace TiDB

namespace DB
{
Expand Down Expand Up @@ -144,7 +149,11 @@ class IDatabase : public std::enable_shared_from_this<IDatabase>

virtual bool isTombstone() const { return false; }
virtual Timestamp getTombstone() const { return 0; }
virtual void alterTombstone(const Context & /*context*/, Timestamp /*tombstone_*/) {}
virtual void alterTombstone(
const Context & /*context*/,
Timestamp /*tombstone_*/,
const TiDB::DBInfoPtr & /*new_db_info*/)
{}

/// Delete metadata, the deletion of which differs from the recursive deletion of the directory, if any.
virtual void drop(const Context & context) = 0;
Expand Down
35 changes: 32 additions & 3 deletions dbms/src/Databases/test/gtest_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
#include <Storages/IStorage.h>
#include <Storages/KVStore/TMTContext.h>
#include <Storages/KVStore/TMTStorages.h>
#include <Storages/KVStore/Types.h>
#include <Storages/MutableSupport.h>
#include <Storages/registerStorages.h>
#include <TestUtils/TiFlashTestBasic.h>
#include <TiDB/Schema/SchemaNameMapper.h>
#include <TiDB/Schema/TiDB.h>
#include <common/logger_useful.h>

#include <optional>
Expand Down Expand Up @@ -942,6 +944,7 @@ try
)",
};

size_t case_no = 0;
for (const auto & statement : statements)
{
{
Expand All @@ -968,22 +971,48 @@ try
LOG_DEBUG(log, "After create [meta={}]", meta);

DB::Timestamp tso = 1000;
db->alterTombstone(*ctx, tso);
db->alterTombstone(*ctx, tso, nullptr);
EXPECT_TRUE(db->isTombstone());
EXPECT_EQ(db->getTombstone(), tso);
if (case_no != 0)
{
auto db_tiflash = std::dynamic_pointer_cast<DatabaseTiFlash>(db);
ASSERT_NE(db_tiflash, nullptr);
auto db_info = db_tiflash->getDatabaseInfo();
ASSERT_EQ(db_info.name, "test_db"); // not changed
}

// Try restore from disk
db = detachThenAttach(*ctx, db_name, std::move(db), log);
EXPECT_TRUE(db->isTombstone());
EXPECT_EQ(db->getTombstone(), tso);

// Recover
db->alterTombstone(*ctx, 0);
// Recover, usually recover with a new database name
auto new_db_info = std::make_shared<TiDB::DBInfo>(
R"json({"charset":"utf8mb4","collate":"utf8mb4_bin","db_name":{"L":"test_new_db","O":"test_db"},"id":1010,"state":5})json",
NullspaceID);
db->alterTombstone(*ctx, 0, new_db_info);
EXPECT_FALSE(db->isTombstone());
if (case_no != 0)
{
auto db_tiflash = std::dynamic_pointer_cast<DatabaseTiFlash>(db);
ASSERT_NE(db_tiflash, nullptr);
auto db_info = db_tiflash->getDatabaseInfo();
ASSERT_EQ(db_info.name, "test_new_db"); // changed by the `new_db_info`
}

// Try restore from disk
db = detachThenAttach(*ctx, db_name, std::move(db), log);
EXPECT_FALSE(db->isTombstone());
if (case_no != 0)
{
auto db_tiflash = std::dynamic_pointer_cast<DatabaseTiFlash>(db);
ASSERT_NE(db_tiflash, nullptr);
auto db_info = db_tiflash->getDatabaseInfo();
ASSERT_EQ(db_info.name, "test_new_db"); // changed by the `new_db_info`
}

case_no += 1;
}
}
CATCH
Expand Down
86 changes: 67 additions & 19 deletions dbms/src/TiDB/Schema/SchemaBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,17 @@ void SchemaBuilder<Getter, NameMapper>::applyDiff(const SchemaDiff & diff)
{
case SchemaActionType::CreateSchema:
{
applyCreateSchema(diff.schema_id);
applyCreateDatabase(diff.schema_id);
break;
}
case SchemaActionType::DropSchema:
{
applyDropSchema(diff.schema_id);
applyDropDatabase(diff.schema_id);
break;
}
case SchemaActionType::ActionRecoverSchema:
{
applyRecoverDatabase(diff.schema_id);
break;
}
case SchemaActionType::CreateTables:
Expand Down Expand Up @@ -869,19 +874,19 @@ String createDatabaseStmt(Context & context, const DBInfo & db_info, const Schem
}

template <typename Getter, typename NameMapper>
bool SchemaBuilder<Getter, NameMapper>::applyCreateSchema(DatabaseID schema_id)
bool SchemaBuilder<Getter, NameMapper>::applyCreateDatabase(DatabaseID database_id)
{
auto db_info = getter.getDatabase(schema_id);
if (unlikely(db_info == nullptr))
auto db_info = getter.getDatabase(database_id);
if (db_info == nullptr)
{
return false;
}
applyCreateSchema(db_info);
applyCreateDatabaseByInfo(db_info);
return true;
}

template <typename Getter, typename NameMapper>
void SchemaBuilder<Getter, NameMapper>::applyCreateSchema(const TiDB::DBInfoPtr & db_info)
void SchemaBuilder<Getter, NameMapper>::applyCreateDatabaseByInfo(const TiDB::DBInfoPtr & db_info)
{
GET_METRIC(tiflash_schema_internal_ddl_count, type_create_db).Increment();
LOG_INFO(log, "Create database {} begin, database_id={}", name_mapper.debugDatabaseName(*db_info), db_info->id);
Expand All @@ -901,29 +906,72 @@ void SchemaBuilder<Getter, NameMapper>::applyCreateSchema(const TiDB::DBInfoPtr
}

template <typename Getter, typename NameMapper>
void SchemaBuilder<Getter, NameMapper>::applyDropSchema(DatabaseID schema_id)
void SchemaBuilder<Getter, NameMapper>::applyRecoverDatabase(DatabaseID database_id)
{
auto db_info = getter.getDatabase(database_id);
if (db_info == nullptr)
{
LOG_INFO(
log,
"Recover database is ignored because database is not exist in TiKV,"
" database_id={}",
database_id);
return;
}
LOG_INFO(log, "Recover database begin, database_id={}", database_id);
auto db_name = name_mapper.mapDatabaseName(database_id, keyspace_id);
auto db = context.tryGetDatabase(db_name);
if (!db)
{
LOG_INFO(
log,
"Recover database is ignored because instance is not exists, may have been physically dropped, "
"database_id={}",
db_name,
database_id);
return;
}

{
//TODO: it seems may need a lot time, maybe we can do it in a background thread
auto table_ids = table_id_map.findTablesByDatabaseID(database_id);
for (auto table_id : table_ids)
{
auto table_info = getter.getTableInfo(database_id, table_id);
applyRecoverLogicalTable(db_info, table_info);
}
}

// Usually `FLASHBACK DATABASE ... TO ...` will rename the database
db->alterTombstone(context, 0, db_info);
databases.addDatabaseInfo(db_info); // add back database info cache
LOG_INFO(log, "Recover database end, database_id={}", database_id);
}

template <typename Getter, typename NameMapper>
void SchemaBuilder<Getter, NameMapper>::applyDropDatabase(DatabaseID database_id)
{
TiDB::DBInfoPtr db_info = databases.getDBInfo(schema_id);
TiDB::DBInfoPtr db_info = databases.getDBInfo(database_id);
if (unlikely(db_info == nullptr))
{
LOG_INFO(log, "Try to drop database but not found, may has been dropped, database_id={}", schema_id);
LOG_INFO(log, "Try to drop database but not found, may has been dropped, database_id={}", database_id);
return;
}

{
//TODO: it seems may need a lot time, maybe we can do it in a background thread
auto table_ids = table_id_map.findTablesByDatabaseID(schema_id);
auto table_ids = table_id_map.findTablesByDatabaseID(database_id);
for (auto table_id : table_ids)
applyDropTable(schema_id, table_id);
applyDropTable(database_id, table_id);
}

applyDropSchema(name_mapper.mapDatabaseName(*db_info));
applyDropDatabaseByName(name_mapper.mapDatabaseName(database_id, keyspace_id));

databases.eraseDBInfo(schema_id);
databases.eraseDBInfo(database_id);
}

template <typename Getter, typename NameMapper>
void SchemaBuilder<Getter, NameMapper>::applyDropSchema(const String & db_name)
void SchemaBuilder<Getter, NameMapper>::applyDropDatabaseByName(const String & db_name)
{
GET_METRIC(tiflash_schema_internal_ddl_count, type_drop_db).Increment();
LOG_INFO(log, "Tombstone database begin, db_name={}", db_name);
Expand All @@ -945,7 +993,7 @@ void SchemaBuilder<Getter, NameMapper>::applyDropSchema(const String & db_name)
// In such way our database (and its belonging tables) will be GC-ed later than TiDB, which is safe and correct.
auto & tmt_context = context.getTMTContext();
auto tombstone = tmt_context.getPDClient()->getTS();
db->alterTombstone(context, tombstone);
db->alterTombstone(context, tombstone, /*new_db_info*/ nullptr); // keep the old db_info

LOG_INFO(log, "Tombstone database end, db_name={}", db_name);
}
Expand Down Expand Up @@ -1204,7 +1252,7 @@ void SchemaBuilder<Getter, NameMapper>::syncAllSchema()
{
break;
}
applyCreateSchema(db_info);
applyCreateDatabaseByInfo(db_info);
{
std::unique_lock<std::mutex> created_db_set_lock(created_db_set_mutex);
created_db_set.emplace(name_mapper.mapDatabaseName(*db_info));
Expand Down Expand Up @@ -1302,7 +1350,7 @@ void SchemaBuilder<Getter, NameMapper>::syncAllSchema()
}
if (created_db_set.count(it->first) == 0 && !isReservedDatabase(context, it->first))
{
applyDropSchema(it->first);
applyDropDatabaseByName(it->first);
LOG_INFO(log, "Database {} dropped during sync all schemas", it->first);
}
}
Expand Down Expand Up @@ -1474,7 +1522,7 @@ void SchemaBuilder<Getter, NameMapper>::dropAllSchema()
{
continue;
}
applyDropSchema(db.first);
applyDropDatabaseByName(db.first);
LOG_INFO(log, "Database {} dropped during drop all schemas", db.first);
}

Expand Down
18 changes: 8 additions & 10 deletions dbms/src/TiDB/Schema/SchemaBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,29 @@ struct SchemaBuilder
bool applyTable(DatabaseID database_id, TableID logical_table_id, TableID physical_table_id, bool force);

private:
void applyDropSchema(DatabaseID schema_id);

void applyDropDatabase(DatabaseID database_id);
/// Parameter db_name should be mapped.
void applyDropSchema(const String & db_name);
void applyDropDatabaseByName(const String & db_name);

bool applyCreateSchema(DatabaseID schema_id);
bool applyCreateDatabase(DatabaseID database_id);
void applyCreateDatabaseByInfo(const TiDB::DBInfoPtr & db_info);

void applyCreateSchema(const TiDB::DBInfoPtr & db_info);
void applyRecoverDatabase(DatabaseID database_id);

void applyCreateTable(DatabaseID database_id, TableID table_id);
void applyCreateStorageInstance(
const TiDB::DBInfoPtr & db_info,
const TiDB::TableInfoPtr & table_info,
bool is_tombstone);

void applyDropTable(DatabaseID database_id, TableID table_id);
/// Parameter schema_name should be mapped.
void applyDropPhysicalTable(const String & db_name, TableID table_id);

void applyRecoverTable(DatabaseID database_id, TiDB::TableID table_id);
void applyRecoverLogicalTable(const TiDB::DBInfoPtr & db_info, const TiDB::TableInfoPtr & table_info);
bool tryRecoverPhysicalTable(const TiDB::DBInfoPtr & db_info, const TiDB::TableInfoPtr & table_info);

/// Parameter schema_name should be mapped.
void applyDropPhysicalTable(const String & db_name, TableID table_id);

void applyPartitionDiff(DatabaseID database_id, TableID table_id);
void applyPartitionDiffOnLogicalTable(
const TiDB::DBInfoPtr & db_info,
Expand All @@ -107,8 +107,6 @@ struct SchemaBuilder

void applySetTiFlashReplica(DatabaseID database_id, TableID table_id);

void applyCreateTable(DatabaseID database_id, TableID table_id);

void applyExchangeTablePartition(const SchemaDiff & diff);
};

Expand Down
4 changes: 1 addition & 3 deletions dbms/src/TiDB/Schema/SchemaGetter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ struct TxnStructure
static String hGet(KeyspaceSnapshot & snap, const String & key, const String & field)
{
String encode_key = encodeHashDataKey(key, field);
String value = snap.Get(encode_key);
return value;
return snap.Get(encode_key);
}

static String mvccGet(KeyspaceSnapshot & snap, const String & key, const String & field)
Expand Down Expand Up @@ -273,7 +272,6 @@ TiDB::DBInfoPtr SchemaGetter::getDatabase(DatabaseID db_id)
{
String key = getDBKey(db_id);
String json = TxnStructure::hGet(snap, DBs, key);

if (json.empty())
return nullptr;

Expand Down
Loading