From a80b6c731316d7ac039dbcf062f19c8f20a821bf Mon Sep 17 00:00:00 2001 From: JaySon Date: Tue, 3 Sep 2024 11:37:44 +0800 Subject: [PATCH] ddl: Skip updating the tombstone_ts if the table is already tombstone (release-6.5) (#9230) close pingcap/tiflash#9227 --- dbms/src/TiDB/Schema/SchemaBuilder.cpp | 117 +++++++++++------- dbms/src/TiDB/Schema/SchemaBuilder.h | 12 +- .../TiDB/Schema/tests/gtest_schema_sync.cpp | 109 ++++++++++++++++ 3 files changed, 188 insertions(+), 50 deletions(-) diff --git a/dbms/src/TiDB/Schema/SchemaBuilder.cpp b/dbms/src/TiDB/Schema/SchemaBuilder.cpp index 76347a55fdb..cf5a6507fcf 100644 --- a/dbms/src/TiDB/Schema/SchemaBuilder.cpp +++ b/dbms/src/TiDB/Schema/SchemaBuilder.cpp @@ -489,7 +489,7 @@ void SchemaBuilder::applyDiff(const SchemaDiff & diff) auto db_info = getter.getDatabase(opt.schema_id); if (db_info == nullptr) throw TiFlashException("miss database: " + std::to_string(diff.schema_id), Errors::DDL::StaleSchema); - applyRenameTable(db_info, opt.table_id); + applyRenameTable(db_info, opt.table_id, "RenameTables"); } return; } @@ -536,7 +536,7 @@ void SchemaBuilder::applyDiff(const SchemaDiff & diff) } case SchemaActionType::RenameTable: { - applyRenameTable(db_info, diff.table_id); + applyRenameTable(db_info, diff.table_id, "RenameTable"); break; } case SchemaActionType::AddTablePartition: @@ -573,7 +573,8 @@ void SchemaBuilder::applyDiff(const SchemaDiff & diff) if (old_table_id) { - applyDropTable(db_info, old_table_id); + String action = fmt::format("{}", magic_enum::enum_name(diff.type)); + applyDropTable(db_info, old_table_id, action); } if (new_table_id) @@ -588,11 +589,11 @@ void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr auto table_info = getter.getTableInfo(db_info->id, table_id); if (table_info == nullptr) { - throw TiFlashException(fmt::format("miss old table id in TiKV {}", table_id), Errors::DDL::StaleSchema); + throw TiFlashException(fmt::format("miss old table id in TiKV when applyPartitionDiff, table_id={}", table_id), Errors::DDL::StaleSchema); } if (!table_info->isLogicalPartitionTable()) { - throw TiFlashException(fmt::format("new table in TiKV not partition table {}", name_mapper.debugCanonicalName(*db_info, *table_info)), + throw TiFlashException(fmt::format("new table in TiKV not partition table when applyPartitionDiff, {}", name_mapper.debugCanonicalName(*db_info, *table_info)), Errors::DDL::TableTypeNotMatch); } @@ -600,10 +601,10 @@ void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr auto storage = tmt_context.getStorages().get(table_info->id); if (storage == nullptr) { - throw TiFlashException(fmt::format("miss table in TiFlash {}", table_id), Errors::DDL::MissingTable); + throw TiFlashException(fmt::format("miss table in TiFlash when applyPartitionDiff, table_id={}", table_id), Errors::DDL::MissingTable); } - applyPartitionDiff(db_info, table_info, storage, /*drop_part_if_not_exist*/ true); + applyPartitionDiffOnLogicalTable(db_info, table_info, storage, /*drop_part_if_not_exist*/ true); } template @@ -637,7 +638,7 @@ TiDB::DBInfoPtr SchemaBuilder::tryFindDatabaseByPartitionTab } template -void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr & db_info, const TableInfoPtr & table_info, const ManageableStoragePtr & storage, bool drop_part_if_not_exist) +void SchemaBuilder::applyPartitionDiffOnLogicalTable(const TiDB::DBInfoPtr & db_info, const TableInfoPtr & table_info, const ManageableStoragePtr & storage, bool drop_part_if_not_exist) { const auto & orig_table_info = storage->getTableInfo(); if (!orig_table_info.isLogicalPartitionTable()) @@ -679,6 +680,7 @@ void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr updated_table_info.partition = table_info->partition; /// Apply changes to physical tables. + auto reason = fmt::format("ApplyPartitionDiff-logical_table_id={}", orig_table_info.id); if (drop_part_if_not_exist) { for (const auto & orig_def : orig_defs) @@ -686,10 +688,10 @@ void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr if (new_part_id_set.count(orig_def.id) == 0) { const auto part_table_name = name_mapper.mapTableNameByID(orig_def.id); - // When `tryLoadSchemaDiffs` fails, we may run into `SchemaBuilder::syncAllSchem` -> `applyPartitionDiff` without `applyExchangeTablePartition` + // When `tryLoadSchemaDiffs` fails, we may run into `SchemaBuilder::syncAllSchema` -> `applyPartitionDiffOnLogicalTable` without `applyExchangeTablePartition` // The physical table maybe `EXCHANGE` to another database, try to find the partition from all database auto part_db_info = tryFindDatabaseByPartitionTable(db_info, part_table_name); - applyDropPhysicalTable(name_mapper.mapDatabaseName(*part_db_info), orig_def.id); + applyDropPhysicalTable(name_mapper.mapDatabaseName(*part_db_info), orig_def.id, /*must_update_tombstone*/ false, reason); } } } @@ -700,7 +702,7 @@ void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr { auto part_table_info = updated_table_info.producePartitionTableInfo(new_def.id, name_mapper); const auto part_table_name = name_mapper.mapTableName(*part_table_info); - // When `tryLoadSchemaDiffs` fails, we may run into `SchemaBuilder::syncAllSchem` -> `applyPartitionDiff` without `applyExchangeTablePartition` + // When `tryLoadSchemaDiffs` fails, we may run into `SchemaBuilder::syncAllSchema` -> `applyPartitionDiffOnLogicalTable` without `applyExchangeTablePartition` // The physical table maybe `EXCHANGE` from another database, try to find the partition from all database auto part_db_info = tryFindDatabaseByPartitionTable(db_info, part_table_name); applyCreatePhysicalTable(part_db_info, part_table_info); @@ -715,31 +717,32 @@ void SchemaBuilder::applyPartitionDiff(const TiDB::DBInfoPtr } template -void SchemaBuilder::applyRenameTable(const DBInfoPtr & new_db_info, TableID table_id) +void SchemaBuilder::applyRenameTable(const DBInfoPtr & new_db_info, TableID table_id, std::string_view action) { auto new_table_info = getter.getTableInfo(new_db_info->id, table_id); if (new_table_info == nullptr) { - throw TiFlashException(fmt::format("miss table id in TiKV {}", table_id), Errors::DDL::StaleSchema); + throw TiFlashException(fmt::format("miss table id in TiKV when renameTable, table_id={} action={}", table_id, action), Errors::DDL::StaleSchema); } auto & tmt_context = context.getTMTContext(); auto storage = tmt_context.getStorages().get(table_id); if (storage == nullptr) { - throw TiFlashException(fmt::format("miss table id in TiFlash {}", table_id), Errors::DDL::MissingTable); + throw TiFlashException(fmt::format("miss table id in TiFlash when renameTable, table_id={} action={}", table_id, action), Errors::DDL::MissingTable); } - applyRenameLogicalTable(new_db_info, new_table_info, storage); + applyRenameLogicalTable(new_db_info, new_table_info, storage, action); } template void SchemaBuilder::applyRenameLogicalTable( const DBInfoPtr & new_db_info, const TableInfoPtr & new_table_info, - const ManageableStoragePtr & storage) + const ManageableStoragePtr & storage, + std::string_view action) { - applyRenamePhysicalTable(new_db_info, *new_table_info, storage); + applyRenamePhysicalTable(new_db_info, *new_table_info, storage, action); if (new_table_info->isLogicalPartitionTable()) { @@ -749,10 +752,16 @@ void SchemaBuilder::applyRenameLogicalTable( auto part_storage = tmt_context.getStorages().get(part_def.id); if (part_storage == nullptr) { - throw Exception(fmt::format("miss old table id in Flash {}", part_def.id)); + throw Exception( // + ErrorCodes::LOGICAL_ERROR, + "Storage instance is not exist in TiFlash, the partition is not created yet in this TiFlash instance, " + "physical_table_id={} logical_table_id={} action={}", + part_def.id, + new_table_info->id, + action); } auto part_table_info = new_table_info->producePartitionTableInfo(part_def.id, name_mapper); - applyRenamePhysicalTable(new_db_info, *part_table_info, part_storage); + applyRenamePhysicalTable(new_db_info, *part_table_info, part_storage, action); } } } @@ -761,7 +770,8 @@ template void SchemaBuilder::applyRenamePhysicalTable( const DBInfoPtr & new_db_info, const TableInfo & new_table_info, - const ManageableStoragePtr & storage) + const ManageableStoragePtr & storage, + std::string_view action) { const auto old_mapped_db_name = storage->getDatabaseName(); const auto new_mapped_db_name = name_mapper.mapDatabaseName(*new_db_info); @@ -769,24 +779,24 @@ void SchemaBuilder::applyRenamePhysicalTable( const auto new_display_table_name = name_mapper.displayTableName(new_table_info); if (old_mapped_db_name == new_mapped_db_name && old_display_table_name == new_display_table_name) { - LOG_DEBUG(log, "Table {} name identical, not renaming.", name_mapper.debugCanonicalName(*new_db_info, new_table_info)); + LOG_DEBUG(log, "Table {} name identical, not renaming, action={}", name_mapper.debugCanonicalName(*new_db_info, new_table_info), action); return; } // There could be a chance that the target database has been dropped in TiKV before // TiFlash accepts the "create database" schema diff. We need to ensure the local // database exist before executing renaming. - const auto action = fmt::format("applyRenamePhysicalTable-table_id={}", new_table_info.id); ensureLocalDatabaseExist(new_db_info->id, new_mapped_db_name, action); const auto old_mapped_tbl_name = storage->getTableName(); GET_METRIC(tiflash_schema_internal_ddl_count, type_rename_column).Increment(); LOG_INFO( log, - "Renaming table {}.{} (display name: {}) to {}.", + "Renaming table {}.{} (display name: {}) to {}, action={}", old_mapped_db_name, old_mapped_tbl_name, old_display_table_name, - name_mapper.debugCanonicalName(*new_db_info, new_table_info)); + name_mapper.debugCanonicalName(*new_db_info, new_table_info), + action); // Note that rename will update table info in table create statement by modifying original table info // with "tidb_display.table" instead of using new_table_info directly, so that other changes @@ -802,11 +812,12 @@ void SchemaBuilder::applyRenamePhysicalTable( LOG_INFO( log, - "Renamed table {}.{} (display name: {}) to {}", + "Renamed table {}.{} (display name: {}) to {}, action={}", old_mapped_db_name, old_mapped_tbl_name, old_display_table_name, - name_mapper.debugCanonicalName(*new_db_info, new_table_info)); + name_mapper.debugCanonicalName(*new_db_info, new_table_info), + action); } template @@ -876,7 +887,7 @@ void SchemaBuilder::applyExchangeTablePartition(const Schema // once it became a partition. // But this method will skip dropping partition id that is not exist in the new table_info, // because the physical table could be changed into a normal table without dropping. - applyPartitionDiff(pt_db_info, table_info, storage, /*drop_part_if_not_exist*/ false); + applyPartitionDiffOnLogicalTable(pt_db_info, table_info, storage, /*drop_part_if_not_exist*/ false); FAIL_POINT_TRIGGER_EXCEPTION(FailPoints::exception_after_step_1_in_exchange_partition); /// step 2 change non partition table to a partition of the partition table @@ -902,7 +913,7 @@ void SchemaBuilder::applyExchangeTablePartition(const Schema FAIL_POINT_TRIGGER_EXCEPTION(FailPoints::exception_before_step_2_rename_in_exchange_partition); if (npt_db_info->id != pt_db_info->id) - applyRenamePhysicalTable(pt_db_info, orig_table_info, storage); + applyRenamePhysicalTable(pt_db_info, orig_table_info, storage, "exchange partition"); FAIL_POINT_TRIGGER_EXCEPTION(FailPoints::exception_after_step_2_in_exchange_partition); /// step 3 change partition of the partition table to non partition table @@ -934,9 +945,9 @@ void SchemaBuilder::applyExchangeTablePartition(const Schema FAIL_POINT_TRIGGER_EXCEPTION(FailPoints::exception_before_step_3_rename_in_exchange_partition); if (npt_db_info->id != pt_db_info->id) - applyRenamePhysicalTable(npt_db_info, orig_table_info, storage); + applyRenamePhysicalTable(npt_db_info, orig_table_info, storage, "exchange partition"); FAIL_POINT_TRIGGER_EXCEPTION(FailPoints::exception_after_step_3_in_exchange_partition); - LOG_INFO(log, "Execute exchange partition done, npt_table_id={} npt_database_id={} pt_table_id={} pt_partition_id={} pt_database_id={}", npt_table_id, npt_database_id, pt_table_id, pt_partition_id, pt_database_id); + LOG_INFO(log, "Execute exchange partition done, npt_table_id={} npt_database_id={} pt_table_id={} pt_partition_id={} pt_database_id={}", npt_table_id, npt_database_id, pt_table_id, pt_partition_id, pt_database_id); } template @@ -1031,11 +1042,11 @@ template void SchemaBuilder::applyDropSchema(const String & db_name) { GET_METRIC(tiflash_schema_internal_ddl_count, type_drop_db).Increment(); - LOG_INFO(log, "Tombstoning database {}", db_name); + LOG_INFO(log, "Tombstone database begin, db_name={}", db_name); auto db = context.tryGetDatabase(db_name); if (db == nullptr) { - LOG_INFO(log, "Database {} does not exists", db_name); + LOG_INFO(log, "Database does not exists, db_name={}", db_name); return; } @@ -1052,7 +1063,7 @@ void SchemaBuilder::applyDropSchema(const String & db_name) auto tombstone = PDClientHelper::getTSO(tmt_context.getPDClient(), PDClientHelper::get_tso_maxtime); db->alterTombstone(context, tombstone, /*new_db_info*/ nullptr); // keep the old db_info - LOG_INFO(log, "Tombstoned database {}, tombstone={}", db_name, tombstone); + LOG_INFO(log, "Tombstone database end, db_name={} tombstone={}", db_name, tombstone); } template @@ -1231,7 +1242,7 @@ void SchemaBuilder::applyCreatePhysicalTable(const DBInfoPtr // in TiDB, then TiFlash may not create the IDatabase instance. Make sure we can access // to the IDatabase when creating IStorage. const auto database_mapped_name = name_mapper.mapDatabaseName(*db_info); - ensureLocalDatabaseExist(db_info->id, database_mapped_name, fmt::format("CreatePhysicalTable-{}", table_info->id)); + ensureLocalDatabaseExist(db_info->id, database_mapped_name, fmt::format("CreatePhysicalTable-table_id={}", table_info->id)); ParserCreateQuery parser; ASTPtr ast = parseQuery(parser, stmt.data(), stmt.data() + stmt.size(), "from syncSchema " + table_info->name, 0); @@ -1308,17 +1319,29 @@ void SchemaBuilder::applyCreateLogicalTable(const TiDB::DBIn } template -void SchemaBuilder::applyDropPhysicalTable(const String & db_name, TableID table_id) +void SchemaBuilder::applyDropPhysicalTable(const String & db_name, TableID table_id, bool must_update_tombstone, std::string_view action) { auto & tmt_context = context.getTMTContext(); auto storage = tmt_context.getStorages().get(table_id); if (storage == nullptr) { - LOG_DEBUG(log, "table {} does not exist.", table_id); + LOG_DEBUG(log, "table does not exist, table_id={} action={}", table_id, action); return; } + + if (!must_update_tombstone) + { + // When must_update_tombstone == false, we can try to skip updating + // the tombstone_ts if the table is already tombstone. + if (auto tombstone_ts = storage->getTombstone(); tombstone_ts != 0) + { + LOG_INFO(log, "Tombstone table {}.{} has been done before, action={} tombstone={}", db_name, name_mapper.debugTableName(storage->getTableInfo()), action, tombstone_ts); + return; + } + } + GET_METRIC(tiflash_schema_internal_ddl_count, type_drop_table).Increment(); - LOG_INFO(log, "Tombstoning table {}.{}", db_name, name_mapper.debugTableName(storage->getTableInfo())); + LOG_INFO(log, "Tombstone table {}.{} begin, action={}", db_name, name_mapper.debugTableName(storage->getTableInfo()), action); const auto tombstone_ts = PDClientHelper::getTSO(tmt_context.getPDClient(), PDClientHelper::get_tso_maxtime); AlterCommands commands; { @@ -1334,11 +1357,11 @@ void SchemaBuilder::applyDropPhysicalTable(const String & db } auto alter_lock = storage->lockForAlter(getThreadName()); storage->alterFromTiDB(alter_lock, commands, db_name, storage->getTableInfo(), name_mapper, context); - LOG_INFO(log, "Tombstoned table {}.{}, tombstone={}", db_name, name_mapper.debugTableName(storage->getTableInfo()), tombstone_ts); + LOG_INFO(log, "Tombstone table {}.{} end, action={} tombstone={}", db_name, name_mapper.debugTableName(storage->getTableInfo()), action, tombstone_ts); } template -void SchemaBuilder::applyDropTable(const DBInfoPtr & db_info, TableID table_id) +void SchemaBuilder::applyDropTable(const DBInfoPtr & db_info, TableID table_id, std::string_view action) { auto & tmt_context = context.getTMTContext(); auto * storage = tmt_context.getStorages().get(table_id).get(); @@ -1347,18 +1370,23 @@ void SchemaBuilder::applyDropTable(const DBInfoPtr & db_info LOG_DEBUG(log, "table {} does not exist.", table_id); return; } + + // `applyDropTable` is only called by applying schema diff. So we should update tombstone_ts. + // If a table is dropped at tso_1. Then the table is recorvered, then droppped again at tso_2. + // When tiflash meet the SchemaDiff of "drop table" at tso_2, it should update the tombstone_ts. + const bool update_tombstone_ts = true; const auto & table_info = storage->getTableInfo(); if (table_info.isLogicalPartitionTable()) { for (const auto & part_def : table_info.partition.definitions) { - applyDropPhysicalTable(name_mapper.mapDatabaseName(*db_info), part_def.id); + applyDropPhysicalTable(name_mapper.mapDatabaseName(*db_info), part_def.id, update_tombstone_ts, action); } } // Drop logical table at last, only logical table drop will be treated as "complete". // Intermediate failure will hide the logical table drop so that schema syncing when restart will re-drop all (despite some physical tables may have dropped). - applyDropPhysicalTable(name_mapper.mapDatabaseName(*db_info), table_info.id); + applyDropPhysicalTable(name_mapper.mapDatabaseName(*db_info), table_info.id, update_tombstone_ts, action); } template @@ -1491,10 +1519,10 @@ void SchemaBuilder::syncAllSchema() if (table->isLogicalPartitionTable()) { /// Apply partition diff if needed. - applyPartitionDiff(db, table, storage, /*drop_part_if_not_exist*/ true); + applyPartitionDiffOnLogicalTable(db, table, storage, /*drop_part_if_not_exist*/ true); } /// Rename if needed. - applyRenameLogicalTable(db, table, storage); + applyRenameLogicalTable(db, table, storage, "SyncAllSchema"); /// Update replica info if needed. applySetTiFlashReplicaOnLogicalTable(db, table, storage); /// Alter if needed. @@ -1510,7 +1538,8 @@ void SchemaBuilder::syncAllSchema() { if (table_set.count(it->first) == 0) { - applyDropPhysicalTable(it->second->getDatabaseName(), it->first); + // If the table is already tombstone, don't need to update its tombstone_ts. + applyDropPhysicalTable(it->second->getDatabaseName(), it->first, /*must_update_tombstone*/ false, "SyncAllSchema"); LOG_INFO(log, "Table {}.{} dropped during sync all schemas", it->second->getDatabaseName(), name_mapper.debugTableName(it->second->getTableInfo())); } } diff --git a/dbms/src/TiDB/Schema/SchemaBuilder.h b/dbms/src/TiDB/Schema/SchemaBuilder.h index c7a9d8c90a1..d144fb59ae2 100644 --- a/dbms/src/TiDB/Schema/SchemaBuilder.h +++ b/dbms/src/TiDB/Schema/SchemaBuilder.h @@ -67,14 +67,14 @@ struct SchemaBuilder void applyCreatePhysicalTable(const TiDB::DBInfoPtr & db_info, const TiDB::TableInfoPtr & table_info); - void applyDropTable(const TiDB::DBInfoPtr & db_info, TableID table_id); + void applyDropTable(const TiDB::DBInfoPtr & db_info, TableID table_id, std::string_view action); /// Parameter schema_name should be mapped. - void applyDropPhysicalTable(const String & db_name, TableID table_id); + void applyDropPhysicalTable(const String & db_name, TableID table_id, bool must_update_tombstone, std::string_view action); void applyPartitionDiff(const TiDB::DBInfoPtr & db_info, TableID table_id); - void applyPartitionDiff(const TiDB::DBInfoPtr & db_info, const TiDB::TableInfoPtr & table_info, const ManageableStoragePtr & storage, bool drop_part_if_not_exist); + void applyPartitionDiffOnLogicalTable(const TiDB::DBInfoPtr & db_info, const TiDB::TableInfoPtr & table_info, const ManageableStoragePtr & storage, bool drop_part_if_not_exist); TiDB::DBInfoPtr tryFindDatabaseByPartitionTable(const TiDB::DBInfoPtr & db_info, const String & part_table_name); void applyAlterTable(const TiDB::DBInfoPtr & db_info, TableID table_id); @@ -83,11 +83,11 @@ struct SchemaBuilder void applyAlterPhysicalTable(const TiDB::DBInfoPtr & db_info, const TiDB::TableInfoPtr & table_info, const ManageableStoragePtr & storage); - void applyRenameTable(const TiDB::DBInfoPtr & new_db_info, TiDB::TableID table_id); + void applyRenameTable(const TiDB::DBInfoPtr & new_db_info, TiDB::TableID table_id, std::string_view action); - void applyRenameLogicalTable(const TiDB::DBInfoPtr & new_db_info, const TiDB::TableInfoPtr & new_table_info, const ManageableStoragePtr & storage); + void applyRenameLogicalTable(const TiDB::DBInfoPtr & new_db_info, const TiDB::TableInfoPtr & new_table_info, const ManageableStoragePtr & storage, std::string_view action); - void applyRenamePhysicalTable(const TiDB::DBInfoPtr & new_db_info, const TiDB::TableInfo & new_table_info, const ManageableStoragePtr & storage); + void applyRenamePhysicalTable(const TiDB::DBInfoPtr & new_db_info, const TiDB::TableInfo & new_table_info, const ManageableStoragePtr & storage, std::string_view action); void applyExchangeTablePartition(const SchemaDiff & diff); diff --git a/dbms/src/TiDB/Schema/tests/gtest_schema_sync.cpp b/dbms/src/TiDB/Schema/tests/gtest_schema_sync.cpp index c6125485ecc..3c5d924875f 100644 --- a/dbms/src/TiDB/Schema/tests/gtest_schema_sync.cpp +++ b/dbms/src/TiDB/Schema/tests/gtest_schema_sync.cpp @@ -29,12 +29,16 @@ #include #include #include +#include + +#include namespace DB { namespace FailPoints { extern const char exception_before_rename_table_old_meta_removed[]; +extern const char force_schema_sync_too_old_schema[]; extern const char force_context_path[]; } // namespace FailPoints namespace tests @@ -331,5 +335,110 @@ try } CATCH +TEST_F(SchemaSyncTest, DropTableTombstoneTSCase1) +try +{ + // tiflash/issues/9227 + auto pd_client = global_ctx.getTMTContext().getPDClient(); + + const String db_name = "mock_db"; + const String tbl_name = "mock_part_tbl"; + + auto cols = ColumnsDescription({ + {"col_1", typeFromString("String")}, + {"col_2", typeFromString("Int64")}, + }); + + /*auto db_id =*/MockTiDB::instance().newDataBase(db_name); + auto logical_table_id = MockTiDB::instance().newTable(db_name, tbl_name, cols, pd_client->getTS(), "", "dt"); + + refreshSchema(); + { + auto storage = mustGetSyncedTable(logical_table_id); + ASSERT_EQ(storage->getTombstone(), 0); + } + + // drop the table + LOG_INFO(Logger::get(), "mock drop table at tidb"); + MockTiDB::instance().dropTable(global_ctx, db_name, tbl_name, /*drop_regions*/ true); + refreshSchema(); + UInt64 tombstone_ts_before_sync_all = 0; + { + // the table should mark as tombstone != 0 + auto storage = mustGetSyncedTable(logical_table_id); + tombstone_ts_before_sync_all = storage->getTombstone(); + ASSERT_NE(tombstone_ts_before_sync_all, 0); + } + LOG_INFO(Logger::get(), "mock drop table at tidb done"); + + LOG_INFO(Logger::get(), "mock tiflash sync all schema"); + FailPointHelper::enableFailPoint(FailPoints::force_schema_sync_too_old_schema); + SCOPE_EXIT({ + FailPointHelper::disableFailPoint(FailPoints::force_schema_sync_too_old_schema); + }); + MockTiDB::instance().newDataBase(db_name + "_copy"); + refreshSchema(); + { + // the table should mark as tombstone != 0 + auto storage = mustGetSyncedTable(logical_table_id); + ASSERT_NE(storage->getTombstone(), 0); + // the tombstone_ts should not changed + ASSERT_EQ(storage->getTombstone(), tombstone_ts_before_sync_all); + } +} +CATCH + +TEST_F(SchemaSyncTest, DropTableTombstoneTSCase2) +try +{ + // tiflash/issues/9227 + auto pd_client = global_ctx.getTMTContext().getPDClient(); + + const String db_name = "mock_db"; + const String tbl_name = "mock_part_tbl"; + + auto cols = ColumnsDescription({ + {"col_1", typeFromString("String")}, + {"col_2", typeFromString("Int64")}, + }); + + /*auto db_id =*/MockTiDB::instance().newDataBase(db_name); + auto logical_table_id = MockTiDB::instance().newTable(db_name, tbl_name, cols, pd_client->getTS(), "", "dt"); + + refreshSchema(); + { + auto storage = mustGetSyncedTable(logical_table_id); + ASSERT_EQ(storage->getTombstone(), 0); + } + + // drop the table during sync all schema + LOG_INFO(Logger::get(), "mock tiflash sync all schema"); + MockTiDB::instance().dropTable(global_ctx, db_name, tbl_name, /*drop_regions*/ true); + FailPointHelper::enableFailPoint(FailPoints::force_schema_sync_too_old_schema); + SCOPE_EXIT({ + FailPointHelper::disableFailPoint(FailPoints::force_schema_sync_too_old_schema); + }); + refreshSchema(); + UInt64 tombstone_ts_by_sync_all = 0; + { + // the table should mark as tombstone != 0 + auto storage = mustGetSyncedTable(logical_table_id); + tombstone_ts_by_sync_all = storage->getTombstone(); + ASSERT_NE(tombstone_ts_by_sync_all, 0); + } + + // trigger sync all schema again, the tombstone_ts should not change + MockTiDB::instance().newDataBase(db_name + "_copy"); + refreshSchema(); + { + // the table should mark as tombstone != 0 + auto storage = mustGetSyncedTable(logical_table_id); + ASSERT_NE(storage->getTombstone(), 0); + // the tombstone_ts should not changed + ASSERT_EQ(storage->getTombstone(), tombstone_ts_by_sync_all); + } +} +CATCH + } // namespace tests } // namespace DB