aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkungurtsev <kungasc@ydb.tech>2023-12-22 11:09:44 +0100
committerGitHub <noreply@github.com>2023-12-22 11:09:44 +0100
commit228b08549a4b7218d00893cfde60acca03b3fb81 (patch)
tree5402291ab12c1897618db7ab8832133f54dd4b4a
parent8fbea85abdb79447bfe9abfec7463ce7c04365e8 (diff)
downloadydb-228b08549a4b7218d00893cfde60acca03b3fb81.tar.gz
KIKIMR-19521 BTreeIndex Test (#653)
-rw-r--r--ydb/core/tablet_flat/benchmark/b_charge.cpp47
-rw-r--r--ydb/core/tablet_flat/benchmark/b_part_index.cpp249
-rw-r--r--ydb/core/tablet_flat/benchmark/ya.make6
-rw-r--r--ydb/core/tablet_flat/flat_part_btree_index_iter.h1
-rw-r--r--ydb/core/tablet_flat/flat_part_loader.cpp11
-rw-r--r--ydb/core/tablet_flat/ut_large/ut_btree_index_large.cpp109
6 files changed, 381 insertions, 42 deletions
diff --git a/ydb/core/tablet_flat/benchmark/b_charge.cpp b/ydb/core/tablet_flat/benchmark/b_charge.cpp
index ece5e52034..da1c06dbbd 100644
--- a/ydb/core/tablet_flat/benchmark/b_charge.cpp
+++ b/ydb/core/tablet_flat/benchmark/b_charge.cpp
@@ -32,35 +32,10 @@ namespace {
ui64 TouchedCount = 0;
};
- struct TCooker {
- TCooker(const TRowScheme &scheme)
- : Tool(scheme)
- , Writer(new TPartScheme(scheme.Cols), { }, NPage::TGroupId(0))
- {
-
- }
-
- TCooker& Add(const NTest::TRow &row, ui64 offset, ui32 page)
- {
- const TCelled key(Tool.LookupKey(row), *Tool.Scheme.Keys, false);
-
- return Writer.Add(key, offset, page), *this;
- }
-
- TSharedData Flush()
- {
- return Writer.Flush();
- }
-
- private:
- const NTest::TRowTool Tool;
- NPage::TIndexWriter Writer;
- };
-
- struct TModel : public benchmark::Fixture {
+ struct TPrechargeFixture : public benchmark::Fixture {
using TGroupId = NPage::TGroupId;
- TModel()
+ TPrechargeFixture()
: Tool(*Mass.Model->Scheme)
{
Y_ABORT_UNLESS(NTest::IndexTools::CountMainPages(*Eggs.Lone()) > 120);
@@ -125,7 +100,7 @@ namespace {
};
}
-BENCHMARK_DEFINE_F(TModel, PrechargeByKeys)(benchmark::State& state) {
+BENCHMARK_DEFINE_F(TPrechargeFixture, PrechargeByKeys)(benchmark::State& state) {
ui64 items = state.range(0);
const auto &keyDefaults = *Tool.Scheme.Keys;
@@ -144,7 +119,7 @@ BENCHMARK_DEFINE_F(TModel, PrechargeByKeys)(benchmark::State& state) {
state.counters["Touched"] = benchmark::Counter(Env->TouchedCount, benchmark::Counter::kAvgIterations);
}
-BENCHMARK_DEFINE_F(TModel, PrechargeByRows)(benchmark::State& state) {
+BENCHMARK_DEFINE_F(TPrechargeFixture, PrechargeByRows)(benchmark::State& state) {
ui64 items = state.range(0);
const auto &keyDefaults = *Tool.Scheme.Keys;
@@ -160,12 +135,18 @@ BENCHMARK_DEFINE_F(TModel, PrechargeByRows)(benchmark::State& state) {
state.counters["Touched"] = Env->TouchedCount / it;
}
-BENCHMARK_REGISTER_F(TModel, PrechargeByKeys)
- ->ArgsProduct({/*items:*/ {0, 100, 1000}, /*fail:*/{0, 1}, /*groups:*/ {0, 1, 2}})
+BENCHMARK_REGISTER_F(TPrechargeFixture, PrechargeByKeys)
+ ->ArgsProduct({
+ /* items: */ {0, 100, 1000},
+ /* fail: */ {0, 1},
+ /* groups: */ {0, 1, 2}})
->Unit(benchmark::kMicrosecond);
-BENCHMARK_REGISTER_F(TModel, PrechargeByRows)
- ->ArgsProduct({/*items:*/ {0, 100, 1000}, /*fail:*/{0, 1}, /*groups:*/ {0, 1, 2}})
+BENCHMARK_REGISTER_F(TPrechargeFixture, PrechargeByRows)
+ ->ArgsProduct({
+ /* items: */ {0, 100, 1000},
+ /* fail: */{0, 1},
+ /* groups: */ {0, 1, 2}})
->Unit(benchmark::kMicrosecond);
}
diff --git a/ydb/core/tablet_flat/benchmark/b_part_index.cpp b/ydb/core/tablet_flat/benchmark/b_part_index.cpp
new file mode 100644
index 0000000000..bdc8759091
--- /dev/null
+++ b/ydb/core/tablet_flat/benchmark/b_part_index.cpp
@@ -0,0 +1,249 @@
+#include <benchmark/benchmark.h>
+
+#include <ydb/core/tablet_flat/flat_row_celled.h>
+#include <ydb/core/tablet_flat/flat_part_charge_range.h>
+#include <ydb/core/tablet_flat/flat_part_charge_create.h>
+#include <ydb/core/tablet_flat/test/libs/rows/cook.h>
+#include <ydb/core/tablet_flat/test/libs/rows/tool.h>
+#include <ydb/core/tablet_flat/test/libs/table/model/large.h>
+#include <ydb/core/tablet_flat/test/libs/table/test_make.h>
+#include <ydb/core/tablet_flat/test/libs/table/test_mixer.h>
+#include "ydb/core/tablet_flat/flat_part_btree_index_iter.h"
+#include "ydb/core/tablet_flat/test/libs/table/wrap_iter.h"
+#include <ydb/core/tablet_flat/test/libs/table/test_writer.h>
+#include <ydb/core/tablet_flat/test/libs/table/test_envs.h>
+#include <ydb/core/tablet_flat/test/libs/table/wrap_part.h>
+#include <ydb/core/tablet_flat/test/libs/table/test_steps.h>
+
+namespace NKikimr {
+namespace NTable {
+
+namespace {
+ using namespace NTest;
+
+ using TCheckIt = TChecker<TWrapIter, TSubset>;
+ using TCheckReverseIt = TChecker<TWrapReverseIter, TSubset>;
+
+ NPage::TConf PageConf(size_t groups, bool writeBTreeIndex) noexcept
+ {
+ NPage::TConf conf{ true, 1024 };
+
+ conf.Groups.resize(groups);
+ for (size_t group : xrange(groups)) {
+ conf.Group(group).PageSize = 1024;
+ conf.Group(group).BTreeIndexNodeTargetSize = 1024;
+ }
+
+ conf.WriteBTreeIndex = writeBTreeIndex;
+
+ conf.SliceSize = conf.Group(0).PageSize * 4;
+
+ return conf;
+ }
+
+ struct TPartIndexSeekFixture : public benchmark::Fixture {
+ using TGroupId = NPage::TGroupId;
+
+ void SetUp(const ::benchmark::State& state)
+ {
+ const bool groups = state.range(1);
+
+ TLayoutCook lay;
+
+ lay
+ .Col(0, 0, NScheme::NTypeIds::Uint32)
+ .Col(0, 1, NScheme::NTypeIds::Uint32)
+ .Col(0, 2, NScheme::NTypeIds::Uint32)
+ .Col(0, 3, NScheme::NTypeIds::Uint32)
+ .Col(groups ? 1 : 0, 4, NScheme::NTypeIds::Uint32)
+ .Key({0, 1, 2});
+
+ TPartCook cook(lay, PageConf(groups ? 2 : 1, true));
+
+ for (ui32 i = 0; (groups ? cook.GetDataBytes(0) + cook.GetDataBytes(1) : cook.GetDataBytes(0)) < 100ull*1024*1024; i++) {
+ cook.Add(*TSchemedCookRow(*lay).Col(i / 10000, i / 100 % 100, i % 100, i, i));
+ }
+
+ Eggs = cook.Finish();
+
+ const auto part = Eggs.Lone();
+
+ 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;
+
+ // 100 MB
+ UNIT_ASSERT_GE(part->Stat.Bytes, 100ull*1024*1024);
+ UNIT_ASSERT_LE(part->Stat.Bytes, 100ull*1024*1024 + 10ull*1024*1024);
+
+ GroupId = TGroupId(groups ? 1 : 0);
+ }
+
+ TPartEggs Eggs;
+ TTestEnv Env;
+ TGroupId GroupId;
+ };
+
+ struct TPartIndexIteratorFixture : public benchmark::Fixture {
+ using TGroupId = NPage::TGroupId;
+
+ void SetUp(const ::benchmark::State& state)
+ {
+ const bool useBTree = state.range(0);
+ const bool groups = state.range(1);
+ const bool history = state.range(2);
+
+ Mass = new NTest::TMass(new NTest::TModelStd(groups), history ? 1000000 : 300000);
+ Subset = TMake(*Mass, PageConf(Mass->Model->Scheme->Families.size(), useBTree)).Mixed(0, 1, TMixerOne{ }, history ? 0.7 : 0);
+
+ if (history) {
+ Checker = new TCheckIt(*Subset, {new TTestEnv()}, TRowVersion(0, 8));
+ CheckerReverse = new TCheckReverseIt(*Subset, {new TTestEnv()}, TRowVersion(0, 8));
+ } else {
+ Checker = new TCheckIt(*Subset, {new TTestEnv()});
+ CheckerReverse = new TCheckReverseIt(*Subset, {new TTestEnv()});
+ }
+ }
+
+ TMersenne<ui64> Rnd;
+ TAutoPtr<NTest::TMass> Mass;
+ TAutoPtr<TSubset> Subset;
+ TAutoPtr<TCheckIt> Checker;
+ TAutoPtr<TCheckReverseIt> CheckerReverse;
+ };
+}
+
+BENCHMARK_DEFINE_F(TPartIndexSeekFixture, SeekRowId)(benchmark::State& state) {
+ const bool useBTree = state.range(0);
+
+ for (auto _ : state) {
+ THolder<IIndexIter> iter;
+
+ if (useBTree) {
+ iter = MakeHolder<TPartBtreeIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ } else {
+ iter = MakeHolder<TPartIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ }
+
+ iter->Seek(RandomNumber<ui32>(Eggs.Lone()->Stat.Rows));
+ }
+}
+
+BENCHMARK_DEFINE_F(TPartIndexSeekFixture, Next)(benchmark::State& state) {
+ const bool useBTree = state.range(0);
+
+ THolder<IIndexIter> iter;
+
+ if (useBTree) {
+ iter = MakeHolder<TPartBtreeIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ } else {
+ iter = MakeHolder<TPartIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ }
+
+ iter->Seek(RandomNumber<ui32>(Eggs.Lone()->Stat.Rows));
+
+ for (auto _ : state) {
+ if (!iter->IsValid()) {
+ iter->Seek(RandomNumber<ui32>(Eggs.Lone()->Stat.Rows));
+ }
+ iter->Next();
+ }
+}
+
+BENCHMARK_DEFINE_F(TPartIndexSeekFixture, Prev)(benchmark::State& state) {
+ const bool useBTree = state.range(0);
+
+ THolder<IIndexIter> iter;
+
+ if (useBTree) {
+ iter = MakeHolder<TPartBtreeIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ } else {
+ iter = MakeHolder<TPartIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ }
+
+ iter->Seek(RandomNumber<ui32>(Eggs.Lone()->Stat.Rows));
+
+ for (auto _ : state) {
+ if (!iter->IsValid()) {
+ iter->Seek(RandomNumber<ui32>(Eggs.Lone()->Stat.Rows));
+ }
+ iter->Prev();
+ }
+}
+
+BENCHMARK_DEFINE_F(TPartIndexSeekFixture, SeekKey)(benchmark::State& state) {
+ const bool useBTree = state.range(0);
+ const ESeek seek = ESeek(state.range(2));
+
+ for (auto _ : state) {
+ THolder<IIndexIter> iter;
+
+ if (useBTree) {
+ iter = MakeHolder<TPartBtreeIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ } else {
+ iter = MakeHolder<TPartIndexIt>(Eggs.Lone().Get(), &Env, GroupId);
+ }
+
+ ui32 rowId = RandomNumber<ui32>(Eggs.Lone()->Stat.Rows);
+ TVector<TCell> key{TCell::Make(rowId / 10000), TCell::Make(rowId / 100 % 100), TCell::Make(rowId % 100)};
+ iter->Seek(seek, key, Eggs.Scheme->Keys.Get());
+ }
+}
+
+BENCHMARK_DEFINE_F(TPartIndexIteratorFixture, DoReads)(benchmark::State& state) {
+ const bool reverse = state.range(3);
+ const ui32 items = state.range(4);
+
+ for (auto _ : state) {
+ auto it = Mass->Saved.Any(Rnd);
+
+ if (reverse) {
+ CheckerReverse->Seek(*it, ESeek::Lower);
+ for (ui32 i = 1; CheckerReverse->GetReady() == EReady::Data && i < items; i++) {
+ CheckerReverse->Next();
+ }
+ } else {
+ Checker->Seek(*it, ESeek::Lower);
+ for (ui32 i = 1; Checker->GetReady() == EReady::Data && i < items; i++) {
+ Checker->Next();
+ }
+ }
+ }
+}
+
+BENCHMARK_REGISTER_F(TPartIndexSeekFixture, SeekRowId)
+ ->ArgsProduct({
+ /* b-tree */ {0, 1},
+ /* groups: */ {0, 1}})
+ ->Unit(benchmark::kMicrosecond);
+
+BENCHMARK_REGISTER_F(TPartIndexSeekFixture, Next)
+ ->ArgsProduct({
+ /* b-tree */ {0, 1},
+ /* groups: */ {0, 1}})
+ ->Unit(benchmark::kMicrosecond);
+
+BENCHMARK_REGISTER_F(TPartIndexSeekFixture, Prev)
+ ->ArgsProduct({
+ /* b-tree */ {0, 1},
+ /* groups: */ {0, 1}})
+ ->Unit(benchmark::kMicrosecond);
+
+BENCHMARK_REGISTER_F(TPartIndexSeekFixture, SeekKey)
+ ->ArgsProduct({
+ /* b-tree */ {0, 1},
+ /* groups: */ {0, 1},
+ /* ESeek: */ {0, 1, 2}})
+ ->Unit(benchmark::kMicrosecond);
+
+BENCHMARK_REGISTER_F(TPartIndexIteratorFixture, DoReads)
+ ->ArgsProduct({
+ /* b-tree */ {0, 1},
+ /* groups: */ {0, 1},
+ /* history: */ {0, 1},
+ /* reverse: */ {0, 1},
+ /* items */ {1, 10, 100}})
+ ->Unit(benchmark::kMicrosecond);
+
+}
+}
diff --git a/ydb/core/tablet_flat/benchmark/ya.make b/ydb/core/tablet_flat/benchmark/ya.make
index 41f04f436a..1ec2a13c43 100644
--- a/ydb/core/tablet_flat/benchmark/ya.make
+++ b/ydb/core/tablet_flat/benchmark/ya.make
@@ -1,10 +1,12 @@
G_BENCHMARK()
-SIZE(MEDIUM)
-TIMEOUT(600)
+TAG(ya:fat)
+SIZE(LARGE)
+TIMEOUT(1200)
SRCS(
b_charge.cpp
+ b_part_index.cpp
)
PEERDIR(
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 3491d58602..92c5c69f2c 100644
--- a/ydb/core/tablet_flat/flat_part_btree_index_iter.h
+++ b/ydb/core/tablet_flat/flat_part_btree_index_iter.h
@@ -116,6 +116,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))
{
const static TCellsIterable EmptyKey(static_cast<const char*>(nullptr), TColumns());
State.emplace_back(Meta, 0, GetEndRowId(), EmptyKey, EmptyKey);
diff --git a/ydb/core/tablet_flat/flat_part_loader.cpp b/ydb/core/tablet_flat/flat_part_loader.cpp
index 639131905e..f3afe7d360 100644
--- a/ydb/core/tablet_flat/flat_part_loader.cpp
+++ b/ydb/core/tablet_flat/flat_part_loader.cpp
@@ -184,8 +184,15 @@ TAutoPtr<NPageCollection::TFetch> TLoader::StageCreatePartView() noexcept
// TODO: put index size to stat?
// TODO: include history indexes bytes
size_t indexesRawSize = 0;
- for (auto indexPage : groupIndexesIds) {
- indexesRawSize += GetPageSize(indexPage);
+ if (AppData()->FeatureFlags.GetEnableLocalDBBtreeIndex()) {
+ for (const auto &meta : BTreeGroupIndexes) {
+ indexesRawSize += meta.IndexSize;
+ }
+ // Note: although we also have flat index, it shouldn't be loaded; so let's not count it here
+ } else {
+ for (auto indexPage : groupIndexesIds) {
+ indexesRawSize += GetPageSize(indexPage);
+ }
}
auto *partStore = new TPartStore(
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 2f67021480..00df27c990 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
@@ -1,5 +1,3 @@
-#include "flat_page_btree_index.h"
-#include "flat_page_btree_index_writer.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>
@@ -35,7 +33,9 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) {
const auto part = eggs.Lone();
- Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Groups[0], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeGroups[0].IndexSize << Endl;
+
UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024);
UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024);
@@ -63,7 +63,9 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) {
const auto part = eggs.Lone();
- Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Groups[0], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeGroups[0].IndexSize << Endl;
+
UNIT_ASSERT_GE(part->Stat.Bytes, 1ull*1024*1024*1024);
UNIT_ASSERT_LE(part->Stat.Bytes, 1ull*1024*1024*1024 + 100*1024*1024);
@@ -91,12 +93,109 @@ Y_UNIT_TEST_SUITE(TBtreeIndexTPartLarge) {
const auto part = eggs.Lone();
- Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Groups[0], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeGroups[0].IndexSize << Endl;
+
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);
}
+
+ Y_UNIT_TEST(CutKeys) {
+ TLayoutCook lay;
+
+ lay
+ .Col(0, 0, NScheme::NTypeIds::Uint64)
+ .Col(0, 1, NScheme::NTypeIds::Uint64)
+ .Col(0, 2, NScheme::NTypeIds::Uint64)
+ .Col(0, 3, NScheme::NTypeIds::String)
+ .Key({0, 1, 2});
+
+ NPage::TConf conf{ true, 7 * 1024 };
+ conf.WriteBTreeIndex = true;
+
+ TPartCook cook(lay, conf);
+
+ for (ui64 i = 0; cook.GetDataBytes(0) < 1ull*1024*1024*1024; i++) {
+ cook.Add(*TSchemedCookRow(*lay).Col(i, i, i, TString(std::to_string(i))));
+ }
+
+ TPartEggs eggs = cook.Finish();
+
+ const auto part = eggs.Lone();
+
+ Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Groups[0], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeGroups[0].IndexSize << Endl;
+
+ 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);
+ }
+
+ Y_UNIT_TEST(Group) {
+ TLayoutCook lay;
+
+ lay
+ .Col(0, 0, NScheme::NTypeIds::Uint32)
+ .Col(1, 1, NScheme::NTypeIds::String)
+ .Key({0});
+
+ NPage::TConf conf{ true, 7 * 1024 };
+ conf.Group(1).PageSize = 7 * 1024;
+ conf.WriteBTreeIndex = true;
+
+ TPartCook cook(lay, conf);
+
+ for (ui32 i = 0; cook.GetDataBytes(0) + cook.GetDataBytes(1) < 1ull*1024*1024*1024; i++) {
+ cook.Add(*TSchemedCookRow(*lay).Col(i, TString(std::to_string(i))));
+ }
+
+ TPartEggs eggs = cook.Finish();
+
+ const auto part = eggs.Lone();
+
+ Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Groups[1], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeGroups[1].IndexSize << Endl;
+
+ 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);
+ }
+
+ Y_UNIT_TEST(History) {
+ TLayoutCook lay;
+
+ lay
+ .Col(0, 0, NScheme::NTypeIds::Uint32)
+ .Col(0, 1, NScheme::NTypeIds::String)
+ .Key({0});
+
+ NPage::TConf conf{ true, 7 * 1024 };
+ conf.WriteBTreeIndex = true;
+
+ TPartCook cook(lay, conf);
+
+ for (ui32 i = 0; cook.GetDataBytes(0) < 1ull*1024*1024*1024; i++) {
+ cook.Ver({0, 2}).Add(*TSchemedCookRow(*lay).Col(i, TString(std::to_string(i))));
+ cook.Ver({0, 1}).Add(*TSchemedCookRow(*lay).Col(i, TString(std::to_string(i + 1))));
+ }
+
+ TPartEggs eggs = cook.Finish();
+
+ const auto part = eggs.Lone();
+
+ Cerr << "DataBytes = " << part->Stat.Bytes << " DataPages = " << IndexTools::CountMainPages(*part) << Endl;
+ Cerr << "FlatIndexBytes = " << part->GetPageSize(part->IndexPages.Historic[0], {}) << " BTreeIndexBytes = " << part->IndexPages.BTreeHistoric[0].IndexSize << Endl;
+
+ 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);
+ }
+
}
#endif