Repository: ydb-platform/ydb
Pull request #18724: Fix vector index build test and make it reproduce #18236, #18278 and #18355
Author: login: vitalif
Labels: name: not-for-changelog
Created: 2025-05-23T09:25:18Z | Merged: 2025-05-27T10:54:00Z

### Changelog category

* Not for changelog 

### Description for reviewers

Test for PRs #18274, #18722, and #18723. It reproduces all three issues, I've checked :)

SetMaxPartitionsCount() is removed because it seems that it was originally added to prevent index table shards from being split, but it doesn't work in case of a large table (ForceShardSplitSize = 2GB), and it's required to reshard the table during the test to reproduce the bug. So it seems that the easiest way is to remove MaxPartitionsCount from the index table at all.


Diff:
diff --git a/ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp b/ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
index 9052410f638d..05b5dd3c0e5f 100644
--- a/ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
@@ -372,9 +372,10 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
             auto cell = TCell::Make(i);
             op.AddSplitBoundary()->SetSerializedKeyPrefix(TSerializedCellVec::Serialize({&cell, 1}));
         }
+        // Prevent merging partitions
+        policy.SetMinPartitionsCount(32768);
+        policy.SetMaxPartitionsCount(0);
     }
-    policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
 
     LOG_DEBUG_S((TlsActivationContext->AsActorContext()), NKikimrServices::BUILD_INDEX, 
         "CreateBuildPropose " << buildInfo.Id << " " << buildInfo.State << " " << propose->Record.ShortDebugString());
diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp
index f33f680667a0..039be70a57ac 100644
--- a/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp
+++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.cpp
@@ -1774,9 +1774,9 @@ namespace NSchemeShardUT_Private {
             if (cfg.KMeansTreeSettings) {
                 cfg.KMeansTreeSettings->SerializeTo(kmeansTreeSettings);
             } else {
-                // some random valid settings
-                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT);
-                kmeansTreeSettings.mutable_settings()->set_vector_dimension(42);
+                // valid settings for tests - uint8 vectors of size 4
+                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_UINT8);
+                kmeansTreeSettings.mutable_settings()->set_vector_dimension(4);
                 kmeansTreeSettings.mutable_settings()->set_metric(Ydb::Table::VectorIndexSettings::DISTANCE_COSINE);
                 kmeansTreeSettings.set_clusters(4);
                 // More than 2 is too long for reboot tests
@@ -2663,4 +2663,28 @@ namespace NSchemeShardUT_Private {
         SendNextValRequest(runtime, sender, path);
         return WaitNextValResult(runtime, sender, expectedStatus);
     }
+
+    NKikimrMiniKQL::TResult ReadTable(TTestActorRuntime& runtime, ui64 tabletId,
+            const TString& table, const TVector<TString>& pk, const TVector<TString>& columns,
+            const TString& rangeFlags)
+    {
+        TStringBuilder keyFmt;
+        for (const auto& k : pk) {
+            keyFmt << "'('" << k << " (Null) (Void)) ";
+        }
+        const auto columnsFmt = "'" + JoinSeq(" '", columns);
+
+        NKikimrMiniKQL::TResult result;
+        TString error;
+        NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, Sprintf(R"((
+            (let range '(%s%s))
+            (let columns '(%s))
+            (let result (SelectRange '__user__%s range columns '()))
+            (return (AsList (SetResult 'Result result) ))
+        ))", rangeFlags.data(), keyFmt.data(), columnsFmt.data(), table.data()), result, error);
+        UNIT_ASSERT_VALUES_EQUAL_C(status, NKikimrProto::EReplyStatus::OK, error);
+        UNIT_ASSERT_VALUES_EQUAL(error, "");
+
+        return result;
+    }
 }
diff --git a/ydb/core/tx/schemeshard/ut_helpers/helpers.h b/ydb/core/tx/schemeshard/ut_helpers/helpers.h
index 5bfdc665f147..f1e56dddaa1f 100644
--- a/ydb/core/tx/schemeshard/ut_helpers/helpers.h
+++ b/ydb/core/tx/schemeshard/ut_helpers/helpers.h
@@ -641,6 +641,7 @@ namespace NSchemeShardUT_Private {
     void UpdateRow(TTestActorRuntime& runtime, const TString& table, const ui32 key, const TString& value, ui64 tabletId = TTestTxConfig::FakeHiveTablets);
     void UpdateRowPg(TTestActorRuntime& runtime, const TString& table, const ui32 key, ui32 value, ui64 tabletId = TTestTxConfig::FakeHiveTablets);
     void UploadRow(TTestActorRuntime& runtime, const TString& tablePath, int partitionIdx, const TVector<ui32>& keyTags, const TVector<ui32>& valueTags, const TVector<TCell>& keys, const TVector<TCell>& values);
+    void WriteOp(TTestActorRuntime& runtime, ui64 schemeshardId, const ui64 txId, const TString& tablePath, int partitionIdx, NKikimrDataEvents::TEvWrite_TOperation::EOperationType operationType, const std::vector<ui32>& columnIds, TSerializedCellMatrix&& data, bool successIsExpected);
     void WriteRow(TTestActorRuntime& runtime, ui64 schemeshardId, const ui64 txId, const TString& tablePath, int partitionIdx, const ui32 key, const TString& value, bool successIsExpected = true);
     void WriteRow(TTestActorRuntime& runtime, const ui64 txId, const TString& tablePath, int partitionIdx, const ui32 key, const TString& value, bool successIsExpected = true);
     void DeleteRow(TTestActorRuntime& runtime, ui64 schemeshardId, const ui64 txId, const TString& tablePath, int partitionIdx, const ui32 key, bool successIsExpected = true);
@@ -654,4 +655,8 @@ namespace NSchemeShardUT_Private {
         TTestActorRuntime& runtime, const TString& path,
         Ydb::StatusIds::StatusCode expectedStatus = Ydb::StatusIds::SUCCESS);
 
+    NKikimrMiniKQL::TResult ReadTable(TTestActorRuntime& runtime, ui64 tabletId,
+        const TString& table, const TVector<TString>& pk, const TVector<TString>& columns, const TString& rangeFlags = "");
+
+
 } //NSchemeShardUT_Private
diff --git a/ydb/core/tx/schemeshard/ut_index/ut_async_index.cpp b/ydb/core/tx/schemeshard/ut_index/ut_async_index.cpp
index 80e7a4472364..f6c737b62123 100644
--- a/ydb/core/tx/schemeshard/ut_index/ut_async_index.cpp
+++ b/ydb/core/tx/schemeshard/ut_index/ut_async_index.cpp
@@ -119,28 +119,6 @@ Y_UNIT_TEST_SUITE(TAsyncIndexTests) {
         return mainTabletIds;
     }
 
-    NKikimrMiniKQL::TResult ReadTable(TTestActorRuntime& runtime, ui64 tabletId,
-            const TString& table, const TVector<TString>& pk, const TVector<TString>& columns)
-    {
-        TStringBuilder keyFmt;
-        for (const auto& k : pk) {
-            keyFmt << "'('" << k << " (Null) (Void)) ";
-        }
-        const auto columnsFmt = "'" + JoinSeq(" '", columns);
-
-        NKikimrMiniKQL::TResult result;
-        TString error;
-        NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, Sprintf(R"((
-            (let range '(%s))
-            (let columns '(%s))
-            (let result (SelectRange '__user__%s range columns '()))
-            (return (AsList (SetResult 'Result result) ))
-        ))", keyFmt.data(), columnsFmt.data(), table.data()), result, error);
-        UNIT_ASSERT_VALUES_EQUAL_C(status, NKikimrProto::EReplyStatus::OK, error);
-
-        return result;
-    }
-
     struct TTableTraits {
         TString Path;
         TVector<TString> Key;
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 95c8758208c6..dd8a13050c9a 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
@@ -8,6 +8,7 @@
 #include <ydb/core/tx/datashard/datashard.h>
 #include <ydb/core/metering/metering.h>
 
+#include <ydb/public/lib/deprecated/kicli/kicli.h>
 #include <ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h>
 
 using namespace NKikimr;
@@ -79,30 +80,37 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
 
         // Just create main table
         TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"(
-              Name: "Table"
-              Columns { Name: "key"       Type: "Uint32" }
-              Columns { Name: "embedding" Type: "String" }
-              KeyColumnNames: ["key"]
+            Name: "Table"
+            Columns { Name: "key"       Type: "Uint32" }
+            Columns { Name: "embedding" Type: "String" }
+            KeyColumnNames: ["key"]
+            SplitBoundary { KeyPrefix { Tuple { Optional { Uint32: 50 } } } }
+            SplitBoundary { KeyPrefix { Tuple { Optional { Uint32: 150 } } } }
         )");
         env.TestWaitNotification(runtime, txId, tenantSchemeShard);
 
-        auto fnWriteRow = [&](ui64 tabletId, ui32 key, TString embedding, const char* table) {
-            TString writeQuery = Sprintf(R"(
-                (
-                    (let key   '( '('key       (Uint32 '%u ) ) ) )
-                    (let row   '( '('embedding (String '%s ) ) ) )
-                    (return (AsList (UpdateRow '__user__%s key row) ))
-                )
-            )", key, embedding.c_str(), table);
-            NKikimrMiniKQL::TResult result;
-            TString err;
-            NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, writeQuery, result, err);
-            UNIT_ASSERT_VALUES_EQUAL(err, "");
-            UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK);
+        // Write data directly into shards
+        auto fillRows = [&](const TString & tablePath, ui32 shard, ui32 min, ui32 max) {
+            TVector<TCell> cells;
+            ui8 str[6] = { 0 };
+            str[4] = (ui8)Ydb::Table::VectorIndexSettings::VECTOR_TYPE_UINT8;
+            for (ui32 key = min; key < max; ++key) {
+                str[0] = ((key+106)* 7) % 256;
+                str[1] = ((key+106)*17) % 256;
+                str[2] = ((key+106)*37) % 256;
+                str[3] = ((key+106)*47) % 256;
+                cells.emplace_back(TCell::Make(key));
+                cells.emplace_back(TCell((const char*)str, 5));
+            }
+            std::vector<ui32> columnIds{1, 2};
+            TSerializedCellMatrix matrix(cells, max-min, 2);
+            WriteOp(runtime, tenantSchemeShard, ++txId, tablePath,
+                shard, NKikimrDataEvents::TEvWrite::TOperation::OPERATION_UPSERT,
+                columnIds, std::move(matrix), true);
         };
-        for (ui32 key = 0; key < 200; ++key) {
-            fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, key, std::to_string(key), "Table");
-        }
+        fillRows("/MyRoot/ServerLessDB/Table", 0, 0, 50);
+        fillRows("/MyRoot/ServerLessDB/Table", 1, 50, 150);
+        fillRows("/MyRoot/ServerLessDB/Table", 2, 150, 200);
 
         runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE);
         runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE);
@@ -118,18 +126,95 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
             meteringMessages << event->Get()->MeteringJson;
         });
 
