@@ -4303,7 +4303,7 @@ const NTable::TScheme& TExecutor::DatabaseScheme()
43034303 return Scheme ();
43044304}
43054305
4306- TIntrusiveConstPtr<NTable::TRowScheme> TExecutor::RowScheme (ui32 table)
4306+ TIntrusiveConstPtr<NTable::TRowScheme> TExecutor::RowScheme (ui32 table) const
43074307{
43084308 return Database->GetRowScheme (table);
43094309}
@@ -4344,6 +4344,80 @@ const NTable::TRowVersionRanges& TExecutor::TableRemovedRowVersions(ui32 table)
43444344 return Database->GetRemovedRowVersions (table);
43454345}
43464346
4347+ bool TExecutor::HasSchemaChanges (ui32 table) const {
4348+ auto *tableInfo = Scheme ().GetTableInfo (table);
4349+ auto rowScheme = RowScheme (table);
4350+ if (!tableInfo || !rowScheme) {
4351+ return false ;
4352+ }
4353+
4354+ auto subset = Database->Subset (table, NTable::TEpoch::Max (), { } , { });
4355+ for (const auto & partView : subset->Flatten ) {
4356+ if (HasSchemaChanges (partView, *tableInfo, *rowScheme)) {
4357+ return true ;
4358+ }
4359+ }
4360+
4361+ return false ;
4362+ }
4363+
4364+ bool TExecutor::HasSchemaChanges (const NTable::TPartView& partView, const NTable::TScheme::TTableInfo& tableInfo, const NTable::TRowScheme& rowScheme) const {
4365+ if (partView.Part ->Stat .Rows == 0 ) {
4366+ return false ;
4367+ }
4368+
4369+ { // Check by key filter existence
4370+ bool partByKeyFilter = bool (partView->ByKey );
4371+ bool schemeByKeyFilter = tableInfo.ByKeyFilter ;
4372+ if (partByKeyFilter != schemeByKeyFilter) {
4373+ return true ;
4374+ }
4375+ }
4376+
4377+ { // Check B-Tree index existence
4378+ if (AppData ()->FeatureFlags .GetEnableLocalDBBtreeIndex () && !partView->IndexPages .HasBTree ()) {
4379+ return true ;
4380+ }
4381+ }
4382+
4383+ { // Check families
4384+ size_t partFamiliesCount = partView->GroupsCount ;
4385+ size_t schemeFamiliesCount = rowScheme.Families .size ();
4386+ if (partFamiliesCount != schemeFamiliesCount) {
4387+ return true ;
4388+ }
4389+
4390+ for (size_t index : xrange (rowScheme.Families .size ())) {
4391+ auto familyId = rowScheme.Families [index];
4392+ static const NTable::TScheme::TFamily defaultFamilySettings;
4393+ const auto & family = tableInfo.Families .ValueRef (familyId, defaultFamilySettings); // Workaround for KIKIMR-17222
4394+
4395+ const auto * schemeGroupRoom = tableInfo.Rooms .FindPtr (family.Room );
4396+ Y_ABORT_UNLESS (schemeGroupRoom, " Cannot find room %" PRIu32 " in table %" PRIu32, family.Room , tableInfo.Id );
4397+
4398+ ui32 partGroupChannel = partView.Part ->GetGroupChannel (NTable::NPage::TGroupId (index));
4399+ if (partGroupChannel != schemeGroupRoom->Main ) {
4400+ return true ;
4401+ }
4402+ }
4403+ }
4404+
4405+ { // Check columns
4406+ THashMap<NTable::TTag, ui32> partColumnGroups, schemeColumnGroups;
4407+ for (const auto & column : partView->Scheme ->AllColumns ) {
4408+ partColumnGroups[column.Tag ] = column.Group ;
4409+ }
4410+ for (const auto & col : rowScheme.Cols ) {
4411+ schemeColumnGroups[col.Tag ] = col.Group ;
4412+ }
4413+ if (partColumnGroups != schemeColumnGroups) {
4414+ return true ;
4415+ }
4416+ }
4417+
4418+ return false ;
4419+ }
4420+
43474421ui64 TExecutor::BeginCompaction (THolder<NTable::TCompactionParams> params)
43484422{
43494423 if (auto logl = Logger->Log (ELnLev::Info))
@@ -4383,37 +4457,29 @@ ui64 TExecutor::BeginCompaction(THolder<NTable::TCompactionParams> params)
43834457
43844458 for (size_t group : xrange (rowScheme->Families .size ())) {
43854459 auto familyId = rowScheme->Families [group];
4386- const auto * family = tableInfo->Families .FindPtr (familyId);
4387- if (Y_UNLIKELY (!family)) {
4388- // FIXME: workaround for KIKIMR-17222
4389- // Column families with default settings may be missing in schema,
4390- // so we have to use a static variable as a substitute
4391- static const NTable::TScheme::TFamily defaultFamilySettings;
4392- family = &defaultFamilySettings;
4393- }
4394- Y_ABORT_UNLESS (family, " Cannot find family %" PRIu32 " in table %" PRIu32, familyId, table);
4460+ static const NTable::TScheme::TFamily defaultFamilySettings;
4461+ const auto & family = tableInfo->Families .ValueRef (familyId, defaultFamilySettings); // Workaround for KIKIMR-17222
43954462
4396- auto roomId = family->Room ;
4397- auto * room = tableInfo->Rooms .FindPtr (roomId);
4398- Y_ABORT_UNLESS (room, " Cannot find room %" PRIu32 " in table %" PRIu32, roomId, table);
4463+ auto * room = tableInfo->Rooms .FindPtr (family.Room );
4464+ Y_ABORT_UNLESS (room, " Cannot find room %" PRIu32 " in table %" PRIu32, family.Room , table);
43994465
44004466 auto & pageGroup = comp->Layout .Groups .at (group);
44014467 auto & writeGroup = comp->Writer .Groups .at (group);
44024468
4403- pageGroup.Codec = family-> Codec ;
4469+ pageGroup.Codec = family. Codec ;
44044470 pageGroup.PageSize = policy->MinDataPageSize ;
44054471 pageGroup.BTreeIndexNodeTargetSize = policy->MinBTreeIndexNodeSize ;
44064472 pageGroup.BTreeIndexNodeKeysMin = policy->MinBTreeIndexNodeKeys ;
44074473
4408- writeGroup.Cache = Max (family-> Cache , cache);
4474+ writeGroup.Cache = Max (family. Cache , cache);
44094475 writeGroup.MaxBlobSize = NBlockIO::BlockSize;
44104476 writeGroup.Channel = room->Main ;
44114477 addChannel (room->Main );
44124478
44134479 if (group == 0 ) {
44144480 // Small/Large edges are taken from the leader family
4415- comp->Layout .SmallEdge = family-> Small ;
4416- comp->Layout .LargeEdge = family-> Large ;
4481+ comp->Layout .SmallEdge = family. Small ;
4482+ comp->Layout .LargeEdge = family. Large ;
44174483
44184484 // Small/Large channels are taken from the leader family
44194485 comp->Writer .BlobsChannel = room->Blobs ;
0 commit comments