Skip to content

Commit 234c4c4

Browse files
authored
Merge bab1f0b into f94bbf3
2 parents f94bbf3 + bab1f0b commit 234c4c4

File tree

6 files changed

+80
-82
lines changed

6 files changed

+80
-82
lines changed

ydb/core/tablet_flat/flat_page_btree_index_writer.h

+51-42
Original file line numberDiff line numberDiff line change
@@ -386,23 +386,35 @@ namespace NKikimr::NTable::NPage {
386386

387387
Levels[0].PushChild(child);
388388
}
389+
390+
void Flush(IPageWriter &pager) {
391+
for (ui32 levelIndex = 0; levelIndex < Levels.size(); levelIndex++) {
392+
bool hasChanges = false;
393+
394+
// Note: in theory we may want to flush one level multiple times when different triggers are applicable
395+
while (CanFlush(levelIndex)) {
396+
DoFlush(levelIndex, pager, false);
397+
hasChanges = true;
398+
}
389399

390-
std::optional<TBtreeIndexMeta> Flush(IPageWriter &pager, bool last) {
391-
Y_ABORT_UNLESS(Levels.size() < Max<ui32>(), "Levels size is out of bounds");
400+
if (!hasChanges) {
401+
break; // no more changes
402+
}
403+
}
404+
}
405+
406+
TBtreeIndexMeta Finish(IPageWriter &pager) {
392407
for (ui32 levelIndex = 0; levelIndex < Levels.size(); levelIndex++) {
393-
if (last && !Levels[levelIndex].GetKeysCount()) {
408+
if (!Levels[levelIndex].GetKeysCount()) {
394409
Y_ABORT_UNLESS(Levels[levelIndex].GetChildrenCount() == 1, "Should be root");
395-
return TBtreeIndexMeta{ Levels[levelIndex].PopChild(), levelIndex, IndexSize };
410+
Y_ABORT_UNLESS(levelIndex + 1 == Levels.size(), "Should be root");
411+
return {Levels[levelIndex].PopChild(), levelIndex, IndexSize};
396412
}
397413

398-
if (!TryFlush(levelIndex, pager, last)) {
399-
Y_ABORT_UNLESS(!last);
400-
break;
401-
}
414+
DoFlush(levelIndex, pager, true);
402415
}
403416

404-
Y_ABORT_UNLESS(!last, "Should have returned root");
405-
return { };
417+
Y_ABORT_UNLESS(false, "Should have returned root");
406418
}
407419

408420
void Reset() {
@@ -415,43 +427,41 @@ namespace NKikimr::NTable::NPage {
415427
}
416428

417429
private:
418-
bool TryFlush(ui32 levelIndex, IPageWriter &pager, bool last) {
419-
if (!last && Levels[levelIndex].GetKeysCount() <= 2 * NodeKeysMax) {
420-
// Note: node should meet both NodeKeysMin and NodeSize restrictions for split
430+
bool CanFlush(ui32 levelIndex) {
431+
const ui64 waitFullNodes = 2;
421432

422-
if (Levels[levelIndex].GetKeysCount() <= 2 * NodeKeysMin) {
423-
// not enough keys for split
424-
return false;
425-
}
426-
427-
// Note: this size check is approximate and we might not produce 2 full-sized pages
428-
if (CalcPageSize(Levels[levelIndex]) <= 2 * NodeTargetSize) {
429-
// not enough bytes for split
430-
return false;
431-
}
433+
if (Levels[levelIndex].GetKeysCount() <= waitFullNodes * NodeKeysMin) {
434+
// node keys min restriction should be always satisfied
435+
return false;
432436
}
433437

434-
Writer.EnsureEmpty();
438+
// Note: size checks are approximate and flush might not produce 2 full-sized pages
435439

436-
// Note: for now we build last nodes from all remaining level's keys
437-
// we may to try splitting them more evenly later
440+
return
441+
Levels[levelIndex].GetKeysCount() > waitFullNodes * NodeKeysMax ||
442+
CalcPageSize(Levels[levelIndex]) > waitFullNodes * NodeTargetSize;
443+
}
438444

439-
while (last || Writer.GetKeysCount() < NodeKeysMin || Writer.CalcPageSize() < NodeTargetSize) {
440-
if (!last && Levels[levelIndex].GetKeysCount() < 3) {
441-
// we shouldn't produce empty nodes (but can violate NodeKeysMin restriction)
442-
break;
443-
}
444-
if (!last && Writer.GetKeysCount() >= NodeKeysMax) {
445-
// have enough keys
446-
break;
445+
void DoFlush(ui32 levelIndex, IPageWriter &pager, bool last) {
446+
Writer.EnsureEmpty();
447+
448+
if (last) {
449+
// Note: for now we build last nodes from all remaining level's keys
450+
// we may to try splitting them more evenly later
451+
452+
while (Levels[levelIndex].GetKeysCount()) {
453+
Writer.AddChild(Levels[levelIndex].PopChild());
454+
Writer.AddKey(Levels[levelIndex].PopKey());
447455
}
448-
if (last && !Levels[levelIndex].GetKeysCount()) {
449-
// nothing left
450-
break;
456+
} else {
457+
while (Writer.GetKeysCount() < NodeKeysMin || (
458+
// can add more to writer if:
459+
Levels[levelIndex].GetKeysCount() > 2 &&
460+
Writer.GetKeysCount() < NodeKeysMax &&
461+
Writer.CalcPageSize() < NodeTargetSize)) {
462+
Writer.AddChild(Levels[levelIndex].PopChild());
463+
Writer.AddKey(Levels[levelIndex].PopKey());
451464
}
452-
453-
Writer.AddChild(Levels[levelIndex].PopChild());
454-
Writer.AddKey(Levels[levelIndex].PopKey());
455465
}
456466
auto lastChild = Levels[levelIndex].PopChild();
457467
Writer.AddChild(lastChild);
@@ -462,6 +472,7 @@ namespace NKikimr::NTable::NPage {
462472

463473
if (levelIndex + 1 == Levels.size()) {
464474
Levels.emplace_back();
475+
Y_ABORT_UNLESS(Levels.size() < Max<ui32>(), "Levels size is out of bounds");
465476
}
466477
Levels[levelIndex + 1].PushChild(TChild{pageId, lastChild.RowCount, lastChild.DataSize, lastChild.ErasedRowCount});
467478
if (!last) {
@@ -475,8 +486,6 @@ namespace NKikimr::NTable::NPage {
475486
} else {
476487
Y_ABORT_UNLESS(Levels[levelIndex].GetKeysCount(), "Shouldn't leave empty levels");
477488
}
478-
479-
return true;
480489
}
481490

482491
size_t CalcPageSize(const TLevel& level) const {

ydb/core/tablet_flat/flat_part_writer.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -532,12 +532,12 @@ namespace NTable {
532532
if (WriteBTreeIndex) {
533533
Current.BTreeGroupIndexes.reserve(Groups.size());
534534
for (auto& g : Groups) {
535-
Current.BTreeGroupIndexes.push_back(g.BTreeIndex.Flush(Pager, true).value());
535+
Current.BTreeGroupIndexes.push_back(g.BTreeIndex.Finish(Pager));
536536
}
537537
if (Current.HistoryWritten > 0) {
538538
Current.BTreeHistoricIndexes.reserve(Histories.size());
539539
for (auto& g : Histories) {
540-
Current.BTreeHistoricIndexes.push_back(g.BTreeIndex.Flush(Pager, true).value());
540+
Current.BTreeHistoricIndexes.push_back(g.BTreeIndex.Finish(Pager));
541541
}
542542
}
543543
}
@@ -807,7 +807,7 @@ namespace NTable {
807807
} else {
808808
g.BTreeIndex.AddShortChild({page, dataPage->Count, raw.size()});
809809
}
810-
g.BTreeIndex.Flush(Pager, false);
810+
g.BTreeIndex.Flush(Pager);
811811
}
812812

813813
// N.B. hack to save the last row/key for the main group

ydb/core/tablet_flat/flat_stat_part.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class TStatsScreenedPartIterator {
4848
for (bool historic : {false, true}) {
4949
for (ui32 groupIndex : xrange(historic ? Part->HistoricGroupsCount : Part->GroupsCount)) {
5050
ui64 groupRowCountResolution, groupDataSizeResolution;
51-
if (groupIndex == 0 && Part->GroupsCount > 1) {
51+
if (groupIndex == 0 && (Part->GroupsCount > 1 || Small || Large)) {
5252
// make steps as small as possible because they will affect groups resolution
5353
groupRowCountResolution = groupDataSizeResolution = 0;
5454
} else {

ydb/core/tablet_flat/flat_stat_table.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,14 @@ bool BuildStats(const TSubset& subset, TStats& stats, ui64 rowCountResolution, u
1212
TDataStats iteratorStats = { };
1313
TStatsIterator statsIterator(subset.Scheme->Keys);
1414

15-
TSet<TEpoch> epochs;
16-
for (const auto& part : subset.Flatten) {
17-
epochs.insert(part->Epoch);
18-
}
19-
// if rowCountResolution = 300, 3-leveled SST, let's move each iterator up to 25 rows
20-
ui64 iterRowCountResolution = rowCountResolution / Max<ui64>(1, epochs.size()) / 4;
21-
ui64 iterDataSizeResolution = dataSizeResolution / Max<ui64>(1, epochs.size()) / 4;
15+
// TODO: deal with resolution
2216

2317
// Make index iterators for all parts
2418
bool started = true;
2519
for (const auto& part : subset.Flatten) {
2620
stats.IndexSize.Add(part->IndexesRawSize, part->Label.Channel());
2721
TAutoPtr<TStatsScreenedPartIterator> iter = new TStatsScreenedPartIterator(part, env, subset.Scheme->Keys, part->Small, part->Large,
28-
iterRowCountResolution, iterDataSizeResolution);
22+
rowCountResolution, dataSizeResolution);
2923
auto ready = iter->Start();
3024
if (ready == EReady::Page) {
3125
started = false;

ydb/core/tablet_flat/ut/ut_btree_index_nodes.cpp

+22-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "flat_page_btree_index.h"
22
#include "flat_page_btree_index_writer.h"
33
#include "test/libs/table/test_writer.h"
4+
#include "ydb/core/tx/datashard/datashard.h"
45
#include <ydb/core/tablet_flat/test/libs/rows/layout.h>
56
#include <library/cpp/testing/unittest/registar.h>
67

@@ -505,11 +506,10 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) {
505506
builder.AddChild(child);
506507

507508
TWriterBundle pager(1, TLogoBlobID());
508-
auto result = builder.Flush(pager, true);
509-
UNIT_ASSERT(result);
509+
auto result = builder.Finish(pager);
510510

511511
TBtreeIndexMeta expected{child, 0, 0};
512-
UNIT_ASSERT_EQUAL_C(*result, expected, "Got " + result->ToString());
512+
UNIT_ASSERT_EQUAL_C(result, expected, "Got " + result.ToString());
513513
}
514514

515515
Y_UNIT_TEST(OneNode) {
@@ -536,15 +536,14 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) {
536536
}
537537

538538
TWriterBundle pager(1, TLogoBlobID());
539-
auto result = builder.Flush(pager, true);
540-
UNIT_ASSERT(result);
539+
auto result = builder.Finish(pager);
541540

542-
Dump(*result, builder.GroupInfo, pager.Back());
541+
Dump(result, builder.GroupInfo, pager.Back());
543542

544543
TBtreeIndexMeta expected{{0, 1155, 11055, 385}, 1, 595};
545-
UNIT_ASSERT_EQUAL_C(*result, expected, "Got " + result->ToString());
544+
UNIT_ASSERT_EQUAL_C(result, expected, "Got " + result.ToString());
546545

547-
CheckKeys(result->PageId, keys, builder.GroupInfo, pager.Back());
546+
CheckKeys(result.PageId, keys, builder.GroupInfo, pager.Back());
548547
}
549548

550549
Y_UNIT_TEST(FewNodes) {
@@ -569,16 +568,21 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) {
569568
TSerializedCellVec deserialized(keys[i]);
570569
builder.AddKey(deserialized.GetCells());
571570
builder.AddChild(children[i + 1]);
572-
UNIT_ASSERT(!builder.Flush(pager, false));
571+
builder.Flush(pager);
573572
}
574573

575-
auto result = builder.Flush(pager, true);
576-
UNIT_ASSERT(result);
574+
auto result = builder.Finish(pager);
577575

578-
Dump(*result, builder.GroupInfo, pager.Back());
579-
580-
UNIT_ASSERT_VALUES_EQUAL(result->LevelCount, 3);
576+
Dump(result, builder.GroupInfo, pager.Back());
581577

578+
TBtreeIndexMeta expected{{9, 0, 0, 0}, 3, 1550};
579+
for (auto c : children) {
580+
expected.RowCount += c.RowCount;
581+
expected.DataSize += c.DataSize;
582+
expected.ErasedRowCount += c.ErasedRowCount;
583+
}
584+
UNIT_ASSERT_EQUAL_C(result, expected, "Got " + result.ToString());
585+
582586
auto checkKeys = [&](TPageId pageId, const TVector<TString>& keys) {
583587
CheckKeys(pageId, keys, builder.GroupInfo, pager.Back());
584588
};
@@ -624,14 +628,6 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) {
624628
checkKeys(9, {
625629
keys[8]
626630
});
627-
628-
TBtreeIndexMeta expected{{9, 0, 0, 0}, 3, 1550};
629-
for (auto c : children) {
630-
expected.RowCount += c.RowCount;
631-
expected.DataSize += c.DataSize;
632-
expected.ErasedRowCount += c.ErasedRowCount;
633-
}
634-
UNIT_ASSERT_EQUAL_C(*result, expected, "Got " + result->ToString());
635631
}
636632

637633
Y_UNIT_TEST(SplitBySize) {
@@ -656,16 +652,15 @@ Y_UNIT_TEST_SUITE(TBtreeIndexBuilder) {
656652
TSerializedCellVec deserialized(keys[i]);
657653
builder.AddKey(deserialized.GetCells());
658654
builder.AddChild(children[i + 1]);
659-
UNIT_ASSERT(!builder.Flush(pager, false));
655+
builder.Flush(pager);
660656
}
661657

662-
auto result = builder.Flush(pager, true);
663-
UNIT_ASSERT(result);
658+
auto result = builder.Finish(pager);
664659

665-
Dump(*result, builder.GroupInfo, pager.Back());
660+
Dump(result, builder.GroupInfo, pager.Back());
666661

667662
TBtreeIndexMeta expected{{15, 15150, 106050, 8080}, 3, 10270};
668-
UNIT_ASSERT_EQUAL_C(*result, expected, "Got " + result->ToString());
663+
UNIT_ASSERT_EQUAL_C(result, expected, "Got " + result.ToString());
669664
}
670665

671666
}

ydb/core/tx/datashard/datashard.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ using namespace NSchemeShard;
3030
using namespace NTabletFlatExecutor;
3131

3232
// NOTE: We really want to batch log records by default in datashards!
33-
// But in unittests we want to test both scenarios
33+
// But in unit tests we want to test both scenarios
3434
bool gAllowLogBatchingDefaultValue = true;
3535

3636
TDuration gDbStatsReportInterval = TDuration::Seconds(10);

0 commit comments

Comments
 (0)