-        TestBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
+        TBlockEvents<TEvDataShard::TEvReshuffleKMeansRequest> reshuffleBlocker(runtime, [&](const auto& ) {
+            return true;
+        });
+
+        AsyncBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
         ui64 buildIndexId = txId;
 
+        // Wait for the first "reshuffle" request (samples will be already collected on the first level)
+        // and reboot the scheme shard to verify that its intermediate state is persisted correctly.
+        // The bug checked here: Sample.Probability was not persisted (#18236).
+        runtime.WaitFor("ReshuffleKMeansRequest", [&]{ return reshuffleBlocker.size(); });
+        Cerr << "... rebooting scheme shard" << Endl;
+        RebootTablet(runtime, tenantSchemeShard, runtime.AllocateEdgeActor());
+
+        // Now wait for the 1st level to be finalized
+        TBlockEvents<TEvSchemeShard::TEvModifySchemeTransaction> level1Blocker(runtime, [&](auto& ev) {
+            const auto& record = ev->Get()->Record;
+            if (record.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpInitiateBuildIndexImplTable) {
+                txId = record.GetTxId();
+                return true;
+            }
+            return false;
+        });
+        reshuffleBlocker.Stop();
+        reshuffleBlocker.Unblock(reshuffleBlocker.size());
+
+        // Reshard the first level table (0build)
+        // First bug checked here: after restarting the schemeshard during reshuffle it
+        //   generates more clusters than requested and dies with VERIFY on shard boundaries (#18278).
+        // Second bug checked here: posting table doesn't contain all rows from the main table
+        //   when the build table is resharded during build (#18355).
+        {
+            auto indexDesc = DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", true, true, true);
+            auto parts = indexDesc.GetPathDescription().GetTablePartitions();
+            UNIT_ASSERT_EQUAL(parts.size(), 4);
+            ui64 cluster = 1;
+            for (const auto & x: parts) {
+                TestSplitTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", Sprintf(R"(
+                    SourceTabletId: %lu
+                    SplitBoundary { KeyPrefix { Tuple { Optional { Uint64: %lu } } Tuple { Optional { Uint32: 50 } } } }
+                    SplitBoundary { KeyPrefix { Tuple { Optional { Uint64: %lu } } Tuple { Optional { Uint32: 150 } } } }
+                )", x.GetDatashardId(), cluster, cluster));
+                env.TestWaitNotification(runtime, txId);
+                cluster++;
+            }
+        }
+
+        level1Blocker.Stop();
+        level1Blocker.Unblock(level1Blocker.size());
+
+        // Now wait for the index build
+        {
+            auto expectedStatus = Ydb::StatusIds::SUCCESS;
+            TAutoPtr<IEventHandle> handle;
+            TEvIndexBuilder::TEvCreateResponse* event = runtime.GrabEdgeEvent<TEvIndexBuilder::TEvCreateResponse>(handle);
+            UNIT_ASSERT(event);
+
+            Cerr << "BUILDINDEX RESPONSE CREATE: " << event->ToString() << Endl;
+            UNIT_ASSERT_EQUAL_C(event->Record.GetStatus(), expectedStatus,
+                                "status mismatch"
+                                    << " got " << Ydb::StatusIds::StatusCode_Name(event->Record.GetStatus())
+                                    << " expected "  << Ydb::StatusIds::StatusCode_Name(expectedStatus)
+                                    << " issues was " << event->Record.GetIssues());
+        }
+
+        env.TestWaitNotification(runtime, buildIndexId, tenantSchemeShard);
+
+        // Check row count in the posting table
+        {
+            auto indexDesc = DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable", true, true, true);
+            auto parts = indexDesc.GetPathDescription().GetTablePartitions();
+            ui32 rows = 0;
+            for (const auto & x: parts) {
+                auto result = ReadTable(runtime, x.GetDatashardId(), "indexImplPostingTable",
+                    {NKikimr::NTableIndex::NTableVectorKmeansTreeIndex::ParentColumn, "key"}, {"key"});
+                auto value = NClient::TValue::Create(result);
+                rows += value["Result"]["List"].Size();
+            }
+            Cerr << "... posting table contains " << rows << " rows" << Endl;
+            UNIT_ASSERT_VALUES_EQUAL(rows, 200);
+        }
+
         auto listing = TestListBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB");
         UNIT_ASSERT_VALUES_EQUAL(listing.EntriesSize(), 1);
 
