diff options
| author | Oleg Doronin <[email protected]> | 2026-07-08 21:52:54 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-07-08 18:52:54 +0000 |
| commit | 673263db5e42fefbd3856dcf321b8814121436ae (patch) | |
| tree | e1eb563902612b5902f99e1d50bca3a4643f8fc7 | |
| parent | b95f311913182f013d6f95cfb0a8526cabf49ceb (diff) | |
backup cancel on propose for cs (#45851)
Co-authored-by: Ilnaz Nizametdinov <[email protected]>
| -rw-r--r-- | ydb/core/tx/schemeshard/schemeshard__operation_backup_restore_common.h | 33 | ||||
| -rw-r--r-- | ydb/core/tx/schemeshard/schemeshard_impl.cpp | 52 | ||||
| -rw-r--r-- | ydb/core/tx/schemeshard/schemeshard_impl.h | 1 | ||||
| -rw-r--r-- | ydb/core/tx/schemeshard/ut_export/ut_export.cpp | 297 | ||||
| -rw-r--r-- | ydb/core/tx/schemeshard/ut_export/ya.make | 3 | ||||
| -rw-r--r-- | ydb/services/ydb/backup_ut/backup_path_ut.cpp | 4 |
6 files changed, 361 insertions, 29 deletions
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_backup_restore_common.h b/ydb/core/tx/schemeshard/schemeshard__operation_backup_restore_common.h index 045b6e218c9..b2851baa8f7 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_backup_restore_common.h +++ b/ydb/core/tx/schemeshard/schemeshard__operation_backup_restore_common.h @@ -73,6 +73,16 @@ public: Y_ABORT_UNLESS(txState->TxType == TxType); Y_ABORT_UNLESS(txState->State == TTxState::ConfigureParts); + // For column tables, backup propose is async (export actor must finish + // before columnshard replies). Handle cancel here to avoid waiting for + // that reply which may never come while export is blocked. + const TPath path = TPath::Init(txState->TargetPathId, context.SS); + if (txState->Cancel && path->IsColumnTable()) { + NIceDb::TNiceDb db(context.GetDB()); + context.SS->ChangeTxState(db, OperationId, TTxState::Aborting); + return true; + } + txState->ClearShardsInProgress(); if constexpr (TKind::NeedSnapshotTime()) { TKind::ProposeTx(OperationId, *txState, context, GetSnapshotTime(context.SS, txState->TargetPathId)); @@ -106,6 +116,7 @@ public: IgnoreMessages(DebugHint(), { TEvHive::TEvCreateTabletReply::EventType , TEvDataShard::TEvProposeTransactionResult::EventType + , TEvColumnShard::TEvProposeTransactionResult::EventType , TEvPrivate::TEvOperationPlan::EventType } ); } @@ -389,6 +400,7 @@ public: this->IgnoreMessages(DebugHint(), { TEvHive::TEvCreateTabletReply::EventType , TEvDataShard::TEvProposeTransactionResult::EventType + , TEvColumnShard::TEvProposeTransactionResult::EventType , TEvPrivate::TEvOperationPlan::EventType } ); } @@ -463,7 +475,10 @@ public: : TxType(type) , OperationId(id) { - IgnoreMessages(DebugHint(), {TEvDataShard::TEvProposeTransactionResult::EventType}); + IgnoreMessages(DebugHint(), + { TEvDataShard::TEvProposeTransactionResult::EventType + , TEvColumnShard::TEvProposeTransactionResult::EventType } + ); } bool HandleReply(TEvDataShard::TEvSchemaChanged::TPtr& ev, TOperationContext& context) override { @@ -547,8 +562,22 @@ class TBackupRestoreOperationBase: public TSubOperation { case TTxState::Waiting: case TTxState::CreateParts: return TTxState::ConfigureParts; - case TTxState::ConfigureParts: + case TTxState::ConfigureParts: { + const TTxState* txState = context.SS->FindTx(OperationId); + Y_ABORT_UNLESS(txState); + Y_ABORT_UNLESS(txState->TxType == TxType); + + const TPath path = TPath::Init(txState->TargetPathId, context.SS); + if (txState->Cancel && path->IsColumnTable()) { + if (txState->State == TTxState::Propose) { + return TTxState::Propose; + } + + Y_ABORT_UNLESS(txState->State == TTxState::Aborting); + return TTxState::Aborting; + } return TTxState::Propose; + } case TTxState::Propose: return TTxState::ProposedWaitParts; case TTxState::ProposedWaitParts: { diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp index 53b4205a734..9efe1205e31 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp @@ -4660,6 +4660,16 @@ void TSchemeShard::PersistColumnTableRemove(NIceDb::TNiceDb& db, TPathId pathId, UpdateDiskSpaceUsage(db, pathId, TPartitionStats(), tableInfo.GetStats().Aggregated, ctx); } + ClearBackupRestoreHistory(db, pathId, tableInfo.BackupHistory); + ClearBackupRestoreHistory(db, pathId, tableInfo.RestoreHistory); + + if (IsLocalId(pathId)) { + db.Table<Schema::BackupSettings>().Key(pathId.LocalPathId).Delete(); + } + db.Table<Schema::MigratedBackupSettings>().Key(pathId.OwnerId, pathId.LocalPathId).Delete(); + + db.Table<Schema::RestoreTasks>().Key(pathId.OwnerId, pathId.LocalPathId).Delete(); + db.Table<Schema::ColumnTables>().Key(pathId.LocalPathId).Delete(); ColumnTables.Drop(pathId); DecrementPathDbRefCount(pathId); @@ -4901,6 +4911,23 @@ void TSchemeShard::PersistRevertedMigration(NIceDb::TNiceDb& db, TPathId pathId, db.Table<Schema::RevertedMigrations>().Key(pathId.LocalPathId, abandonedSchemeShardId).Update(); } +void TSchemeShard::ClearBackupRestoreHistory(NIceDb::TNiceDb& db, TPathId pathId, const TMap<TTxId, TTableInfo::TBackupRestoreResult>& history) { + for (const auto& [txId, result] : history) { + for (const auto& [shard, _] : result.ShardStatuses) { + if (IsLocalId(shard)) { + db.Table<Schema::ShardBackupStatus>().Key(txId, shard.GetLocalId()).Delete(); + } + db.Table<Schema::MigratedShardBackupStatus>().Key(txId, shard.GetOwnerId(), shard.GetLocalId()).Delete(); + db.Table<Schema::TxShardStatus>().Key(txId, shard.GetOwnerId(), shard.GetLocalId()).Delete(); + } + + if (IsLocalId(pathId)) { + db.Table<Schema::CompletedBackups>().Key(pathId.LocalPathId, txId, result.CompletionDateTime).Delete(); + } + db.Table<Schema::MigratedCompletedBackups>().Key(pathId.OwnerId, pathId.LocalPathId, txId, result.CompletionDateTime).Delete(); + } +} + void TSchemeShard::PersistRemoveTable(NIceDb::TNiceDb& db, TPathId pathId, const TActorContext& ctx) { Y_ABORT_UNLESS(PathsById.contains(pathId)); @@ -4911,29 +4938,8 @@ void TSchemeShard::PersistRemoveTable(NIceDb::TNiceDb& db, TPathId pathId, const } const TTableInfo::TPtr tableInfo = Tables.at(pathId); - auto clearHistory = [&](const TMap<TTxId, TTableInfo::TBackupRestoreResult>& history) { - for (auto& bItem: history) { - TTxId txId = bItem.first; - const auto& result = bItem.second; - - for (auto& sItem: result.ShardStatuses) { - auto shard = sItem.first; - if (IsLocalId(shard)) { - db.Table<Schema::ShardBackupStatus>().Key(txId, shard.GetLocalId()).Delete(); - } - db.Table<Schema::MigratedShardBackupStatus>().Key(txId, shard.GetOwnerId(), shard.GetLocalId()).Delete(); - db.Table<Schema::TxShardStatus>().Key(txId, shard.GetOwnerId(), shard.GetLocalId()).Delete(); - } - - if (IsLocalId(pathId)) { - db.Table<Schema::CompletedBackups>().Key(pathId.LocalPathId, txId, result.CompletionDateTime).Delete(); - } - db.Table<Schema::MigratedCompletedBackups>().Key(pathId.OwnerId, pathId.LocalPathId, txId, result.CompletionDateTime).Delete(); - } - }; - - clearHistory(tableInfo->BackupHistory); - clearHistory(tableInfo->RestoreHistory); + ClearBackupRestoreHistory(db, pathId, tableInfo->BackupHistory); + ClearBackupRestoreHistory(db, pathId, tableInfo->RestoreHistory); if (IsLocalId(pathId)) { db.Table<Schema::BackupSettings>().Key(pathId.LocalPathId).Delete(); diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.h b/ydb/core/tx/schemeshard/schemeshard_impl.h index 971dec790d1..8d297ab5f63 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.h +++ b/ydb/core/tx/schemeshard/schemeshard_impl.h @@ -938,6 +938,7 @@ public: void PersistRemoveKesusInfo(NIceDb::TNiceDb& db, TPathId pathId); void PersistRemoveTableIndex(NIceDb::TNiceDb& db, TPathId tableId); void PersistRemoveTable(NIceDb::TNiceDb& db, TPathId tableId, const TActorContext& ctx); + void ClearBackupRestoreHistory(NIceDb::TNiceDb& db, TPathId pathId, const TMap<TTxId, TTableInfo::TBackupRestoreResult>& history); void PersistRevertedMigration(NIceDb::TNiceDb& db, TPathId pathId, TTabletId abandonedSchemeShardId); void UpdateDiskSpaceUsage(NIceDb::TNiceDb& db, TPathId pathId, const TPartitionStats& newPartitionStats, const TPartitionStats& oldPartitionStats, const TActorContext &ctx); diff --git a/ydb/core/tx/schemeshard/ut_export/ut_export.cpp b/ydb/core/tx/schemeshard/ut_export/ut_export.cpp index 905da16f1fc..509539eba70 100644 --- a/ydb/core/tx/schemeshard/ut_export/ut_export.cpp +++ b/ydb/core/tx/schemeshard/ut_export/ut_export.cpp @@ -3,6 +3,7 @@ #include <ydb/public/api/protos/ydb_topic.pb.h> #include <ydb/core/backup/common/encryption.h> +#include <ydb/core/base/counters.h> #include <ydb/core/base/table_index.h> #include <ydb/core/metering/metering.h> #include <ydb/core/protos/s3_settings.pb.h> @@ -10,6 +11,8 @@ #include <ydb/core/tablet_flat/shared_cache_events.h> #include <ydb/core/testlib/actors/block_events.h> #include <ydb/core/testlib/audit_helpers/audit_helper.h> +#include <ydb/core/tx/columnshard/columnshard_private_events.h> +#include <ydb/core/tx/columnshard/test_helper/columnshard_ut_common.h> #include <ydb/core/tx/datashard/datashard.h> #include <ydb/core/tx/schemeshard/schemeshard_billing_helpers.h> #include <ydb/core/tx/schemeshard/ut_helpers/helpers.h> @@ -18,6 +21,7 @@ #include <ydb/core/wrappers/s3_wrapper.h> #include <ydb/core/wrappers/ut_helpers/s3_mock.h> #include <ydb/library/aws_init/aws.h> +#include <ydb/public/lib/value/value.h> #include <library/cpp/testing/hook/hook.h> @@ -1164,6 +1168,188 @@ namespace { Env().TestWaitNotification(Runtime(), exportTxId); } + struct TColumnTableInfo { + ui64 PathId = 0; + ui64 ShardId = 0; + }; + + struct TColumnTableSlowS3ExportContext { + ui64 TxId = 0; + ui64 ExportId = 0; + ui64 ShardId = 0; + ui64 PathId = 0; + THolder<NActors::TBlockEvents<NKikimr::NColumnShard::TEvPrivate::TEvBackupExportRecordBatch>> BlockExportBatch; + std::function<ui64()> GetAliveCounter; + }; + + void InitColumnTableExportSlowS3Test(bool enableScanWriteLog = true) { + Env(); + Runtime().GetAppData().FeatureFlags.SetEnableColumnTablesBackup(true); + Runtime().SetLogPriority(NKikimrServices::TX_COLUMNSHARD, NActors::NLog::PRI_DEBUG); + if (enableScanWriteLog) { + Runtime().SetLogPriority(NKikimrServices::TX_COLUMNSHARD_SCAN, NActors::NLog::PRI_DEBUG); + Runtime().SetLogPriority(NKikimrServices::TX_COLUMNSHARD_WRITE, NActors::NLog::PRI_DEBUG); + } + } + + std::function<ui64()> MakeColumnTableExportAliveCounter() { + return [this]() { + auto subgroup = GetServiceCounters(Runtime().GetDynamicCounters(0), "tablets") + ->GetSubgroup("subsystem", "columnshard") + ->GetSubgroup("module_id", "ExportActor"); + return subgroup->GetCounter("Value/Export/Actors/Alive", false)->Val(); + }; + } + + TColumnTableInfo CreateColumnTableWithData(ui64& txId, const TString& tableName) { + TestCreateColumnTable(Runtime(), ++txId, "/MyRoot", Sprintf(R"( + Name: "%s" + ColumnShardCount: 1 + Schema { + Columns { Name: "timestamp" Type: "Timestamp" NotNull: true } + Columns { Name: "value" Type: "Utf8" } + KeyColumnNames: "timestamp" + } + )", tableName.c_str())); + Env().TestWaitNotification(Runtime(), txId); + + TColumnTableInfo info; + { + auto describe = DescribePath(Runtime(), Sprintf("/MyRoot/%s", tableName.c_str())); + TestDescribeResult(describe, {NLs::PathExist}); + info.PathId = describe.GetPathId(); + const auto& sharding = describe.GetPathDescription().GetColumnTableDescription().GetSharding(); + UNIT_ASSERT_VALUES_EQUAL(sharding.ColumnShardsSize(), 1); + info.ShardId = sharding.GetColumnShards()[0]; + } + UNIT_ASSERT(info.ShardId); + UNIT_ASSERT(info.PathId); + + { + TActorId sender = Runtime().AllocateEdgeActor(); + const std::vector<NArrow::NTest::TTestColumn> ydbSchema = { + NArrow::NTest::TTestColumn("timestamp", NScheme::TTypeInfo(NScheme::NTypeIds::Timestamp)).SetNullable(false), + NArrow::NTest::TTestColumn("value", NScheme::TTypeInfo(NScheme::NTypeIds::Utf8)), + }; + const auto data = NTxUT::MakeTestBlob({0, 100}, ydbSchema, {}, {"timestamp"}); + ui64 writeId = 0; + std::vector<ui64> writeIds; + ++txId; + NTxUT::WriteData(Runtime(), sender, info.ShardId, ++writeId, info.PathId, data, ydbSchema, &writeIds, NEvWrite::EModificationType::Upsert, txId); + auto planStep = NTxUT::ProposeCommit(Runtime(), sender, info.ShardId, txId, writeIds, txId); + NTxUT::PlanCommit(Runtime(), sender, info.ShardId, planStep, {txId}); + } + + return info; + } + + ui64 StartColumnTableS3Export(ui64& txId, const TString& tableName, const TString& destinationPrefix) { + const ui64 exportTxId = ++txId; + TestExport(Runtime(), exportTxId, "/MyRoot", Sprintf(R"( + ExportToS3Settings { + endpoint: "localhost:%d" + scheme: HTTP + items { + source_path: "/MyRoot/%s" + destination_prefix: "%s" + } + } + )", S3Port(), tableName.c_str(), destinationPrefix.c_str())); + return exportTxId; + } + + TColumnTableSlowS3ExportContext SetupColumnTableSlowS3Export( + ui64 startTxId = 100, + const TString& tableName = "ColumnTable", + const TString& destinationPrefix = "", + bool enableScanWriteLog = true) + { + InitColumnTableExportSlowS3Test(enableScanWriteLog); + + TColumnTableSlowS3ExportContext ctx; + ctx.TxId = startTxId; + + const auto tableInfo = CreateColumnTableWithData(ctx.TxId, tableName); + ctx.PathId = tableInfo.PathId; + ctx.ShardId = tableInfo.ShardId; + + ctx.BlockExportBatch = MakeHolder<NActors::TBlockEvents<NKikimr::NColumnShard::TEvPrivate::TEvBackupExportRecordBatch>>(Runtime()); + ctx.ExportId = StartColumnTableS3Export(ctx.TxId, tableName, destinationPrefix); + + ctx.GetAliveCounter = MakeColumnTableExportAliveCounter(); + Runtime().WaitFor("export actor alive", [&]{ return ctx.GetAliveCounter() != 0; }, TDuration::Seconds(60)); + + return ctx; + } + + void VerifyExportCancelledAndForget(ui64& txId, ui64 exportId) { + Env().TestWaitNotification(Runtime(), exportId); + + auto desc = TestGetExport(Runtime(), exportId, "/MyRoot", Ydb::StatusIds::CANCELLED); + auto entry = desc.GetResponse().GetEntry(); + UNIT_ASSERT_VALUES_EQUAL(entry.GetProgress(), Ydb::Export::ExportProgress::PROGRESS_CANCELLED); + + TestForgetExport(Runtime(), ++txId, "/MyRoot", exportId); + Env().TestWaitNotification(Runtime(), exportId); + + TestGetExport(Runtime(), exportId, "/MyRoot", Ydb::StatusIds::NOT_FOUND); + } + + void FinalizeColumnTableSlowS3Export(TColumnTableSlowS3ExportContext& ctx) { + Runtime().WaitFor("export actors stopped", [&]{ return ctx.GetAliveCounter() == 0; }, TDuration::Seconds(60)); + ctx.BlockExportBatch->Stop(); + ctx.BlockExportBatch->Unblock(); + } + + ui64 CountCompletedBackupsRows() { + const auto result = LocalMiniKQL(Runtime(), TTestTxConfig::SchemeShard, R"( + ( + (let range '( + '('PathId (Null) (Void)) + '('TxId (Null) (Void)) + '('DateTimeOfCompletion (Null) (Void)) + )) + (let fields '('PathId)) + (return (AsList + (SetResult 'Result (SelectRange 'CompletedBackups range fields '())) + )) + ) + )"); + return NKikimr::NClient::TValue::Create(result)[0]["List"].Size(); + } + + void CancelColumnTableExportWithReboot(bool rebootCS, bool rebootSS, bool rebootBeforeCancel) { + auto ctx = SetupColumnTableSlowS3Export(); + ui64 txId = ctx.TxId; + const ui64 exportId = ctx.ExportId; + const ui64 shardId = ctx.ShardId; + + if (rebootBeforeCancel) { + if (rebootCS) { + RebootTablet(Runtime(), shardId, Runtime().AllocateEdgeActor()); + } + if (rebootSS) { + RebootTablet(Runtime(), TTestTxConfig::SchemeShard, Runtime().AllocateEdgeActor()); + } + } + + TestCancelExport(Runtime(), ++txId, "/MyRoot", exportId); + + if (!rebootBeforeCancel) { + if (rebootCS) { + RebootTablet(Runtime(), shardId, Runtime().AllocateEdgeActor()); + } + if (rebootSS) { + RebootTablet(Runtime(), TTestTxConfig::SchemeShard, Runtime().AllocateEdgeActor()); + } + } + + TestCancelExport(Runtime(), ++txId, "/MyRoot", exportId); + + VerifyExportCancelledAndForget(txId, exportId); + FinalizeColumnTableSlowS3Export(ctx); + } + private: TPortManager PortManager; ui16 S3ServerPort = 0; @@ -4790,4 +4976,115 @@ CREATE EXTERNAL TABLE IF NOT EXISTS `ExternalTable` ( const TString decrypted(decryptedData.Data(), decryptedData.Size()); UNIT_ASSERT_VALUES_EQUAL_C(decrypted, expected, "Encrypted buffer corruption detected"); } + + Y_UNIT_TEST(CancelColumnTableExportDuringSlowS3ViaSSPipeline) { + auto ctx = SetupColumnTableSlowS3Export(); + ui64 txId = ctx.TxId; + + TestCancelExport(Runtime(), ++txId, "/MyRoot", ctx.ExportId); + + VerifyExportCancelledAndForget(txId, ctx.ExportId); + FinalizeColumnTableSlowS3Export(ctx); + } + + Y_UNIT_TEST(MultipleCancelsColumnTableExportDuringSlowS3ViaSSPipeline) { + auto ctx = SetupColumnTableSlowS3Export(); + ui64 txId = ctx.TxId; + + TestCancelExport(Runtime(), ++txId, "/MyRoot", ctx.ExportId); + TestCancelExport(Runtime(), ++txId, "/MyRoot", ctx.ExportId); + TestCancelExport(Runtime(), ++txId, "/MyRoot", ctx.ExportId); + + VerifyExportCancelledAndForget(txId, ctx.ExportId); + FinalizeColumnTableSlowS3Export(ctx); + } + + Y_UNIT_TEST(CancelColumnTableExportRebootCSThenCancelAgain) { + CancelColumnTableExportWithReboot(/*rebootCS=*/true, /*rebootSS=*/false, /*rebootBeforeCancel=*/false); + } + + Y_UNIT_TEST(CancelColumnTableExportRebootSSThenCancelAgain) { + CancelColumnTableExportWithReboot(/*rebootCS=*/false, /*rebootSS=*/true, /*rebootBeforeCancel=*/false); + } + + Y_UNIT_TEST(CancelColumnTableExportRebootBothThenCancelAgain) { + CancelColumnTableExportWithReboot(/*rebootCS=*/true, /*rebootSS=*/true, /*rebootBeforeCancel=*/false); + } + + Y_UNIT_TEST(RebootCSThenCancelColumnTableExportTwice) { + CancelColumnTableExportWithReboot(/*rebootCS=*/true, /*rebootSS=*/false, /*rebootBeforeCancel=*/true); + } + + Y_UNIT_TEST(RebootSSThenCancelColumnTableExportTwice) { + CancelColumnTableExportWithReboot(/*rebootCS=*/false, /*rebootSS=*/true, /*rebootBeforeCancel=*/true); + } + + Y_UNIT_TEST(RebootBothThenCancelColumnTableExportTwice) { + CancelColumnTableExportWithReboot(/*rebootCS=*/true, /*rebootSS=*/true, /*rebootBeforeCancel=*/true); + } + + Y_UNIT_TEST(CancelTwoColumnTableExportsDuringSlowS3ViaSSPipeline) { + InitColumnTableExportSlowS3Test(); + ui64 txId = 100; + + for (const auto& tableName : {"ColumnTable1", "ColumnTable2"}) { + CreateColumnTableWithData(txId, tableName); + } + + TColumnTableSlowS3ExportContext ctx; + ctx.BlockExportBatch = MakeHolder<NActors::TBlockEvents<NKikimr::NColumnShard::TEvPrivate::TEvBackupExportRecordBatch>>(Runtime()); + ctx.GetAliveCounter = MakeColumnTableExportAliveCounter(); + + const ui64 exportTxId1 = StartColumnTableS3Export(txId, "ColumnTable1", "table1"); + const ui64 exportTxId2 = StartColumnTableS3Export(txId, "ColumnTable2", "table2"); + + Runtime().WaitFor("export actors alive", [&]{ return ctx.GetAliveCounter() >= 2; }, TDuration::Seconds(60)); + + TestCancelExport(Runtime(), ++txId, "/MyRoot", exportTxId1); + TestCancelExport(Runtime(), ++txId, "/MyRoot", exportTxId2); + + VerifyExportCancelledAndForget(txId, exportTxId1); + VerifyExportCancelledAndForget(txId, exportTxId2); + FinalizeColumnTableSlowS3Export(ctx); + } + + Y_UNIT_TEST(CancelColumnTableExportThenForgetThenReboot) { + auto ctx = SetupColumnTableSlowS3Export(/*startTxId=*/100, "ColumnTable", "", /*enableScanWriteLog=*/false); + ui64 txId = ctx.TxId; + + TestCancelExport(Runtime(), ++txId, "/MyRoot", ctx.ExportId); + TestCancelExport(Runtime(), ++txId, "/MyRoot", ctx.ExportId); + + VerifyExportCancelledAndForget(txId, ctx.ExportId); + FinalizeColumnTableSlowS3Export(ctx); + + RebootTablet(Runtime(), TTestTxConfig::SchemeShard, Runtime().AllocateEdgeActor()); + } + + Y_UNIT_TEST(DropColumnTableAfterCompletedExportClearsBackupHistory) { + InitColumnTableExportSlowS3Test(); + Runtime().GetAppData().FeatureFlags.SetEnableExportAutoDropping(false); + + ui64 txId = 100; + CreateColumnTableWithData(txId, "ColumnTable"); + + const ui64 exportId = StartColumnTableS3Export(txId, "ColumnTable", "dest"); + Env().TestWaitNotification(Runtime(), exportId); + TestGetExport(Runtime(), exportId, "/MyRoot", Ydb::StatusIds::SUCCESS); + + const TString exportCopyPath = Sprintf("/MyRoot/export-%" PRIu64 "/0", exportId); + TestDescribeResult(DescribePath(Runtime(), exportCopyPath), {NLs::PathExist}); + UNIT_ASSERT_VALUES_UNEQUAL(CountCompletedBackupsRows(), 0u); + + TestDropColumnTable(Runtime(), ++txId, Sprintf("/MyRoot/export-%" PRIu64, exportId), "0"); + Env().TestWaitNotification(Runtime(), txId); + + UNIT_ASSERT_VALUES_EQUAL(CountCompletedBackupsRows(), 0u); + TestDescribeResult(DescribePath(Runtime(), exportCopyPath), {NLs::PathNotExist}); + + RebootTablet(Runtime(), TTestTxConfig::SchemeShard, Runtime().AllocateEdgeActor()); + + TestDescribeResult(DescribePath(Runtime(), "/MyRoot/ColumnTable"), {NLs::PathExist}); + UNIT_ASSERT_VALUES_EQUAL(CountCompletedBackupsRows(), 0u); + } } diff --git a/ydb/core/tx/schemeshard/ut_export/ya.make b/ydb/core/tx/schemeshard/ut_export/ya.make index 0d5ed984ac2..b5ea6b42b29 100644 --- a/ydb/core/tx/schemeshard/ut_export/ya.make +++ b/ydb/core/tx/schemeshard/ut_export/ya.make @@ -20,6 +20,9 @@ IF (NOT OS_WINDOWS) library/cpp/svnversion ydb/core/testlib/default ydb/core/tx + ydb/core/tx/columnshard + ydb/core/tx/columnshard/hooks/testing + ydb/core/tx/columnshard/test_helper ydb/core/tx/schemeshard/ut_helpers ydb/core/util ydb/core/wrappers/ut_helpers diff --git a/ydb/services/ydb/backup_ut/backup_path_ut.cpp b/ydb/services/ydb/backup_ut/backup_path_ut.cpp index c137ec424ef..0297a6ff37a 100644 --- a/ydb/services/ydb/backup_ut/backup_path_ut.cpp +++ b/ydb/services/ydb/backup_ut/backup_path_ut.cpp @@ -1661,10 +1661,6 @@ void CancelWhileProcessingImpl(TBackupTestFixture& f, bool isOlap) { f.Server().GetRuntime()->GetAppData().FeatureFlags.SetEnableFsBackups(true); - if (isOlap) { - return; - } - auto createSchemaResult = f.YdbQueryClient().ExecuteQuery(fmt::format(R"sql( CREATE TABLE `/Root/Table0` ( key Uint32 NOT NULL, |
