Skip to content

Commit 4efd77c

Browse files
authored
Implemented limit on olap table columnt count (#8742)
1 parent be644f0 commit 4efd77c

File tree

13 files changed

+240
-5
lines changed

13 files changed

+240
-5
lines changed

ydb/core/protos/flat_tx_scheme.proto

+2
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ message TSchemeLimits {
190190

191191
optional uint64 MaxExports = 16;
192192
optional uint64 MaxImports = 17;
193+
194+
optional uint64 MaxColumnTableColumns = 18;
193195
}
194196

195197
message TEvInitTenantSchemeShard {

ydb/core/tx/schemeshard/olap/operations/alter/standalone/update.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ NKikimr::TConclusionStatus TStandaloneSchemaUpdate::DoInitializeImpl(const TUpda
3636
return TConclusionStatus::Fail("schema update error: " + collector->GetErrorMessage() + ". in alter constructor STANDALONE_UPDATE");
3737
}
3838
}
39+
40+
const TString& parentPathStr = context.GetModification()->GetWorkingDir();
41+
if (parentPathStr) { // Not empty only if called from Propose, not from ProgressState
42+
NSchemeShard::TPath parentPath = NSchemeShard::TPath::Resolve(parentPathStr, context.GetSSOperationContext()->SS);
43+
auto domainInfo = parentPath.DomainInfo();
44+
const TSchemeLimits& limits = domainInfo->GetSchemeLimits();
45+
if (targetSchema.GetColumns().GetColumns().size() > limits.MaxColumnTableColumns) {
46+
TString errStr = TStringBuilder()
47+
<< "Too many columns"
48+
<< ": new: " << targetSchema.GetColumns().GetColumns().size()
49+
<< ". Limit: " << limits.MaxColumnTableColumns;
50+
return TConclusionStatus::Fail(errStr);
51+
}
52+
}
53+
3954
auto description = originalTable.GetTableInfoVerified().Description;
4055
targetSchema.Serialize(*description.MutableSchema());
4156
auto ttl = originalTable.GetTableTTLOptional() ? *originalTable.GetTableTTLOptional() : TOlapTTL();

ydb/core/tx/schemeshard/olap/operations/alter_store.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#include <ydb/core/tx/schemeshard/schemeshard__operation_common.h>
33
#include <ydb/core/tx/schemeshard/schemeshard_impl.h>
44

5+
#include "checks.h"
6+
57
namespace {
68

79
using namespace NKikimr;
@@ -458,7 +460,8 @@ class TAlterOlapStore: public TSubOperation {
458460
return result;
459461
}
460462

461-
TPath path = TPath::Resolve(parentPathStr, context.SS).Dive(name);
463+
TPath parentPath = TPath::Resolve(parentPathStr, context.SS);
464+
TPath path = parentPath.Dive(name);
462465
{
463466
TPath::TChecker checks = path.Check();
464467
checks
@@ -504,6 +507,15 @@ class TAlterOlapStore: public TSubOperation {
504507
if (!alterData) {
505508
return result;
506509
}
510+
511+
auto domainInfo = parentPath.DomainInfo();
512+
const TSchemeLimits& limits = domainInfo->GetSchemeLimits();
513+
514+
if (!NKikimr::NSchemeShard::NOlap::CheckLimits(limits, alterData, errStr)) {
515+
result->SetError(NKikimrScheme::StatusSchemeError, errStr);
516+
return result;
517+
}
518+
507519
storeInfo->AlterData = alterData;
508520

509521
NIceDb::TNiceDb db(context.GetDB());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
namespace NKikimr::NSchemeShard::NOlap {
4+
inline bool CheckLimits(const TSchemeLimits& limits, TOlapStoreInfo::TPtr alterData, TString& errStr) {
5+
for (auto& [_, preset]: alterData->SchemaPresets) {
6+
ui64 columnCount = preset.GetColumns().GetColumns().size();
7+
if (columnCount > limits.MaxColumnTableColumns) {
8+
errStr = TStringBuilder()
9+
<< "Too many columns"
10+
<< ". new: " << columnCount
11+
<< ". Limit: " << limits.MaxColumnTableColumns;
12+
return false;
13+
}
14+
}
15+
return true;
16+
}
17+
}
18+
19+

ydb/core/tx/schemeshard/olap/operations/create_store.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <ydb/core/tx/columnshard/columnshard.h>
88
#include <ydb/core/mind/hive/hive.h>
99

10+
#include "checks.h"
11+
1012
using namespace NKikimr;
1113
using namespace NKikimr::NSchemeShard;
1214

@@ -394,12 +396,20 @@ class TCreateOlapStore: public TSubOperation {
394396
return result;
395397
}
396398

399+
auto domainInfo = parentPath.DomainInfo();
400+
const TSchemeLimits& limits = domainInfo->GetSchemeLimits();
401+
397402
TProposeErrorCollector errors(*result);
398403
TOlapStoreInfo::TPtr storeInfo = std::make_shared<TOlapStoreInfo>();
399404
if (!storeInfo->ParseFromRequest(createDescription, errors)) {
400405
return result;
401406
}
402407

408+
if (!NKikimr::NSchemeShard::NOlap::CheckLimits(limits, storeInfo, errStr)) {
409+
result->SetError(NKikimrScheme::StatusSchemeError, errStr);
410+
return result;
411+
}
412+
403413
// Construct channels bindings for columnshards
404414
TChannelsBindings channelsBindings;
405415
if (!context.SS->GetOlapChannelsBindings(dstPath.GetPathIdForDomain(), storeInfo->GetStorageConfig(), channelsBindings, errStr)) {

ydb/core/tx/schemeshard/olap/operations/create_table.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -681,11 +681,23 @@ class TCreateColumnTable: public TSubOperation {
681681
TProposeErrorCollector errors(*result);
682682
TColumnTableInfo::TPtr tableInfo;
683683
bool needUpdateObject = false;
684+
auto domainInfo = parentPath.DomainInfo();
685+
const TSchemeLimits& limits = domainInfo->GetSchemeLimits();
686+
684687
if (storeInfo) {
685688
TOlapPresetConstructor tableConstructor(*storeInfo);
686689
tableInfo = tableConstructor.BuildTableInfo(createDescription, context, errors);
687690
needUpdateObject = tableConstructor.GetNeedUpdateObject();
688691
} else {
692+
ui64 columnCount = createDescription.schema().columns().size();
693+
if (columnCount > limits.MaxColumnTableColumns) {
694+
TString errStr = TStringBuilder()
695+
<< "Too many columns"
696+
<< ". new: " << columnCount
697+
<< ". Limit: " << limits.MaxColumnTableColumns;
698+
result->SetError(NKikimrScheme::StatusSchemeError, errStr);
699+
return result;
700+
}
689701
TOlapTableConstructor tableConstructor;
690702
tableInfo = tableConstructor.BuildTableInfo(createDescription, context, errors);
691703
}

ydb/core/tx/schemeshard/schemeshard__init.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,7 @@ struct TSchemeShard::TTxInit : public TTransactionBase<TSchemeShard> {
12431243
.MaxPathElementLength = rowSet.template GetValueOrDefault<Schema::SubDomains::PathElementLength>(defaults.MaxPathElementLength),
12441244
.ExtraPathSymbolsAllowed = rowSet.template GetValueOrDefault<Schema::SubDomains::ExtraPathSymbolsAllowed>(defaults.ExtraPathSymbolsAllowed),
12451245
.MaxTableColumns = rowSet.template GetValueOrDefault<Schema::SubDomains::TableColumnsLimit>(defaults.MaxTableColumns),
1246+
.MaxColumnTableColumns = rowSet.template GetValueOrDefault<Schema::SubDomains::ColumnTableColumnsLimit>(defaults.MaxColumnTableColumns),
12461247
.MaxTableColumnNameLength = rowSet.template GetValueOrDefault<Schema::SubDomains::TableColumnNameLengthLimit>(defaults.MaxTableColumnNameLength),
12471248
.MaxTableKeyColumns = rowSet.template GetValueOrDefault<Schema::SubDomains::TableKeyColumnsLimit>(defaults.MaxTableKeyColumns),
12481249
.MaxTableIndices = rowSet.template GetValueOrDefault<Schema::SubDomains::TableIndicesLimit>(defaults.MaxTableIndices),

ydb/core/tx/schemeshard/schemeshard_schema.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ struct Schema : NIceDb::Schema {
768768
struct ImportsLimit : Column<29, NScheme::NTypeIds::Uint64> {};
769769
struct AuditSettings : Column<30, NScheme::NTypeIds::String> {};
770770
struct ServerlessComputeResourcesMode : Column<31, NScheme::NTypeIds::Uint32> { using Type = EServerlessComputeResourcesMode; };
771+
struct ColumnTableColumnsLimit : Column<32, NScheme::NTypeIds::Uint64> {};
771772

772773
using TKey = TableKey<PathId>;
773774
using TColumns = TableColumns<
@@ -801,7 +802,8 @@ struct Schema : NIceDb::Schema {
801802
ExportsLimit,
802803
ImportsLimit,
803804
AuditSettings,
804-
ServerlessComputeResourcesMode
805+
ServerlessComputeResourcesMode,
806+
ColumnTableColumnsLimit
805807
>;
806808
};
807809

ydb/core/tx/schemeshard/schemeshard_types.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ TSchemeLimits TSchemeLimits::FromProto(const NKikimrScheme::TSchemeLimits& proto
2020
if (proto.HasMaxTableColumns()) {
2121
result.MaxTableColumns = proto.GetMaxTableColumns();
2222
}
23+
if (proto.HasMaxColumnTableColumns()) {
24+
result.MaxColumnTableColumns = proto.GetMaxColumnTableColumns();
25+
}
2326
if (proto.HasMaxTableColumnNameLength()) {
2427
result.MaxTableColumnNameLength = proto.GetMaxTableColumnNameLength();
2528
}
@@ -69,6 +72,7 @@ NKikimrScheme::TSchemeLimits TSchemeLimits::AsProto() const {
6972
result.SetMaxAclBytesSize(MaxAclBytesSize);
7073

7174
result.SetMaxTableColumns(MaxTableColumns);
75+
result.SetMaxColumnTableColumns(MaxColumnTableColumns);
7276
result.SetMaxTableColumnNameLength(MaxTableColumnNameLength);
7377
result.SetMaxTableKeyColumns(MaxTableKeyColumns);
7478
result.SetMaxTableIndices(MaxTableIndices);

ydb/core/tx/schemeshard/schemeshard_types.h

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct TSchemeLimits {
3939

4040
// table
4141
ui64 MaxTableColumns = 200;
42+
ui64 MaxColumnTableColumns = 10000;
4243
ui64 MaxTableColumnNameLength = 255;
4344
ui64 MaxTableKeyColumns = 20;
4445
ui64 MaxTableIndices = 20;

ydb/core/tx/schemeshard/ut_helpers/helpers.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,7 @@ namespace NSchemeShardUT_Private {
15061506
(let child '('ChildrenLimit (Uint64 '%lu)))
15071507
(let acl '('AclByteSizeLimit (Uint64 '%lu)))
15081508
(let columns '('TableColumnsLimit (Uint64 '%lu)))
1509+
(let columnColumns '('ColumnTableColumnsLimit (Uint64 '%lu)))
15091510
(let colName '('TableColumnNameLengthLimit (Uint64 '%lu)))
15101511
(let keyCols '('TableKeyColumnsLimit (Uint64 '%lu)))
15111512
(let indices '('TableIndicesLimit (Uint64 '%lu)))
@@ -1518,11 +1519,11 @@ namespace NSchemeShardUT_Private {
15181519
(let pqPartitions '('PQPartitionsLimit (Uint64 '%lu)))
15191520
(let exports '('ExportsLimit (Uint64 '%lu)))
15201521
(let imports '('ImportsLimit (Uint64 '%lu)))
1521-
(let ret (AsList (UpdateRow 'SubDomains key '(depth paths child acl columns colName keyCols indices streams shards pathShards consCopy maxPathLength extraSymbols pqPartitions exports imports))))
1522+
(let ret (AsList (UpdateRow 'SubDomains key '(depth paths child acl columns columnColumns colName keyCols indices streams shards pathShards consCopy maxPathLength extraSymbols pqPartitions exports imports))))
15221523
(return ret)
15231524
)
15241525
)", domainId, limits.MaxDepth, limits.MaxPaths, limits.MaxChildrenInDir, limits.MaxAclBytesSize,
1525-
limits.MaxTableColumns, limits.MaxTableColumnNameLength, limits.MaxTableKeyColumns,
1526+
limits.MaxTableColumns, limits.MaxColumnTableColumns, limits.MaxTableColumnNameLength, limits.MaxTableKeyColumns,
15261527
limits.MaxTableIndices, limits.MaxTableCdcStreams,
15271528
limits.MaxShards, limits.MaxShardsInPath, limits.MaxConsistentCopyTargets,
15281529
limits.MaxPathElementLength, escapedStr.c_str(), limits.MaxPQPartitions,

ydb/core/tx/schemeshard/ut_subdomain/ut_subdomain.cpp

+150
Original file line numberDiff line numberDiff line change
@@ -2568,6 +2568,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardSubDomainTest) {
25682568

25692569
}
25702570

2571+
25712572
//clear subdomain
25722573
{
25732574
TestDescribeResult(DescribePath(runtime, "/MyRoot"),
@@ -2585,6 +2586,155 @@ Y_UNIT_TEST_SUITE(TSchemeShardSubDomainTest) {
25852586
}
25862587
}
25872588

2589+
Y_UNIT_TEST(ColumnSchemeLimitsRejects) {
2590+
TTestBasicRuntime runtime;
2591+
TTestEnv env(runtime);
2592+
ui64 txId = 100;
2593+
2594+
TSchemeLimits lowLimits;
2595+
lowLimits.MaxDepth = 4;
2596+
lowLimits.MaxPaths = 3;
2597+
lowLimits.MaxChildrenInDir = 3;
2598+
lowLimits.MaxAclBytesSize = 25;
2599+
lowLimits.MaxTableColumns = 3;
2600+
lowLimits.MaxColumnTableColumns = 3;
2601+
lowLimits.MaxTableColumnNameLength = 10;
2602+
lowLimits.MaxTableKeyColumns = 1;
2603+
lowLimits.MaxShards = 6;
2604+
lowLimits.MaxShardsInPath = 4;
2605+
lowLimits.MaxPQPartitions = 20;
2606+
2607+
2608+
//lowLimits.ExtraPathSymbolsAllowed = "!\"#$%&'()*+,-.:;<=>?@[\\]^_`{|}~";
2609+
SetSchemeshardSchemaLimits(runtime, lowLimits);
2610+
TestDescribeResult(DescribePath(runtime, "/MyRoot"),
2611+
{NLs::PathExist,
2612+
NLs::DomainLimitsIs(lowLimits.MaxPaths, lowLimits.MaxShards, lowLimits.MaxPQPartitions)});
2613+
2614+
{
2615+
TestCreateSubDomain(runtime, txId++, "/MyRoot",
2616+
"PlanResolution: 50 "
2617+
"Coordinators: 1 "
2618+
"Mediators: 1 "
2619+
"TimeCastBucketsPerMediator: 2 "
2620+
"Name: \"USER_0\""
2621+
" DatabaseQuotas {"
2622+
" data_stream_shards_quota: 2"
2623+
" data_stream_reserved_storage_quota: 200000"
2624+
"}");
2625+
}
2626+
2627+
//create column tables, column limits
2628+
{
2629+
TestMkDir(runtime, txId++, "/MyRoot/USER_0", "C");
2630+
env.TestWaitNotification(runtime, txId - 1);
2631+
2632+
// MaxColumnTableColumns
2633+
TestCreateColumnTable(runtime, txId++, "/MyRoot/USER_0/C", R"(
2634+
Name: "C2"
2635+
ColumnShardCount: 1
2636+
Schema {
2637+
Columns { Name: "RowId" Type: "Uint64", NotNull: true }
2638+
Columns { Name: "Value0" Type: "Utf8" }
2639+
Columns { Name: "Value1" Type: "Utf8" }
2640+
KeyColumnNames: "RowId"
2641+
Engine: COLUMN_ENGINE_REPLACING_TIMESERIES
2642+
}
2643+
)", {NKikimrScheme::StatusAccepted});
2644+
env.TestWaitNotification(runtime, txId - 1);
2645+
2646+
TestAlterColumnTable(runtime, txId++, "/MyRoot/USER_0/C", R"(
2647+
Name: "C2"
2648+
AlterSchema {
2649+
DropColumns {Name: "Value0"}
2650+
}
2651+
)", {NKikimrScheme::StatusAccepted});
2652+
env.TestWaitNotification(runtime, txId - 1);
2653+
2654+
TestAlterColumnTable(runtime, txId++, "/MyRoot/USER_0/C", R"(
2655+
Name: "C2"
2656+
AlterSchema {
2657+
DropColumns {Name: "Value1"}
2658+
AddColumns { Name: "Value2" Type: "Utf8" }
2659+
AddColumns { Name: "Value3" Type: "Utf8" }
2660+
AddColumns { Name: "Value4" Type: "Utf8" }
2661+
}
2662+
)", {NKikimrScheme::StatusSchemeError});
2663+
env.TestWaitNotification(runtime, txId - 1);
2664+
2665+
TestCreateColumnTable(runtime, txId++, "/MyRoot/USER_0/C", R"(
2666+
Name: "C1"
2667+
ColumnShardCount: 1
2668+
Schema {
2669+
Columns { Name: "RowId" Type: "Uint64", NotNull: true }
2670+
Columns { Name: "Value0" Type: "Utf8" }
2671+
Columns { Name: "Value1" Type: "Utf8" }
2672+
Columns { Name: "Value2" Type: "Utf8" }
2673+
KeyColumnNames: "RowId"
2674+
Engine: COLUMN_ENGINE_REPLACING_TIMESERIES
2675+
}
2676+
)", {NKikimrScheme::StatusSchemeError});
2677+
2678+
TString olapSchema = R"(
2679+
Name: "OlapStore1"
2680+
ColumnShardCount: 1
2681+
SchemaPresets {
2682+
Name: "default"
2683+
Schema {
2684+
Columns { Name: "timestamp" Type: "Timestamp" NotNull: true }
2685+
Columns { Name: "data" Type: "Utf8" }
2686+
KeyColumnNames: "timestamp"
2687+
Engine: COLUMN_ENGINE_REPLACING_TIMESERIES
2688+
}
2689+
}
2690+
)";
2691+
2692+
TestCreateOlapStore(runtime, txId++, "/MyRoot", olapSchema, {NKikimrScheme::StatusAccepted});
2693+
env.TestWaitNotification(runtime, txId - 1);
2694+
2695+
TString olapSchemaBig = R"(
2696+
Name: "OlapStoreBig"
2697+
ColumnShardCount: 1
2698+
SchemaPresets {
2699+
Name: "default"
2700+
Schema {
2701+
Columns { Name: "timestamp" Type: "Timestamp" NotNull: true }
2702+
Columns { Name: "data" Type: "Utf8" }
2703+
Columns { Name: "data2" Type: "Utf8" }
2704+
Columns { Name: "data3" Type: "Utf8" }
2705+
KeyColumnNames: "timestamp"
2706+
Engine: COLUMN_ENGINE_REPLACING_TIMESERIES
2707+
}
2708+
}
2709+
)";
2710+
2711+
TestCreateOlapStore(runtime, txId++, "/MyRoot", olapSchemaBig, {NKikimrScheme::StatusSchemeError});
2712+
env.TestWaitNotification(runtime, txId - 1);
2713+
2714+
TestAlterOlapStore(runtime, txId++, "/MyRoot", R"(
2715+
Name: "OlapStore1"
2716+
AlterSchemaPresets {
2717+
Name: "default"
2718+
AlterSchema {
2719+
AddColumns { Name: "comment" Type: "Utf8" }
2720+
}
2721+
}
2722+
)", {NKikimrScheme::StatusAccepted});
2723+
env.TestWaitNotification(runtime, txId - 1);
2724+
2725+
TestAlterOlapStore(runtime, txId++, "/MyRoot", R"(
2726+
Name: "OlapStore1"
2727+
AlterSchemaPresets {
2728+
Name: "default"
2729+
AlterSchema {
2730+
AddColumns { Name: "comment2" Type: "Utf8" }
2731+
}
2732+
}
2733+
)", {NKikimrScheme::StatusSchemeError});
2734+
env.TestWaitNotification(runtime, txId - 1);
2735+
}
2736+
}
2737+
25882738
Y_UNIT_TEST(SchemeLimitsRejectsWithIndexedTables) {
25892739
TTestBasicRuntime runtime;
25902740
TTestEnv env(runtime);

ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema

+7-1
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,11 @@
14541454
"ColumnId": 31,
14551455
"ColumnName": "ServerlessComputeResourcesMode",
14561456
"ColumnType": "Uint32"
1457+
},
1458+
{
1459+
"ColumnId": 32,
1460+
"ColumnName": "ColumnTableColumnsLimit",
1461+
"ColumnType": "Uint64"
14571462
}
14581463
],
14591464
"ColumnsDropped": [],
@@ -1490,7 +1495,8 @@
14901495
28,
14911496
29,
14921497
30,
1493-
31
1498+
31,
1499+
32
14941500
],
14951501
"RoomID": 0,
14961502
"Codec": 0,

0 commit comments

Comments
 (0)