-        env.TestWaitNotification(runtime, txId, tenantSchemeShard);
-
-        auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", txId);
+        auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", buildIndexId);
         UNIT_ASSERT_VALUES_EQUAL(descr.GetIndexBuild().GetState(), Ydb::Table::IndexBuildState::STATE_DONE);
 
-        const TString meteringData = R"({"usage":{"start":0,"quantity":128,"finish":0,"unit":"request_unit","type":"delta"},"tags":{},"id":"106-72075186233409549-2-0-0-0-0-200-0-1290-0","cloud_id":"CLOUD_ID_VAL","source_wt":0,"source_id":"sless-docapi-ydb-ss","resource_id":"DATABASE_ID_VAL","schema":"ydb.serverless.requests.v1","folder_id":"FOLDER_ID_VAL","version":"1.0.0"})""\n";
+        const TString meteringData = R"({"usage":{"start":0,"quantity":431,"finish":0,"unit":"request_unit","type":"delta"},"tags":{},"id":"109-72075186233409549-2-0-0-0-0-619-605-11328-10960","cloud_id":"CLOUD_ID_VAL","source_wt":0,"source_id":"sless-docapi-ydb-ss","resource_id":"DATABASE_ID_VAL","schema":"ydb.serverless.requests.v1","folder_id":"FOLDER_ID_VAL","version":"1.0.0"})""\n";
 
         UNIT_ASSERT_NO_DIFF(meteringMessages, meteringData);
 
@@ -152,6 +237,7 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
         )");
         env.TestWaitNotification(runtime, txId, tenantSchemeShard);
 
+        Cerr << "... rebooting scheme shard" << Endl;
         RebootTablet(runtime, tenantSchemeShard, runtime.AllocateEdgeActor());
 
         TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"),
@@ -200,16 +286,14 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
                             NLs::ExtractTenantSchemeshard(&tenantSchemeShard)});
 
         TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/CommonDB", R"(
-              Name: "Table"
-              Columns { Name: "key"       Type: "Uint32" }
-              Columns { Name: "embedding" Type: "String" }
-              KeyColumnNames: ["key"]
+            Name: "Table"
+            Columns { Name: "key"       Type: "Uint32" }
+            Columns { Name: "embedding" Type: "String" }
+            KeyColumnNames: ["key"]
         )");
         env.TestWaitNotification(runtime, txId, tenantSchemeShard);
 
-        for (ui32 key = 100; key < 300; ++key) {
-            fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, key, std::to_string(key), "Table");
-        }
+        fillRows("/MyRoot/CommonDB/Table", 0, 100, 300);
 
         TVector<TString> billRecords;
         observerHolder = runtime.AddObserver<NMetering::TEvMetering::TEvWriteMeteringJson>([&](NMetering::TEvMetering::TEvWriteMeteringJson::TPtr& event) {
diff --git a/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp b/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp
index fcd16bdfe6ba..8f5bfaf83a51 100644
--- a/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp
+++ b/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp
@@ -399,42 +399,12 @@ namespace {
         return ConvertTestData({{"", data}});
     }
 
-    NKikimrMiniKQL::TResult ReadTableImpl(TTestActorRuntime& runtime, ui64 tabletId, const TString& query) {
-        NKikimrMiniKQL::TResult result;
-
-        TString error;
-        NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, query, result, error);
-        UNIT_ASSERT_VALUES_EQUAL_C(status, NKikimrProto::EReplyStatus::OK, error);
-        UNIT_ASSERT_VALUES_EQUAL(error, "");
-
-        return result;
-    }
-
     struct TReadKeyDesc {
         TString Name;
         TString Type;
         TString Atom;
     };
 
-    NKikimrMiniKQL::TResult ReadTable(TTestActorRuntime& runtime, ui64 tabletId,
-            const TString& table = "Table",
-            const TReadKeyDesc& keyDesc = {"key", "Utf8", "\"\""},
-            const TVector<TString>& columns = {"key", "value"},
-            const TString& rangeFlags = "") {
-
-        const auto rangeFmt = Sprintf("'%s (%s '%s)", keyDesc.Name.data(), keyDesc.Type.data(), keyDesc.Atom.data());
-        const auto columnsFmt = "'" + JoinSeq(" '", columns);
-
-        return ReadTableImpl(runtime, tabletId, Sprintf(R"(
-            (
-                (let range '(%s '(%s (Void) )))
-                (let columns '(%s) )
-                (let result (SelectRange '__user__%s range columns '()))
-                (return (AsList (SetResult 'Result result) ))
-            )
-        )", rangeFlags.c_str(), rangeFmt.data(), columnsFmt.data(), table.data()));
-    }
-
     using TDelayFunc = std::function<bool(TAutoPtr<IEventHandle>&)>;
 
     auto SetDelayObserver(TTestActorRuntime& runtime, THolder<IEventHandle>& delayed, TDelayFunc delayFunc) {
@@ -518,7 +488,7 @@ Y_UNIT_TEST_SUITE(TRestoreTests) {
             KeyColumnNames: ["key"]
         )", {data});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -600,7 +570,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
 
         const auto desc = DescribePath(runtime, "/MyRoot/Table", true, true);
@@ -630,11 +600,11 @@ value {
         )", {a, b});
 
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(a.YsonStr, content);
         }
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(b.YsonStr, content);
         }
     }
@@ -652,7 +622,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key", "Uint32", "0"});
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -668,7 +638,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data}, batchSize);
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -750,7 +720,7 @@ value {
         UNIT_ASSERT_VALUES_EQUAL(result->GetRowsProcessed(), 2);
 
         env.TestWaitNotification(runtime, txId);
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -792,7 +762,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data}, batchSize);
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -887,7 +857,7 @@ value {
             KeyColumnNames: ["key"]
         )_", {data}, data.Data.size() + 1);
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key", "Uint64", "0"}, {
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {
             "key",
             "int32_value",
             "uint32_value",
@@ -1409,7 +1379,7 @@ value {
                     << R"(["valueA"])" // value
                 << "];"
             << "];\%false]]]";
-            auto content = ReadTable(runtime, restoredFirstTablet, "Restored", {"key", "Uint32", "0"});
+            auto content = ReadTable(runtime, restoredFirstTablet, "Restored", {"key"}, {"key", "value"});
             NKqp::CompareYson(expectedJson, content);
         }
         {
@@ -1419,7 +1389,7 @@ value {
                     << R"(["valueB"])" // value
                 << "];"
             << "];\%false]]]";
-            auto content = ReadTable(runtime, restoredSecondTablet, "Restored", {"key", "Uint32", "0"});
+            auto content = ReadTable(runtime, restoredSecondTablet, "Restored", {"key"}, {"key", "value"});
             NKqp::CompareYson(expectedJson, content);
         }
     }
@@ -1566,12 +1536,12 @@ value {
                     << R"(["valueB"])" // value
                 << "];"
             << "];\%false]]]";
-            auto content = ReadTable(runtime, restoredFirstTablet, "Restored", {"key", "Uint32", "0"});
+            auto content = ReadTable(runtime, restoredFirstTablet, "Restored", {"key"}, {"key", "value"});
             NKqp::CompareYson(expectedJson, content);
         }
         {
             auto expectedJson = "[[[[];\%false]]]";
-            auto content = ReadTable(runtime, restoredSecondTablet, "Restored", {"key", "Uint32", "0"});
+            auto content = ReadTable(runtime, restoredSecondTablet, "Restored", {"key"}, {"key", "value"});
             NKqp::CompareYson(expectedJson, content);
         }
     }
