diff --git a/ydb/core/tablet_flat/benchmark/b_part_index.cpp b/ydb/core/tablet_flat/benchmark/b_part_index.cpp index bdc875909192..c991a2d13fff 100644 --- a/ydb/core/tablet_flat/benchmark/b_part_index.cpp +++ b/ydb/core/tablet_flat/benchmark/b_part_index.cpp @@ -70,7 +70,7 @@ namespace { Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl; Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Groups[groups ? 1 : 0], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeGroups[groups ? 1 : 0].IndexSize << Endl; - Cerr << "Levels = " << part->IndexPages.BTreeGroups[groups ? 1 : 0].LevelsCount << Endl; + Cerr << "Levels = " << part->IndexPages.BTreeGroups[groups ? 1 : 0].LevelCount << Endl; // 100 MB UNIT_ASSERT_GE(part->Stat.Bytes, 100ull*1024*1024); diff --git a/ydb/core/tablet_flat/flat_page_btree_index.h b/ydb/core/tablet_flat/flat_page_btree_index.h index 968fb5f9c742..0fc722dcce92 100644 --- a/ydb/core/tablet_flat/flat_page_btree_index.h +++ b/ydb/core/tablet_flat/flat_page_btree_index.h @@ -85,7 +85,7 @@ namespace NKikimr::NTable::NPage { struct TShortChild { TPageId PageId; - TRowId Count; + TRowId RowCount; ui64 DataSize; auto operator<=>(const TShortChild&) const = default; @@ -95,22 +95,22 @@ namespace NKikimr::NTable::NPage { struct TChild { TPageId PageId; - TRowId Count; + TRowId RowCount; ui64 DataSize; - TRowId ErasedCount; + TRowId ErasedRowCount; auto operator<=>(const TChild&) const = default; TString ToString() const noexcept { - return TStringBuilder() << "PageId: " << PageId << " Count: " << Count << " DataSize: " << DataSize << " Erased: " << ErasedCount; + return TStringBuilder() << "PageId: " << PageId << " RowCount: " << RowCount << " DataSize: " << DataSize << " ErasedRowCount: " << ErasedRowCount; } } Y_PACKED; static_assert(sizeof(TChild) == 28, "Invalid TBtreeIndexNode TChild size"); static_assert(offsetof(TChild, PageId) == offsetof(TShortChild, PageId)); - static_assert(offsetof(TChild, Count) == offsetof(TShortChild, Count)); + static_assert(offsetof(TChild, RowCount) == offsetof(TShortChild, RowCount)); static_assert(offsetof(TChild, DataSize) == offsetof(TShortChild, DataSize)); #pragma pack(pop) @@ -306,7 +306,7 @@ namespace NKikimr::NTable::NPage { { if (Header->IsShortChildFormat) { const TShortChild* const shortChild = TDeref::At(Children, pos * sizeof(TShortChild)); - return { shortChild->PageId, shortChild->Count, shortChild->DataSize, 0 }; + return { shortChild->PageId, shortChild->RowCount, shortChild->DataSize, 0 }; } else { return *TDeref::At(Children, pos * sizeof(TChild)); } @@ -316,7 +316,7 @@ namespace NKikimr::NTable::NPage { return beginRowId <= rowId && rowId < endRowId; } - TRecIdx Seek(TRowId rowId, std::optional on) const noexcept + TRecIdx Seek(TRowId rowId, std::optional on = { }) const noexcept { const TRecIdx childrenCount = GetChildrenCount(); if (on && on >= childrenCount) { @@ -326,19 +326,19 @@ namespace NKikimr::NTable::NPage { auto range = xrange(0u, childrenCount); const auto cmp = [this](TRowId rowId, TPos pos) { - return rowId < GetShortChild(pos).Count; + return rowId < GetShortChild(pos).RowCount; }; TRecIdx result; if (!on) { // Will do a full binary search on full range - } else if (GetShortChild(*on).Count <= rowId) { + } else if (GetShortChild(*on).RowCount <= rowId) { // Try a short linear search first result = *on; for (int linear = 0; linear < 4; ++linear) { result++; Y_ABORT_UNLESS(result < childrenCount, "Should always seek some child"); - if (GetShortChild(result).Count > rowId) { + if (GetShortChild(result).RowCount > rowId) { return result; } } @@ -352,7 +352,7 @@ namespace NKikimr::NTable::NPage { if (result == 0) { return 0; } - if (GetShortChild(result - 1).Count <= rowId) { + if (GetShortChild(result - 1).RowCount <= rowId) { return result; } result--; @@ -464,14 +464,14 @@ namespace NKikimr::NTable::NPage { }; struct TBtreeIndexMeta : public TBtreeIndexNode::TChild { - size_t LevelsCount; + ui32 LevelCount; ui64 IndexSize; auto operator<=>(const TBtreeIndexMeta&) const = default; TString ToString() const noexcept { - return TStringBuilder() << TBtreeIndexNode::TChild::ToString() << " LevelsCount: " << LevelsCount << " IndexSize: " << IndexSize; + return TStringBuilder() << TBtreeIndexNode::TChild::ToString() << " LevelCount: " << LevelCount << " IndexSize: " << IndexSize; } }; } diff --git a/ydb/core/tablet_flat/flat_page_btree_index_writer.h b/ydb/core/tablet_flat/flat_page_btree_index_writer.h index 0c7b084f0556..2a4627bf7e2d 100644 --- a/ydb/core/tablet_flat/flat_page_btree_index_writer.h +++ b/ydb/core/tablet_flat/flat_page_btree_index_writer.h @@ -50,7 +50,7 @@ namespace NKikimr::NTable::NPage { } void AddChild(TChild child) { - Y_ABORT_UNLESS(child.ErasedCount == 0 || !IsShortChildFormat(), "Short format can't have ErasedCount"); + Y_ABORT_UNLESS(child.ErasedRowCount == 0 || !IsShortChildFormat(), "Short format can't have ErasedRowCount"); Children.push_back(child); } @@ -249,7 +249,7 @@ namespace NKikimr::NTable::NPage { void PlaceChild(const TChild& child) noexcept { if (IsShortChildFormat()) { - Place() = TShortChild{child.PageId, child.Count, child.DataSize}; + Place() = TShortChild{child.PageId, child.RowCount, child.DataSize}; } else { Place() = child; } @@ -375,20 +375,21 @@ namespace NKikimr::NTable::NPage { } void AddShortChild(TShortChild child) { - AddChild(TChild{child.PageId, child.Count, child.DataSize, 0}); + AddChild(TChild{child.PageId, child.RowCount, child.DataSize, 0}); } void AddChild(TChild child) { // aggregate in order to perform search by row id from any leaf node - child.Count = (ChildrenCount += child.Count); - child.DataSize = (ChildrenSize += child.DataSize); - child.ErasedCount = (ChildrenErasedCount += child.ErasedCount); + child.RowCount = (ChildRowCount += child.RowCount); + child.DataSize = (ChildSize += child.DataSize); + child.ErasedRowCount = (ChildErasedRowCount += child.ErasedRowCount); Levels[0].PushChild(child); } std::optional Flush(IPageWriter &pager, bool last) { - for (size_t levelIndex = 0; levelIndex < Levels.size(); levelIndex++) { + Y_ABORT_UNLESS(Levels.size() < Max(), "Levels size is out of bounds"); + for (ui32 levelIndex = 0; levelIndex < Levels.size(); levelIndex++) { if (last && !Levels[levelIndex].GetKeysCount()) { Y_ABORT_UNLESS(Levels[levelIndex].GetChildrenCount() == 1, "Should be root"); return TBtreeIndexMeta{ Levels[levelIndex].PopChild(), levelIndex, IndexSize }; @@ -408,13 +409,13 @@ namespace NKikimr::NTable::NPage { IndexSize = 0; Writer.Reset(); Levels = { TLevel() }; - ChildrenCount = 0; - ChildrenErasedCount = 0; - ChildrenSize = 0; + ChildRowCount = 0; + ChildErasedRowCount = 0; + ChildSize = 0; } private: - bool TryFlush(size_t levelIndex, IPageWriter &pager, bool last) { + bool TryFlush(ui32 levelIndex, IPageWriter &pager, bool last) { if (!last && Levels[levelIndex].GetKeysCount() <= 2 * NodeKeysMax) { // Note: node should meet both NodeKeysMin and NodeSize restrictions for split @@ -462,7 +463,7 @@ namespace NKikimr::NTable::NPage { if (levelIndex + 1 == Levels.size()) { Levels.emplace_back(); } - Levels[levelIndex + 1].PushChild(TChild{pageId, lastChild.Count, lastChild.DataSize, lastChild.ErasedCount}); + Levels[levelIndex + 1].PushChild(TChild{pageId, lastChild.RowCount, lastChild.DataSize, lastChild.ErasedRowCount}); if (!last) { Levels[levelIndex + 1].PushKey(Levels[levelIndex].PopKey()); } @@ -497,9 +498,9 @@ namespace NKikimr::NTable::NPage { const ui32 NodeKeysMin; const ui32 NodeKeysMax; - TRowId ChildrenCount = 0; - TRowId ChildrenErasedCount = 0; - ui64 ChildrenSize = 0; + TRowId ChildRowCount = 0; + TRowId ChildErasedRowCount = 0; + ui64 ChildSize = 0; }; } diff --git a/ydb/core/tablet_flat/flat_part_btree_index_iter.h b/ydb/core/tablet_flat/flat_part_btree_index_iter.h index 92c5c69f2cb0..d924e670de40 100644 --- a/ydb/core/tablet_flat/flat_part_btree_index_iter.h +++ b/ydb/core/tablet_flat/flat_part_btree_index_iter.h @@ -1,7 +1,6 @@ #pragma once #include "flat_part_iface.h" -#include "flat_page_index.h" #include "flat_table_part.h" #include "flat_part_index_iter_iface.h" @@ -116,7 +115,7 @@ class TPartBtreeIndexIt : public IIndexIter { , GroupId(groupId) , GroupInfo(part->Scheme->GetLayout(groupId)) , Meta(groupId.IsHistoric() ? part->IndexPages.BTreeHistoric[groupId.Index] : part->IndexPages.BTreeGroups[groupId.Index]) - , State(Reserve(Meta.LevelsCount + 1)) + , State(Reserve(Meta.LevelCount + 1)) { const static TCellsIterable EmptyKey(static_cast(nullptr), TColumns()); State.emplace_back(Meta, 0, GetEndRowId(), EmptyKey, EmptyKey); @@ -181,7 +180,7 @@ class TPartBtreeIndexIt : public IIndexIter { EReady Next() override { Y_ABORT_UNLESS(!IsExhausted()); - if (Meta.LevelsCount == 0) { + if (Meta.LevelCount == 0) { return Exhaust(); } @@ -195,7 +194,7 @@ class TPartBtreeIndexIt : public IIndexIter { PushNextState(*State.back().Pos + 1); } - for (size_t level : xrange(State.size() - 1, Meta.LevelsCount)) { + for (ui32 level : xrange(State.size() - 1, Meta.LevelCount)) { if (!TryLoad(State[level])) { // exiting with an intermediate state Y_DEBUG_ABORT_UNLESS(!IsLeaf() && !IsExhausted()); @@ -212,7 +211,7 @@ class TPartBtreeIndexIt : public IIndexIter { EReady Prev() override { Y_ABORT_UNLESS(!IsExhausted()); - if (Meta.LevelsCount == 0) { + if (Meta.LevelCount == 0) { return Exhaust(); } @@ -226,7 +225,7 @@ class TPartBtreeIndexIt : public IIndexIter { PushNextState(*State.back().Pos - 1); } - for (size_t level : xrange(State.size() - 1, Meta.LevelsCount)) { + for (ui32 level : xrange(State.size() - 1, Meta.LevelCount)) { if (!TryLoad(State[level])) { // exiting with an intermediate state Y_DEBUG_ABORT_UNLESS(!IsLeaf() && !IsExhausted()); @@ -247,7 +246,7 @@ class TPartBtreeIndexIt : public IIndexIter { } TRowId GetEndRowId() const override { - return Meta.Count; + return Meta.RowCount; } TPageId GetPageId() const override { @@ -287,7 +286,7 @@ class TPartBtreeIndexIt : public IIndexIter { State[0].Pos = { }; } - for (size_t level : xrange(State.size() - 1, Meta.LevelsCount)) { + for (ui32 level : xrange(State.size() - 1, Meta.LevelCount)) { auto &state = State[level]; Y_DEBUG_ABORT_UNLESS(seek.BelongsTo(state)); if (!TryLoad(state)) { @@ -317,7 +316,7 @@ class TPartBtreeIndexIt : public IIndexIter { bool IsLeaf() const noexcept { // Note: it is possible to have 0 levels in B-Tree // so we may have exhausted state with leaf (data) node - return State.size() == Meta.LevelsCount + 1 && !IsExhausted(); + return State.size() == Meta.LevelCount + 1 && !IsExhausted(); } EReady Exhaust() { @@ -335,8 +334,8 @@ class TPartBtreeIndexIt : public IIndexIter { auto child = current.Node->GetChild(pos); - TRowId beginRowId = pos ? current.Node->GetChild(pos - 1).Count : current.BeginRowId; - TRowId endRowId = child.Count; + TRowId beginRowId = pos ? current.Node->GetChild(pos - 1).RowCount : current.BeginRowId; + TRowId endRowId = child.RowCount; TCellsIterable beginKey = pos ? current.Node->GetKeyCellsIterable(pos - 1, GroupInfo.ColsKeyIdx) : current.BeginKey; TCellsIterable endKey = pos < current.Node->GetKeysCount() ? current.Node->GetKeyCellsIterable(pos, GroupInfo.ColsKeyIdx) : current.EndKey; diff --git a/ydb/core/tablet_flat/flat_part_charge.h b/ydb/core/tablet_flat/flat_part_charge.h index 3a7e676c7792..a4a3cfbed490 100644 --- a/ydb/core/tablet_flat/flat_part_charge.h +++ b/ydb/core/tablet_flat/flat_part_charge.h @@ -42,7 +42,7 @@ namespace NTable { } } - TResult Do(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, + TResult Do(const TCells key1, const TCells key2, TRowId row1, TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { auto index = Index.TryLoadRaw(); @@ -110,7 +110,7 @@ namespace NTable { return { ready, overshot }; } - TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, + TResult DoReverse(const TCells key1, const TCells key2, TRowId row1, TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { auto index = Index.TryLoadRaw(); @@ -252,7 +252,7 @@ namespace NTable { } } if (itemsLimit && prechargeCurrentFirstRowId <= prechargeCurrentLastRowId) { - ui64 left = itemsLimit - items; // we count only foolprof taken rows, so here we may precharge some extra rows + ui64 left = itemsLimit - items; // we count only foolproof taken rows, so here we may precharge some extra rows if (prechargeCurrentLastRowId - prechargeCurrentFirstRowId > left) { prechargeCurrentLastRowId = prechargeCurrentFirstRowId + left; } @@ -347,7 +347,7 @@ namespace NTable { } if (itemsLimit && prechargeCurrentFirstRowId >= prechargeCurrentLastRowId) { - ui64 left = itemsLimit - items; // we count only foolprof taken rows, so here we may precharge some extra rows + ui64 left = itemsLimit - items; // we count only foolproof taken rows, so here we may precharge some extra rows if (prechargeCurrentFirstRowId - prechargeCurrentLastRowId > left) { prechargeCurrentLastRowId = prechargeCurrentFirstRowId - left; } diff --git a/ydb/core/tablet_flat/flat_part_charge_btree_index.h b/ydb/core/tablet_flat/flat_part_charge_btree_index.h index 2c802e71882b..5876cc2eea65 100644 --- a/ydb/core/tablet_flat/flat_part_charge_btree_index.h +++ b/ydb/core/tablet_flat/flat_part_charge_btree_index.h @@ -6,45 +6,177 @@ namespace NKikimr::NTable { - class TChargeBTreeIndex : public ICharge { - public: - TChargeBTreeIndex(IPages *env, const TPart &part, TTagsRef tags, bool includeHistory = false) { - Y_UNUSED(env); - Y_UNUSED(part); - Y_UNUSED(tags); - Y_UNUSED(includeHistory); - } - - TResult Do(const TCells key1, const TCells key2, const TRowId row1, - const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, - ui64 bytesLimit) const noexcept override { - // TODO: implement - Y_UNUSED(key1); - Y_UNUSED(key2); - Y_UNUSED(row1); - Y_UNUSED(row2); - Y_UNUSED(keyDefaults); - Y_UNUSED(itemsLimit); - Y_UNUSED(bytesLimit); - return {true, false}; - } - - TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, - const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, - ui64 bytesLimit) const noexcept override { - // TODO: implement - Y_UNUSED(key1); - Y_UNUSED(key2); - Y_UNUSED(row1); - Y_UNUSED(row2); - Y_UNUSED(keyDefaults); - Y_UNUSED(itemsLimit); - Y_UNUSED(bytesLimit); - return {true, false}; - } - - private: +class TChargeBTreeIndex : public ICharge { + using TBtreeIndexNode = NPage::TBtreeIndexNode; + using TBtreeIndexMeta = NPage::TBtreeIndexMeta; + using TRecIdx = NPage::TRecIdx; + using TGroupId = NPage::TGroupId; +public: + TChargeBTreeIndex(IPages *env, const TPart &part, TTagsRef tags, bool includeHistory = false) + : Part(&part) + , Env(env) { + Y_UNUSED(env); + Y_UNUSED(part); + Y_UNUSED(tags); + Y_UNUSED(includeHistory); + } + +public: + TResult Do(const TCells key1, const TCells key2, TRowId row1, TRowId row2, + const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { + bool ready = true; + + Y_UNUSED(key1); + Y_UNUSED(key2); + Y_UNUSED(keyDefaults); + Y_UNUSED(itemsLimit); + Y_UNUSED(bytesLimit); + + const auto& meta = Part->IndexPages.BTreeGroups[0]; + + if (Y_UNLIKELY(row1 >= meta.RowCount)) { + return { true, true }; // already out of bounds, nothing to precharge + } + if (Y_UNLIKELY(row1 > row2)) { + row2 = row1; // will not go further than row1 + } + + TVector level, nextLevel(Reserve(2)); + for (ui32 height = 0; height < meta.LevelCount && ready; height++) { + if (height == 0) { + ready &= TryLoadNode(meta.PageId, nextLevel); + } else { + for (ui32 i : xrange(level.size())) { + TRecIdx from = 0, to = level[i].GetKeysCount(); + if (i == 0) { + from = level[i].Seek(row1); + } + if (i + 1 == level.size() && row2 < meta.RowCount) { + to = level[i].Seek(row2); + } + for (TRecIdx j : xrange(from, to + 1)) { + ready &= TryLoadNode(level[i].GetShortChild(j).PageId, nextLevel); + } + } + } + + level.swap(nextLevel); + nextLevel.clear(); + } + + if (!ready) { + // some index pages are missing, do not continue + return {false, false}; + } + + if (meta.LevelCount == 0) { + ready &= HasDataPage(meta.PageId, { }); + } else { + for (ui32 i : xrange(level.size())) { + TRecIdx from = 0, to = level[i].GetKeysCount(); + if (i == 0) { + from = level[i].Seek(row1); + } + if (i + 1 == level.size() && row2 < meta.RowCount) { + to = level[i].Seek(row2); + } + for (TRecIdx j : xrange(from, to + 1)) { + ready &= HasDataPage(level[i].GetShortChild(j).PageId, { }); + } + } + } + + // TODO: overshot for keys search + return {ready, false}; + } + + TResult DoReverse(const TCells key1, const TCells key2, TRowId row1, TRowId row2, + const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { + bool ready = true; + + Y_UNUSED(key1); + Y_UNUSED(key2); + Y_UNUSED(keyDefaults); + Y_UNUSED(itemsLimit); + Y_UNUSED(bytesLimit); + + const auto& meta = Part->IndexPages.BTreeGroups[0]; + + if (Y_UNLIKELY(row1 >= meta.RowCount)) { + row1 = meta.RowCount - 1; // start from the last row + } + if (Y_UNLIKELY(row1 < row2)) { + row2 = row1; // will not go further than row1 + } + + // level contains nodes in reverse order + TVector level, nextLevel(Reserve(2)); + for (ui32 height = 0; height < meta.LevelCount && ready; height++) { + if (height == 0) { + ready &= TryLoadNode(meta.PageId, nextLevel); + } else { + for (ui32 i : xrange(level.size())) { + TRecIdx from = level[i].GetKeysCount(), to = 0; + if (i == 0) { + from = level[i].Seek(row1); + } + if (i + 1 == level.size() && row2 < meta.RowCount) { + to = level[i].Seek(row2); + } + for (TRecIdx j = from + 1; j > to; j--) { + ready &= TryLoadNode(level[i].GetShortChild(j - 1).PageId, nextLevel); + } + } + } + + level.swap(nextLevel); + nextLevel.clear(); + } + + if (!ready) { + // some index pages are missing, do not continue + return {false, false}; + } + + if (meta.LevelCount == 0) { + ready &= HasDataPage(meta.PageId, { }); + } else { + for (ui32 i : xrange(level.size())) { + TRecIdx from = level[i].GetKeysCount(), to = 0; + if (i == 0) { + from = level[i].Seek(row1); + } + if (i + 1 == level.size() && row2 < meta.RowCount) { + to = level[i].Seek(row2); + } + for (TRecIdx j = from + 1; j > to; j--) { + ready &= HasDataPage(level[i].GetShortChild(j - 1).PageId, { }); + } + } + } + + // TODO: overshot for keys search + return {ready, false}; + } + +private: + bool HasDataPage(TPageId pageId, TGroupId groupId) const noexcept { + return Env->TryGetPage(Part, pageId, groupId); + } + + bool TryLoadNode(TPageId pageId, TVector& level) const noexcept { + auto page = Env->TryGetPage(Part, pageId); + if (page) { + level.emplace_back(*page); + return true; + } + return false; + } + +private: + const TPart* const Part; + IPages* const Env; }; } diff --git a/ydb/core/tablet_flat/flat_part_charge_iface.h b/ydb/core/tablet_flat/flat_part_charge_iface.h index 46e84175d6b0..126b99e0b66d 100644 --- a/ydb/core/tablet_flat/flat_part_charge_iface.h +++ b/ydb/core/tablet_flat/flat_part_charge_iface.h @@ -17,7 +17,7 @@ namespace NKikimr::NTable { * * Important caveat: assumes iteration won't touch any row > row2 */ - bool Do(const TRowId row1, const TRowId row2, + bool Do(TRowId row1, TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { return Do(TCells{}, TCells{}, row1, row2, @@ -29,7 +29,7 @@ namespace NKikimr::NTable { * * Important caveat: assumes iteration won't touch any row > row2 */ - bool DoReverse(const TRowId row1, const TRowId row2, + bool DoReverse(TRowId row1, TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { return DoReverse(TCells{}, TCells{}, row1, row2, @@ -39,13 +39,13 @@ namespace NKikimr::NTable { /** * Precharges data for rows between max(key1, row1) and min(key2, row2) inclusive */ - virtual TResult Do(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, + virtual TResult Do(const TCells key1, const TCells key2, TRowId row1, TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept = 0; /** * Precharges data for rows between min(key1, row1) and max(key2, row2) inclusive in reverse */ - virtual TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, + virtual TResult DoReverse(const TCells key1, const TCells key2, TRowId row1, TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept = 0; virtual ~ICharge() = default; diff --git a/ydb/core/tablet_flat/flat_part_dump.cpp b/ydb/core/tablet_flat/flat_part_dump.cpp index 976fe8fbc2ba..d7a83f037305 100644 --- a/ydb/core/tablet_flat/flat_part_dump.cpp +++ b/ydb/core/tablet_flat/flat_part_dump.cpp @@ -168,7 +168,7 @@ namespace { { if (part.IndexPages.BTreeGroups) { auto meta = part.IndexPages.BTreeGroups.front(); - if (meta.LevelsCount) { + if (meta.LevelCount) { BTreeIndexNode(part, meta); } else { Out diff --git a/ydb/core/tablet_flat/flat_part_loader.cpp b/ydb/core/tablet_flat/flat_part_loader.cpp index fcf6820fdeca..294e2be31516 100644 --- a/ydb/core/tablet_flat/flat_part_loader.cpp +++ b/ydb/core/tablet_flat/flat_part_loader.cpp @@ -83,10 +83,10 @@ void TLoader::StageParseMeta() noexcept for (const auto &meta : history ? layout.GetBTreeHistoricIndexes() : layout.GetBTreeGroupIndexes()) { NPage::TBtreeIndexMeta converted{{ meta.GetRootPageId(), - meta.GetCount(), + meta.GetRowCount(), meta.GetDataSize(), - meta.GetErasedCount()}, - meta.GetLevelsCount(), + meta.GetErasedRowCount()}, + meta.GetLevelCount(), meta.GetIndexSize()}; (history ? BTreeHistoricIndexes : BTreeGroupIndexes).push_back(converted); } diff --git a/ydb/core/tablet_flat/flat_part_writer.h b/ydb/core/tablet_flat/flat_part_writer.h index e35c2979b0bb..572f1e8d54fc 100644 --- a/ydb/core/tablet_flat/flat_part_writer.h +++ b/ydb/core/tablet_flat/flat_part_writer.h @@ -666,11 +666,11 @@ namespace NTable { for (auto meta : history ? Current.BTreeHistoricIndexes : Current.BTreeGroupIndexes) { auto m = history ? lay->AddBTreeHistoricIndexes() : lay->AddBTreeGroupIndexes(); m->SetRootPageId(meta.PageId); - m->SetLevelsCount(meta.LevelsCount); + m->SetLevelCount(meta.LevelCount); m->SetIndexSize(meta.IndexSize); m->SetDataSize(meta.DataSize); - m->SetCount(meta.Count); - m->SetErasedCount(meta.ErasedCount); + m->SetRowCount(meta.RowCount); + m->SetErasedRowCount(meta.ErasedRowCount); } } diff --git a/ydb/core/tablet_flat/protos/flat_table_part.proto b/ydb/core/tablet_flat/protos/flat_table_part.proto index 4155ca9006ae..00efe95b59f8 100644 --- a/ydb/core/tablet_flat/protos/flat_table_part.proto +++ b/ydb/core/tablet_flat/protos/flat_table_part.proto @@ -25,11 +25,11 @@ message TPartScheme { message TBTreeIndexMeta { optional uint32 RootPageId = 1; - optional uint32 LevelsCount = 2; + optional uint32 LevelCount = 2; optional uint64 IndexSize = 3; optional uint64 DataSize = 4; - optional uint64 Count = 5; // Total number of data rows - optional uint64 ErasedCount = 6; // Total number of erased data rows + optional uint64 RowCount = 5; // Total number of data rows + optional uint64 ErasedRowCount = 6; // Total number of erased data rows } message TLayout { diff --git a/ydb/core/tablet_flat/test/libs/table/test_writer.h b/ydb/core/tablet_flat/test/libs/table/test_writer.h index 4a4936470850..5ed43de879d2 100644 --- a/ydb/core/tablet_flat/test/libs/table/test_writer.h +++ b/ydb/core/tablet_flat/test/libs/table/test_writer.h @@ -129,10 +129,10 @@ namespace NTest { for (const auto &meta : history ? lay.GetBTreeHistoricIndexes() : lay.GetBTreeGroupIndexes()) { NPage::TBtreeIndexMeta converted{{ meta.GetRootPageId(), - meta.GetCount(), + meta.GetRowCount(), meta.GetDataSize(), - meta.GetErasedCount()}, - meta.GetLevelsCount(), + meta.GetErasedRowCount()}, + meta.GetLevelCount(), meta.GetIndexSize()}; (history ? BTreeHistoricIndexes : BTreeGroupIndexes).push_back(converted); } diff --git a/ydb/core/tablet_flat/ut/ut_btree_index.cpp b/ydb/core/tablet_flat/ut/ut_btree_index.cpp index 88bf2fb4b340..1ef4a8923013 100644 --- a/ydb/core/tablet_flat/ut/ut_btree_index.cpp +++ b/ydb/core/tablet_flat/ut/ut_btree_index.cpp @@ -1,6 +1,8 @@ #include "flat_page_btree_index.h" #include "flat_page_btree_index_writer.h" #include "flat_part_btree_index_iter.h" +#include "flat_part_charge.h" +#include "flat_part_charge_btree_index.h" #include "test/libs/table/test_writer.h" #include #include @@ -13,15 +15,32 @@ namespace { using TChild = TBtreeIndexNode::TChild; struct TTouchEnv : public NTest::TTestEnv { - const TSharedData* TryGetPage(const TPart *part, TPageId id, TGroupId groupId) override + const TSharedData* TryGetPage(const TPart *part, TPageId pageId, TGroupId groupId) override { - UNIT_ASSERT_C(part->GetPageType(id) == EPage::BTreeIndex || part->GetPageType(id) == EPage::Index, "Shouldn't request non-index pages"); - if (!Touched[groupId].insert(id).second) { - return NTest::TTestEnv::TryGetPage(part, id, groupId); + Touched[groupId].insert(pageId); + if (Loaded[groupId].contains(pageId)) { + return NTest::TTestEnv::TryGetPage(part, pageId, groupId); } return nullptr; } + static void LoadTouched(IPages& env, bool clearHas) { + auto touchEnv = dynamic_cast(&env); + if (touchEnv) { + auto &has = touchEnv->Loaded; + auto &touched = touchEnv->Touched; + + if (clearHas) { + has.clear(); + } + for (const auto &g : touched) { + has[g.first].insert(g.second.begin(), g.second.end()); + } + touched.clear(); + } + } + + TMap> Loaded; TMap> Touched; }; @@ -155,7 +174,7 @@ namespace { UNIT_ASSERT_VALUES_EQUAL(node.GetKeysCount() + 1, children.size()); for (TRecIdx i : xrange(node.GetKeysCount() + 1)) { UNIT_ASSERT_EQUAL(node.GetChild(i), children[i]); - TShortChild shortChild{children[i].PageId, children[i].Count, children[i].DataSize}; + TShortChild shortChild{children[i].PageId, children[i].RowCount, children[i].DataSize}; UNIT_ASSERT_EQUAL(node.GetShortChild(i), shortChild); } } @@ -295,7 +314,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexNode) { writer.AddKey(deserialized.GetCells()); } for (auto &c : children) { - c.ErasedCount = 0; + c.ErasedRowCount = 0; writer.AddChild(c); } @@ -340,7 +359,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexNode) { writer.AddKey(deserialized.GetCells()); } for (auto &c : children) { - c.ErasedCount = 0; + c.ErasedRowCount = 0; writer.AddChild(c); } @@ -575,7 +594,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) { Dump(*result, builder.GroupInfo, pager.Back()); - UNIT_ASSERT_VALUES_EQUAL(result->LevelsCount, 3); + UNIT_ASSERT_VALUES_EQUAL(result->LevelCount, 3); auto checkKeys = [&](TPageId pageId, const TVector& keys) { CheckKeys(pageId, keys, builder.GroupInfo, pager.Back()); @@ -625,9 +644,9 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) { TBtreeIndexMeta expected{{9, 0, 0, 0}, 3, 1550}; for (auto c : children) { - expected.Count += c.Count; + expected.RowCount += c.RowCount; expected.DataSize += c.DataSize; - expected.ErasedCount += c.ErasedCount; + expected.ErasedRowCount += c.ErasedRowCount; } UNIT_ASSERT_EQUAL_C(*result, expected, "Got " + result->ToString()); } @@ -670,6 +689,13 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) { Y_UNIT_TEST_SUITE(TBtreeIndexTPart) { + Y_UNIT_TEST(Conf) { + NPage::TConf conf; + + // do not accidentally turn this setting on in trunk + UNIT_ASSERT_VALUES_EQUAL(conf.WriteBTreeIndex, false); + } + Y_UNIT_TEST(NoNodes) { TLayoutCook lay; @@ -898,50 +924,47 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { } } - EReady Retry(std::function action, const TString& message, ui32 failsAllowed = 10) { + EReady Retry(std::function action, IPages& env, const TString& message, ui32 failsAllowed = 10) { while (true) { if (auto ready = action(); ready != EReady::Page) { return ready; } + TTouchEnv::LoadTouched(env, false); UNIT_ASSERT_C(failsAllowed--, "Too many fails " + message); } - return EReady::Page; + Y_UNREACHABLE(); } - template - EReady SeekRowId(TIter& iter, TRowId rowId, const TString& message, ui32 failsAllowed = 10) { + EReady SeekRowId(IIndexIter& iter, IPages& env, TRowId rowId, const TString& message, ui32 failsAllowed = 10) { return Retry([&]() { return iter.Seek(rowId); - }, message, failsAllowed); + }, env, message, failsAllowed); } - template - EReady SeekLast(TIter& iter, const TString& message, ui32 failsAllowed = 10) { + EReady SeekLast(IIndexIter& iter, IPages& env, const TString& message, ui32 failsAllowed = 10) { return Retry([&]() { return iter.SeekLast(); - }, message, failsAllowed); + }, env, message, failsAllowed); } - template - EReady SeekKey(TIter& iter, ESeek seek, bool reverse, TCells key, const TKeyCellDefaults *keyDefaults, const TString& message, ui32 failsAllowed = 10) { + EReady SeekKey(IIndexIter& iter, IPages& env, ESeek seek, bool reverse, TCells key, const TKeyCellDefaults *keyDefaults, const TString& message, ui32 failsAllowed = 10) { return Retry([&]() { if (reverse) { return iter.SeekReverse(seek, key, keyDefaults); } else { return iter.Seek(seek, key, keyDefaults); } - }, message, failsAllowed); + }, env, message, failsAllowed); } - template - EReady NextPrev(TIter& iter, bool next, const TString& message, ui32 failsAllowed = 10) { + EReady NextPrev(IIndexIter& iter, IPages& env, bool next, const TString& message, ui32 failsAllowed = 10) { return Retry([&]() { if (next) { return iter.Next(); } else { return iter.Prev(); } - }, message, failsAllowed); + }, env, message, failsAllowed); } template @@ -955,8 +978,8 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { // checking initial seek: { TString message = TStringBuilder() << "SeekRowId<" << typeid(TEnv).name() << "> " << rowId1; - EReady bTreeReady = SeekRowId(bTree, rowId1, message); - EReady flatReady = SeekRowId(flat, rowId1, message); + EReady bTreeReady = SeekRowId(bTree, env, rowId1, message); + EReady flatReady = SeekRowId(flat, env, rowId1, message); UNIT_ASSERT_VALUES_EQUAL(bTreeReady, rowId1 < part.Stat.Rows ? EReady::Data : EReady::Gone); AssertEqual(bTree, bTreeReady, flat, flatReady, message); } @@ -964,8 +987,8 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { // checking repositioning: { TString message = TStringBuilder() << "SeekRowId<" << typeid(TEnv).name() << "> " << rowId1 << " -> " << rowId2; - EReady bTreeReady = SeekRowId(bTree, rowId2, message); - EReady flatReady = SeekRowId(flat, rowId2, message); + EReady bTreeReady = SeekRowId(bTree, env, rowId2, message); + EReady flatReady = SeekRowId(flat, env, rowId2, message); UNIT_ASSERT_VALUES_EQUAL(bTreeReady, rowId2 < part.Stat.Rows ? EReady::Data : EReady::Gone); AssertEqual(bTree, bTreeReady, flat, flatReady, message); } @@ -980,8 +1003,8 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { TPartIndexIt flat(&part, &env, { }); TString message = TStringBuilder() << "SeekLast<" << typeid(TEnv).name() << ">"; - EReady bTreeReady = SeekLast(bTree, message); - EReady flatReady = SeekLast(flat, message); + EReady bTreeReady = SeekLast(bTree, env, message); + EReady flatReady = SeekLast(flat, env, message); UNIT_ASSERT_VALUES_EQUAL(bTreeReady, EReady::Data); AssertEqual(bTree, bTreeReady, flat, flatReady, message); } @@ -1003,8 +1026,8 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { message << c.AsValue() << " "; } - EReady bTreeReady = SeekKey(bTree, seek, reverse, key, keyDefaults, message); - EReady flatReady = SeekKey(flat, seek, reverse, key, keyDefaults, message); + EReady bTreeReady = SeekKey(bTree, env, seek, reverse, key, keyDefaults, message); + EReady flatReady = SeekKey(flat, env, seek, reverse, key, keyDefaults, message); UNIT_ASSERT_VALUES_EQUAL_C(bTreeReady, key.empty() ? flatReady : EReady::Data, "Can't be exhausted"); AssertEqual(bTree, bTreeReady, flat, flatReady, message, !key.empty()); @@ -1029,8 +1052,8 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { // checking initial seek: { TString message = TStringBuilder() << "CheckNext<" << typeid(TEnv).name() << "> " << rowId; - EReady bTreeReady = SeekRowId(bTree, rowId, message); - EReady flatReady = SeekRowId(flat, rowId, message); + EReady bTreeReady = SeekRowId(bTree, env, rowId, message); + EReady flatReady = SeekRowId(flat, env, rowId, message); UNIT_ASSERT_VALUES_EQUAL(bTreeReady, rowId < part.Stat.Rows ? EReady::Data : EReady::Gone); AssertEqual(bTree, bTreeReady, flat, flatReady, message); } @@ -1039,8 +1062,8 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { while (true) { TString message = TStringBuilder() << "CheckNext<" << typeid(TEnv).name() << "> " << rowId << " -> " << rowId; - EReady bTreeReady = NextPrev(bTree, next, message); - EReady flatReady = NextPrev(flat, next, message); + EReady bTreeReady = NextPrev(bTree, env, next, message); + EReady flatReady = NextPrev(flat, env, next, message); AssertEqual(bTree, bTreeReady, flat, flatReady, message); if (flatReady == EReady::Gone) { break; @@ -1071,7 +1094,7 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { Cerr << DumpPart(part, 1) << Endl; - UNIT_ASSERT_VALUES_EQUAL(part.IndexPages.BTreeGroups[0].LevelsCount, levels); + UNIT_ASSERT_VALUES_EQUAL(part.IndexPages.BTreeGroups[0].LevelCount, levels); CheckSeekRowId(part); CheckSeekRowId(part); @@ -1083,11 +1106,120 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) { CheckNextPrev(part); } - Y_UNIT_TEST(Conf) { + Y_UNIT_TEST(NoNodes) { NPage::TConf conf; - // to not accidentally turn this setting on in trunk - UNIT_ASSERT_VALUES_EQUAL(conf.WriteBTreeIndex, false); + CheckPart(std::move(conf), 100, 0); + } + + Y_UNIT_TEST(OneNode) { + NPage::TConf conf; + conf.Group(0).PageRows = 2; + + CheckPart(std::move(conf), 100, 1); + } + + Y_UNIT_TEST(FewNodes) { + NPage::TConf conf; + conf.Group(0).PageRows = 2; + conf.Group(0).BTreeIndexNodeKeysMin = 3; + conf.Group(0).BTreeIndexNodeKeysMax = 4; + + CheckPart(std::move(conf), 300, 3); + } +} + +Y_UNIT_TEST_SUITE(TChargeBTreeIndex) { + void AssertEqual(const TPartStore& part, const TMap>& bTree, const TMap>& flat, const TString& message) { + TSet groupIds; + for (const auto &c : {bTree, flat}) { + for (const auto &g : c) { + groupIds.insert(g.first); + } + } + + for (TGroupId groupId : groupIds) { + TSet bTreeDataPages, flatDataPages; + for (TPageId pageId : bTree.Value(groupId, TSet{})) { + if (part.GetPageType(pageId, groupId) == EPage::DataPage) { + bTreeDataPages.insert(pageId); + } + } + for (TPageId pageId : flat.Value(groupId, TSet{})) { + if (part.GetPageType(pageId, groupId) == EPage::DataPage) { + flatDataPages.insert(pageId); + } + } + + UNIT_ASSERT_VALUES_EQUAL_C(flatDataPages, bTreeDataPages, message); + } + } + + void AssertEqual(const TPartStore& part, const TTouchEnv& bTree, const TTouchEnv& flat, const TString& message) { + AssertEqual(part, bTree.Loaded, flat.Loaded, message); + AssertEqual(part, bTree.Touched, flat.Touched, message); + } + + void DoChargeRowId(ICharge& charge, IPages& env, const TRowId row1, const TRowId row2, ui64 itemsLimit, ui64 bytesLimit, + bool reverse, const TKeyCellDefaults &keyDefaults, const TString& message, ui32 failsAllowed = 10) { + while (true) { + bool ready = reverse + ? charge.DoReverse(row1, row2, keyDefaults, itemsLimit, bytesLimit) + : charge.Do(row1, row2, keyDefaults, itemsLimit, bytesLimit); + if (ready) { + return; + } + TTouchEnv::LoadTouched(env, false); + UNIT_ASSERT_C(failsAllowed--, "Too many fails " + message); + } + Y_UNREACHABLE(); + } + + void CheckChargeRowId(const TPartStore& part, TTagsRef tags, const TKeyCellDefaults *keyDefaults, bool reverse) { + for (TRowId rowId1 : xrange(part.Stat.Rows + 1)) { + for (TRowId rowId2 : xrange(part.Stat.Rows + 1)) { + TTouchEnv bTreeEnv, flatEnv; + TChargeBTreeIndex bTree(&bTreeEnv, part, tags, true); + TCharge flat(&flatEnv, part, tags, true); + + TString message = TStringBuilder() << (reverse ? "ChargeRowIdReverse " : "ChargeRowId ") << rowId1 << " " << rowId2; + DoChargeRowId(bTree, bTreeEnv, rowId1, rowId2, 0, 0, reverse, *keyDefaults, message); + DoChargeRowId(flat, flatEnv, rowId1, rowId2, 0, 0, reverse, *keyDefaults, message); + AssertEqual(part, bTreeEnv, flatEnv, message); + } + } + } + + void CheckPart(TConf&& conf, ui32 rows, ui32 levels) { + TLayoutCook lay; + + lay + .Col(0, 0, NScheme::NTypeIds::Uint32) + .Col(0, 1, NScheme::NTypeIds::Uint32) + .Key({0, 1}); + + conf.WriteBTreeIndex = true; + TPartCook cook(lay, conf); + + for (ui32 i : xrange(1u, rows + 1)) { + cook.Add(*TSchemedCookRow(*lay).Col(i / 7, i % 7)); + } + + TPartEggs eggs = cook.Finish(); + + const auto part = *eggs.Lone(); + + Cerr << DumpPart(part, 1) << Endl; + + UNIT_ASSERT_VALUES_EQUAL(part.IndexPages.BTreeGroups[0].LevelCount, levels); + + auto tags = TVector(); + for (auto c : eggs.Scheme->Cols) { + tags.push_back(c.Tag); + } + + CheckChargeRowId(part, tags, eggs.Scheme->Keys.Get(), false); + CheckChargeRowId(part, tags, eggs.Scheme->Keys.Get(), true); } Y_UNIT_TEST(NoNodes) { diff --git a/ydb/core/tablet_flat/ut/ut_part.cpp b/ydb/core/tablet_flat/ut/ut_part.cpp index 9be2c733299a..9d5c21c44758 100644 --- a/ydb/core/tablet_flat/ut/ut_part.cpp +++ b/ydb/core/tablet_flat/ut/ut_part.cpp @@ -440,7 +440,7 @@ Y_UNIT_TEST_SUITE(TPart) { { /*_ Ensure that B-Tree index has enough layers */ if (part.IndexPages.BTreeGroups.size()) { - UNIT_ASSERT_VALUES_EQUAL(part.IndexPages.BTreeGroups[0].LevelsCount, 3); + UNIT_ASSERT_VALUES_EQUAL(part.IndexPages.BTreeGroups[0].LevelCount, 3); } } diff --git a/ydb/core/tablet_flat/ut_large/ut_btree_index_large.cpp b/ydb/core/tablet_flat/ut_large/ut_btree_index_large.cpp index 00df27c990dc..3af2bfb805a0 100644 --- a/ydb/core/tablet_flat/ut_large/ut_btree_index_large.cpp +++ b/ydb/core/tablet_flat/ut_large/ut_btree_index_large.cpp @@ -39,7 +39,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) { UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024); UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024); - UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelsCount, 3); + UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelCount, 3); } Y_UNIT_TEST(MiddleKeys1GB) { @@ -69,7 +69,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) { UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024); UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024); - UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelsCount, 3); + UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelCount, 3); } Y_UNIT_TEST(BigKeys1GB) { @@ -99,7 +99,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) { UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024); UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024); - UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelsCount, 6); + UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelCount, 6); } Y_UNIT_TEST(CutKeys) { @@ -131,7 +131,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) { UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024); UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024); - UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelsCount, 3); + UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[0].LevelCount, 3); } Y_UNIT_TEST(Group) { @@ -162,7 +162,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) { UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024); UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024); - UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[1].LevelsCount, 2); + UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeGroups[1].LevelCount, 2); } Y_UNIT_TEST(History) { @@ -193,7 +193,7 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) { UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024); UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024); - UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeHistoric[0].LevelsCount, 3); + UNIT_ASSERT_VALUES_EQUAL(part->IndexPages.BTreeHistoric[0].LevelCount, 3); } }