diff options
author | ijon <ijon@yandex-team.com> | 2023-03-17 12:21:32 +0300 |
---|---|---|
committer | ijon <ijon@yandex-team.com> | 2023-03-17 12:21:32 +0300 |
commit | 781b388f6f446cefcaa7fa4d787342b56e584f8d (patch) | |
tree | a11a527f3060b9b84eed16250274e22287b1118c | |
parent | 0355d87069435442cdfe6f9ef56344128972df98 (diff) | |
download | ydb-781b388f6f446cefcaa7fa4d787342b56e584f8d.tar.gz |
schemeshard: add test for index table's split-by-load behavior
- add test to verify that split-by-load for index tables adopts main table's current
partition count as index table's MaxPartitionsCount (but only if it isn't explicitly set)
- remove unconditional setting of MaxPartitionsCount for any index
table on creation
-rw-r--r-- | ydb/core/tx/schemeshard/schemeshard__table_stats.cpp | 3 | ||||
-rw-r--r-- | ydb/core/tx/schemeshard/schemeshard_utils.cpp | 1 | ||||
-rw-r--r-- | ydb/core/tx/schemeshard/ut_base.cpp | 10 | ||||
-rw-r--r-- | ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp | 16 | ||||
-rw-r--r-- | ydb/core/tx/schemeshard/ut_helpers/ls_checks.h | 4 | ||||
-rw-r--r-- | ydb/core/tx/schemeshard/ut_split_merge.cpp | 430 |
6 files changed, 454 insertions, 10 deletions
diff --git a/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp b/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp index 30a6a0e1142..8e96b09715e 100644 --- a/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp @@ -331,7 +331,6 @@ bool TTxStoreTableStats::PersistSingleStats(const TPathId& pathId, return false; } - if (rec.GetShardState() != NKikimrTxDataShard::Ready) { return true; } @@ -423,7 +422,7 @@ void TSchemeShard::Handle(TEvDataShard::TEvPeriodicTableStats::TPtr& ev, const T << " cpuUsage " << tabletMetrics.GetCPU()/10000.0); TStatsId statsId(pathId, datashardId); - + switch(TableStatsQueue.Add(statsId, ev.Release())) { case READY: ExecuteTableStatsBatch(ctx); diff --git a/ydb/core/tx/schemeshard/schemeshard_utils.cpp b/ydb/core/tx/schemeshard/schemeshard_utils.cpp index b94c2a79f8d..b2392abfda6 100644 --- a/ydb/core/tx/schemeshard/schemeshard_utils.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_utils.cpp @@ -414,7 +414,6 @@ NKikimrSchemeOp::TPartitionConfig PartitionConfigForIndexes( } else { result.MutablePartitioningPolicy()->SetSizeToSplit(2_GB); result.MutablePartitioningPolicy()->SetMinPartitionsCount(1); - result.MutablePartitioningPolicy()->SetMaxPartitionsCount(5000); } if (baseTablePartitionConfig.HasPipelineConfig()) { result.MutablePipelineConfig()->CopyFrom(baseTablePartitionConfig.GetPipelineConfig()); diff --git a/ydb/core/tx/schemeshard/ut_base.cpp b/ydb/core/tx/schemeshard/ut_base.cpp index e81a0c5bf14..74d08de026f 100644 --- a/ydb/core/tx/schemeshard/ut_base.cpp +++ b/ydb/core/tx/schemeshard/ut_base.cpp @@ -1777,7 +1777,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) { NLs::IndexKeys({"value1"})}); TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/DirA/Table1/UserDefinedIndexByValue1/indexImplTable", true, true), {NLs::Finished, - NLs::MaxPartitionsCountEqual(5000), + NLs::NoMaxPartitionsCount, NLs::SizeToSplitEqual(2<<30)}); // 2G TestDescribeResult(DescribePrivatePath(runtime, "/MyRoot/DirA/Table1/UserDefinedIndexByValues"), {NLs::Finished, @@ -10273,7 +10273,8 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) { NLs::PathVersionEqual(4), NLs::PartitionCount(1), NLs::MinPartitionsCountEqual(1), - NLs::MaxPartitionsCountEqual(5000)}); + NLs::NoMaxPartitionsCount + }); TestSplitTable(runtime, ++txId, "/MyRoot/table/indexByValue/indexImplTable", R"( @@ -10295,7 +10296,8 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) { NLs::PathVersionEqual(5), NLs::PartitionCount(3), NLs::MinPartitionsCountEqual(1), - NLs::MaxPartitionsCountEqual(5000)}); + NLs::NoMaxPartitionsCount + }); // request without token TestAlterTable(runtime, ++txId, "/MyRoot/table/indexByValue/", R"( @@ -10398,7 +10400,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) { {NLs::PathExist, NLs::PartitionCount(1), NLs::MinPartitionsCountEqual(1), - NLs::MaxPartitionsCountEqual(5000), + NLs::NoMaxPartitionsCount, NLs::SizeToSplitEqual(100500)}); } diff --git a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp index 0dfe288f18f..75a374c57d4 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp +++ b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp @@ -893,12 +893,28 @@ TCheckFunc MinPartitionsCountEqual(ui32 count) { }; } +void HasMinPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record) { + UNIT_ASSERT(record.GetPathDescription().GetTable().GetPartitionConfig().GetPartitioningPolicy().HasMinPartitionsCount()); +} + +void NoMinPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record) { + UNIT_ASSERT(!record.GetPathDescription().GetTable().GetPartitionConfig().GetPartitioningPolicy().HasMinPartitionsCount()); +} + TCheckFunc MaxPartitionsCountEqual(ui32 count) { return [=] (const NKikimrScheme::TEvDescribeSchemeResult& record) { UNIT_ASSERT_VALUES_EQUAL(record.GetPathDescription().GetTable().GetPartitionConfig().GetPartitioningPolicy().GetMaxPartitionsCount(), count); }; } +void HasMaxPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record) { + UNIT_ASSERT(record.GetPathDescription().GetTable().GetPartitionConfig().GetPartitioningPolicy().HasMaxPartitionsCount()); +} + +void NoMaxPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record) { + UNIT_ASSERT(!record.GetPathDescription().GetTable().GetPartitionConfig().GetPartitioningPolicy().HasMaxPartitionsCount()); +} + TCheckFunc PartitioningByLoadStatus(bool status) { return [=] (const NKikimrScheme::TEvDescribeSchemeResult& record) { UNIT_ASSERT_VALUES_EQUAL(record.GetPathDescription().GetTable().GetPartitionConfig().GetPartitioningPolicy().GetSplitByLoadSettings().GetEnabled(), status); diff --git a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h index d76c74d41f3..ed99b31869e 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h +++ b/ydb/core/tx/schemeshard/ut_helpers/ls_checks.h @@ -97,7 +97,11 @@ namespace NLs { TCheckFunc FollowerGroups(const TVector<NKikimrHive::TFollowerGroup>& followerGroup = TVector<NKikimrHive::TFollowerGroup>{}); TCheckFunc SizeToSplitEqual(ui32 size); TCheckFunc MinPartitionsCountEqual(ui32 count); + void HasMinPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record); + void NoMinPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record); TCheckFunc MaxPartitionsCountEqual(ui32 count); + void HasMaxPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record); + void NoMaxPartitionsCount(const NKikimrScheme::TEvDescribeSchemeResult& record); TCheckFunc PartitioningByLoadStatus(bool status); TCheckFunc ColumnFamiliesCount(ui32 size); TCheckFunc ColumnFamiliesHas(ui32 familyId); diff --git a/ydb/core/tx/schemeshard/ut_split_merge.cpp b/ydb/core/tx/schemeshard/ut_split_merge.cpp index 52c490efd54..acbcfb959ed 100644 --- a/ydb/core/tx/schemeshard/ut_split_merge.cpp +++ b/ydb/core/tx/schemeshard/ut_split_merge.cpp @@ -1,13 +1,12 @@ #include <ydb/core/tx/schemeshard/ut_helpers/helpers.h> - -#include <ydb/library/yql/minikql/mkql_node.h> +#include <ydb/core/tx/schemeshard/schemeshard_utils.h> using namespace NKikimr; using namespace NKikimr::NMiniKQL; using namespace NSchemeShard; using namespace NSchemeShardUT_Private; -Y_UNIT_TEST_SUITE(TSchemeShardSplitTest) { +Y_UNIT_TEST_SUITE(TSchemeShardSplitBySizeTest) { Y_UNIT_TEST(Test) { } @@ -407,3 +406,428 @@ Y_UNIT_TEST_SUITE(TSchemeShardSplitTest) { } } + +namespace { + +using NFmt::TPrintableTypedCells; + +TString ToSerialized(ui64 key) { + const auto cell = TCell::Make(key); + const TSerializedCellVec saved(TSerializedCellVec::Serialize(TArrayRef<const TCell>(&cell, 1))); + return TString(saved.GetBuffer()); +} + +ui64 FromSerialized(const TString& buf) { + TSerializedCellVec saved(buf); + // Cerr << "TEST FromSerialized, " << TPrintableTypedCells(saved.GetCells(), {NScheme::TTypeInfo(NScheme::NTypeIds::Uint64), NScheme::TTypeInfo(NScheme::NTypeIds::Uint64)}) << Endl; + auto& cell = saved.GetCells()[0]; + // Cerr << "TEST FromSerialized, cell " << cell.IsInline() << ", " << cell.IsNull() << ", " << cell.Size() << Endl; + return cell.IsNull() ? 0 : cell.AsValue<ui64>(); +} + +void HistogramAddBucket(NKikimrTableStats::THistogram& hist, ui64 key, ui64 value) { + auto bucket = hist.AddBuckets(); + bucket->SetKey(ToSerialized(key)); + bucket->SetValue(value); +}; + +constexpr ui64 CpuLoadMicroseconds(const ui64 percent) { + return percent * 1000000 / 100; +} + +// const ui64 CpuLoadPercent(const ui64 microseconds) { +// return microseconds * 100 / 1000000; +// } + +// Quick and dirty simulator for cpu overload and key range splitting of datashards. +// Should be used in test runtime EventObservers. +// +// Assumed index configuration: 1 initial datashard, Uint64 key. +// +struct TLoadAndSplitSimulator { + NKikimrTabletBase::TMetrics MetricsPatch; + NKikimrTableStats::THistogram KeyAccessHistogramPatch; + ui64 TableLocalPathId; + + std::map<ui64, std::pair<ui64, ui64>> DatashardsKeyRanges; + TInstant LastSplitAckTime; + ui64 SplitAckCount = 0; + ui64 PeriodicTableStatsCount = 0; + ui64 KeyAccessSampleReqCount = 0; + ui64 SplitReqCount = 0; + + TLoadAndSplitSimulator(ui64 tableLocalPathId, ui64 initialDatashardId, ui64 targetCpuLoadPercent) + : TableLocalPathId(tableLocalPathId) + { + MetricsPatch.SetCPU(CpuLoadMicroseconds(targetCpuLoadPercent)); + + //NOTE: histogram must have at least 3 buckets with different keys to be able to produce split key + // (see ydb/core/tx/schemeshard/schemeshard__table_stats_histogram.cpp, DoFindSplitKey() and ChooseSplitKeyByKeySample()) + HistogramAddBucket(KeyAccessHistogramPatch, 999998, 1000); + HistogramAddBucket(KeyAccessHistogramPatch, 999999, 1000); + HistogramAddBucket(KeyAccessHistogramPatch, 1000000, 1000); + + DatashardsKeyRanges[initialDatashardId] = std::make_pair(0, 1000000); + + Cerr << "TEST TLoadAndSplitSimulator for table id " << TableLocalPathId + << ", target CPU load " << targetCpuLoadPercent << "%" + << Endl; + } + + void ChangeEvent(TAutoPtr<IEventHandle>& ev) { + switch (ev->GetTypeRewrite()) { + case TEvDataShard::EvPeriodicTableStats: + // replace real stats with the simulated ones + { + auto x = reinterpret_cast<TEvDataShard::TEvPeriodicTableStats::TPtr*>(&ev); + auto& record = (*x).Get()->Get()->Record; + + if (record.GetTableLocalId() != TableLocalPathId) { + return; + } + + auto prevCPU = record.GetTabletMetrics().GetCPU(); + record.MutableTabletMetrics()->MergeFrom(MetricsPatch); + auto newCPU = record.GetTabletMetrics().GetCPU(); + + Cerr << "TEST TLoadAndSplitSimulator for table id " << TableLocalPathId + << ", intercept EvPeriodicTableStats, from datashard " << record.GetDatashardId() + << ", patch CPU: " << prevCPU << "->" << newCPU + << Endl; + + ++PeriodicTableStatsCount; + } + break; + case TEvDataShard::EvGetTableStats: + // count requests for key access samples, as they indicate consideration of performing a split + { + auto x = reinterpret_cast<TEvDataShard::TEvGetTableStats::TPtr*>(&ev); + auto& record = (*x).Get()->Get()->Record; + + if (record.GetTableId() != TableLocalPathId) { + return; + } + + // Cerr << "TEST TLoadAndSplitSimulator for table id " << TableLocalPathId + // << ", intercept EvGetTableStats" << Endl; + + if (record.GetCollectKeySample()) { + ++KeyAccessSampleReqCount; + } + } + break; + case TEvDataShard::EvGetTableStatsResult: + // replace real key access samples with the simulated ones + { + auto x = reinterpret_cast<TEvDataShard::TEvGetTableStatsResult::TPtr*>(&ev); + auto& record = (*x).Get()->Get()->Record; + + if (record.GetTableLocalId() != TableLocalPathId) { + return; + } + + record.MutableTableStats()->MutableKeyAccessSample()->CopyFrom(KeyAccessHistogramPatch); + + auto [start, end] = DatashardsKeyRanges[record.GetDatashardId()]; + //NOTE: zero end means infinity -- this is a final shard + if (end == 0) { + end = 1000000; + } + ui64 splitPoint = (end - start) / 2; + record.MutableTableStats()->MutableKeyAccessSample()->MutableBuckets(0)->SetKey(ToSerialized(splitPoint - 1)); + record.MutableTableStats()->MutableKeyAccessSample()->MutableBuckets(1)->SetKey(ToSerialized(splitPoint)); + record.MutableTableStats()->MutableKeyAccessSample()->MutableBuckets(2)->SetKey(ToSerialized(splitPoint + 1)); + + Cerr << "TEST TLoadAndSplitSimulator for table id " << TableLocalPathId + << ", intercept EvGetTableStatsResult, from datashard " << record.GetDatashardId() + << ", patch KeyAccessSample: split point " << splitPoint + << Endl; + } + break; + case TEvDataShard::EvSplit: + // save key ranges of the new datashards + { + auto x = reinterpret_cast<TEvDataShard::TEvSplit::TPtr*>(&ev); + auto& record = (*x).Get()->Get()->Record; + + // remove info for the source shard(s) that will be splitted + // (split will have single source range) + for (const auto& i : record.GetSplitDescription().GetSourceRanges()) { + DatashardsKeyRanges.erase(i.GetTabletID()); + } + // add info for destination shards + for (const auto& i : record.GetSplitDescription().GetDestinationRanges()) { + auto& [start, end] = DatashardsKeyRanges[i.GetTabletID()]; + start = FromSerialized(i.GetKeyRangeBegin()); + //NOTE: empty KeyRangeEnd means infinity + auto keyRangeEnd = i.GetKeyRangeEnd(); + end = (keyRangeEnd.size() > 0) ? FromSerialized(keyRangeEnd) : 0; + } + + Cerr << "TEST TLoadAndSplitSimulator for table id " << TableLocalPathId + << ", intercept EvSplit, to datashard " << record.GetSplitDescription().GetSourceRanges(0).GetTabletID() + << ", event:" + << Endl + << record.DebugString() + << Endl; + + ++SplitReqCount; + } + break; + case TEvDataShard::EvSplitAck: + // count splits + { + auto x = reinterpret_cast<TEvDataShard::TEvSplitAck::TPtr*>(&ev); + auto& record = (*x).Get()->Get()->Record; + + auto now = TInstant::Now(); + auto elapsed = now - LastSplitAckTime; + LastSplitAckTime = now; + + Cerr << "TEST TLoadAndSplitSimulator for table id " << TableLocalPathId + << ", intercept EvSplitAck, from datashard " << record.GetTabletId() + << ", " << elapsed << " since last split ack" + << Endl; + + ++SplitAckCount; + } + break; + } + }; +}; + +TTestEnv SetupEnv(TTestBasicRuntime &runtime) { + TTestEnvOptions opts; + opts.EnableBackgroundCompaction(false); + + TTestEnv env(runtime, opts); + + NDataShard::gDbStatsReportInterval = TDuration::Seconds(0); + NDataShard::gDbStatsDataSizeResolution = 10; + NDataShard::gDbStatsRowCountResolution = 10; + + { + auto& appData = runtime.GetAppData(); + + appData.FeatureFlags.SetEnablePersistentPartitionStats(true); + + // disable batching + appData.SchemeShardConfig.SetStatsBatchTimeoutMs(0); + appData.SchemeShardConfig.SetStatsMaxBatchSize(0); + } + + runtime.SetLogPriority(NKikimrServices::FLAT_TX_SCHEMESHARD, NActors::NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NActors::NLog::PRI_DEBUG); + + // apply config changes to schemeshard via reboot + //FIXME: make it possible to set config before initial boot + GracefulRestartTablet(runtime, TTestTxConfig::SchemeShard, runtime.AllocateEdgeActor()); + + return env; +} + +} // anonymous namespace + +Y_UNIT_TEST_SUITE(TSchemeShardSplitByLoad) { + + void SplitByLoad(TTestBasicRuntime &runtime, const TString &tablePath, ui32 targetCpuLoadPercent) { + auto tableInfo = DescribePrivatePath(runtime, tablePath, true, true); + Cerr << "TEST table initial state:" << Endl << tableInfo.DebugString() << Endl; + + const ui64 tableLocalPathId = tableInfo.GetPathDescription().GetSelf().GetPathId(); + const ui64 initialDatashardId = tableInfo.GetPathDescription().GetTablePartitions(0).GetDatashardId(); + + TLoadAndSplitSimulator simulator(tableLocalPathId, initialDatashardId, targetCpuLoadPercent); + + runtime.SetObserverFunc([&simulator](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& event) { + simulator.ChangeEvent(event); + return TTestActorRuntime::EEventAction::PROCESS; + }); + { + TDispatchOptions opts; + opts.CustomFinalCondition = [&simulator]() { + auto now = TInstant::Now(); + // Cerr << "TEST SplitByLoad, CustomFinalCondition, SplitAckCount " << simulator.SplitAckCount << ", " << (now - simulator.LastSplitAckTime) << " since last split" << Endl; + return simulator.SplitAckCount > 0 && (now - simulator.LastSplitAckTime) > TDuration::Seconds(3); + }; + runtime.DispatchEvents(opts/*, TDuration::Seconds(120)*/); + } + Cerr << "TEST SplitByLoad, splitted " << simulator.SplitAckCount << " times" + << ", datashard count " << simulator.DatashardsKeyRanges.size() + << Endl; + // Cerr << "TEST SplitByLoad, PeriodicTableStats " << simulator.PeriodicTableStatsCount << Endl; + // Cerr << "TEST SplitByLoad, KeyAccessSampleReq " << simulator.KeyAccessSampleReqCount << Endl; + // Cerr << "TEST SplitByLoad, SplitReq " << simulator.SplitReqCount << Endl; + } + + void NoSplitByLoad(TTestBasicRuntime &runtime, const TString &tablePath, ui32 targetCpuLoadPercent) { + auto tableInfo = DescribePrivatePath(runtime, tablePath, true, true); + Cerr << "TEST table initial state:" << Endl << tableInfo.DebugString() << Endl; + + const ui64 tableLocalPathId = tableInfo.GetPathDescription().GetSelf().GetPathId(); + const ui64 initialDatashardId = tableInfo.GetPathDescription().GetTablePartitions(0).GetDatashardId(); + + TLoadAndSplitSimulator simulator(tableLocalPathId, initialDatashardId, targetCpuLoadPercent); + + runtime.SetObserverFunc([&simulator](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& event) { + simulator.ChangeEvent(event); + return TTestActorRuntime::EEventAction::PROCESS; + }); + { + TDispatchOptions opts; + opts.CustomFinalCondition = [&simulator]() { + // Cerr << "TEST SplitByLoad, PeriodicTableStats " << simulator.PeriodicTableStatsCount << ", KeyAccessSampleReq " << simulator.KeyAccessSampleReqCount << Endl; + return simulator.PeriodicTableStatsCount > 10 && simulator.KeyAccessSampleReqCount == 0; + }; + runtime.DispatchEvents(opts, TDuration::Seconds(60)); + } + Cerr << "TEST SplitByLoad, splitted " << simulator.SplitAckCount << " times" + << ", datashard count " << simulator.DatashardsKeyRanges.size() + << Endl; + // Cerr << "TEST SplitByLoad, PeriodicTableStats " << simulator.PeriodicTableStatsCount << Endl; + // Cerr << "TEST SplitByLoad, KeyAccessSampleReq " << simulator.KeyAccessSampleReqCount << Endl; + // Cerr << "TEST SplitByLoad, SplitReq " << simulator.SplitReqCount << Endl; + } + + Y_UNIT_TEST(TableSplitsUpToMaxPartitionsCount) { + TTestBasicRuntime runtime; + auto env = SetupEnv(runtime); + + const ui32 expectedPartitionCount = 5; + const ui32 cpuLoadThreshold = 1; // percents + const ui64 cpuLoadSimulated = 100; // percents + + const auto tableScheme = Sprintf( + R"( + Name: "Table" + Columns { Name: "key" Type: "Uint64"} + Columns { Name: "value" Type: "Uint64"} + KeyColumnNames: ["key"] + UniformPartitionsCount: 1 + PartitionConfig { + PartitioningPolicy { + + MaxPartitionsCount: %d # replacement field for required number of partitions + + SplitByLoadSettings: { + Enabled: true + + CpuPercentageThreshold: %d # replacement field for cpu load split threshold, percents + + } + } + } + )", + expectedPartitionCount, + cpuLoadThreshold + ); + + ui64 txId = 100; + TestCreateTable(runtime, ++txId, "/MyRoot", tableScheme); + env.TestWaitNotification(runtime, txId); + + SplitByLoad(runtime, "/MyRoot/Table", cpuLoadSimulated); + + auto tableInfo = DescribePrivatePath(runtime, "/MyRoot/Table", true, true); + Cerr << "TEST table final state:" << Endl << tableInfo.DebugString() << Endl; + TestDescribeResult(tableInfo, {NLs::PartitionCount(expectedPartitionCount)}); + } + + Y_UNIT_TEST(IndexTableSplitsUpToMainTableCurrentPartitionCount) { + TTestBasicRuntime runtime; + auto env = SetupEnv(runtime); + + const ui32 expectedPartitionCount = 5; + const ui32 cpuLoadThreshold = 1; // percents + const ui64 cpuLoadSimulated = 100; // percents + + const auto mainTableScheme = Sprintf( + R"( + TableDescription { + Name: "Table" + Columns { Name: "key" Type: "Uint64"} + Columns { Name: "value" Type: "Uint64"} + KeyColumnNames: ["key"] + + UniformPartitionsCount: %d # replacement field for required number of partitions + + PartitionConfig { + PartitioningPolicy { + MaxPartitionsCount: 10 + SplitByLoadSettings: { + Enabled: true + + CpuPercentageThreshold: %d # replacement field for cpu load split threshold, percents + + } + } + } + } + IndexDescription { + Name: "by-value" + KeyColumnNames: ["value"] + } + )", + expectedPartitionCount, + cpuLoadThreshold + ); + + ui64 txId = 100; + TestCreateIndexedTable(runtime, ++txId, "/MyRoot", mainTableScheme); + env.TestWaitNotification(runtime, txId); + + SplitByLoad(runtime, "/MyRoot/Table/by-value/indexImplTable", cpuLoadSimulated); + + auto tableInfo = DescribePrivatePath(runtime, "/MyRoot/Table/by-value/indexImplTable", true, true); + Cerr << "TEST table final state:" << Endl << tableInfo.DebugString() << Endl; + TestDescribeResult(tableInfo, {NLs::PartitionCount(expectedPartitionCount)}); + } + + Y_UNIT_TEST(IndexTableDoesNotSplitsIfDisabledByMainTable) { + TTestBasicRuntime runtime; + auto env = SetupEnv(runtime); + + const ui32 cpuLoadThreshold = 1; // percents + const ui64 cpuLoadSimulated = 100; // percents + + const auto mainTableScheme = Sprintf( + R"( + TableDescription { + Name: "Table" + Columns { Name: "key" Type: "Uint64"} + Columns { Name: "value" Type: "Uint64"} + KeyColumnNames: ["key"] + + UniformPartitionsCount: 5 + + PartitionConfig { + PartitioningPolicy { + MaxPartitionsCount: 10 + SplitByLoadSettings: { + Enabled: false + + CpuPercentageThreshold: %d # replacement field for cpu load split threshold, percents + + } + } + } + } + IndexDescription { + Name: "by-value" + KeyColumnNames: ["value"] + } + )", + cpuLoadThreshold + ); + + ui64 txId = 100; + TestCreateIndexedTable(runtime, ++txId, "/MyRoot", mainTableScheme); + env.TestWaitNotification(runtime, txId); + + NoSplitByLoad(runtime, "/MyRoot/Table/by-value/indexImplTable", cpuLoadSimulated); + + auto tableInfo = DescribePrivatePath(runtime, "/MyRoot/Table/by-value/indexImplTable", true, true); + Cerr << "TEST table final state:" << Endl << tableInfo.DebugString() << Endl; + TestDescribeResult(tableInfo, {NLs::PartitionCount(1)}); + } +} |