@@ -1759,8 +1729,6 @@ value {
                 << "[[\"" << "wR7fZX2pskeuVjwCPabujA==" << "\"]]" // uuid
             << "]];\%false]]]";
 
-            const TReadKeyDesc readKeyDesc = {"key", "Uint64", "0"};
-
             const TVector<TString> readColumns = {
                 "key",
                 "int32_value",
@@ -1789,10 +1757,10 @@ value {
                 "uuid_value",
             };
 
-            auto contentOriginalTable = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", readKeyDesc, readColumns);
+            auto contentOriginalTable = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, readColumns);
             NKqp::CompareYson(expectedJson, contentOriginalTable);
 
-            auto contentRestoredTable = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 2, commonPrefix ? "Table" : "Restored", readKeyDesc, readColumns);
+            auto contentRestoredTable = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 2, commonPrefix ? "Table" : "Restored", {"key"}, readColumns);
             NKqp::CompareYson(expectedJson, contentRestoredTable);
         }
     }
@@ -2145,7 +2113,7 @@ value {
                     << R"(["valueA"])" // value
                 << "];"
             << "];\%false]]]";
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 2, "Restored", {"key", "Uint32", "0"});
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 2, "Restored", {"key"}, {"key", "value"});
             NKqp::CompareYson(expectedJson, content);
         }
     }
@@ -2402,7 +2370,7 @@ value {
         UNIT_ASSERT(requests > expected);
         UNIT_ASSERT_VALUES_EQUAL(responses, expected);
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key", "Uint32", "0"});
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -2421,7 +2389,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data}, batchSize);
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -2447,7 +2415,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -2465,7 +2433,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key", "Uint64", "0"});
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -2488,11 +2456,11 @@ value {
         )", {a, b});
 
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(a.YsonStr, content);
         }
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(b.YsonStr, content);
         }
     }
@@ -2510,7 +2478,7 @@ value {
             KeyColumnNames: ["key"]
         )", {data});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -2612,7 +2580,7 @@ value {
         TestCancelTxTable(runtime, ++txId, restoreTxId);
         env.TestWaitNotification(runtime, {restoreTxId, txId});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 
@@ -2678,7 +2646,7 @@ value {
         runtime.Send(progress.Release(), 0, true);
         env.TestWaitNotification(runtime, {restoreTxId, txId});
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.YsonStr, content);
     }
 }
@@ -2740,7 +2708,7 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
 
-                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
                 NKqp::CompareYson(data.YsonStr, content);
             }
         });
@@ -2770,11 +2738,11 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
                 {
-                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
                     NKqp::CompareYson(a.YsonStr, content);
                 }
                 {
-                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1);
+                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "Table", {"key"}, {"key", "value"});
                     NKqp::CompareYson(b.YsonStr, content);
                 }
             }
@@ -2822,11 +2790,11 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
                 {
-                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
                     NKqp::CompareYson(a.YsonStr, content);
                 }
                 {
-                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1);
+                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "Table", {"key"}, {"key", "value"});
                     NKqp::CompareYson(b.YsonStr, content);
                 }
             }
@@ -2852,7 +2820,7 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
 
-                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key", "Uint32", "0"});
+                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
                 NKqp::CompareYson(data.YsonStr, content);
             }
         });
@@ -2877,7 +2845,7 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
 
-                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
                 NKqp::CompareYson(data.YsonStr, content);
             }
         });
@@ -2903,7 +2871,7 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
 
-                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
                 NKqp::CompareYson(data.YsonStr, content);
             }
         });
@@ -2929,7 +2897,7 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
 
-                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
                 NKqp::CompareYson(data.YsonStr, content);
             }
         });
@@ -2955,7 +2923,7 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
 
-                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key", "Uint64", "0"});
+                auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
                 NKqp::CompareYson(data.YsonStr, content);
             }
         });
@@ -2985,11 +2953,11 @@ Y_UNIT_TEST_SUITE(TRestoreWithRebootsTests) {
             {
                 TInactiveZone inactive(activeZone);
                 {
-                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
                     NKqp::CompareYson(a.YsonStr, content);
                 }
                 {
-                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1);
+                    auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "Table", {"key"}, {"key", "value"});
                     NKqp::CompareYson(b.YsonStr, content);
                 }
             }
@@ -3189,7 +3157,7 @@ Y_UNIT_TEST_SUITE(TImportTests) {
             }
         )");
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.Data[0].YsonStr, content);
     }
 
@@ -3226,11 +3194,11 @@ Y_UNIT_TEST_SUITE(TImportTests) {
         )");
 
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(data.Data[0].YsonStr, content);
         }
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(data.Data[1].YsonStr, content);
         }
     }
@@ -3274,13 +3242,12 @@ Y_UNIT_TEST_SUITE(TImportTests) {
         )");
 
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0);
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "Table", {"key"}, {"key", "value"});
             NKqp::CompareYson(data.Data[0].YsonStr, content);
         }
 
         for (ui32 i = 0; i < indexes; ++i) {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1 + i,
-                "indexImplTable", {"value", "Utf8", "\"\""}, {"value", "key"}, "'ExcFrom");
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1 + i, "indexImplTable", {"value"}, {"value", "key"}, "'ExcFrom ");
             NKqp::CompareYson(data.Data[0].YsonStr, content);
         }
     }
@@ -3340,11 +3307,11 @@ Y_UNIT_TEST_SUITE(TImportTests) {
         )");
 
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "TableA");
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 0, "TableA", {"key"}, {"key", "value"});
             NKqp::CompareYson(a.Data[0].YsonStr, content);
         }
         {
-            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "TableB");
+            auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets + 1, "TableB", {"key"}, {"key", "value"});
             NKqp::CompareYson(b.Data[0].YsonStr, content);
         }
     }
@@ -3377,7 +3344,7 @@ Y_UNIT_TEST_SUITE(TImportTests) {
             }
         )");
 
-        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets);
+        auto content = ReadTable(runtime, TTestTxConfig::FakeHiveTablets, "Table", {"key"}, {"key", "value"});
         NKqp::CompareYson(data.Data[0].YsonStr, content);
     }
 


