diff --git a/ydb/core/tx/schemeshard/schemeshard_build_index.cpp b/ydb/core/tx/schemeshard/schemeshard_build_index.cpp index e3687e5bc811..b2b8fa09037c 100644 --- a/ydb/core/tx/schemeshard/schemeshard_build_index.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_build_index.cpp @@ -46,7 +46,8 @@ void TSchemeShard::Handle(TEvPrivate::TEvIndexBuildingMakeABill::TPtr& ev, const void TSchemeShard::PersistCreateBuildIndex(NIceDb::TNiceDb& db, const TIndexBuildInfo& info) { Y_ABORT_UNLESS(info.BuildKind != TIndexBuildInfo::EBuildKind::BuildKindUnspecified); - db.Table().Key(info.Id).Update( + auto persistedBuildIndex = db.Table().Key(info.Id); + persistedBuildIndex.Update( NIceDb::TUpdate(info.Uid), NIceDb::TUpdate(info.DomainPathId.OwnerId), NIceDb::TUpdate(info.DomainPathId.LocalPathId), @@ -59,9 +60,28 @@ void TSchemeShard::PersistCreateBuildIndex(NIceDb::TNiceDb& db, const TIndexBuil NIceDb::TUpdate(info.Limits.MaxShards), NIceDb::TUpdate(info.Limits.MaxRetries), NIceDb::TUpdate(ui32(info.BuildKind)) - - // TODO save info.ImplTableDescriptions ); + // Persist details of the index build operation: ImplTableDescriptions and SpecializedIndexDescription. + // We have chosen TIndexCreationConfig's string representation as the serialization format. + if (bool hasSpecializedDescription = !std::holds_alternative(info.SpecializedIndexDescription); + info.ImplTableDescriptions || hasSpecializedDescription + ) { + NKikimrSchemeOp::TIndexCreationConfig serializableRepresentation; + + for (const auto& description : info.ImplTableDescriptions) { + *serializableRepresentation.AddIndexImplTableDescriptions() = description; + } + + std::visit([&](const T& specializedDescription) { + if constexpr (std::is_same_v) { + *serializableRepresentation.MutableVectorIndexKmeansTreeDescription() = specializedDescription; + } + }, info.SpecializedIndexDescription); + + persistedBuildIndex.Update( + NIceDb::TUpdate(serializableRepresentation.SerializeAsString()) + ); + } ui32 columnNo = 0; for (ui32 i = 0; i < info.IndexColumns.size(); ++i, ++columnNo) { diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.h b/ydb/core/tx/schemeshard/schemeshard_info_types.h index 48fb99304f97..cb3d763d141e 100644 --- a/ydb/core/tx/schemeshard/schemeshard_info_types.h +++ b/ydb/core/tx/schemeshard/schemeshard_info_types.h @@ -2991,7 +2991,7 @@ struct TIndexBuildInfo: public TSimpleRefCount { // TODO(mbkkt) move to TVectorIndexKmeansTreeDescription ui32 K = 4; ui32 Levels = 5; - + // progress enum EState : ui32 { Sample = 0, @@ -3007,7 +3007,7 @@ struct TIndexBuildInfo: public TSimpleRefCount { EState State = Sample; ui32 ChildBegin = 1; // included - + static ui32 BinPow(ui32 k, ui32 l) { ui32 r = 1; while (l != 0) { @@ -3282,7 +3282,26 @@ struct TIndexBuildInfo: public TSimpleRefCount { indexInfo->IndexName = row.template GetValue(); indexInfo->IndexType = row.template GetValue(); - // TODO load indexInfo->ImplTableDescriptions + // Restore the operation details: ImplTableDescriptions and SpecializedIndexDescription. + if (row.template HaveValue()) { + NKikimrSchemeOp::TIndexCreationConfig creationConfig; + Y_ABORT_UNLESS(creationConfig.ParseFromString(row.template GetValue())); + + auto& descriptions = *creationConfig.MutableIndexImplTableDescriptions(); + indexInfo->ImplTableDescriptions.reserve(descriptions.size()); + for (auto& description : descriptions) { + indexInfo->ImplTableDescriptions.emplace_back(std::move(description)); + } + + switch (creationConfig.GetSpecializedIndexDescriptionCase()) { + case NKikimrSchemeOp::TIndexCreationConfig::kVectorIndexKmeansTreeDescription: + indexInfo->SpecializedIndexDescription = std::move(*creationConfig.MutableVectorIndexKmeansTreeDescription()); + break; + case NKikimrSchemeOp::TIndexCreationConfig::SPECIALIZEDINDEXDESCRIPTION_NOT_SET: + /* do nothing */ + break; + } + } indexInfo->State = TIndexBuildInfo::EState( row.template GetValue()); diff --git a/ydb/core/tx/schemeshard/schemeshard_schema.h b/ydb/core/tx/schemeshard/schemeshard_schema.h index d9df1b67edc1..db5df8b9de83 100644 --- a/ydb/core/tx/schemeshard/schemeshard_schema.h +++ b/ydb/core/tx/schemeshard/schemeshard_schema.h @@ -1325,6 +1325,9 @@ struct Schema : NIceDb::Schema { struct AlterMainTableTxStatus : Column<32, NScheme::NTypeIds::Uint32> { using Type = NKikimrScheme::EStatus; }; struct AlterMainTableTxDone : Column<33, NScheme::NTypeIds::Bool> {}; + // Serialized as string NKikimrSchemeOp::TIndexCreationConfig protobuf. + struct CreationConfig : Column<34, NScheme::NTypeIds::String> { using Type = TString; }; + using TKey = TableKey; using TColumns = TableColumns< Id, @@ -1359,7 +1362,8 @@ struct Schema : NIceDb::Schema { BuildKind, AlterMainTableTxId, AlterMainTableTxStatus, - AlterMainTableTxDone + AlterMainTableTxDone, + CreationConfig >; }; diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp index 520f0508337a..be722fb1d994 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp +++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp @@ -1699,11 +1699,23 @@ namespace NSchemeShardUT_Private { } break; case NKikimrSchemeOp::EIndexTypeGlobalVectorKmeansTree: { auto& settings = *index.mutable_global_vector_kmeans_tree_index(); - settings = Ydb::Table::GlobalVectorKMeansTreeIndex(); - // some random valid settings - settings.mutable_vector_settings()->mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT); - settings.mutable_vector_settings()->mutable_settings()->set_vector_dimension(42); - settings.mutable_vector_settings()->mutable_settings()->set_metric(Ydb::Table::VectorIndexSettings::DISTANCE_COSINE); + + auto& vectorIndexSettings = *settings.mutable_vector_settings()->mutable_settings(); + if (cfg.VectorIndexSettings) { + cfg.VectorIndexSettings->SerializeTo(vectorIndexSettings); + } else { + // some random valid settings + vectorIndexSettings.set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT); + vectorIndexSettings.set_vector_dimension(42); + vectorIndexSettings.set_metric(Ydb::Table::VectorIndexSettings::DISTANCE_COSINE); + } + + if (cfg.GlobalIndexSettings) { + cfg.GlobalIndexSettings[0].SerializeTo(*settings.mutable_level_table_settings()); + if (cfg.GlobalIndexSettings.size() > 1) { + cfg.GlobalIndexSettings[1].SerializeTo(*settings.mutable_posting_table_settings()); + } + } } break; default: UNIT_ASSERT_C(false, "Unknown index type: " << static_cast(cfg.IndexType)); diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.h b/ydb/core/tx/schemeshard/ut_helpers/helpers.h index 93a7ad7617fb..cff85d0125d1 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/helpers.h +++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.h @@ -64,6 +64,7 @@ namespace NYdb::NTable { struct TGlobalIndexSettings; + struct TVectorIndexSettings; } namespace NSchemeShardUT_Private { @@ -371,6 +372,8 @@ namespace NSchemeShardUT_Private { TVector IndexColumns; TVector DataColumns; TVector GlobalIndexSettings = {}; + // implementation note: it was made a pointer, not optional, to enable forward declaration + std::unique_ptr VectorIndexSettings = {}; }; std::unique_ptr CreateBuildColumnRequest(ui64 id, const TString& dbName, const TString& src, const TString& columnName, const Ydb::TypedValue& literal); diff --git a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp index d41d5fa2b5e1..2f440b74c04a 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp +++ b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp @@ -853,7 +853,7 @@ TCheckFunc IndexDataColumns(const TVector& dataColumnNames) { }; } -TCheckFunc VectorIndexDescription(Ydb::Table::VectorIndexSettings_Metric metric, +TCheckFunc VectorIndexDescription(Ydb::Table::VectorIndexSettings_Metric metric, Ydb::Table::VectorIndexSettings_VectorType vectorType, ui32 vectorDimension ) { @@ -1309,11 +1309,63 @@ TCheckFunc PartitionKeys(TVector lastShardKeys) { const auto& pathDescr = record.GetPathDescription(); UNIT_ASSERT_VALUES_EQUAL(lastShardKeys.size(), pathDescr.TablePartitionsSize()); for (size_t i = 0; i < lastShardKeys.size(); ++i) { - UNIT_ASSERT_STRING_CONTAINS(pathDescr.GetTablePartitions(i).GetEndOfRangeKeyPrefix(), lastShardKeys[i]); + const auto& partition = pathDescr.GetTablePartitions(i); + UNIT_ASSERT_STRING_CONTAINS_C( + partition.GetEndOfRangeKeyPrefix(), lastShardKeys[i], + "partition index: " << i << '\n' + << "actual key prefix: " << partition.GetEndOfRangeKeyPrefix().Quote() << '\n' + << "expected key prefix: " << lastShardKeys[i].Quote() << '\n' + ); } }; } +namespace { + +// Serializes / deserializes a value of type T to a cell vector string representation. +template +struct TSplitBoundarySerializer { + static TString Serialize(T splitBoundary) { + const auto cell = TCell::Make(splitBoundary); + TSerializedCellVec cellVec(TArrayRef(&cell, 1)); + return cellVec.ReleaseBuffer(); + } + + static TVector Deserialize(const TString& serializedCells) { + TSerializedCellVec cells(serializedCells); + TVector values; + for (const auto& cell : cells.GetCells()) { + if (cell.IsNull()) { + // the last cell + break; + } + values.emplace_back(cell.AsValue()); + } + return values; + } +}; + +} + +template +TCheckFunc SplitBoundaries(TVector&& expectedBoundaries) { + return [expectedBoundaries = std::move(expectedBoundaries)] (const NKikimrScheme::TEvDescribeSchemeResult& record) { + const auto& pathDescr = record.GetPathDescription(); + UNIT_ASSERT_VALUES_EQUAL(pathDescr.TablePartitionsSize(), expectedBoundaries.size() + 1); + for (size_t i = 0; i < expectedBoundaries.size(); ++i) { + const auto& partition = pathDescr.GetTablePartitions(i); + const auto actualBoundary = TSplitBoundarySerializer::Deserialize(partition.GetEndOfRangeKeyPrefix()).at(0); + UNIT_ASSERT_VALUES_EQUAL_C( + actualBoundary, expectedBoundaries[i], + "partition index: " << i << '\n' + << "actual key prefix: " << partition.GetEndOfRangeKeyPrefix().Quote() << '\n' + ); + } + }; +} + +template TCheckFunc SplitBoundaries(TVector&&); + TCheckFunc ServerlessComputeResourcesMode(NKikimrSubDomains::EServerlessComputeResourcesMode serverlessComputeResourcesMode) { return [=] (const NKikimrScheme::TEvDescribeSchemeResult& record) { UNIT_ASSERT_C(IsGoodDomainStatus(record.GetStatus()), "Unexpected status: " << record.GetStatus()); diff --git a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h index 4c6ade01140c..59fd61bf4233 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h +++ b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h @@ -102,6 +102,10 @@ namespace NLs { void CheckBoundaries(const NKikimrScheme::TEvDescribeSchemeResult& record); TCheckFunc PartitionCount(ui32 count); TCheckFunc PartitionKeys(TVector lastShardKeys); + // Checks if the serialized representation of an expected boundary is a prefix of the actual one. + // Similar to PartitionKeys check, but does not require you to pass split boundaries in a serialized form. + template + TCheckFunc SplitBoundaries(TVector&& expectedBoundaries); TCheckFunc FollowerCount(ui32 count); TCheckFunc CrossDataCenterFollowerCount(ui32 count); TCheckFunc AllowFollowerPromotion(bool val); @@ -141,7 +145,7 @@ namespace NLs { TCheckFunc IndexState(NKikimrSchemeOp::EIndexState state); TCheckFunc IndexKeys(const TVector& keyNames); TCheckFunc IndexDataColumns(const TVector& dataColumnNames); - + TCheckFunc VectorIndexDescription(Ydb::Table::VectorIndexSettings_Metric metric, Ydb::Table::VectorIndexSettings_VectorType vectorType, ui32 vectorDimension diff --git a/ydb/core/tx/schemeshard/ut_index_build/ut_index_build.cpp b/ydb/core/tx/schemeshard/ut_index_build/ut_index_build.cpp index 5cf2ef6cb5c1..7ca8c653a3c0 100644 --- a/ydb/core/tx/schemeshard/ut_index_build/ut_index_build.cpp +++ b/ydb/core/tx/schemeshard/ut_index_build/ut_index_build.cpp @@ -934,6 +934,78 @@ Y_UNIT_TEST_SUITE(IndexBuildTest) { } } + Y_UNIT_TEST(IndexPartitioningIsPersisted) { + TTestBasicRuntime runtime; + TTestEnv env(runtime); + ui64 txId = 100; + + TestCreateTable(runtime, ++txId, "/MyRoot", R"( + Name: "Table" + Columns { Name: "key" Type: "Uint64" } + Columns { Name: "value" Type: "Utf8" } + KeyColumnNames: [ "key" ] + )"); + env.TestWaitNotification(runtime, txId); + + Ydb::Table::GlobalIndexSettings settings; + UNIT_ASSERT(google::protobuf::TextFormat::ParseFromString(R"( + partition_at_keys { + split_points { + type { tuple_type { elements { optional_type { item { type_id: UTF8 } } } } } + value { items { text_value: "alice" } } + } + split_points { + type { tuple_type { elements { optional_type { item { type_id: UTF8 } } } } } + value { items { text_value: "bob" } } + } + } + partitioning_settings { + min_partitions_count: 3 + max_partitions_count: 3 + } + )", &settings)); + + TBlockEvents indexCreationBlocker(runtime, [](const auto& ev) { + const auto& modifyScheme = ev->Get()->Record.GetTransaction(0); + return modifyScheme.GetOperationType() == NKikimrSchemeOp::ESchemeOpCreateIndexBuild; + }); + + const ui64 buildIndexTx = ++txId; + TestBuildIndex(runtime, buildIndexTx, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/Table", TBuildIndexConfig{ + "Index", NKikimrSchemeOp::EIndexTypeGlobal, { "value" }, {}, + { NYdb::NTable::TGlobalIndexSettings::FromProto(settings) } + }); + + RebootTablet(runtime, TTestTxConfig::SchemeShard, runtime.AllocateEdgeActor()); + + indexCreationBlocker.Stop().Unblock(); + env.TestWaitNotification(runtime, buildIndexTx); + + auto buildIndexOperation = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexTx); + UNIT_ASSERT_VALUES_EQUAL_C( + buildIndexOperation.GetIndexBuild().GetState(), Ydb::Table::IndexBuildState::STATE_DONE, + buildIndexOperation.DebugString() + ); + + TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"), { + NLs::IsTable, + NLs::IndexesCount(1) + }); + + TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/Table/Index"), { + NLs::PathExist, + NLs::IndexState(NKikimrSchemeOp::EIndexState::EIndexStateReady) + }); + + TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/Table/Index/indexImplTable", true, true), { + NLs::IsTable, + NLs::PartitionCount(3), + NLs::MinPartitionsCountEqual(3), + NLs::MaxPartitionsCountEqual(3), + NLs::PartitionKeys({"alice", "bob", ""}) + }); + } + Y_UNIT_TEST(DropIndex) { TTestBasicRuntime runtime; TTestEnv env(runtime); diff --git a/ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp b/ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp index 9991c82229ea..9300e78b06c6 100644 --- a/ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp +++ b/ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp @@ -1,11 +1,14 @@ #include #include #include +#include #include #include #include +#include + using namespace NKikimr; using namespace NSchemeShard; using namespace NSchemeShardUT_Private; @@ -225,4 +228,104 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) { UNIT_ASSERT_VALUES_EQUAL(billRecords.size(), 0); } + + Y_UNIT_TEST(VectorIndexDescriptionIsPersisted) { + TTestBasicRuntime runtime; + TTestEnv env(runtime); + ui64 txId = 100; + + TestCreateTable(runtime, ++txId, "/MyRoot", R"( + Name: "vectors" + Columns { Name: "id" Type: "Uint64" } + Columns { Name: "embedding" Type: "String" } + Columns { Name: "covered" Type: "String" } + KeyColumnNames: [ "id" ] + )"); + env.TestWaitNotification(runtime, txId); + + NYdb::NTable::TGlobalIndexSettings globalIndexSettings; + { + Ydb::Table::GlobalIndexSettings proto; + UNIT_ASSERT(google::protobuf::TextFormat::ParseFromString(R"( + partition_at_keys { + split_points { + type { tuple_type { elements { optional_type { item { type_id: UINT32 } } } } } + value { items { uint32_value: 12345 } } + } + split_points { + type { tuple_type { elements { optional_type { item { type_id: UINT32 } } } } } + value { items { uint32_value: 54321 } } + } + } + partitioning_settings { + min_partitions_count: 3 + max_partitions_count: 3 + } + )", &proto)); + globalIndexSettings = NYdb::NTable::TGlobalIndexSettings::FromProto(proto); + } + + std::unique_ptr vectorIndexSettings; + { + Ydb::Table::VectorIndexSettings proto; + UNIT_ASSERT(google::protobuf::TextFormat::ParseFromString(R"( + metric: DISTANCE_COSINE, + vector_type: VECTOR_TYPE_FLOAT, + vector_dimension: 1024 + )", &proto)); + using T = NYdb::NTable::TVectorIndexSettings; + vectorIndexSettings = std::make_unique(T::FromProto(proto)); + } + + TBlockEvents indexCreationBlocker(runtime, [](const auto& ev) { + const auto& modifyScheme = ev->Get()->Record.GetTransaction(0); + return modifyScheme.GetOperationType() == NKikimrSchemeOp::ESchemeOpCreateIndexBuild; + }); + + const ui64 buildIndexTx = ++txId; + TestBuildIndex(runtime, buildIndexTx, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/vectors", TBuildIndexConfig{ + "by_embedding", NKikimrSchemeOp::EIndexTypeGlobalVectorKmeansTree, { "embedding" }, { "covered" }, + { globalIndexSettings, globalIndexSettings }, std::move(vectorIndexSettings) + }); + + RebootTablet(runtime, TTestTxConfig::SchemeShard, runtime.AllocateEdgeActor()); + + indexCreationBlocker.Stop().Unblock(); + env.TestWaitNotification(runtime, buildIndexTx); + + auto buildIndexOperation = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexTx); + UNIT_ASSERT_VALUES_EQUAL_C( + buildIndexOperation.GetIndexBuild().GetState(), Ydb::Table::IndexBuildState::STATE_DONE, + buildIndexOperation.DebugString() + ); + + TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/vectors/by_embedding"), { + NLs::PathExist, + NLs::IndexState(NKikimrSchemeOp::EIndexStateReady), + NLs::IndexType(NKikimrSchemeOp::EIndexTypeGlobalVectorKmeansTree), + NLs::IndexKeys({"embedding"}), + NLs::IndexDataColumns({"covered"}), + NLs::VectorIndexDescription( + Ydb::Table::VectorIndexSettings::DISTANCE_COSINE, + Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT, + 1024 + ) + }); + + using namespace NKikimr::NTableIndex::NTableVectorKmeansTreeIndex; + TestDescribeResult(DescribePrivatePath(runtime, JoinFsPaths("/MyRoot/vectors/by_embedding", LevelTable), true, true), { + NLs::IsTable, + NLs::PartitionCount(3), + NLs::MinPartitionsCountEqual(3), + NLs::MaxPartitionsCountEqual(3), + NLs::SplitBoundaries({12345, 54321}) + }); + TestDescribeResult(DescribePrivatePath(runtime, JoinFsPaths("/MyRoot/vectors/by_embedding", PostingTable), true, true), { + NLs::IsTable, + NLs::PartitionCount(3), + NLs::MinPartitionsCountEqual(3), + NLs::MaxPartitionsCountEqual(3), + NLs::SplitBoundaries({12345, 54321}) + }); + } } diff --git a/ydb/core/tx/schemeshard/ut_index_build_reboots/ut_index_build_reboots.cpp b/ydb/core/tx/schemeshard/ut_index_build_reboots/ut_index_build_reboots.cpp index 8f6135105977..229d7f31adb8 100644 --- a/ydb/core/tx/schemeshard/ut_index_build_reboots/ut_index_build_reboots.cpp +++ b/ydb/core/tx/schemeshard/ut_index_build_reboots/ut_index_build_reboots.cpp @@ -450,4 +450,75 @@ Y_UNIT_TEST_SUITE(IndexBuildTestReboots) { }); } + + Y_UNIT_TEST(IndexPartitioning) { + TTestWithReboots t(false); + t.Run([&](TTestActorRuntime& runtime, bool& activeZone) { + { + TInactiveZone inactive(activeZone); + + TestCreateTable(runtime, ++t.TxId, "/MyRoot", R"( + Name: "Table" + Columns { Name: "key" Type: "Uint32" } + Columns { Name: "value" Type: "Utf8" } + KeyColumnNames: [ "key" ] + )"); + t.TestEnv->TestWaitNotification(runtime, t.TxId); + } + + Ydb::Table::GlobalIndexSettings settings; + UNIT_ASSERT(google::protobuf::TextFormat::ParseFromString(R"( + partition_at_keys { + split_points { + type { tuple_type { elements { optional_type { item { type_id: UTF8 } } } } } + value { items { text_value: "alice" } } + } + split_points { + type { tuple_type { elements { optional_type { item { type_id: UTF8 } } } } } + value { items { text_value: "bob" } } + } + } + partitioning_settings { + min_partitions_count: 3 + max_partitions_count: 3 + } + )", &settings)); + + const ui64 buildIndexId = ++t.TxId; + AsyncBuildIndex(runtime, buildIndexId, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/Table", TBuildIndexConfig{ + "Index", NKikimrSchemeOp::EIndexTypeGlobal, { "value" }, {}, + { NYdb::NTable::TGlobalIndexSettings::FromProto(settings) } + }); + + { + auto descr = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexId); + UNIT_ASSERT_VALUES_EQUAL(descr.GetIndexBuild().GetState(), Ydb::Table::IndexBuildState::STATE_PREPARING); + } + + t.TestEnv->TestWaitNotification(runtime, buildIndexId); + + { + auto descr = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexId); + UNIT_ASSERT_VALUES_EQUAL(descr.GetIndexBuild().GetState(), Ydb::Table::IndexBuildState::STATE_DONE); + } + + TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"), { + NLs::IsTable, + NLs::IndexesCount(1) + }); + + TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/Table/Index"), { + NLs::PathExist, + NLs::IndexState(NKikimrSchemeOp::EIndexState::EIndexStateReady) + }); + + TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/Table/Index/indexImplTable", true, true), { + NLs::IsTable, + NLs::PartitionCount(3), + NLs::MinPartitionsCountEqual(3), + NLs::MaxPartitionsCountEqual(3), + NLs::PartitionKeys({"alice", "bob", ""}) + }); + }); + } } diff --git a/ydb/core/tx/schemeshard/ut_index_build_reboots/ya.make b/ydb/core/tx/schemeshard/ut_index_build_reboots/ya.make index cf907e095934..e3949577f7a2 100644 --- a/ydb/core/tx/schemeshard/ut_index_build_reboots/ya.make +++ b/ydb/core/tx/schemeshard/ut_index_build_reboots/ya.make @@ -24,6 +24,7 @@ PEERDIR( ydb/core/tx ydb/core/tx/schemeshard/ut_helpers ydb/library/yql/public/udf/service/exception_policy + ydb/public/sdk/cpp/client/ydb_table ) SRCS( diff --git a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema index 2d81fdc889b0..5b08a08f41d9 100644 --- a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema +++ b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema @@ -4800,6 +4800,11 @@ "ColumnId": 33, "ColumnName": "AlterMainTableTxDone", "ColumnType": "Bool" + }, + { + "ColumnId": 34, + "ColumnName": "CreationConfig", + "ColumnType": "String" } ], "ColumnsDropped": [], @@ -4838,7 +4843,8 @@ 30, 31, 32, - 33 + 33, + 34 ], "RoomID": 0, "Codec": 0,