aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkungurtsev <kungasc@ydb.tech>2023-12-29 21:27:19 +0100
committerGitHub <noreply@github.com>2023-12-29 21:27:19 +0100
commit279bff472e65f41778673a8cb7cc623aadd379c7 (patch)
treeb45d7bceaa465c40cc1d31bc1a0a21e92ee6cb1d
parent9bf478e2ffb06b7cca0ac7c39c1f44cb1f337a29 (diff)
downloadydb-279bff472e65f41778673a8cb7cc623aadd379c7.tar.gz
KIKIMR-19522 BTreeIndex Precharge RowId (#754)
-rw-r--r--ydb/core/tablet_flat/benchmark/b_part_index.cpp2
-rw-r--r--ydb/core/tablet_flat/flat_page_btree_index.h26
-rw-r--r--ydb/core/tablet_flat/flat_page_btree_index_writer.h31
-rw-r--r--ydb/core/tablet_flat/flat_part_btree_index_iter.h21
-rw-r--r--ydb/core/tablet_flat/flat_part_charge.h8
-rw-r--r--ydb/core/tablet_flat/flat_part_charge_btree_index.h208
-rw-r--r--ydb/core/tablet_flat/flat_part_charge_iface.h8
-rw-r--r--ydb/core/tablet_flat/flat_part_dump.cpp2
-rw-r--r--ydb/core/tablet_flat/flat_part_loader.cpp6
-rw-r--r--ydb/core/tablet_flat/flat_part_writer.h6
-rw-r--r--ydb/core/tablet_flat/protos/flat_table_part.proto6
-rw-r--r--ydb/core/tablet_flat/test/libs/table/test_writer.h6
-rw-r--r--ydb/core/tablet_flat/ut/ut_btree_index.cpp212
-rw-r--r--ydb/core/tablet_flat/ut/ut_part.cpp2
-rw-r--r--ydb/core/tablet_flat/ut_large/ut_btree_index_large.cpp12
15 files changed, 410 insertions, 146 deletions
diff --git a/ydb/core/tablet_flat/benchmark/b_part_index.cpp b/ydb/core/tablet_flat/benchmark/b_part_index.cpp
index bdc87590919..c991a2d13ff 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 968fb5f9c74..0fc722dcce9 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<const TShortChild>::At(Children, pos * sizeof(TShortChild));
- return { shortChild->PageId, shortChild->Count, shortChild->DataSize, 0 };
+ return { shortChild->PageId, shortChild->RowCount, shortChild->DataSize, 0 };
} else {
return *TDeref<const TChild>::At(Children, pos * sizeof(TChild));
}
@@ -316,7 +316,7 @@ namespace NKikimr::NTable::NPage {
return beginRowId <= rowId && rowId < endRowId;
}
- TRecIdx Seek(TRowId rowId, std::optional<TRecIdx> on) const noexcept
+ TRecIdx Seek(TRowId rowId, std::optional<TRecIdx> 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 0c7b084f055..2a4627bf7e2 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>() = TShortChild{child.PageId, child.Count, child.DataSize};
+ Place<TShortChild>() = TShortChild{child.PageId, child.RowCount, child.DataSize};
} else {
Place<TChild>() = 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<TBtreeIndexMeta> Flush(IPageWriter &pager, bool last) {
- for (size_t levelIndex = 0; levelIndex < Levels.size(); levelIndex++) {
+ Y_ABORT_UNLESS(Levels.size() < Max<ui32>(), "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 92c5c69f2cb..d924e670de4 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 @@ public:
, 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<const char*>(nullptr), TColumns());
State.emplace_back(Meta, 0, GetEndRowId(), EmptyKey, EmptyKey);
@@ -181,7 +180,7 @@ public:
EReady Next() override {
Y_ABORT_UNLESS(!IsExhausted());
- if (Meta.LevelsCount == 0) {
+ if (Meta.LevelCount == 0) {
return Exhaust();
}
@@ -195,7 +194,7 @@ public:
PushNextState(*State.back().Pos + 1);
}
- for (size_t level : xrange(State.size() - 1, Meta.LevelsCount)) {
+ for (ui32 level : xrange<ui32>(State.size() - 1, Meta.LevelCount)) {
if (!TryLoad(State[level])) {
// exiting with an intermediate state
Y_DEBUG_ABORT_UNLESS(!IsLeaf() && !IsExhausted());
@@ -212,7 +211,7 @@ public:
EReady Prev() override {
Y_ABORT_UNLESS(!IsExhausted());
- if (Meta.LevelsCount == 0) {
+ if (Meta.LevelCount == 0) {
return Exhaust();
}
@@ -226,7 +225,7 @@ public:
PushNextState(*State.back().Pos - 1);
}
- for (size_t level : xrange(State.size() - 1, Meta.LevelsCount)) {
+ for (ui32 level : xrange<ui32>(State.size() - 1, Meta.LevelCount)) {
if (!TryLoad(State[level])) {
// exiting with an intermediate state
Y_DEBUG_ABORT_UNLESS(!IsLeaf() && !IsExhausted());
@@ -247,7 +246,7 @@ public:
}
TRowId GetEndRowId() const override {
- return Meta.Count;
+ return Meta.RowCount;
}
TPageId GetPageId() const override {
@@ -287,7 +286,7 @@ private:
State[0].Pos = { };
}
- for (size_t level : xrange(State.size() - 1, Meta.LevelsCount)) {
+ for (ui32 level : xrange<ui32>(State.size() - 1, Meta.LevelCount)) {
auto &state = State[level];
Y_DEBUG_ABORT_UNLESS(seek.BelongsTo(state));
if (!TryLoad(state)) {
@@ -317,7 +316,7 @@ private:
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 @@ private:
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 3a7e676c779..a4a3cfbed49 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 2c802e71882..5876cc2eea6 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<TBtreeIndexNode> 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<ui32>(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<ui32>(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<TBtreeIndexNode> 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<ui32>(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<ui32>(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<TBtreeIndexNode>& 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 46e84175d6b..126b99e0b66 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 976fe8fbc2b..d7a83f03730 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 fcf6820fdec..294e2be3151 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 e35c2979b0b..572f1e8d54f 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 4155ca9006a..00efe95b59f 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 4a493647085..5ed43de879d 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 88bf2fb4b34..1ef4a892301 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 <ydb/core/tablet_flat/test/libs/rows/layout.h>
#include <library/cpp/testing/unittest/registar.h>
@@ -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<TTouchEnv*>(&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<TGroupId, TSet<TPageId>> Loaded;
TMap<TGroupId, TSet<TPageId>> 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<TString>& 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<EReady()> action, const TString& message, ui32 failsAllowed = 10) {
+ EReady Retry(std::function<EReady()> 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<typename TIter>
- 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<typename TIter>
- 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<typename TIter>
- 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<typename TIter>
- 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<typename TEnv>
@@ -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<ui32>() << " ";
}
- 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<TTestEnv>(part);
CheckSeekRowId<TTouchEnv>(part);
@@ -1083,11 +1106,120 @@ Y_UNIT_TEST_SUITE(TPartBtreeIndexIt) {
CheckNextPrev<TTouchEnv>(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<TGroupId, TSet<TPageId>>& bTree, const TMap<TGroupId, TSet<TPageId>>& flat, const TString& message) {
+ TSet<TGroupId> groupIds;
+ for (const auto &c : {bTree, flat}) {
+ for (const auto &g : c) {
+ groupIds.insert(g.first);
+ }
+ }
+
+ for (TGroupId groupId : groupIds) {
+ TSet<TPageId> bTreeDataPages, flatDataPages;
+ for (TPageId pageId : bTree.Value(groupId, TSet<TPageId>{})) {
+ if (part.GetPageType(pageId, groupId) == EPage::DataPage) {
+ bTreeDataPages.insert(pageId);
+ }
+ }
+ for (TPageId pageId : flat.Value(groupId, TSet<TPageId>{})) {
+ 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<TTag>();
+ 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 9be2c733299..9d5c21c4475 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 00df27c990d..3af2bfb805a 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);
}
}