Reviews:
user: login: kungasc
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T10:43:20Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T15:10:33Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T16:45:51Z
user: login: kungasc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T07:58:10Z
user: login: kungasc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T07:59:02Z
user: login: kungasc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T07:59:32Z
user: login: kungasc
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T07:59:45Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-26T08:22:08Z
user: login: kungasc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T08:24:04Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-26T08:24:53Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-26T08:26:42Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-26T08:27:38Z
user: login: kungasc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T08:34:51Z
user: login: kungasc
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T08:41:33Z
user: login: vitalif
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-26T08:46:17Z
user: login: kungasc
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-26T17:07:45Z
user: login: CyberROFL
body: На будущее попрошу не смешивать разные изменения в один pr. Здесь у тебя как минимум багфикс и рефакторинг в тестах.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-27T10:53:58Z

Review comments:
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: kungasc
body: а min нужен?
created_at: 2025-05-23T10:37:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1774,9 +1774,9 @@ namespace NSchemeShardUT_Private {
             if (cfg.KMeansTreeSettings) {
                 cfg.KMeansTreeSettings->SerializeTo(kmeansTreeSettings);
             } else {
-                // some random valid settings
-                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT);
-                kmeansTreeSettings.mutable_settings()->set_vector_dimension(42);
+                // valid settings for tests - uint8 vectors of size 4
+                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_UINT8);
path: ydb/core/tx/schemeshard/ut_helpers/helpers.cpp
user: login: kungasc
body: я кстати в тестах например TTxDataShardPrefixKMeansScan.DoBadRequest такое же видел, может везде сразу проверим что типы правильные и исправим если нет?
created_at: 2025-05-23T10:41:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -118,18 +126,95 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
             meteringMessages << event->Get()->MeteringJson;
         });
 
-        TestBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
+        TBlockEvents<TEvDataShard::TEvReshuffleKMeansRequest> reshuffleBlocker(runtime, [&](const auto& ) {
+            return true;
+        });
+
+        AsyncBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
         ui64 buildIndexId = txId;
 
+        // Wait for the first "reshuffle" request (samples will be already collected on the first level)
+        // and reboot the scheme shard to verify that its intermediate state is persisted correctly.
+        // The bug checked here: Sample.Probability was not persisted (#18236).
+        runtime.WaitFor("ReshuffleKMeansRequest", [&]{ return reshuffleBlocker.size(); });
+        Cerr << "... rebooting scheme shard" << Endl;
+        RebootTablet(runtime, tenantSchemeShard, runtime.AllocateEdgeActor());
+
+        // Now wait for the 1st level to be finalized
+        TBlockEvents<TEvSchemeShard::TEvModifySchemeTransaction> level1Blocker(runtime, [&](auto& ev) {
+            const auto& record = ev->Get()->Record;
+            if (record.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpInitiateBuildIndexImplTable) {
+                txId = record.GetTxId();
+                return true;
+            }
+            return false;
+        });
+        reshuffleBlocker.Stop();
+        reshuffleBlocker.Unblock(reshuffleBlocker.size());
+
+        // Reshard the first level table (0build)
+        // First bug checked here: after restarting the schemeshard during reshuffle it
+        //   generates more clusters than requested and dies with VERIFY on shard boundaries (#18278).
+        // Second bug checked here: posting table doesn't contain all rows from the main table
+        //   when the build table is resharded during build (#18355).
+        {
+            auto indexDesc = DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", true, true, true);
+            auto parts = indexDesc.GetPathDescription().GetTablePartitions();
+            UNIT_ASSERT_EQUAL(parts.size(), 4);
+            ui64 cluster = 1;
+            for (const auto & x: parts) {
+                TestSplitTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", Sprintf(R"(
path: ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp
user: login: kungasc
body: хочется два теста, когда сплит по границам двух кластеров и когда посередине
created_at: 2025-05-23T10:43:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1774,9 +1774,9 @@ namespace NSchemeShardUT_Private {
             if (cfg.KMeansTreeSettings) {
                 cfg.KMeansTreeSettings->SerializeTo(kmeansTreeSettings);
             } else {
-                // some random valid settings
-                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT);
-                kmeansTreeSettings.mutable_settings()->set_vector_dimension(42);
+                // valid settings for tests - uint8 vectors of size 4
+                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_UINT8);
path: ydb/core/tx/schemeshard/ut_helpers/helpers.cpp
user: login: vitalif
body: Там вроде лажи с размерностью нет, там set_vector_dimension(2)
created_at: 2025-05-23T15:10:33Z
author_association: COLLABORATOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: vitalif
body: min надо, потому что иначе https://ydb.tech/docs/ru/concepts/datamodel/table#partition_at_keys

>При включенном автоматическом партиционировании необходимо также не забыть установить корректное значение параметра AUTO_PARTITIONING_MIN_PARTITIONS_COUNT, чтобы все партиции не объединились в одну сразу после создания таблицы.

Хотя в теории всё равно может наверное какая-то гадость при заливке произойти - типа, сделали 200 шардов, налили первый, он разросся больше 2 ГБ, поделили, увидели, что шардов стало 201, но все кроме 1 и 2 пустые, смержили 2 и 3, и так далее...

Короче, в идеале, конечно, в рамках этого теста тут бы не трогать ничего вообще, но пока что-то иначе протестировать не получается :-). Щас опять попробовал добавить туда

```
        TestAlterTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB/Table/index1", R"(
            Name: "indexImplPostingTable0build"
            PartitionConfig {
                PartitioningPolicy {
                    MinPartitionsCount: 0
                    MaxPartitionsCount: 0
                }
            }
        )");
        env.TestWaitNotification(runtime, txId);
```

валится с `Unexpected result: StatusMultipleModifications: path '[OwnerId: 72075186233409549, LocalPathId: 2]' has been locked by tx: 281474976725757`

причём это про то, что залочена сама таблица, а не индексная

в общем, короче, если бы кто подсказал, как здесь снять min/max partition count, не убирая его в build_index__progress совсем...
created_at: 2025-05-23T16:45:51Z
author_association: COLLABORATOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: kungasc
body: indexImplPostingTable0build лочится перед сканом, мб поэтому StatusMultipleModifications?


created_at: 2025-05-26T07:58:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: kungasc
body: > Хотя в теории всё равно может наверное какая-то гадость при заливке произойти - типа, сделали 200 шардов, налили первый, он разросся больше 2 ГБ, поделили, увидели, что шардов стало 201, но все кроме 1 и 2 пустые, смержили 2 и 3, и так далее...

ну видимо да, пока что в ydb нет понятия ключ по которому нельзя мерджить партиции, но вроде хотели добавить
created_at: 2025-05-26T07:59:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1774,9 +1774,9 @@ namespace NSchemeShardUT_Private {
             if (cfg.KMeansTreeSettings) {
                 cfg.KMeansTreeSettings->SerializeTo(kmeansTreeSettings);
             } else {
-                // some random valid settings
-                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_FLOAT);
-                kmeansTreeSettings.mutable_settings()->set_vector_dimension(42);
+                // valid settings for tests - uint8 vectors of size 4
+                kmeansTreeSettings.mutable_settings()->set_vector_type(Ydb::Table::VectorIndexSettings::VECTOR_TYPE_UINT8);
path: ydb/core/tx/schemeshard/ut_helpers/helpers.cpp
user: login: kungasc
body: там тоже VECTOR_TYPE_FLOAT, а нужен VECTOR_TYPE_UINT8, ну ладно сам поправлю уже
created_at: 2025-05-26T07:59:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: vitalif
body: В общем тут Саша подсказал такую идею - так как MinPartitionsCount влияет только на merge, то если его поставить очень большим, партиции сливаться не будут. Сделал пока что именно так - поставил Min = 32768.
created_at: 2025-05-26T08:22:08Z
author_association: COLLABORATOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: kungasc
body: это только у build таблиц?
created_at: 2025-05-26T08:24:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -118,18 +126,95 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
             meteringMessages << event->Get()->MeteringJson;
         });
 
-        TestBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
+        TBlockEvents<TEvDataShard::TEvReshuffleKMeansRequest> reshuffleBlocker(runtime, [&](const auto& ) {
+            return true;
+        });
+
+        AsyncBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
         ui64 buildIndexId = txId;
 
+        // Wait for the first "reshuffle" request (samples will be already collected on the first level)
+        // and reboot the scheme shard to verify that its intermediate state is persisted correctly.
+        // The bug checked here: Sample.Probability was not persisted (#18236).
+        runtime.WaitFor("ReshuffleKMeansRequest", [&]{ return reshuffleBlocker.size(); });
+        Cerr << "... rebooting scheme shard" << Endl;
+        RebootTablet(runtime, tenantSchemeShard, runtime.AllocateEdgeActor());
+
+        // Now wait for the 1st level to be finalized
+        TBlockEvents<TEvSchemeShard::TEvModifySchemeTransaction> level1Blocker(runtime, [&](auto& ev) {
+            const auto& record = ev->Get()->Record;
+            if (record.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpInitiateBuildIndexImplTable) {
+                txId = record.GetTxId();
+                return true;
+            }
+            return false;
+        });
+        reshuffleBlocker.Stop();
+        reshuffleBlocker.Unblock(reshuffleBlocker.size());
+
+        // Reshard the first level table (0build)
+        // First bug checked here: after restarting the schemeshard during reshuffle it
+        //   generates more clusters than requested and dies with VERIFY on shard boundaries (#18278).
+        // Second bug checked here: posting table doesn't contain all rows from the main table
+        //   when the build table is resharded during build (#18355).
+        {
+            auto indexDesc = DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", true, true, true);
+            auto parts = indexDesc.GetPathDescription().GetTablePartitions();
+            UNIT_ASSERT_EQUAL(parts.size(), 4);
+            ui64 cluster = 1;
+            for (const auto & x: parts) {
+                TestSplitTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", Sprintf(R"(
path: ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp
user: login: vitalif
body: Вроде бы ситуация, когда партиции поделены не по границе кластера, на практике не возможна. А если пытаться это всё-таки спровоцировать на промежуточных таблицах и проверять - это придётся ещё учиться обходить ограничение MinPartitionsCount, которое я как раз только что поправил... Давай в общем так замержим пока...
created_at: 2025-05-26T08:24:53Z
author_association: COLLABORATOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: vitalif
body: Кстати ещё нет, но сейчас сделаю, чтобы да. :-)
created_at: 2025-05-26T08:26:42Z
author_association: COLLABORATOR
diff_hunk: @@ -373,7 +373,6 @@ THolder<TEvSchemeShard::TEvModifySchemeTransaction> CreateBuildPropose(
         }
     }
     policy.SetMinPartitionsCount(op.SplitBoundarySize() + 1);
-    policy.SetMaxPartitionsCount(op.SplitBoundarySize() + 1);
path: ydb/core/tx/schemeshard/schemeshard_build_index__progress.cpp
user: login: vitalif
body: Сделал
created_at: 2025-05-26T08:27:38Z
author_association: COLLABORATOR
diff_hunk: @@ -118,18 +126,95 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
             meteringMessages << event->Get()->MeteringJson;
         });
 
