summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaliy Filippov <[email protected]>2026-07-07 20:35:06 +0300
committerGitHub <[email protected]>2026-07-07 20:35:06 +0300
commit4857ba293db2b6c093addbe3eaffff63fcef813d (patch)
tree046d7af60ea38ffdac6491195f25a2361c765a27
parentc74bc5e3de9658c03c31dadcb2e6b2c73fb66a00 (diff)
Skip unfinished indexes during consistent table copy (and thus export/backup) (#45746)
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_consistent_copy_tables.cpp10
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp5
-rw-r--r--ydb/core/tx/schemeshard/ut_consistent_copy_tables/ut_consistent_copy_tables.cpp56
3 files changed, 69 insertions, 2 deletions
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_consistent_copy_tables.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_consistent_copy_tables.cpp
index 78f359d1abc..993d05f2bf2 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_consistent_copy_tables.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_consistent_copy_tables.cpp
@@ -309,11 +309,17 @@ bool CreateConsistentCopyTables(
continue;
}
+ Y_ABORT_UNLESS(srcIndexPath.Base()->PathId == pathId);
+ TTableIndexInfo::TPtr indexInfo = context.SS->Indexes.at(pathId);
+ if (indexInfo->State != NKikimrSchemeOp::EIndexState::EIndexStateReady) {
+ LOG_TRACE_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD,
+ "CreateConsistentCopyTables: Skipping a non-ready index " << name << " in state " << indexInfo->State);
+ continue;
+ }
+
LOG_TRACE_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD,
"CreateConsistentCopyTables: Creating index copy operation for: " << name);
- Y_ABORT_UNLESS(srcIndexPath.Base()->PathId == pathId);
- TTableIndexInfo::TPtr indexInfo = context.SS->Indexes.at(pathId);
auto scheme = CreateIndexTask(indexInfo, dstIndexPath);
if (!scheme) {
result = {CreateReject(nextId, NKikimrScheme::EStatus::StatusInvalidParameter,
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp
index f3186bf3e6f..2cdc2bc3a8f 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp
@@ -1047,6 +1047,11 @@ TVector<ISubOperation::TPtr> CreateCopyTable(TOperationId nextId, const TTxTrans
Y_ABORT_UNLESS(childPath.Base()->PathId == pathId);
TTableIndexInfo::TPtr indexInfo = context.SS->Indexes.at(pathId);
+
+ if (indexInfo->State != NKikimrSchemeOp::EIndexState::EIndexStateReady) {
+ continue;
+ }
+
{
auto schema = TransactionTemplate(dstPath.PathString(), NKikimrSchemeOp::EOperationType::ESchemeOpCreateTableIndex);
schema.SetFailOnExist(tx.GetFailOnExist());
diff --git a/ydb/core/tx/schemeshard/ut_consistent_copy_tables/ut_consistent_copy_tables.cpp b/ydb/core/tx/schemeshard/ut_consistent_copy_tables/ut_consistent_copy_tables.cpp
index 98de0df26a8..0c8b1efcaa2 100644
--- a/ydb/core/tx/schemeshard/ut_consistent_copy_tables/ut_consistent_copy_tables.cpp
+++ b/ydb/core/tx/schemeshard/ut_consistent_copy_tables/ut_consistent_copy_tables.cpp
@@ -1,4 +1,7 @@
+#include <ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h>
+
#include <ydb/core/base/table_index.h>
+#include <ydb/core/testlib/actors/block_events.h>
#include <ydb/core/tx/schemeshard/ut_helpers/helpers.h>
#include <ydb/core/tx/schemeshard/ut_helpers/local_indexes.h>
#include <ydb/core/protos/schemeshard/operations.pb.h>
@@ -698,4 +701,57 @@ Y_UNIT_TEST_SUITE(TSchemeShardConsistentCopyTablesTest) {
}
});
}
+
+ Y_UNIT_TEST(SkipUnfinishedIndex) {
+ TTestBasicRuntime runtime;
+ TTestEnv env(runtime);
+ ui64 txId = 100;
+
+ SetupLogging(runtime);
+
+ // Create table
+ TestCreateIndexedTable(runtime, ++txId, "/MyRoot", R"(
+ TableDescription {
+ Name: "Table1"
+ Columns { Name: "key" Type: "Uint32" }
+ Columns { Name: "value" Type: "Utf8" }
+ KeyColumnNames: ["key"]
+ }
+ )");
+ env.TestWaitNotification(runtime, txId);
+
+ TBlockEvents<TEvSchemeShard::TEvModifySchemeTransaction> indexBlocker(runtime, [&](const auto& ev) {
+ const auto& rec = ev->Get()->Record;
+ return rec.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpApplyIndexBuild;
+ });
+
+ const ui64 buildIndexTx = ++txId;
+ AsyncBuildIndex(runtime, buildIndexTx, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/Table1",
+ TBuildIndexConfig{"index1", NKikimrSchemeOp::EIndexTypeGlobal, {"value"}, {}, {}});
+ runtime.WaitFor("Index finalize request", [&]{ return indexBlocker.size(); });
+
+ // Perform consistent copy with indexes - it should skip the unfinished index
+ const ui64 copyTx = ++txId;
+ AsyncConsistentCopyTables(runtime, copyTx, "/MyRoot", R"(
+ CopyTableDescriptions {
+ SrcPath: "/MyRoot/Table1"
+ DstPath: "/MyRoot/TableBackup"
+ IsBackup: true
+ }
+ )");
+ env.TestWaitNotification(runtime, copyTx);
+
+ // Let index build finish (it shouldn't fail!)
+ indexBlocker.Stop().Unblock();
+ env.TestWaitNotification(runtime, buildIndexTx);
+
+ auto descr = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexTx);
+ UNIT_ASSERT_VALUES_EQUAL(descr.GetIndexBuild().GetState(), Ydb::Table::IndexBuildState::STATE_DONE);
+
+ // Check that the unfinished index is not copied
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/TableBackup/index1"), {NLs::PathNotExist});
+
+ // Check that the table is not left locked by dropping it
+ TestDropTable(runtime, ++txId, "/MyRoot", "Table1");
+ }
}