aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsvc <svc@yandex-team.ru>2022-02-11 20:16:50 +0300
committersvc <svc@yandex-team.ru>2022-02-11 20:16:50 +0300
commit05ac286ec4ba733e0b158caa74c576e49b24b23e (patch)
treec6745be0ed51113b82280626fd47c296a0867390
parent2a307bcbf7913175505081578c9f70f76071bd6e (diff)
downloadydb-05ac286ec4ba733e0b158caa74c576e49b24b23e.tar.gz
KIKIMR-13964 alter index directly by administator
ref:673a9bc62ce066c5d033ffa17f9826953bb4e06a
-rw-r--r--ydb/core/kqp/ut/kqp_indexes_multishard_ut.cpp124
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation.cpp5
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_alter_index.cpp40
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp65
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.cpp7
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.h1
-rw-r--r--ydb/core/tx/schemeshard/schemeshard__operation_part.h1
-rw-r--r--ydb/core/tx/schemeshard/schemeshard_info_types.cpp8
-rw-r--r--ydb/core/tx/schemeshard/ut_base.cpp232
-rw-r--r--ydb/core/tx/schemeshard/ut_index_build.cpp10
-rw-r--r--ydb/core/tx/schemeshard/ut_index_build_reboots.cpp2
11 files changed, 461 insertions, 34 deletions
diff --git a/ydb/core/kqp/ut/kqp_indexes_multishard_ut.cpp b/ydb/core/kqp/ut/kqp_indexes_multishard_ut.cpp
index c80b2282be..59b3b823c9 100644
--- a/ydb/core/kqp/ut/kqp_indexes_multishard_ut.cpp
+++ b/ydb/core/kqp/ut/kqp_indexes_multishard_ut.cpp
@@ -67,7 +67,129 @@ Y_UNIT_TEST_SUITE(KqpMultishardIndex) {
UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
UNIT_ASSERT_VALUES_EQUAL(NYdb::FormatResultSetYson(result.GetResultSet(0)), "[[[4294967295u];[4u];[\"v4\"]]]");
}
- }
+ }
+
+ Y_UNIT_TEST_NEW_ENGINE(YqWorksFineAfterAlterIndexTableDirectly) {
+ TKikimrRunner kikimr(SyntaxV1Settings());
+ CreateTableWithMultishardIndex(kikimr.GetTestClient());
+ auto db = kikimr.GetTableClient();
+ auto session = db.CreateSession().GetValueSync().GetSession();
+
+ {
+ const TString query(Q_(R"(
+ UPSERT INTO `/Root/MultiShardIndexed` (key, fk, value) VALUES
+ (1, 1000000000, "v1"),
+ (2, 2000000000, "v2"),
+ (3, 3000000000, "v3"),
+ (4, 4294967295, "v4");
+ )"));
+
+ auto result = session.ExecuteDataQuery(
+ query,
+ TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx())
+ .ExtractValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ kikimr.GetTestServer().GetRuntime()->GetAppData().AdministrationAllowedSIDs.push_back("root@builtin");
+
+ { // without token request is forbidded
+ Tests::TClient& client = kikimr.GetTestClient();
+ const TString scheme = R"(
+ Name: "indexImplTable"
+ PartitionConfig {
+ PartitioningPolicy {
+ MinPartitionsCount: 1
+ SizeToSplit: 100500
+ FastSplitSettings {
+ SizeThreshold: 100500
+ RowCountThreshold: 100500
+ }
+ }
+ }
+ )";
+ auto result = client.AlterTable("/Root/MultiShardIndexed/index", scheme, "user@builtin");
+ UNIT_ASSERT_VALUES_EQUAL_C(result->Record.GetStatus(), NMsgBusProxy::MSTATUS_ERROR, "User must not be able to alter index impl table");
+ UNIT_ASSERT_VALUES_EQUAL(result->Record.GetErrorReason(), "Administrative access denied");
+ }
+
+ { // with root token request is accepted
+ Tests::TClient& client = kikimr.GetTestClient();
+ const TString scheme = R"(
+ Name: "indexImplTable"
+ PartitionConfig {
+ PartitioningPolicy {
+ MinPartitionsCount: 1
+ SizeToSplit: 100500
+ FastSplitSettings {
+ SizeThreshold: 100500
+ RowCountThreshold: 100500
+ }
+ }
+ }
+ )";
+ auto result = client.AlterTable("/Root/MultiShardIndexed/index", scheme, "root@builtin");
+ UNIT_ASSERT_VALUES_EQUAL_C(result->Record.GetStatus(), NMsgBusProxy::MSTATUS_OK, "Super user must be able to alter partition config");
+ }
+
+ { // after alter yql works fine
+ const TString query(Q_(R"(
+ SELECT * FROM `/Root/MultiShardIndexed` VIEW index ORDER BY fk DESC LIMIT 1;
+ )"));
+
+ auto result = session.ExecuteDataQuery(
+ query,
+ TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx())
+ .ExtractValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ UNIT_ASSERT_VALUES_EQUAL(NYdb::FormatResultSetYson(result.GetResultSet(0)), "[[[4294967295u];[4u];[\"v4\"]]]");
+ }
+
+ { // write request works well too
+ const TString query(Q_(R"(
+ UPSERT INTO `/Root/MultiShardIndexed` (key, fk, value) VALUES
+ (1, 1000000000, "v1"),
+ (2, 2000000000, "v2"),
+ (3, 3000000000, "v3"),
+ (4, 4294967295, "v4");
+ )"));
+
+ auto result = session.ExecuteDataQuery(
+ query,
+ TTxControl::BeginTx(TTxSettings::SerializableRW()).CommitTx())
+ .ExtractValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+ }
+
+ { // just for sure, public api got error when alter index
+ auto settings = NYdb::NTable::TAlterTableSettings()
+ .BeginAlterPartitioningSettings()
+ .SetPartitionSizeMb(50)
+ .SetMinPartitionsCount(4)
+ .SetMaxPartitionsCount(5)
+ .EndAlterPartitioningSettings();
+
+ auto result = session.AlterTable("/Root/MultiShardIndexed/index/indexImplTable", settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SCHEME_ERROR, result.GetIssues().ToString());
+ }
+
+ { // however public api is able to perform alter index if user has AlterSchema right and user is a member of the list AdministrationAllowedSIDs
+ auto clSettings = NYdb::NTable::TClientSettings().AuthToken("root@builtin").UseQueryCache(false);
+ auto client = NYdb::NTable::TTableClient(kikimr.GetDriver(), clSettings);
+ auto session = client.CreateSession().GetValueSync().GetSession();
+
+ auto settings = NYdb::NTable::TAlterTableSettings()
+ .BeginAlterPartitioningSettings()
+ .SetPartitionSizeMb(50)
+ .SetMinPartitionsCount(4)
+ .SetMaxPartitionsCount(5)
+ .EndAlterPartitioningSettings();
+
+ auto result = session.AlterTable("/Root/MultiShardIndexed/index/indexImplTable", settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ }
+
+ }
}
}
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation.cpp b/ydb/core/tx/schemeshard/schemeshard__operation.cpp
index daf1218bcf..cdd5f0ba73 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation.cpp
@@ -932,7 +932,7 @@ ISubOperationBase::TPtr TOperation::ConstructPart(NKikimrSchemeOp::EOperationTyp
case NKikimrSchemeOp::EOperationType::ESchemeOpCreateTable:
return CreateNewTable(NextPartId(), tx);
case NKikimrSchemeOp::EOperationType::ESchemeOpAlterTable:
- return CreateAlterTable(NextPartId(), tx);
+ Y_FAIL("in general, alter table is multipart operation now due table indexes");
case NKikimrSchemeOp::EOperationType::ESchemeOpSplitMergeTablePartitions:
return CreateSplitMerge(NextPartId(), tx);
case NKikimrSchemeOp::EOperationType::ESchemeOpBackup:
@@ -1130,6 +1130,9 @@ TVector<ISubOperationBase::TPtr> TOperation::ConstructParts(const TTxTransaction
return CreateDropCdcStream(NextPartId(), tx, context);
case NKikimrSchemeOp::EOperationType::ESchemeOpMoveTable:
return CreateConsistentMoveTable(NextPartId(), tx, context);
+ case NKikimrSchemeOp::EOperationType::ESchemeOpAlterTable:
+ return CreateConsistentAlterTable(NextPartId(), tx, context);
+
default:
return {ConstructPart(opType, tx)};
}
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_index.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_index.cpp
index 10688f0991..3617728fbe 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_index.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_index.cpp
@@ -52,6 +52,12 @@ public:
context.SS->ClearDescribePathCaches(path);
context.OnComplete.PublishToSchemeBoard(OperationId, path->PathId);
+ auto parentDir = context.SS->PathsById.at(path->ParentPathId);
+ ++parentDir->DirAlterVersion;
+ context.SS->PersistPathDirAlterVersion(db, parentDir);
+ context.SS->ClearDescribePathCaches(parentDir);
+ context.OnComplete.PublishToSchemeBoard(OperationId, parentDir->PathId);
+
context.SS->ChangeTxState(db, OperationId, TTxState::Done);
return true;
}
@@ -206,29 +212,28 @@ public:
return result;
}
- TTableIndexInfo::TPtr indexData = context.SS->Indexes.at(dstPath.Base()->PathId);
+ auto indexPath = dstPath.Base();
+
+ context.MemChanges.GrabPath(context.SS, indexPath->PathId);
+ context.MemChanges.GrabPath(context.SS, indexPath->ParentPathId);
+ context.MemChanges.GrabNewTxState(context.SS, OperationId);
+ context.MemChanges.GrabIndex(context.SS, indexPath->PathId);
+
+ context.DbChanges.PersistPath(indexPath->PathId);
+ context.DbChanges.PersistAlterIndex(indexPath->PathId);
+ context.DbChanges.PersistTxState(OperationId);
+
+ TTableIndexInfo::TPtr indexData = context.SS->Indexes.at(indexPath->PathId);
TTableIndexInfo::TPtr newIndexData = indexData->CreateNextVersion();
- if (!newIndexData) {
- result->SetError(TEvSchemeShard::EStatus::StatusInvalidParameter, errMsg);
- return result;
- }
+ Y_VERIFY(newIndexData);
newIndexData->State = tableIndexAlter.GetState();
- NIceDb::TNiceDb db(context.Txc.DB);
- // store table index description
- auto indexPath = dstPath.Base();
-
Y_VERIFY(!context.SS->FindTx(OperationId));
TTxState& txState = context.SS->CreateTx(OperationId, TTxState::TxAlterTableIndex, indexPath->PathId);
txState.State = TTxState::Propose;
indexPath->PathState = NKikimrSchemeOp::EPathStateAlter;
indexPath->LastTxId = OperationId.GetTxId();
- context.SS->PersistLastTxId(db, indexPath);
-
- context.SS->PersistTableIndexAlterData(db, indexPath->PathId);
-
- context.SS->PersistTxState(db, OperationId);
context.OnComplete.ActivateTx(OperationId);
@@ -237,8 +242,11 @@ public:
return result;
}
- void AbortPropose(TOperationContext&) override {
- Y_FAIL("no AbortPropose for TAlterTableIndex");
+ void AbortPropose(TOperationContext& context) override {
+ LOG_NOTICE_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD,
+ "TAlterTableIndex AbortPropose"
+ << ", opId: " << OperationId
+ << ", at schemeshard: " << context.SS->TabletID());
}
void AbortUnsafe(TTxId forceDropTxId, TOperationContext& context) override {
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp
index b6c0b6c8b2..849a111d91 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_table.cpp
@@ -46,8 +46,6 @@ TTableInfo::TAlterDataPtr ParseParams(const TPath& path, TTableInfo::TPtr table,
const TAppData* appData = AppData(context.Ctx);
if (!path.IsCommonSensePath()) {
- Y_VERIFY_DEBUG(IsSuperUser(context.UserToken.Get()) || context.IsAllowedPrivateTables, "Only superuser can alter index impl table");
-
if (alter.ColumnsSize() != 0 || alter.DropColumnsSize() != 0) {
errStr = "Adding or dropping columns in index table is not supported";
status = NKikimrScheme::StatusInvalidParameter;
@@ -512,8 +510,8 @@ public:
.IsTable()
.NotUnderOperation();
- if (!context.IsAllowedPrivateTables && !IsSuperUser(context.UserToken.Get())) {
- checks.IsCommonSensePath(); //forbid alter impl index tables
+ if (!context.IsAllowedPrivateTables) {
+ checks.IsCommonSensePath(); //forbid alter impl index tables outside consistent operation
}
if (!checks) {
@@ -642,5 +640,64 @@ ISubOperationBase::TPtr CreateFinalizeBuildIndexImplTable(TOperationId id, TTxSt
return obj.Release();
}
+TVector<ISubOperationBase::TPtr> CreateConsistentAlterTable(TOperationId id, const TTxTransaction& tx, TOperationContext& context) {
+ Y_VERIFY(tx.GetOperationType() == NKikimrSchemeOp::EOperationType::ESchemeOpAlterTable);
+
+ auto alter = tx.GetAlterTable();
+
+ const TString& parentPathStr = tx.GetWorkingDir();
+ const TString& name = alter.GetName();
+
+ TPathId pathId = alter.HasPathId() ? PathIdFromPathId(alter.GetPathId()) : InvalidPathId;
+
+ if (!alter.HasName() && !pathId) {
+ return {CreateAlterTable(id, tx)};
+ }
+
+ TPath path = pathId
+ ? TPath::Init(pathId, context.SS)
+ : TPath::Resolve(parentPathStr, context.SS).Dive(name);
+
+ if (!path.IsResolved()) {
+ return {CreateAlterTable(id, tx)};
+ }
+
+ if (!path->IsTable()) {
+ return {CreateAlterTable(id, tx)};
+ }
+
+ if (path.IsCommonSensePath()) {
+ return {CreateAlterTable(id, tx)};
+ }
+
+ TPath parent = path.Parent();
+
+ if (!parent.IsTableIndex()) {
+ return {CreateAlterTable(id, tx)};
+ }
+
+ TVector<ISubOperationBase::TPtr> result;
+
+ // only for super user use
+ // until correct and safe altering index api is released
+ if (!IsSuperUser(context.UserToken.Get())) {
+ return {CreateAlterTable(id, tx)};
+ }
+
+ {
+ auto tableIndexAltering = TransactionTemplate(parent.Parent().PathString(), NKikimrSchemeOp::EOperationType::ESchemeOpAlterTableIndex);
+ auto alterIndex = tableIndexAltering.MutableAlterTableIndex();
+ alterIndex->SetName(parent.LeafName());
+ alterIndex->SetState(NKikimrSchemeOp::EIndexState::EIndexStateReady);
+
+ result.push_back(CreateAlterTableIndex(NextPartId(id, result), tableIndexAltering));
+ }
+
+ result.push_back(CreateAlterTable(NextPartId(id, result), tx));
+
+
+ return result;
+}
+
}
}
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.cpp
index e4151fd8df..d7efc1dbf5 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.cpp
@@ -63,6 +63,13 @@ void TMemoryChanges::GrabNewIndex(TSchemeShard* ss, const TPathId& pathId) {
Indexes.emplace(pathId, nullptr);
}
+void TMemoryChanges::GrabIndex(TSchemeShard* ss, const TPathId& pathId) {
+ Y_VERIFY(ss->Indexes.contains(pathId));
+
+ TTableIndexInfo::TPtr copy = new TTableIndexInfo(*ss->Indexes.at(pathId));
+ Indexes.emplace(pathId, copy);
+}
+
void TMemoryChanges::GrabNewCdcStream(TSchemeShard* ss, const TPathId& pathId) {
Y_VERIFY(!ss->CdcStreams.contains(pathId));
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.h b/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.h
index c6ec264ffe..7bc04e3beb 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.h
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_memory_changes.h
@@ -53,6 +53,7 @@ public:
void GrabDomain(TSchemeShard* ss, const TPathId& pathId);
void GrabNewIndex(TSchemeShard* ss, const TPathId& pathId);
+ void GrabIndex(TSchemeShard* ss, const TPathId& pathId);
void GrabNewCdcStream(TSchemeShard* ss, const TPathId& pathId);
diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_part.h b/ydb/core/tx/schemeshard/schemeshard__operation_part.h
index 4a639e6342..579b52a461 100644
--- a/ydb/core/tx/schemeshard/schemeshard__operation_part.h
+++ b/ydb/core/tx/schemeshard/schemeshard__operation_part.h
@@ -211,6 +211,7 @@ TVector<ISubOperationBase::TPtr> CreateCopyTable(TOperationId nextId, const TTxT
ISubOperationBase::TPtr CreateAlterTable(TOperationId id, const TTxTransaction& tx);
ISubOperationBase::TPtr CreateAlterTable(TOperationId id, TTxState::ETxState state);
+TVector<ISubOperationBase::TPtr> CreateConsistentAlterTable(TOperationId id, const TTxTransaction& tx, TOperationContext& context);
ISubOperationBase::TPtr CreateSplitMerge(TOperationId id, const TTxTransaction& tx);
ISubOperationBase::TPtr CreateSplitMerge(TOperationId id, TTxState::ETxState state);
diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.cpp b/ydb/core/tx/schemeshard/schemeshard_info_types.cpp
index fcb564b606..332746dae0 100644
--- a/ydb/core/tx/schemeshard/schemeshard_info_types.cpp
+++ b/ydb/core/tx/schemeshard/schemeshard_info_types.cpp
@@ -449,7 +449,7 @@ bool TPartitionConfigMerger::ApplyChanges(
if (changes.HasCrossDataCenterFollowerCount()) {
if (result.FollowerGroupsSize()) {
- errDesr = TStringBuilder() << "Forbided downgrade from FollowerGroup option to the HasCrossDataCenterFollowerCount option";
+ errDesr = TStringBuilder() << "Forbidded downgrade from FollowerGroup option to the HasCrossDataCenterFollowerCount option";
return false;
}
@@ -464,12 +464,12 @@ bool TPartitionConfigMerger::ApplyChanges(
if (changes.HasFollowerCount()) {
if (result.HasCrossDataCenterFollowerCount()) {
- errDesr = TStringBuilder() << "Forbided downgrade from CrossDataCenterFollowerCount option to the FollowerGroup option";
+ errDesr = TStringBuilder() << "Forbidded downgrade from CrossDataCenterFollowerCount option to the FollowerGroup option";
return false;
}
if (result.FollowerGroupsSize()) {
- errDesr = TStringBuilder() << "Forbided downgrade from FollowerGroup option to the FollowerGroup option";
+ errDesr = TStringBuilder() << "Forbidded downgrade from FollowerGroup option to the FollowerGroup option";
return false;
}
@@ -478,7 +478,7 @@ bool TPartitionConfigMerger::ApplyChanges(
if (changes.HasAllowFollowerPromotion()) {
if (result.FollowerGroupsSize()) {
- errDesr = TStringBuilder() << "Forbided downgrade from FollowerGroup option to the AllowFollowerPromotion option";
+ errDesr = TStringBuilder() << "Forbidded downgrade from FollowerGroup option to the AllowFollowerPromotion option";
return false;
}
diff --git a/ydb/core/tx/schemeshard/ut_base.cpp b/ydb/core/tx/schemeshard/ut_base.cpp
index a76dcf9d5b..9b135fc880 100644
--- a/ydb/core/tx/schemeshard/ut_base.cpp
+++ b/ydb/core/tx/schemeshard/ut_base.cpp
@@ -2135,6 +2135,11 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) {
Columns { Name: "add_2" Type: "Uint64"}
)", {TEvSchemeShard::EStatus::StatusNameConflict});
+ TestAlterTable(runtime, ++txId, "/MyRoot/DirA/Table1/UserDefinedIndexByValue0", R"(
+ Name: "indexImplTable"
+ DropColumns { Name: "key" Type: "Uint64"}
+ )", {TEvSchemeShard::EStatus::StatusNameConflict});
+
TestCopyTable(runtime, ++txId, "/MyRoot/DirA", "copy_is_ok", "/MyRoot/DirA/Table1");
env.TestWaitNotification(runtime, txId);
@@ -9747,7 +9752,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) {
TestDescribeResult(DescribePath(runtime, "/MyRoot/Table1"),
{NLs::IsTable,
- NLs::PathVersionEqual(7),
+ NLs::PathVersionEqual(8),
NLs::CheckColumns("Table1", {"key", "value"}, {}, {"key"}),
NLs::IndexesCount(0)});
@@ -9776,7 +9781,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) {
TestDescribeResult(DescribePath(runtime, "/MyRoot/Table1"),
{NLs::IsTable,
- NLs::PathVersionEqual(7),
+ NLs::PathVersionEqual(8),
NLs::IndexesCount(0)});
TestDescribeResult(DescribePath(runtime, "/MyRoot/Copy1"),
@@ -9847,4 +9852,227 @@ Y_UNIT_TEST_SUITE(TSchemeShardTest) {
}
}
+
+ Y_UNIT_TEST(AlterIndexTableDirectly) {
+ TTestBasicRuntime runtime;
+
+ TTestEnvOptions opts;
+ opts.EnableBackgroundCompaction(false);
+
+ TTestEnv env(runtime, opts);
+
+ ui64 txId = 100;
+
+ NDataShard::gDbStatsReportInterval = TDuration::Seconds(1);
+ NDataShard::gDbStatsDataSizeResolution = 10;
+ NDataShard::gDbStatsRowCountResolution = 10;
+
+ runtime.GetAppData().AdministrationAllowedSIDs.push_back("true-root@builtin");
+
+ runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NActors::NLog::PRI_DEBUG);
+
+ TestCreateTable(runtime, ++txId, "/MyRoot", R"(
+ Name: "table"
+ Columns { Name: "key" Type: "Uint32" }
+ Columns { Name: "value" Type: "Utf8" }
+ KeyColumnNames: ["key"]
+ )");
+ env.TestWaitNotification(runtime, {txId, txId-1});
+
+ {
+ auto fnWriteRow = [&] (ui64 tabletId, ui32 key, TString value, const char* table) {
+ TString writeQuery = Sprintf(R"(
+ (
+ (let key '( '('key (Uint32 '%u ) ) ) )
+ (let row '( '('value (Utf8 '%s) ) ) )
+ (return (AsList (UpdateRow '__user__%s key row) ))
+ )
+ )", key, value.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);;
+ };
+
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 1, "A", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 2, "B", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 3, "C", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 4, "D", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 5, "E", "table");
+
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 6, "F", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 7, "G", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 8, "H", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 9, "I", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 10, "J", "table");
+
+
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 11, "K", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 12, "L", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 13, "M", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 14, "N", "table");
+ fnWriteRow(TTestTxConfig::FakeHiveTablets, 15, "O", "table");
+ }
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table"),
+ {NLs::PathExist,
+ NLs::IndexesCount(0),
+ NLs::PathVersionEqual(3)});
+
+ {
+ TestBuilIndex(runtime, ++txId, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/table", "indexByValue", {"value"});
+ ui64 builIndexId = txId;
+
+ auto listing = TestListBuilIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot");
+ Y_ASSERT(listing.EntriesSize() == 1);
+
+ env.TestWaitNotification(runtime, builIndexId, TTestTxConfig::SchemeShard);
+
+ auto descr = TestGetBuilIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", builIndexId);
+ Y_ASSERT(descr.GetIndexBuild().GetState() == Ydb::Table::IndexBuildState::STATE_DONE);
+ }
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table"),
+ {NLs::PathExist,
+ NLs::IndexesCount(1),
+ NLs::PathVersionEqual(6)});
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table/indexByValue", true, true, true),
+ {NLs::PathExist,
+ NLs::PathVersionEqual(3)});
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table/indexByValue/indexImplTable", true, true, true),
+ {NLs::PathExist,
+ NLs::PathVersionEqual(4),
+ NLs::PartitionCount(1),
+ NLs::MinPartitionsCountEqual(0),
+ NLs::MaxPartitionsCountEqual(100)});
+
+
+ TestSplitTable(runtime, ++txId, "/MyRoot/table/indexByValue/indexImplTable", R"(
+ SourceTabletId: 9437195
+ SplitBoundary {
+ KeyPrefix {
+ Tuple { Optional { Text: "B" } }
+ }
+ }
+ SplitBoundary {
+ KeyPrefix {
+ Tuple { Optional { Text: "D" } } Tuple {}
+ }
+ })");
+ env.TestWaitNotification(runtime, txId);
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table/indexByValue/indexImplTable", true, true, true),
+ {NLs::PathExist,
+ NLs::PathVersionEqual(5),
+ NLs::PartitionCount(3),
+ NLs::MinPartitionsCountEqual(0),
+ NLs::MaxPartitionsCountEqual(100)});
+
+ // request without token
+ TestAlterTable(runtime, ++txId, "/MyRoot/table/indexByValue/", R"(
+ Name: "indexImplTable"
+ PartitionConfig {
+ PartitioningPolicy {
+ MinPartitionsCount: 1
+ SizeToSplit: 100502
+ FastSplitSettings {
+ SizeThreshold: 100502
+ RowCountThreshold: 100502
+ }
+ }
+ }
+ )", {NKikimrScheme::StatusNameConflict});
+
+ { // request with not a super user token
+ auto request = AlterTableRequest(++txId, "/MyRoot/table/indexByValue/", R"(
+ Name: "indexImplTable"
+ PartitionConfig {
+ PartitioningPolicy {
+ MinPartitionsCount: 1
+ SizeToSplit: 100501
+ FastSplitSettings {
+ SizeThreshold: 100501
+ RowCountThreshold: 100501
+ }
+ }
+ }
+ )");
+
+ auto wellCookedToken = NACLib::TUserToken(TVector<TString>{"not-a-root@builtin"});
+ request->Record.SetUserToken(wellCookedToken.SerializeAsString());
+ TActorId sender = runtime.AllocateEdgeActor();
+ ForwardToTablet(runtime, TTestTxConfig::SchemeShard, sender, request);
+ TestModificationResults(runtime, txId, {TEvSchemeShard::EStatus::StatusNameConflict});
+ }
+
+ {
+ auto request = AlterTableRequest(++txId, "/MyRoot/table/indexByValue/", R"(
+ Name: "indexImplTable"
+ PartitionConfig {
+ PartitioningPolicy {
+ MinPartitionsCount: 1
+ SizeToSplit: 100500
+ FastSplitSettings {
+ SizeThreshold: 100500
+ RowCountThreshold: 100500
+ }
+ }
+ }
+ )");
+ auto wellCookedToken = NACLib::TUserToken(TVector<TString>{"true-root@builtin"});
+ request->Record.SetUserToken(wellCookedToken.SerializeAsString());
+ TActorId sender = runtime.AllocateEdgeActor();
+ ForwardToTablet(runtime, TTestTxConfig::SchemeShard, sender, request);
+ TestModificationResults(runtime, txId, {TEvSchemeShard::EStatus::StatusAccepted});
+
+ env.TestWaitNotification(runtime, txId);
+ }
+
+ while (true) {
+ TVector<THolder<IEventHandle>> suppressed;
+ auto prevObserver = SetSuppressObserver(runtime, suppressed, TEvDataShard::TEvPeriodicTableStats::EventType);
+
+ WaitForSuppressed(runtime, suppressed, 10, prevObserver);
+ for (auto &msg : suppressed) {
+ runtime.Send(msg.Release());
+ }
+ suppressed.clear();
+
+ bool itIsEnough = false;
+
+ auto desrc = DescribePath(runtime, "/MyRoot/table/indexByValue/indexImplTable", true, true, true);
+
+ NLs::TCheckFunc checkPartitionCount = [&] (const NKikimrScheme::TEvDescribeSchemeResult& record) {
+ if (record.GetPathDescription().TablePartitionsSize() == 1) {
+ itIsEnough = true;
+ }
+ };
+
+ auto pathVersion = TestDescribeResult(desrc, {checkPartitionCount});
+
+ if (itIsEnough) {
+ break;
+ }
+
+ for (const auto& tPart: desrc.GetPathDescription().GetTablePartitions()) {
+ TActorId sender = runtime.AllocateEdgeActor();
+ auto evTx = new TEvDataShard::TEvCompactBorrowed(pathVersion.PathId);
+ ForwardToTablet(runtime, tPart.GetDatashardId(), sender, evTx);
+ }
+ }
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table/indexByValue", true, true, true),
+ {NLs::PathExist,
+ NLs::PathVersionEqual(4)});
+
+ TestDescribeResult(DescribePath(runtime, "/MyRoot/table/indexByValue/indexImplTable", true, true, true),
+ {NLs::PathExist,
+ NLs::PathVersionOneOf({8}),
+ NLs::PartitionCount(1),
+ NLs::MinPartitionsCountEqual(1),
+ NLs::MaxPartitionsCountEqual(100)});
+ }
}
diff --git a/ydb/core/tx/schemeshard/ut_index_build.cpp b/ydb/core/tx/schemeshard/ut_index_build.cpp
index 88860481cc..bde0dbc59f 100644
--- a/ydb/core/tx/schemeshard/ut_index_build.cpp
+++ b/ydb/core/tx/schemeshard/ut_index_build.cpp
@@ -298,7 +298,7 @@ Y_UNIT_TEST_SUITE(IndexBuildTest) {
TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"),
{NLs::PathExist,
NLs::IndexesCount(1),
- NLs::PathVersionEqual(5)});
+ NLs::PathVersionEqual(6)});
TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table/index1", true, true, true),
{NLs::PathExist,
@@ -319,7 +319,7 @@ Y_UNIT_TEST_SUITE(IndexBuildTest) {
TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"),
{NLs::PathExist,
NLs::IndexesCount(0),
- NLs::PathVersionEqual(7)});
+ NLs::PathVersionEqual(8)});
// Test that index build succeeds on recreated columns
@@ -561,7 +561,7 @@ Y_UNIT_TEST_SUITE(IndexBuildTest) {
TestDescribeResult(DescribePath(runtime, "/MyRoot/WithFollowers"),
{NLs::PathExist,
NLs::IndexesCount(1),
- NLs::PathVersionEqual(5)});
+ NLs::PathVersionEqual(6)});
TestDescribeResult(DescribePath(runtime, "/MyRoot/WithFollowers/UserDefinedIndexByValue0", true, true, true),
{NLs::PathExist,
@@ -580,7 +580,7 @@ Y_UNIT_TEST_SUITE(IndexBuildTest) {
TestDescribeResult(DescribePath(runtime, "/MyRoot/WithFollowers"),
{NLs::PathExist,
NLs::IndexesCount(0),
- NLs::PathVersionEqual(7)});
+ NLs::PathVersionEqual(8)});
}
Y_UNIT_TEST(RejectsCreate) {
@@ -992,7 +992,7 @@ Y_UNIT_TEST_SUITE(IndexBuildTest) {
TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"),
{NLs::PathExist,
NLs::IndexesCount(1),
- NLs::PathVersionEqual(5)});
+ NLs::PathVersionEqual(6)});
TestDescribeResult(DescribePath(runtime, "/MyRoot/Table/index1", true, true, true),
{NLs::PathExist});
diff --git a/ydb/core/tx/schemeshard/ut_index_build_reboots.cpp b/ydb/core/tx/schemeshard/ut_index_build_reboots.cpp
index d270fd87e6..543d52895d 100644
--- a/ydb/core/tx/schemeshard/ut_index_build_reboots.cpp
+++ b/ydb/core/tx/schemeshard/ut_index_build_reboots.cpp
@@ -415,7 +415,7 @@ Y_UNIT_TEST_SUITE(IndexBuildTestReboots) {
TestDescribeResult(DescribePath(runtime, "/MyRoot/dir/Table"),
{NLs::PathExist,
NLs::IndexesCount(1),
- NLs::PathVersionEqual(5)});
+ NLs::PathVersionEqual(6)});
TestDescribeResult(DescribePath(runtime, "/MyRoot/dir/Table/index1", true, true, true),
{NLs::PathExist});