-        TestBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
+        TBlockEvents<TEvDataShard::TEvReshuffleKMeansRequest> reshuffleBlocker(runtime, [&](const auto& ) {
+            return true;
+        });
+
+        AsyncBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
         ui64 buildIndexId = txId;
 
+        // Wait for the first "reshuffle" request (samples will be already collected on the first level)
+        // and reboot the scheme shard to verify that its intermediate state is persisted correctly.
+        // The bug checked here: Sample.Probability was not persisted (#18236).
+        runtime.WaitFor("ReshuffleKMeansRequest", [&]{ return reshuffleBlocker.size(); });
+        Cerr << "... rebooting scheme shard" << Endl;
+        RebootTablet(runtime, tenantSchemeShard, runtime.AllocateEdgeActor());
+
+        // Now wait for the 1st level to be finalized
+        TBlockEvents<TEvSchemeShard::TEvModifySchemeTransaction> level1Blocker(runtime, [&](auto& ev) {
+            const auto& record = ev->Get()->Record;
+            if (record.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpInitiateBuildIndexImplTable) {
+                txId = record.GetTxId();
+                return true;
+            }
+            return false;
+        });
+        reshuffleBlocker.Stop();
+        reshuffleBlocker.Unblock(reshuffleBlocker.size());
+
+        // Reshard the first level table (0build)
+        // First bug checked here: after restarting the schemeshard during reshuffle it
+        //   generates more clusters than requested and dies with VERIFY on shard boundaries (#18278).
+        // Second bug checked here: posting table doesn't contain all rows from the main table
+        //   when the build table is resharded during build (#18355).
+        {
+            auto indexDesc = DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", true, true, true);
+            auto parts = indexDesc.GetPathDescription().GetTablePartitions();
+            UNIT_ASSERT_EQUAL(parts.size(), 4);
+            ui64 cluster = 1;
+            for (const auto & x: parts) {
+                TestSplitTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", Sprintf(R"(
path: ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp
user: login: kungasc
body: обсудили что нет, на уровне >1 и неравномерных кластерах может как угодно сплитится
created_at: 2025-05-26T08:34:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -118,18 +126,95 @@ Y_UNIT_TEST_SUITE (VectorIndexBuildTest) {
             meteringMessages << event->Get()->MeteringJson;
         });
 
-        TestBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
+        TBlockEvents<TEvDataShard::TEvReshuffleKMeansRequest> reshuffleBlocker(runtime, [&](const auto& ) {
+            return true;
+        });
+
+        AsyncBuildVectorIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "index1", "embedding");
         ui64 buildIndexId = txId;
 
+        // Wait for the first "reshuffle" request (samples will be already collected on the first level)
+        // and reboot the scheme shard to verify that its intermediate state is persisted correctly.
+        // The bug checked here: Sample.Probability was not persisted (#18236).
+        runtime.WaitFor("ReshuffleKMeansRequest", [&]{ return reshuffleBlocker.size(); });
+        Cerr << "... rebooting scheme shard" << Endl;
+        RebootTablet(runtime, tenantSchemeShard, runtime.AllocateEdgeActor());
+
+        // Now wait for the 1st level to be finalized
+        TBlockEvents<TEvSchemeShard::TEvModifySchemeTransaction> level1Blocker(runtime, [&](auto& ev) {
+            const auto& record = ev->Get()->Record;
+            if (record.GetTransaction(0).GetOperationType() == NKikimrSchemeOp::ESchemeOpInitiateBuildIndexImplTable) {
+                txId = record.GetTxId();
+                return true;
+            }
+            return false;
+        });
+        reshuffleBlocker.Stop();
+        reshuffleBlocker.Unblock(reshuffleBlocker.size());
+
+        // Reshard the first level table (0build)
+        // First bug checked here: after restarting the schemeshard during reshuffle it
+        //   generates more clusters than requested and dies with VERIFY on shard boundaries (#18278).
+        // Second bug checked here: posting table doesn't contain all rows from the main table
+        //   when the build table is resharded during build (#18355).
+        {
+            auto indexDesc = DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", true, true, true);
+            auto parts = indexDesc.GetPathDescription().GetTablePartitions();
+            UNIT_ASSERT_EQUAL(parts.size(), 4);
+            ui64 cluster = 1;
+            for (const auto & x: parts) {
+                TestSplitTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB/Table/index1/indexImplPostingTable0build", Sprintf(R"(
path: ydb/core/tx/schemeshard/ut_index_build/ut_vector_index_build.cpp
user: login: vitalif
body: это да, но это при 3 уровнях, а там ещё нет теста на 3 уровня, только на 2
created_at: 2025-05-26T08:46:17Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-23T09:25:35Z
body: <!-- status pr=18724, validate PR description status -->
:green_circle: `2025-05-23 10:32:05 UTC` The validation of the Pull Request description is successful.
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-23T09:26:55Z
body: <!-- status pr=18724, preset=release-asan, run=43920 -->
:white_circle: `2025-05-23 09:26:55 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15206967101/job/42772260215) **linux-x86_64-release-asan** for f1867b08f6880627364784b5d8aa378a9505d0d5 has started.
:white_circle: `2025-05-23 09:27:06 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15206967101/ya-x86-64-asan/index.html)
:white_circle: `2025-05-23 09:30:02 UTC` ya make is running...
:red_circle: `2025-05-23 09:39:17 UTC` Build failed, see the [logs](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15206967101/ya-x86-64-asan/ya_make_output.txt). Also see [fail summary](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15206967101/ya-x86-64-asan/try_1/fail_summary.txt)
:yellow_circle: `2025-05-23 09:39:34 UTC` ydbd size **3.9 GiB** changed* by **+209.0 KiB**, which is >= 100.0 KiB vs main: **Warning**
|[ydbd size dash](https://datalens.yandex/cu6hzmpaki700)|main: 985adf4d2e990d931958ed19662b61b9987b07e5 |merge: f1867b08f6880627364784b5d8aa378a9505d0d5 |diff | diff %|
|:--- | ---: | ---: | ---: | ---: |
|ydbd size|**4 146 183 528** Bytes |**4 146 397 544** Bytes|**+209.0 KiB**|**+0.005%**|
|ydbd stripped size|**1 439 832 600** Bytes|**1 439 811 736** Bytes|**-20.4 KiB**|**-0.001%**|

<sup>*please be aware that the difference is based on comparing your commit and the last completed build from the post-commit, check [comparation](https://github.com/ydb-platform/ydb/compare/985adf4d2e990d931958ed19662b61b9987b07e5..f1867b08f6880627364784b5d8aa378a9505d0d5)</sup>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-23T09:28:42Z
body: <!-- status pr=18724, preset=relwithdebinfo, run=43920 -->
:white_circle: `2025-05-23 09:28:41 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15206967101/job/42772260211) **linux-x86_64-relwithdebinfo** for f1867b08f6880627364784b5d8aa378a9505d0d5 has started.
:white_circle: `2025-05-23 09:28:52 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15206967101/ya-x86-64/index.html)
:white_circle: `2025-05-23 09:31:43 UTC` ya make is running...
:red_circle: `2025-05-23 09:37:27 UTC` Build failed, see the [logs](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15206967101/ya-x86-64/ya_make_output.txt). Also see [fail summary](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15206967101/ya-x86-64/try_1/fail_summary.txt)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-26T08:42:10Z
body: <!-- status pr=18724, preset=release-asan, run=44078 -->
:white_circle: `2025-05-26 10:47:45 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15249848887/job/42890861166) **linux-x86_64-release-asan** for 6d850c4ccb7ea43fd85054164819776825688a4d has started.
:white_circle: `2025-05-26 10:47:56 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15249848887/ya-x86-64-asan/index.html)
:white_circle: `2025-05-26 10:51:05 UTC` ya make is running...
:red_circle: `2025-05-26 11:03:05 UTC` Build failed, see the [logs](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15249848887/ya-x86-64-asan/ya_make_output.txt). Also see [fail summary](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15249848887/ya-x86-64-asan/try_1/fail_summary.txt)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-26T08:43:01Z
body: <!-- status pr=18724, preset=relwithdebinfo, run=44078 -->
:white_circle: `2025-05-26 10:47:45 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15249848887/job/42890861170) **linux-x86_64-relwithdebinfo** for 6d850c4ccb7ea43fd85054164819776825688a4d has started.
:white_circle: `2025-05-26 10:47:56 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15249848887/ya-x86-64/index.html)
:white_circle: `2025-05-26 10:50:49 UTC` ya make is running...
:red_circle: `2025-05-26 10:58:17 UTC` Build failed, see the [logs](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15249848887/ya-x86-64/ya_make_output.txt). Also see [fail summary](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15249848887/ya-x86-64/try_1/fail_summary.txt)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-26T13:47:16Z
body: <!-- status pr=18724, preset=release-asan, run=44150 -->
:white_circle: `2025-05-26 13:47:15 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15255549041/job/42902181507) **linux-x86_64-release-asan** for c8bb2104a821f91c74fa5bdcf4d2af8a6277841c has started.
:white_circle: `2025-05-26 13:47:26 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255549041/ya-x86-64-asan/index.html)
:white_circle: `2025-05-26 13:50:17 UTC` ya make is running...
:black_circle: `2025-05-26 14:00:08 UTC` Check cancelled
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-26T13:47:16Z
body: <!-- status pr=18724, preset=relwithdebinfo, run=44150 -->
:white_circle: `2025-05-26 13:47:16 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15255549041/job/42902181527) **linux-x86_64-relwithdebinfo** for c8bb2104a821f91c74fa5bdcf4d2af8a6277841c has started.
:white_circle: `2025-05-26 13:47:27 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255549041/ya-x86-64/index.html)
:white_circle: `2025-05-26 13:50:26 UTC` ya make is running...
:black_circle: `2025-05-26 14:00:01 UTC` Check cancelled
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-26T14:03:35Z
body: <!-- status pr=18724, preset=relwithdebinfo, run=44157 -->
:white_circle: `2025-05-26 14:03:34 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15255851057/job/42903243321) **linux-x86_64-relwithdebinfo** for 36f851a01033e3e812d691c6f141633bdbff90f2 has started.
:white_circle: `2025-05-26 14:03:46 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/index.html)
:white_circle: `2025-05-26 14:06:37 UTC` ya make is running...
:yellow_circle: `2025-05-26 15:20:00 UTC` Some tests failed, follow the links below. Going to retry failed tests...

