Skip to content

Commit 7792457

Browse files
authored
24-3: schemeshard: preserialize Table.SplitBoundary for describe result (#6847)
merged 83a86c2 from main Preserialize table's split boundaries the same way table partitions are. The size of both depend on the same variable: number of shards in the table, but TablePartitions was preserialized (and cached) while Table.SplitBoundaries wasn't. Preserializing all potentially huge parts of DescribeSchemeResult message before it gets to the interconnect saves interconnect actors additional serialization costs. And when partitioning of the huge tables goes through the period of a rapid change that additional serialization causes interconnect to overload. Single shortcoming though: preserialized SplitBoundary is not used (cannot be used) when boundaries of the index tables are requested through describe request on table index. KIKIMR-21686
1 parent 56c68e1 commit 7792457

7 files changed

+113
-84
lines changed

ydb/core/tx/schemeshard/schemeshard__operation_alter_continuous_backup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ TVector<ISubOperation::TPtr> CreateAlterContinuousBackup(TOperationId opId, cons
8383
const NScheme::TTypeRegistry* typeRegistry = AppData(context.Ctx)->TypeRegistry;
8484

8585
NKikimrSchemeOp::TTableDescription schema;
86-
context.SS->DescribeTable(table, typeRegistry, true, false, &schema);
86+
context.SS->DescribeTable(table, typeRegistry, true, &schema);
8787
schema.MutablePartitionConfig()->CopyFrom(table->TableDescription.GetPartitionConfig());
8888

8989
TString errStr;

ydb/core/tx/schemeshard/schemeshard__operation_copy_table.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ void PrepareScheme(NKikimrSchemeOp::TTableDescription* schema, const TString& na
1414
const NScheme::TTypeRegistry* typeRegistry = AppData(context.Ctx)->TypeRegistry;
1515

1616
NKikimrSchemeOp::TTableDescription completedSchema;
17-
context.SS->DescribeTable(srcTableInfo, typeRegistry, true, false, &completedSchema);
17+
context.SS->DescribeTable(srcTableInfo, typeRegistry, true, &completedSchema);
1818
completedSchema.SetName(name);
1919

2020
//inherit all from Src except PartitionConfig, PartitionConfig could be altered

ydb/core/tx/schemeshard/schemeshard_impl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,8 +598,9 @@ void TSchemeShard::ClearDescribePathCaches(const TPathElement::TPtr node, bool f
598598
} else if (node->PathType == NKikimrSchemeOp::EPathType::EPathTypeTable) {
599599
Y_ABORT_UNLESS(Tables.contains(node->PathId));
600600
TTableInfo::TPtr tabletInfo = Tables.at(node->PathId);
601-
tabletInfo->PreSerializedPathDescription.clear();
602-
tabletInfo->PreSerializedPathDescriptionWithoutRangeKey.clear();
601+
tabletInfo->PreserializedTablePartitions.clear();
602+
tabletInfo->PreserializedTablePartitionsNoKeys.clear();
603+
tabletInfo->PreserializedTableSplitBoundaries.clear();
603604
}
604605
}
605606

ydb/core/tx/schemeshard/schemeshard_impl.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ class TSchemeShard
10151015
void FillAsyncIndexInfo(const TPathId& tableId, NKikimrTxDataShard::TFlatSchemeTransaction& tx);
10161016

10171017
void DescribeTable(const TTableInfo::TPtr tableInfo, const NScheme::TTypeRegistry* typeRegistry,
1018-
bool fillConfig, bool fillBoundaries, NKikimrSchemeOp::TTableDescription* entry) const;
1018+
bool fillConfig, NKikimrSchemeOp::TTableDescription* entry) const;
10191019
void DescribeTableIndex(const TPathId& pathId, const TString& name,
10201020
bool fillConfig, bool fillBoundaries, NKikimrSchemeOp::TIndexDescription& entry
10211021
) const;
@@ -1031,7 +1031,6 @@ class TSchemeShard
10311031
void DescribeReplication(const TPathId& pathId, const TString& name, NKikimrSchemeOp::TReplicationDescription& desc);
10321032
void DescribeReplication(const TPathId& pathId, const TString& name, TReplicationInfo::TPtr info, NKikimrSchemeOp::TReplicationDescription& desc);
10331033
void DescribeBlobDepot(const TPathId& pathId, const TString& name, NKikimrSchemeOp::TBlobDepotDescription& desc);
1034-
static void FillTableBoundaries(const TTableInfo::TPtr tableInfo, google::protobuf::RepeatedPtrField<NKikimrSchemeOp::TSplitBoundary>& boundaries);
10351034

10361035
void Handle(NKikimr::NOlap::NBackground::TEvExecuteGeneralLocalTransaction::TPtr& ev, const TActorContext& ctx);
10371036
void Handle(NKikimr::NOlap::NBackground::TEvRemoveSession::TPtr& ev, const TActorContext& ctx);

ydb/core/tx/schemeshard/schemeshard_info_types.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,10 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData(
356356
const TTableInfo::TColumn& sourceColumn = source->Columns[colId];
357357

358358
if (col.HasDefaultFromSequence()) {
359-
if (sourceColumn.PType.GetTypeId() != NScheme::NTypeIds::Int64
359+
if (sourceColumn.PType.GetTypeId() != NScheme::NTypeIds::Int64
360360
&& NPg::PgTypeIdFromTypeDesc(sourceColumn.PType.GetTypeDesc()) != INT8OID) {
361-
TString sequenceType = sourceColumn.PType.GetTypeId() == NScheme::NTypeIds::Pg
362-
? NPg::PgTypeNameFromTypeDesc(NPg::TypeDescFromPgTypeId(INT8OID))
361+
TString sequenceType = sourceColumn.PType.GetTypeId() == NScheme::NTypeIds::Pg
362+
? NPg::PgTypeNameFromTypeDesc(NPg::TypeDescFromPgTypeId(INT8OID))
363363
: NScheme::TypeName(NScheme::NTypeIds::Int64);
364364
errStr = Sprintf(
365365
"Sequence value type '%s' must be equal to the column type '%s'", sequenceType.c_str(),
@@ -411,7 +411,7 @@ TTableInfo::TAlterDataPtr TTableInfo::CreateAlterData(
411411
return nullptr;
412412
default:
413413
break;
414-
}
414+
}
415415
}
416416
} else {
417417
auto* typeDesc = NPg::TypeDescFromPgTypeName(typeName);
@@ -1614,8 +1614,9 @@ void TTableInfo::SetPartitioning(TVector<TTableShardInfo>&& newPartitioning) {
16141614
Stats.PartitionStats.swap(newPartitionStats);
16151615
Stats.Aggregated = newAggregatedStats;
16161616
Partitions.swap(newPartitioning);
1617-
PreSerializedPathDescription.clear();
1618-
PreSerializedPathDescriptionWithoutRangeKey.clear();
1617+
PreserializedTablePartitions.clear();
1618+
PreserializedTablePartitionsNoKeys.clear();
1619+
PreserializedTableSplitBoundaries.clear();
16191620

16201621
CondEraseSchedule.clear();
16211622
InFlightCondErase.clear();

ydb/core/tx/schemeshard/schemeshard_info_types.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,11 @@ struct TTableInfo : public TSimpleRefCount<TTableInfo> {
436436
TMap<TTxId, TBackupRestoreResult> BackupHistory;
437437
TMap<TTxId, TBackupRestoreResult> RestoreHistory;
438438

439-
TString PreSerializedPathDescription;
440-
TString PreSerializedPathDescriptionWithoutRangeKey;
439+
// Preserialized TDescribeSchemeResult with PathDescription.TablePartitions field filled
440+
TString PreserializedTablePartitions;
441+
TString PreserializedTablePartitionsNoKeys;
442+
// Preserialized TDescribeSchemeResult with PathDescription.Table.SplitBoundary field filled
443+
TString PreserializedTableSplitBoundaries;
441444

442445
THashMap<TShardIdx, NKikimrSchemeOp::TPartitionConfig> PerShardPartitionConfig;
443446

ydb/core/tx/schemeshard/schemeshard_path_describer.cpp

Lines changed: 95 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,68 @@ void TPathDescriber::DescribeDir(const TPath& path) {
217217
DescribeChildren(path);
218218
}
219219

220+
void FillTableBoundaries(
221+
google::protobuf::RepeatedPtrField<NKikimrSchemeOp::TSplitBoundary>* result,
222+
const TTableInfo::TPtr tableInfo
223+
) {
224+
TString errStr;
225+
// Number of split boundaries equals to number of partitions - 1
226+
result->Reserve(tableInfo->GetPartitions().size() - 1);
227+
for (ui32 pi = 0; pi < tableInfo->GetPartitions().size() - 1; ++pi) {
228+
const auto& p = tableInfo->GetPartitions()[pi];
229+
TSerializedCellVec endKey(p.EndOfRange);
230+
auto boundary = result->Add()->MutableKeyPrefix();
231+
for (ui32 ki = 0; ki < endKey.GetCells().size(); ++ki){
232+
const auto& c = endKey.GetCells()[ki];
233+
auto type = tableInfo->Columns[tableInfo->KeyColumnIds[ki]].PType;
234+
bool ok = NMiniKQL::CellToValue(type, c, *boundary->AddTuple(), errStr);
235+
Y_ABORT_UNLESS(ok, "Failed to build key tuple at position %" PRIu32 " error: %s", ki, errStr.data());
236+
}
237+
}
238+
}
239+
240+
void FillTablePartitions(
241+
google::protobuf::RepeatedPtrField<NKikimrSchemeOp::TTablePartition>* result,
242+
const TTableInfo::TPtr tableInfo,
243+
const THashMap<TShardIdx, TShardInfo>& shardInfos,
244+
bool includeKeys
245+
) {
246+
result->Reserve(tableInfo->GetPartitions().size());
247+
for (auto& p : tableInfo->GetPartitions()) {
248+
const auto& tabletId = ui64(shardInfos.at(p.ShardIdx).TabletID);
249+
const auto& key = p.EndOfRange;
250+
251+
auto part = result->Add();
252+
part->SetDatashardId(tabletId);
253+
if (includeKeys) {
254+
// Currently we only support uniform partitioning where each range is [start, end)
255+
// +inf as the end of the last range is represented by empty TCell vector
256+
part->SetIsPoint(false);
257+
part->SetIsInclusive(false);
258+
part->SetEndOfRangeKeyPrefix(key);
259+
}
260+
}
261+
}
262+
263+
const TString& GetSerializedTablePartitions(
264+
const TTableInfo::TPtr tableInfo,
265+
const THashMap<TShardIdx, TShardInfo>& shardInfos,
266+
bool returnRangeKey
267+
) {
268+
TString& cache = (returnRangeKey
269+
? tableInfo->PreserializedTablePartitions
270+
: tableInfo->PreserializedTablePartitionsNoKeys
271+
);
272+
273+
if (cache.empty()) {
274+
NKikimrScheme::TEvDescribeSchemeResult result;
275+
FillTablePartitions(result.MutablePathDescription()->MutableTablePartitions(), tableInfo, shardInfos, returnRangeKey);
276+
Y_PROTOBUF_SUPPRESS_NODISCARD result.SerializeToString(&cache);
277+
}
278+
279+
return cache;
280+
}
281+
220282
void TPathDescriber::DescribeTable(const TActorContext& ctx, TPathId pathId, TPathElement::TPtr pathEl) {
221283
const NScheme::TTypeRegistry* typeRegistry = AppData(ctx)->TypeRegistry;
222284
const TTableInfo::TPtr tableInfo = *Self->Tables.FindPtr(pathId);
@@ -238,50 +300,30 @@ void TPathDescriber::DescribeTable(const TActorContext& ctx, TPathId pathId, TPa
238300
returnRangeKey = Params.GetOptions().GetReturnRangeKey();
239301
}
240302

241-
Self->DescribeTable(tableInfo, typeRegistry, returnConfig, returnBoundaries, entry);
303+
Self->DescribeTable(tableInfo, typeRegistry, returnConfig, entry);
242304
entry->SetName(pathEl->Name);
243305

244-
if (returnPartitioning) {
245-
// partitions
246-
if (tableInfo->PreSerializedPathDescription.empty()) {
306+
if (returnBoundaries) {
307+
// split boundaries (split keys without shard's tablet-ids)
308+
if (tableInfo->PreserializedTableSplitBoundaries.empty()) {
247309
NKikimrScheme::TEvDescribeSchemeResult preSerializedResult;
248-
NKikimrScheme::TEvDescribeSchemeResult preSerializedResultWithoutRangeKey;
249-
250-
NKikimrSchemeOp::TPathDescription& pathDescription = *preSerializedResult.MutablePathDescription();
251-
NKikimrSchemeOp::TPathDescription& pathDescriptionWithoutRangeKey = *preSerializedResultWithoutRangeKey.MutablePathDescription();
252-
253-
pathDescription.MutableTablePartitions()->Reserve(tableInfo->GetPartitions().size());
254-
pathDescriptionWithoutRangeKey.MutableTablePartitions()->Reserve(tableInfo->GetPartitions().size());
255-
for (auto& p : tableInfo->GetPartitions()) {
256-
auto part = pathDescription.AddTablePartitions();
257-
auto partWithoutRangeKey = pathDescriptionWithoutRangeKey.AddTablePartitions();
258-
auto datashardIdx = p.ShardIdx;
259-
auto datashardTabletId = Self->ShardInfos[datashardIdx].TabletID;
260-
// Currently we only support uniform partitioning where each range is [start, end)
261-
// +inf as the end of the last range is represented by empty TCell vector
262-
part->SetDatashardId(ui64(datashardTabletId));
263-
partWithoutRangeKey->SetDatashardId(ui64(datashardTabletId));
264-
265-
part->SetIsPoint(false);
266-
partWithoutRangeKey->SetIsPoint(false);
267-
268-
part->SetIsInclusive(false);
269-
partWithoutRangeKey->SetIsInclusive(false);
270-
271-
part->SetEndOfRangeKeyPrefix(p.EndOfRange);
272-
}
273-
Y_PROTOBUF_SUPPRESS_NODISCARD preSerializedResult.SerializeToString(&tableInfo->PreSerializedPathDescription);
274-
Y_PROTOBUF_SUPPRESS_NODISCARD preSerializedResultWithoutRangeKey.SerializeToString(&tableInfo->PreSerializedPathDescriptionWithoutRangeKey);
275-
}
276-
if (returnRangeKey) {
277-
Result->PreSerializedData += tableInfo->PreSerializedPathDescription;
278-
} else {
279-
Result->PreSerializedData += tableInfo->PreSerializedPathDescriptionWithoutRangeKey;
280-
}
281-
if (!pathEl->IsCreateFinished()) {
282-
tableInfo->PreSerializedPathDescription.clear(); // KIKIMR-4337
283-
tableInfo->PreSerializedPathDescriptionWithoutRangeKey.clear();
310+
auto& tableDesc = *preSerializedResult.MutablePathDescription()->MutableTable();
311+
FillTableBoundaries(tableDesc.MutableSplitBoundary(), tableInfo);
312+
Y_PROTOBUF_SUPPRESS_NODISCARD preSerializedResult.SerializeToString(&tableInfo->PreserializedTableSplitBoundaries);
284313
}
314+
Result->PreSerializedData += tableInfo->PreserializedTableSplitBoundaries;
315+
}
316+
317+
if (returnPartitioning) {
318+
// partitions (shard tablet-ids with range keys)
319+
Result->PreSerializedData += GetSerializedTablePartitions(tableInfo, Self->ShardInfos, returnRangeKey);
320+
}
321+
322+
// KIKIMR-4337: table info is in flux until table is finally created
323+
if (!pathEl->IsCreateFinished()) {
324+
tableInfo->PreserializedTablePartitions.clear();
325+
tableInfo->PreserializedTablePartitionsNoKeys.clear();
326+
tableInfo->PreserializedTableSplitBoundaries.clear();
285327
}
286328

287329
FillAggregatedStats(*Result->Record.MutablePathDescription(), tableInfo->GetStats());
@@ -1122,8 +1164,12 @@ THolder<TEvSchemeShard::TEvDescribeSchemeResultBuilder> DescribePath(
11221164
return DescribePath(self, ctx, pathId, options);
11231165
}
11241166

1125-
void TSchemeShard::DescribeTable(const TTableInfo::TPtr tableInfo, const NScheme::TTypeRegistry* typeRegistry,
1126-
bool fillConfig, bool fillBoundaries, NKikimrSchemeOp::TTableDescription* entry) const
1167+
void TSchemeShard::DescribeTable(
1168+
const TTableInfo::TPtr tableInfo,
1169+
const NScheme::TTypeRegistry* typeRegistry,
1170+
bool fillConfig,
1171+
NKikimrSchemeOp::TTableDescription* entry
1172+
) const
11271173
{
11281174
Y_UNUSED(typeRegistry);
11291175
THashMap<ui32, TString> familyNames;
@@ -1192,10 +1238,6 @@ void TSchemeShard::DescribeTable(const TTableInfo::TPtr tableInfo, const NScheme
11921238
FillPartitionConfig(tableInfo->PartitionConfig(), *entry->MutablePartitionConfig());
11931239
}
11941240

1195-
if (fillBoundaries) {
1196-
FillTableBoundaries(tableInfo, *entry->MutableSplitBoundary());
1197-
}
1198-
11991241
if (tableInfo->HasTTLSettings()) {
12001242
entry->MutableTTLSettings()->CopyFrom(tableInfo->TTLSettings());
12011243
}
@@ -1238,23 +1280,23 @@ void TSchemeShard::DescribeTableIndex(const TPathId& pathId, const TString& name
12381280
*entry.MutableDataColumnNames()->Add() = dataColumns;
12391281
}
12401282

1241-
auto* indexPath = PathsById.FindPtr(pathId);
1283+
auto indexPath = *PathsById.FindPtr(pathId);
12421284
Y_ABORT_UNLESS(indexPath);
1243-
Y_ABORT_UNLESS((*indexPath)->GetChildren().size() == 1);
1244-
const auto& indexImplTablePathId = (*indexPath)->GetChildren().begin()->second;
1285+
Y_ABORT_UNLESS(indexPath->GetChildren().size() == 1);
1286+
const auto& indexImplTablePathId = indexPath->GetChildren().begin()->second;
12451287

1246-
auto* tableInfo = Tables.FindPtr(indexImplTablePathId);
1288+
auto tableInfo = *Tables.FindPtr(indexImplTablePathId);
12471289
Y_ABORT_UNLESS(tableInfo);
12481290

1249-
const auto& tableStats = (*tableInfo)->GetStats().Aggregated;
1291+
const auto& tableStats = tableInfo->GetStats().Aggregated;
12501292
entry.SetDataSize(tableStats.DataSize + tableStats.IndexSize);
12511293

12521294
auto* tableDescription = entry.AddIndexImplTableDescriptions();
12531295
if (fillConfig) {
1254-
FillPartitionConfig((*tableInfo)->PartitionConfig(), *tableDescription->MutablePartitionConfig());
1296+
FillPartitionConfig(tableInfo->PartitionConfig(), *tableDescription->MutablePartitionConfig());
12551297
}
12561298
if (fillBoundaries) {
1257-
FillTableBoundaries(*tableInfo, *tableDescription->MutableSplitBoundary());
1299+
FillTableBoundaries(tableDescription->MutableSplitBoundary(), tableInfo);
12581300
}
12591301
}
12601302

@@ -1401,22 +1443,5 @@ void TSchemeShard::DescribeBlobDepot(const TPathId& pathId, const TString& name,
14011443
desc.SetTabletId(static_cast<ui64>(it->second->BlobDepotTabletId));
14021444
}
14031445

1404-
void TSchemeShard::FillTableBoundaries(const TTableInfo::TPtr tableInfo, google::protobuf::RepeatedPtrField<NKikimrSchemeOp::TSplitBoundary>& boundaries) {
1405-
TString errStr;
1406-
// Number of split boundaries equals to number of partitions - 1
1407-
boundaries.Reserve(tableInfo->GetPartitions().size() - 1);
1408-
for (ui32 pi = 0; pi < tableInfo->GetPartitions().size() - 1; ++pi) {
1409-
const auto& p = tableInfo->GetPartitions()[pi];
1410-
TSerializedCellVec endKey(p.EndOfRange);
1411-
auto boundary = boundaries.Add()->MutableKeyPrefix();
1412-
for (ui32 ki = 0; ki < endKey.GetCells().size(); ++ki){
1413-
const auto& c = endKey.GetCells()[ki];
1414-
auto type = tableInfo->Columns[tableInfo->KeyColumnIds[ki]].PType;
1415-
bool ok = NMiniKQL::CellToValue(type, c, *boundary->AddTuple(), errStr);
1416-
Y_ABORT_UNLESS(ok, "Failed to build key tuple at position %" PRIu32 " error: %s", ki, errStr.data());
1417-
}
1418-
}
1419-
}
1420-
14211446
} // NSchemeShard
14221447
} // NKikimr

0 commit comments

Comments
 (0)