aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorijon <ijon@yandex-team.com>2023-03-17 12:21:32 +0300
committerijon <ijon@yandex-team.com>2023-03-17 12:21:32 +0300
commit781b388f6f446cefcaa7fa4d787342b56e584f8d (patch)
treea11a527f3060b9b84eed16250274e22287b1118c
parent0355d87069435442cdfe6f9ef56344128972df98 (diff)
downloadydb-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.cpp3
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_utils.cpp1
-rw-r--r--ydb/core/tx/schemeshard/ut_base.cpp10
-rw-r--r--ydb/core/tx/schemeshard/ut_helpers/ls_checks.cpp16
-rw-r--r--ydb/core/tx/schemeshard/ut_helpers/ls_checks.h4
-rw-r--r--ydb/core/tx/schemeshard/ut_split_merge.cpp430
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)});
+ }
+}