<details>


[Test history](https://nebius.testmo.net/automation/runs/view/167833) | [Ya make output](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/ya_make_output.txt) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/test_bloat/tree_map.html)
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/ydb/tree/main/.github/config/muted_ya.txt "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [21387](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/ya-test.html) | [20001](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/ya-test.html#PASS) | 0 | [4](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/ya-test.html#FAIL) | [1347](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/ya-test.html#SKIP) | [35](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/ya-test.html#MUTE) |

</details>

:white_circle: `2025-05-26 15:21:45 UTC` ya make is running... (failed tests rerun, try 2)
:yellow_circle: `2025-05-26 16:08:58 UTC` Some tests failed, follow the links below. Going to retry failed tests...

<details>


[Test history](https://nebius.testmo.net/automation/runs/view/167882) | [Ya make output](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/ya_make_output.txt) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/test_bloat/tree_map.html) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/test_bloat/tree_map.html)
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/ydb/tree/main/.github/config/muted_ya.txt "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [156 (only retried tests)](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/ya-test.html) | [115](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/ya-test.html#PASS) | 0 | [1](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/ya-test.html#FAIL) | [8](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/ya-test.html#SKIP) | [32](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/ya-test.html#MUTE) |

</details>

:white_circle: `2025-05-26 16:09:09 UTC` ya make is running... (failed tests rerun, try 3)
:green_circle: `2025-05-26 16:48:18 UTC` Tests successful.

[Test history](https://nebius.testmo.net/automation/runs/view/167921) | [Ya make output](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/ya_make_output.txt) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_1/test_bloat/tree_map.html) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_2/test_bloat/tree_map.html) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_3/test_bloat/tree_map.html)
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/ydb/tree/main/.github/config/muted_ya.txt "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [140 (only retried tests)](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_3/ya-test.html) | [109](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_3/ya-test.html#PASS) | 0 | 0 | 0 | [31](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64/try_3/ya-test.html#MUTE) |

:green_circle: `2025-05-26 16:48:30 UTC` Build successful.
:yellow_circle: `2025-05-26 16:48:51 UTC` ydbd size **2.2 GiB** changed* by **+248.4 KiB**, which is >= 100.0 KiB vs main: **Warning**
|[ydbd size dash](https://datalens.yandex/cu6hzmpaki700)|main: d617cc14c32e50f51615fe1d3a4c783289b10641 |merge: 36f851a01033e3e812d691c6f141633bdbff90f2 |diff | diff %|
|:--- | ---: | ---: | ---: | ---: |
|ydbd size|**2 358 248 400** Bytes |**2 358 502 800** Bytes|**+248.4 KiB**|**+0.011%**|
|ydbd stripped size|**495 390 920** Bytes|**495 444 232** Bytes|**+52.1 KiB**|**+0.011%**|

<sup>*please be aware that the difference is based on comparing your commit and the last completed build from the post-commit, check [comparation](https://github.com/ydb-platform/ydb/compare/d617cc14c32e50f51615fe1d3a4c783289b10641..36f851a01033e3e812d691c6f141633bdbff90f2)</sup>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-26T14:03:36Z
body: <!-- status pr=18724, preset=release-asan, run=44157 -->
:white_circle: `2025-05-26 14:03:35 UTC` Pre-commit [check](https://github.com/ydb-platform/ydb/actions/runs/15255851057/job/42903243333) **linux-x86_64-release-asan** for 36f851a01033e3e812d691c6f141633bdbff90f2 has started.
:white_circle: `2025-05-26 14:03:47 UTC` Artifacts will be uploaded [here](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/index.html)
:white_circle: `2025-05-26 14:06:53 UTC` ya make is running...
:yellow_circle: `2025-05-26 15:52:49 UTC` Some tests failed, follow the links below. This fail is not in blocking policy yet Going to retry failed tests...

<details>


[Test history](https://nebius.testmo.net/automation/runs/view/167834) | [Ya make output](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/ya_make_output.txt) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/test_bloat/tree_map.html)
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/ydb/tree/main/.github/config/muted_ya.txt "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [13416](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/ya-test.html) | [13222](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/ya-test.html#PASS) | 0 | [124](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/ya-test.html#FAIL) | [45](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/ya-test.html#SKIP) | [25](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/ya-test.html#MUTE) |

</details>

:white_circle: `2025-05-26 15:53:57 UTC` ya make is running... (failed tests rerun, try 2)
:yellow_circle: `2025-05-26 16:29:17 UTC` Some tests failed, follow the links below. This fail is not in blocking policy yet Going to retry failed tests...

<details>


[Test history](https://nebius.testmo.net/automation/runs/view/167911) | [Ya make output](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/ya_make_output.txt) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/test_bloat/tree_map.html) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/test_bloat/tree_map.html)
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/ydb/tree/main/.github/config/muted_ya.txt "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [2066 (only retried tests)](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/ya-test.html) | [1968](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/ya-test.html#PASS) | 0 | [56](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/ya-test.html#FAIL) | [20](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/ya-test.html#SKIP) | [22](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/ya-test.html#MUTE) |

</details>

:white_circle: `2025-05-26 16:29:37 UTC` ya make is running... (failed tests rerun, try 3)
:yellow_circle: `2025-05-26 16:59:54 UTC` Some tests failed, follow the links below. This fail is not in blocking policy yet

[Test history](https://nebius.testmo.net/automation/runs/view/167945) | [Ya make output](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/ya_make_output.txt) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_1/test_bloat/tree_map.html) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_2/test_bloat/tree_map.html) | [Test bloat](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_3/test_bloat/tree_map.html)
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/ydb/tree/main/.github/config/muted_ya.txt "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [1164 (only retried tests)](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_3/ya-test.html) | [1076](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_3/ya-test.html#PASS) | 0 | [44](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_3/ya-test.html#FAIL) | [23](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_3/ya-test.html#SKIP) | [21](https://storage.yandexcloud.net/ydb-gh-logs/ydb-platform/ydb/PR-check/15255851057/ya-x86-64-asan/try_3/ya-test.html#MUTE) |

:green_circle: `2025-05-26 17:00:08 UTC` Build successful.
:yellow_circle: `2025-05-26 17:00:39 UTC` ydbd size **3.9 GiB** changed* by **+428.1 KiB**, which is >= 100.0 KiB vs main: **Warning**
|[ydbd size dash](https://datalens.yandex/cu6hzmpaki700)|main: d617cc14c32e50f51615fe1d3a4c783289b10641 |merge: 36f851a01033e3e812d691c6f141633bdbff90f2 |diff | diff %|
|:--- | ---: | ---: | ---: | ---: |
|ydbd size|**4 147 273 176** Bytes |**4 147 711 504** Bytes|**+428.1 KiB**|**+0.011%**|
|ydbd stripped size|**1 440 065 016** Bytes|**1 440 208 824** Bytes|**+140.4 KiB**|**+0.010%**|

<sup>*please be aware that the difference is based on comparing your commit and the last completed build from the post-commit, check [comparation](https://github.com/ydb-platform/ydb/compare/d617cc14c32e50f51615fe1d3a4c783289b10641..36f851a01033e3e812d691c6f141633bdbff90f2)</sup>
author_association: NONE
user: login: vitalif
created_at: 2025-05-27T11:09:10Z
body: > На будущее попрошу не смешивать разные изменения в один pr. Здесь у тебя как минимум багфикс и рефакторинг в тестах.

Да, ОК, я в принципе всегда стараюсь рефакторить отдельно, но тут вроде небольшая правка - я просто себе выносил для нового теста пару нужных методов, и заодно пришлось их использования "дедуплицировать") поэтому вроде показалось, что тут не критично.
author_association: COLLABORATOR