diff --git a/ydb/core/tablet_flat/flat_part_charge.h b/ydb/core/tablet_flat/flat_part_charge.h index 6e2531eec4f2..3a7e676c7792 100644 --- a/ydb/core/tablet_flat/flat_part_charge.h +++ b/ydb/core/tablet_flat/flat_part_charge.h @@ -42,68 +42,8 @@ namespace NTable { } } - bool Do(const TRowId row1, const TRowId row2, + TResult Do(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override - { - auto index = Index.TryLoadRaw(); - if (!index) { - return false; - } - - auto startRow = row1; - auto endRow = row2; - - // Page that contains row1 - auto first = index->LookupRow(row1); - if (Y_UNLIKELY(!first)) { - return true; // already out of bounds, nothing to precharge - } - - // Page that contains row2 - auto last = index->LookupRow(row2, first); - if (Y_UNLIKELY(last < first)) { - last = first; - endRow = Min(endRow, index->GetLastRowId(last)); - } - - return DoPrecharge(TCells{}, TCells{}, TIter{}, TIter{}, first, last, startRow, endRow, keyDefaults, itemsLimit, bytesLimit); - } - - bool DoReverse(const TRowId row1, const TRowId row2, - const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override - { - auto index = Index.TryLoadRaw(); - if (!index) { - return false; - } - - auto startRow = row1; - auto endRow = row2; - - // Page that contains row1 - auto first = index->LookupRow(row1); - if (Y_UNLIKELY(!first)) { - // Looks like row1 is out of bounds, start from the last row - startRow = Min(row1, index->GetEndRowId() - 1); - first = --(*index)->End(); - if (Y_UNLIKELY(!first)) { - return true; // empty index? - } - } - - // Page that contains row2 - auto last = index->LookupRow(row2, first); - if (Y_UNLIKELY(last > first)) { - last = first; // will not go past the first page - endRow = Max(endRow, last->GetRowId()); - } - - return DoPrechargeReverse(TCells{}, TCells{}, TIter{}, TIter{}, first, last, startRow, endRow, keyDefaults, itemsLimit, bytesLimit); - } - - TResult Do(const TCells key1, const TCells key2, const TRowId row1, - const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, - ui64 bytesLimit) const noexcept override { auto index = Index.TryLoadRaw(); if (!index) { @@ -164,14 +104,14 @@ namespace NTable { } } - bool ready = DoPrecharge(key1, key2, key1Page, key2Page, first, last, startRow, endRow, keyDefaults, itemsLimit, bytesLimit); + bool ready = DoPrecharge(key1, key2, key1Page, key2Page, first, last, + startRow, endRow, keyDefaults, itemsLimit, bytesLimit); return { ready, overshot }; } - TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, - const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, - ui64 bytesLimit) const noexcept override + TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, + const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { auto index = Index.TryLoadRaw(); if (!index) { @@ -237,7 +177,8 @@ namespace NTable { } } - bool ready = DoPrechargeReverse(key1, key2, key1Page, key2Page, first, last, startRow, endRow, keyDefaults, itemsLimit, bytesLimit); + bool ready = DoPrechargeReverse(key1, key2, key1Page, key2Page, first, last, + startRow, endRow, keyDefaults, itemsLimit, bytesLimit); return { ready, overshot }; } @@ -254,10 +195,8 @@ namespace NTable { * * If @param key1Page specified, @param first should be the same. */ - bool DoPrecharge(const TCells key1, const TCells key2, - const TIter key1Page, const TIter key2Page, - const TIter first, const TIter last, - TRowId startRowId, TRowId endRowId, + bool DoPrecharge(const TCells key1, const TCells key2, const TIter key1Page, const TIter key2Page, + const TIter first, const TIter last, TRowId startRowId, TRowId endRowId, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { bool ready = true; @@ -352,10 +291,8 @@ namespace NTable { * * If @param key1Page specified, @param first should be the same. */ - bool DoPrechargeReverse(const TCells key1, const TCells key2, - const TIter key1Page, const TIter key2Page, - TIter first, TIter last, - TRowId startRowId, TRowId endRowId, + bool DoPrechargeReverse(const TCells key1, const TCells key2, const TIter key1Page, const TIter key2Page, + TIter first, TIter last, TRowId startRowId, TRowId endRowId, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { bool ready = true; @@ -562,8 +499,8 @@ namespace NTable { /** * Precharges pages that contain row1 to row2 inclusive */ - bool DoPrechargeGroup(TGroupState& g, TRowId row1, TRowId row2, ui64& bytes) const noexcept { - auto groupIndex = g.GroupIndex.TryLoadRaw(); + bool DoPrechargeGroup(TGroupState& group, TRowId row1, TRowId row2, ui64& bytes) const noexcept { + auto groupIndex = group.GroupIndex.TryLoadRaw(); if (!groupIndex) { if (bytes) { // Note: we can't continue if we have bytes limit @@ -574,29 +511,29 @@ namespace NTable { bool ready = true; - if (!g.Index || row1 < g.Index->GetRowId() || row1 > g.LastRowId) { - g.Index = groupIndex->LookupRow(row1, g.Index); - if (Y_UNLIKELY(!g.Index)) { + if (!group.Index || row1 < group.Index->GetRowId() || row1 > group.LastRowId) { + group.Index = groupIndex->LookupRow(row1, group.Index); + if (Y_UNLIKELY(!group.Index)) { // Looks like row1 doesn't even exist - g.LastRowId = Max(); + group.LastRowId = Max(); return ready; } - g.LastRowId = groupIndex->GetLastRowId(g.Index); - auto pageId = g.Index->GetPageId(); - ready &= bool(Env->TryGetPage(Part, pageId, g.GroupId)); - bytes += Part->GetPageSize(pageId, g.GroupId); + group.LastRowId = groupIndex->GetLastRowId(group.Index); + auto pageId = group.Index->GetPageId(); + ready &= bool(Env->TryGetPage(Part, pageId, group.GroupId)); + bytes += Part->GetPageSize(pageId, group.GroupId); } - while (g.LastRowId < row2) { - if (!++g.Index) { + while (group.LastRowId < row2) { + if (!++group.Index) { // Looks like row2 doesn't even exist - g.LastRowId = Max(); + group.LastRowId = Max(); return ready; } - g.LastRowId = groupIndex->GetLastRowId(g.Index); - auto pageId = g.Index->GetPageId(); - ready &= bool(Env->TryGetPage(Part, pageId, g.GroupId)); - bytes += Part->GetPageSize(pageId, g.GroupId); + group.LastRowId = groupIndex->GetLastRowId(group.Index); + auto pageId = group.Index->GetPageId(); + ready &= bool(Env->TryGetPage(Part, pageId, group.GroupId)); + bytes += Part->GetPageSize(pageId, group.GroupId); } return ready; @@ -605,8 +542,8 @@ namespace NTable { /** * Precharges pages that contain row1 to row2 inclusive in reverse */ - bool DoPrechargeGroupReverse(TGroupState& g, TRowId row1, TRowId row2, ui64& bytes) const noexcept { - auto groupIndex = g.GroupIndex.TryLoadRaw(); + bool DoPrechargeGroupReverse(TGroupState& group, TRowId row1, TRowId row2, ui64& bytes) const noexcept { + auto groupIndex = group.GroupIndex.TryLoadRaw(); if (!groupIndex) { if (bytes) { // Note: we can't continue if we have bytes limit @@ -617,29 +554,29 @@ namespace NTable { bool ready = true; - if (!g.Index || row1 < g.Index->GetRowId() || row1 > g.LastRowId) { - g.Index = groupIndex->LookupRow(row1, g.Index); - if (Y_UNLIKELY(!g.Index)) { + if (!group.Index || row1 < group.Index->GetRowId() || row1 > group.LastRowId) { + group.Index = groupIndex->LookupRow(row1, group.Index); + if (Y_UNLIKELY(!group.Index)) { // Looks like row1 doesn't even exist - g.LastRowId = Max(); + group.LastRowId = Max(); return ready; } - g.LastRowId = groupIndex->GetLastRowId(g.Index); - auto pageId = g.Index->GetPageId(); - ready &= bool(Env->TryGetPage(Part, pageId, g.GroupId)); - bytes += Part->GetPageSize(pageId, g.GroupId); + group.LastRowId = groupIndex->GetLastRowId(group.Index); + auto pageId = group.Index->GetPageId(); + ready &= bool(Env->TryGetPage(Part, pageId, group.GroupId)); + bytes += Part->GetPageSize(pageId, group.GroupId); } - while (g.Index->GetRowId() > row2) { - if (g.Index.Off() == 0) { + while (group.Index->GetRowId() > row2) { + if (group.Index.Off() == 0) { // This was the last page we could precharge return ready; } - g.LastRowId = g.Index->GetRowId() - 1; - --g.Index; - auto pageId = g.Index->GetPageId(); - ready &= bool(Env->TryGetPage(Part, pageId, g.GroupId)); - bytes += Part->GetPageSize(pageId, g.GroupId); + group.LastRowId = group.Index->GetRowId() - 1; + --group.Index; + auto pageId = group.Index->GetPageId(); + ready &= bool(Env->TryGetPage(Part, pageId, group.GroupId)); + bytes += Part->GetPageSize(pageId, group.GroupId); } return ready; 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 6a10a57cabe1..2c802e71882b 100644 --- a/ydb/core/tablet_flat/flat_part_charge_btree_index.h +++ b/ydb/core/tablet_flat/flat_part_charge_btree_index.h @@ -15,29 +15,7 @@ namespace NKikimr::NTable { Y_UNUSED(includeHistory); } - virtual bool Do(const TRowId row1, const TRowId row2, - const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { - // TODO: implement - Y_UNUSED(row1); - Y_UNUSED(row2); - Y_UNUSED(keyDefaults); - Y_UNUSED(itemsLimit); - Y_UNUSED(bytesLimit); - return true; - } - - virtual bool DoReverse(const TRowId row1, const TRowId row2, - const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept override { - // TODO: implement - Y_UNUSED(row1); - Y_UNUSED(row2); - Y_UNUSED(keyDefaults); - Y_UNUSED(itemsLimit); - Y_UNUSED(bytesLimit); - return true; - } - - virtual TResult Do(const TCells key1, const TCells key2, const TRowId row1, + 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 @@ -51,7 +29,7 @@ namespace NKikimr::NTable { return {true, false}; } - virtual TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, + 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 @@ -64,6 +42,9 @@ namespace NKikimr::NTable { Y_UNUSED(bytesLimit); return {true, false}; } + + private: + }; } diff --git a/ydb/core/tablet_flat/flat_part_charge_iface.h b/ydb/core/tablet_flat/flat_part_charge_iface.h index 698e927262c4..46e84175d6b0 100644 --- a/ydb/core/tablet_flat/flat_part_charge_iface.h +++ b/ydb/core/tablet_flat/flat_part_charge_iface.h @@ -17,30 +17,36 @@ namespace NKikimr::NTable { * * Important caveat: assumes iteration won't touch any row > row2 */ - virtual bool Do(const TRowId row1, const TRowId row2, - const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept = 0; + bool Do(const TRowId row1, const TRowId row2, + const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept + { + return Do(TCells{}, TCells{}, row1, row2, + keyDefaults, itemsLimit, bytesLimit).Ready; + } /** * Precharges data for rows between row1 and row2 inclusive in reverse * * Important caveat: assumes iteration won't touch any row > row2 */ - virtual bool DoReverse(const TRowId row1, const TRowId row2, - const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept = 0; + bool DoReverse(const TRowId row1, const TRowId row2, + const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept + { + return DoReverse(TCells{}, TCells{}, row1, row2, + keyDefaults, itemsLimit, bytesLimit).Ready; + } /** * 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, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, - ui64 bytesLimit) const noexcept = 0; + virtual TResult Do(const TCells key1, const TCells key2, const TRowId row1, const 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, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, - ui64 bytesLimit) const noexcept = 0; + virtual TResult DoReverse(const TCells key1, const TCells key2, const TRowId row1, const TRowId row2, + const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept = 0; virtual ~ICharge() = default; }; diff --git a/ydb/core/tablet_flat/ut/ut_charge.cpp b/ydb/core/tablet_flat/ut/ut_charge.cpp index 195577ffc78a..ca0bf896af05 100644 --- a/ydb/core/tablet_flat/ut/ut_charge.cpp +++ b/ydb/core/tablet_flat/ut/ut_charge.cpp @@ -125,7 +125,7 @@ namespace { for (auto seq: xrange(Mass.Saved.Size())) { /* ... but rows pack has 4 rows per each page, the first row in - each pack is ommited and used as spacer between pages. */ + each pack is omitted and used as spacer between pages. */ if (seq % 4 > 0) { if (history) { @@ -161,8 +161,14 @@ namespace { void CheckByRows(TPageId row1, TPageId row2, ui64 items, const TMap& shouldPrecharge) const { - CheckPrechargeByRows(row1, row2, items, false, shouldPrecharge); - CheckPrechargeByRows(row1, row2, items, true, shouldPrecharge); + CheckPrechargeByRows(row1, row2, items, false, shouldPrecharge, false); + CheckPrechargeByRows(row1, row2, items, true, shouldPrecharge, false); + } + + void CheckByRowsReverse(TPageId row1, TPageId row2, ui64 items, const TMap& shouldPrecharge) const + { + CheckPrechargeByRows(row1, row2, items, false, shouldPrecharge, true); + CheckPrechargeByRows(row1, row2, items, true, shouldPrecharge, true); } void CheckIndex(ui32 lower, ui32 upper, ui64 items, const TMap& shouldPrecharge, TSet stickyIndex) const { @@ -205,10 +211,8 @@ namespace { CheckPrecharged(env.Touched, shouldPrecharge, sticky, flags); } - void CheckPrechargeByRows(TPageId row1, TPageId row2, ui64 items, bool fail, TMap shouldPrecharge) const + void CheckPrechargeByRows(TPageId row1, TPageId row2, ui64 items, bool fail, TMap shouldPrecharge, bool reverse) const { - Y_ABORT_UNLESS(row1 <= row2 && row2 < 3 * 9); - auto sticky = GetIndexPages(); TTouchEnv env(fail, sticky); @@ -225,10 +229,12 @@ namespace { tags.push_back(c.Tag); } - UNIT_ASSERT_VALUES_EQUAL_C( - !fail, - CreateCharge(&env, *run.begin()->Part, tags, false)->Do(row1, row2, keyDefaults, items, Max()), - AssertMessage(fail)); + auto charge = CreateCharge(&env, *run.begin()->Part, tags, false); + bool result = reverse + ? charge->DoReverse(row1, row2, keyDefaults, items, Max()) + : charge->Do(row1, row2, keyDefaults, items, Max()); + + UNIT_ASSERT_VALUES_EQUAL_C(!fail, result, AssertMessage(fail)); CheckPrecharged(env.Touched, shouldPrecharge, sticky, fail ? TPageIdFlags::IfFail : TPageIdFlags::IfNoFail); } @@ -256,7 +262,7 @@ namespace { wrap.Next().Is(key > upper ? EReady::Gone : EReady::Data); } - // forcebly touch the next stop element that is greater than upper + // forcibly touch the next stop element that is greater than upper // because instead of having |1 2 3| and stopping as soon as we see 2 // we may have |1*2 2*2 3*2| = |2 4 6| and be requested with upper = 5 (not 4) if (key > upper) { @@ -292,7 +298,7 @@ namespace { wrap.Next().Is(key < upper || key == (ui32)-1 ? EReady::Gone : EReady::Data); } - // forcebly touch the next stop element that is greater than upper + // forcibly touch the next stop element that is greater than upper // because instead of having |1 2 3| and stopping as soon as we see 2 // we may have |1*2 2*2 3*2| = |2 4 6| and be requested with upper = 2 (not 4) if (key < upper || key == (ui32)-1) { @@ -358,7 +364,7 @@ namespace { expectedValue.insert(absoluteId.Value(p.Page, p.Page)); } } - UNIT_ASSERT_VALUES_EQUAL_C(expectedValue, actualValue, AssertMesage(groupId, flags)); + UNIT_ASSERT_VALUES_EQUAL_C(expectedValue, actualValue, AssertMessage(groupId, flags)); } } @@ -367,12 +373,12 @@ namespace { "Seq: " + std::to_string(CurrentStep()) + " Fail: " + (fail ? "Yes" : "No"); } - std::string AssertMesage(TGroupId group) const { + std::string AssertMessage(TGroupId group) const { return "Seq: " + std::to_string(CurrentStep()) + " Group: " + std::to_string(group.Index) + "," + std::to_string(group.IsHistoric()); } - std::string AssertMesage(TGroupId group, TPageIdFlags flags) const { + std::string AssertMessage(TGroupId group, TPageIdFlags flags) const { auto result = "Seq: " + std::to_string(CurrentStep()) + " Group: " + std::to_string(group.Index) + "," + std::to_string(group.IsHistoric()); @@ -604,7 +610,7 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(209).CheckByKeys(5, 13, 0, TMap{ {TGroupId{0}, {1, 2, 3, 4_I}}, - {TGroupId{1}, {1_g, 2_g, 3, 4}}, // pages 3, 4 are always neded + {TGroupId{1}, {1_g, 2_g, 3, 4}}, // pages 3, 4 are always needed {TGroupId{2}, {3_g, 4_g, 5_g, 6, 7, 8, 9_g}} // pages 6, 7, 8 are always needed }); @@ -628,7 +634,7 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(213).CheckByKeys(6, 13, 0, TMap{ {TGroupId{0}, {1, 2, 3, 4_I}}, - {TGroupId{1}, {2_g, 3, 4}}, // pages 3, 4 are always neded + {TGroupId{1}, {2_g, 3, 4}}, // pages 3, 4 are always needed {TGroupId{2}, {4_g, 5_g, 6, 7, 8, 9_g}} // pages 6, 7, 8 are always needed }); @@ -646,7 +652,7 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(216).CheckByKeys(7, 13, 0, TMap{ {TGroupId{0}, {1, 2, 3, 4_I}}, - {TGroupId{1}, {2_g, 3, 4}}, // pages 3, 4 are always neded + {TGroupId{1}, {2_g, 3, 4}}, // pages 3, 4 are always needed {TGroupId{2}, {5_g, 6, 7, 8, 9_g}} // pages 6, 7, 8 are always needed }); @@ -664,7 +670,7 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(219).CheckByKeys(8, 13, 0, TMap{ {TGroupId{0}, {1, 2, 3, 4_I}}, - {TGroupId{1}, {3, 4}}, // pages 3, 4 are always neded + {TGroupId{1}, {3, 4}}, // pages 3, 4 are always needed {TGroupId{2}, {6, 7, 8, 9_g}} // pages 6, 7, 8 are always needed }); @@ -747,13 +753,13 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(101).CheckByKeys(5, 13, 999, TMap{ {TGroupId{0}, {1, 2, 3, 4_I}}, - {TGroupId{1}, {1_g, 2_g, 3, 4}}, // pages 3, 4 are always neded + {TGroupId{1}, {1_g, 2_g, 3, 4}}, // pages 3, 4 are always needed {TGroupId{2}, {3_g, 4_g, 5_g, 6, 7, 8, 9_g}} // pages 6, 7, 8 are always needed }); me.To(102).CheckByKeys(5, 13, 7, TMap{ {TGroupId{0}, {1, 2, 3, 4_I}}, - {TGroupId{1}, {1_g, 2_g, 3, 4}}, // pages 3, 4 are always neded + {TGroupId{1}, {1_g, 2_g, 3, 4}}, // pages 3, 4 are always needed {TGroupId{2}, {3_g, 4_g, 5_g, 6, 7, 8, 9_g}} // pages 6, 7, 8 are always needed }); @@ -771,8 +777,8 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(105).CheckByKeys(5, 13, 4, TMap{ {TGroupId{0}, {1, 2, 3_f, 4_f}}, - {TGroupId{1}, {1_g, 2_g, 3, 4_f}}, // here we touh extra pages, but it's fine - {TGroupId{2}, {3_g, 4_g, 5_g, 6, 7, 8_f}} // here we touh extra pages, but it's fine + {TGroupId{1}, {1_g, 2_g, 3, 4_f}}, // here we touch extra pages, but it's fine + {TGroupId{2}, {3_g, 4_g, 5_g, 6, 7, 8_f}} // here we touch extra pages, but it's fine }); me.To(106).CheckByKeys(7, 13, 3, TMap{ @@ -911,12 +917,12 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(200).CheckByKeysReverse(15, 3, 6, TMap{ {TGroupId{0}, {3, 2, 1, 0_f}}, - {TGroupId{2}, {11_g, 10_g, 9_g, 8, 7, 6, 5, 4_f, 3_f}} // here we touh extra pages, but it's fine + {TGroupId{2}, {11_g, 10_g, 9_g, 8, 7, 6, 5, 4_f, 3_f}} // here we touch extra pages, but it's fine }); me.To(201).CheckByKeysReverse(15, 3, 5, TMap{ {TGroupId{0}, {3, 2, 1_f}}, - {TGroupId{2}, {11_g, 10_g, 9_g, 8, 7, 6, 5_f, 4_f, 3_f}} // here we touh extra pages, but it's fine + {TGroupId{2}, {11_g, 10_g, 9_g, 8, 7, 6, 5_f, 4_f, 3_f}} // here we touch extra pages, but it's fine }); me.To(202).CheckByKeysReverse(15, 5, 5, TMap{ @@ -926,22 +932,22 @@ Y_UNIT_TEST_SUITE(Charge) { me.To(203).CheckByKeysReverse(13, 3, 4, TMap{ {TGroupId{0}, {3, 2, 1}}, - {TGroupId{2}, {9_g, 8, 7, 6, 5, 4_f}} // here we touh extra pages, but it's fine + {TGroupId{2}, {9_g, 8, 7, 6, 5, 4_f}} // here we touch extra pages, but it's fine }); me.To(204).CheckByKeysReverse(13, 3, 3, TMap{ {TGroupId{0}, {3, 2, 1_f}}, - {TGroupId{2}, {9_g, 8, 7, 6, 5_f}} // here we touh extra pages, but it's fine + {TGroupId{2}, {9_g, 8, 7, 6, 5_f}} // here we touch extra pages, but it's fine }); me.To(205).CheckByKeysReverse(13, 3, 2, TMap{ {TGroupId{0}, {3, 2}}, - {TGroupId{2}, {9_g, 8, 7, 6_f}} // here we touh extra pages, but it's fine + {TGroupId{2}, {9_g, 8, 7, 6_f}} // here we touch extra pages, but it's fine }); me.To(206).CheckByKeysReverse(13, 3, 1, TMap{ {TGroupId{0}, {3, 2}}, - {TGroupId{2}, {9_g, 8, 7_f}} // here we touh extra pages, but it's fine + {TGroupId{2}, {9_g, 8, 7_f}} // here we touch extra pages, but it's fine }); } @@ -1207,10 +1213,102 @@ Y_UNIT_TEST_SUITE(Charge) { {TGroupId{2}, {2, 3, 4, 5, 6}} }); - me.To(107).CheckByRows(4, 8, 0, TMap{ - {TGroupId{0}, {1, 2}}, - {TGroupId{1}, {2, 3, 4}}, - {TGroupId{2}, {4, 5, 6, 7, 8}} + me.To(107).CheckByRows(3, 5, 0, TMap{ + {TGroupId{0}, {1}}, + {TGroupId{1}, {1, 2}}, + {TGroupId{2}, {3, 4, 5}} + }); + + me.To(200).CheckByRows(8, 7, 0, TMap{ + {TGroupId{0}, {2}}, + {TGroupId{1}, {}}, + {TGroupId{2}, {}} + }); + + me.To(201).CheckByRows(7, 1, 0, TMap{ + {TGroupId{0}, {2}}, + {TGroupId{1}, {}}, + {TGroupId{2}, {}} + }); + } + + Y_UNIT_TEST(ByRowsReverse) + { + TModel me(true); + + /* + + row ids by pages: + group0 = ..|18 19 20|21 22 23|24 25 26| + group1 = ..|18 19|20 21|22 23|24 25|26| + group2 = ..|18|19|20|21|22|23|24|25|26| + + */ + + me.To(100).CheckByRowsReverse(26, 26, 0, TMap{ + {TGroupId{0}, {8}}, + {TGroupId{1}, {13}}, + {TGroupId{2}, {26}} + }); + + me.To(101).CheckByRowsReverse(26, 25, 0, TMap{ + {TGroupId{0}, {8}}, + {TGroupId{1}, {13, 12}}, + {TGroupId{2}, {26, 25}} + }); + + me.To(102).CheckByRowsReverse(26, 24, 0, TMap{ + {TGroupId{0}, {8}}, + {TGroupId{1}, {13, 12}}, + {TGroupId{2}, {26, 25, 24}} + }); + + me.To(103).CheckByRowsReverse(26, 23, 0, TMap{ + {TGroupId{0}, {8, 7}}, + {TGroupId{1}, {13, 12, 11}}, + {TGroupId{2}, {26, 25, 24, 23}} + }); + + me.To(104).CheckByRowsReverse(26, 22, 0, TMap{ + {TGroupId{0}, {8, 7}}, + {TGroupId{1}, {13, 12, 11}}, + {TGroupId{2}, {26, 25, 24, 23, 22}} + }); + + me.To(105).CheckByRowsReverse(25, 19, 0, TMap{ + {TGroupId{0}, {8, 7, 6}}, + {TGroupId{1}, {12, 11, 10, 9}}, + {TGroupId{2}, {25, 24, 23, 22, 21, 20, 19}} + }); + + me.To(106).CheckByRowsReverse(24, 20, 0, TMap{ + {TGroupId{0}, {8, 7, 6}}, + {TGroupId{1}, {12, 11, 10}}, + {TGroupId{2}, {24, 23, 22, 21, 20}} + }); + + me.To(107).CheckByRowsReverse(23, 21, 0, TMap{ + {TGroupId{0}, {7}}, + {TGroupId{1}, {11, 10}}, + {TGroupId{2}, {23, 22, 21}} + }); + + me.To(200).CheckByRowsReverse(8, 9, 0, TMap{ + {TGroupId{0}, {2}}, + {TGroupId{1}, {}}, + {TGroupId{2}, {}} + }); + + me.To(201).CheckByRowsReverse(9, 15, 0, TMap{ + {TGroupId{0}, {3}}, + {TGroupId{1}, {}}, + {TGroupId{2}, {}} + }); + + me.To(202).CheckByRowsReverse(100, 23, 0, TMap{ + {TGroupId{0}, {8, 7}}, + {TGroupId{1}, {13, 12, 11}}, + {TGroupId{2}, {26, 25, 24, 23}} }); } @@ -1229,36 +1327,88 @@ Y_UNIT_TEST_SUITE(Charge) { // Precharge touches [row1 .. Min(row2, row1 + itemsLimit)] rows (1 extra row) - me.To(101).CheckByRows(1, 7, 6, TMap{ + me.To(100).CheckByRows(1, 7, 6, TMap{ {TGroupId{0}, {0, 1, 2}}, {TGroupId{1}, {0, 1, 2, 3}}, {TGroupId{2}, {1, 2, 3, 4, 5, 6, 7}} }); - me.To(102).CheckByRows(1, 7, 5, TMap{ + me.To(101).CheckByRows(1, 7, 5, TMap{ {TGroupId{0}, {0, 1, 2}}, {TGroupId{1}, {0, 1, 2, 3}}, {TGroupId{2}, {1, 2, 3, 4, 5, 6}} }); - me.To(103).CheckByRows(1, 7, 4, TMap{ + me.To(102).CheckByRows(1, 7, 4, TMap{ {TGroupId{0}, {0, 1}}, {TGroupId{1}, {0, 1, 2}}, {TGroupId{2}, {1, 2, 3, 4, 5}} }); - me.To(104).CheckByRows(1, 7, 1, TMap{ + me.To(103).CheckByRows(1, 7, 1, TMap{ {TGroupId{0}, {0}}, {TGroupId{1}, {0, 1}}, {TGroupId{2}, {1, 2}} }); - me.To(105).CheckByRows(3, 20, 5, TMap{ + me.To(104).CheckByRows(3, 20, 5, TMap{ {TGroupId{0}, {1, 2}}, {TGroupId{1}, {1, 2, 3, 4}}, {TGroupId{2}, {3, 4, 5, 6, 7, 8}} }); } + + Y_UNIT_TEST(ByRowsLimitsReverse) + { + TModel me(true); + + /* + + row ids by pages: + group0 = ..|18 19 20|21 22 23|24 25 26| + group1 = ..|18 19|20 21|22 23|24 25|26| + group2 = ..|18|19|20|21|22|23|24|25|26| + + */ + + // Precharge touches [Max(row2, row1 - itemsLimit) .. row1] rows (1 extra row) + + me.To(100).CheckByRowsReverse(25, 19, 6, TMap{ + {TGroupId{0}, {8, 7, 6}}, + {TGroupId{1}, {12, 11, 10, 9}}, + {TGroupId{2}, {25, 24, 23, 22, 21, 20, 19}} + }); + + me.To(101).CheckByRowsReverse(25, 19, 5, TMap{ + {TGroupId{0}, {8, 7, 6}}, + {TGroupId{1}, {12, 11, 10}}, + {TGroupId{2}, {25, 24, 23, 22, 21, 20}} + }); + + me.To(102).CheckByRowsReverse(25, 19, 4, TMap{ + {TGroupId{0}, {8, 7}}, + {TGroupId{1}, {12, 11, 10}}, + {TGroupId{2}, {25, 24, 23, 22, 21}} + }); + + me.To(103).CheckByRowsReverse(25, 19, 1, TMap{ + {TGroupId{0}, {8}}, + {TGroupId{1}, {12}}, + {TGroupId{2}, {25, 24}} + }); + + me.To(104).CheckByRowsReverse(23, 3, 5, TMap{ + {TGroupId{0}, {7, 6}}, + {TGroupId{1}, {11, 10, 9}}, + {TGroupId{2}, {23, 22, 21, 20, 19, 18}} + }); + + me.To(200).CheckByRowsReverse(100, 3, 5, TMap{ + {TGroupId{0}, {8, 7}}, + {TGroupId{1}, {13, 12, 11, 10}}, + {TGroupId{2}, {26, 25, 24, 23, 22, 21}} + }); + } } }