diff options
author | kungasc <kungasc@yandex-team.com> | 2023-09-18 23:34:46 +0300 |
---|---|---|
committer | kungasc <kungasc@yandex-team.com> | 2023-09-18 23:53:56 +0300 |
commit | 55d8ae0f29a754250bb75958428dfe3b543cdaf9 (patch) | |
tree | 0837d0292cfd0a27d1cf4740b3ea9d12bc288fcd | |
parent | c8409f20e76dba22a1e9928a4bdaa9595cf91e46 (diff) | |
download | ydb-55d8ae0f29a754250bb75958428dfe3b543cdaf9.tar.gz |
KIKIMR-19139 Load index in Precharge
-rw-r--r-- | ydb/core/tablet_flat/flat_part_charge.h | 134 | ||||
-rw-r--r-- | ydb/core/tablet_flat/flat_part_index_iter.h | 8 | ||||
-rw-r--r-- | ydb/core/tablet_flat/ut/ut_charge.cpp | 279 | ||||
-rw-r--r-- | ydb/core/tablet_flat/ut/ut_comp_shard.cpp | 44 | ||||
-rw-r--r-- | ydb/core/tablet_flat/ut/ut_part.cpp | 5 |
5 files changed, 382 insertions, 88 deletions
diff --git a/ydb/core/tablet_flat/flat_part_charge.h b/ydb/core/tablet_flat/flat_part_charge.h index 7c93416dfd..b8aa25e8bf 100644 --- a/ydb/core/tablet_flat/flat_part_charge.h +++ b/ydb/core/tablet_flat/flat_part_charge.h @@ -4,6 +4,7 @@ #include "flat_table_part.h" #include "flat_part_iface.h" #include "flat_part_slice.h" +#include "flat_part_index_iter.h" #include <util/generic/bitmap.h> @@ -15,7 +16,8 @@ namespace NTable { using TCells = NPage::TCells; using TIter = NPage::TIndex::TIter; using TDataPage = NPage::TDataPage; - + using TGroupId = NPage::TGroupId; + struct TResult { bool Ready; /* All required pages are already in memory */ bool Overshot; /* Search may start outside of bounds */ @@ -25,21 +27,21 @@ namespace NTable { : Env(env) , Part(&part) , Scheme(*Part->Scheme) - , Index(Part->Index) - , HistoryIndex( - includeHistory && Part->HistoricIndexes - ? &Part->GetGroupIndex(NPage::TGroupId(0, true)) - : nullptr) + , Index(Part, Env, TGroupId()) { + if (includeHistory && Part->IndexPages.Historic) { + HistoryIndex.emplace(Part, Env, TGroupId(0, true)); + } + TDynBitMap seen; for (TTag tag : tags) { if (const auto* col = Scheme.FindColumnByTag(tag)) { if (col->Group != 0 && !seen.Get(col->Group)) { NPage::TGroupId groupId(col->Group); - Groups.emplace_back(Part->GetGroupIndex(groupId), groupId); + Groups.emplace_back(TPartIndexIt(Part, Env, groupId), groupId); if (HistoryIndex) { NPage::TGroupId historyGroupId(col->Group, true); - HistoryGroups.emplace_back(Part->GetGroupIndex(historyGroupId), historyGroupId); + HistoryGroups.emplace_back(TPartIndexIt(Part, Env, historyGroupId), historyGroupId); } seen.Set(col->Group); } @@ -178,16 +180,21 @@ namespace NTable { Y_VERIFY_DEBUG(beginRowId < endRowId, "Unexpected empty row range"); Y_VERIFY_DEBUG(!Groups, "Unexpected column groups during SplitKey precharge"); + auto index = Index.TryLoadRaw(); + if (!index) { + return false; + } + bool ready = true; // The first page that may contain splitKey - auto found = Index.LookupKey(splitKey, Scheme.Groups[0], ESeek::Lower, &keyDefaults); + auto found = index->LookupKey(splitKey, Scheme.Groups[0], ESeek::Lower, &keyDefaults); // Note: as we may have cut index key we may both need prev and next pages if (auto prev = found; prev.Off() && --prev) { TRowId pageBegin = prev->GetRowId(); - TRowId pageEnd = found ? found->GetRowId() : Index.GetEndRowId(); + TRowId pageEnd = found ? found->GetRowId() : index->GetEndRowId(); if (pageBegin < endRowId && beginRowId < pageEnd) { ready &= bool(Env->TryGetPage(Part, prev->GetPageId())); } @@ -197,7 +204,7 @@ namespace NTable { bool needNext = true; if (found->GetRowId() < beginRowId) { // iterator may re-seek to the first page that's in range - auto adjusted = Index.LookupRow(beginRowId, found); + auto adjusted = index->LookupRow(beginRowId, found); if (found != adjusted) { found = adjusted; needNext = false; @@ -227,20 +234,25 @@ namespace NTable { bool Do(const TRowId row1, const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { + auto index = Index.TryLoadRaw(); + if (!index) { + return false; + } + auto startRow = row1; auto endRow = row2; // Page that contains row1 - auto first = Index.LookupRow(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); + auto last = index->LookupRow(row2, first); if (Y_UNLIKELY(last < first)) { last = first; - endRow = Min(endRow, Index.GetLastRowId(last)); + endRow = Min(endRow, index->GetLastRowId(last)); } return DoPrecharge(TCells{}, TCells{}, TIter{}, TIter{}, first, last, startRow, endRow, keyDefaults, itemsLimit, bytesLimit); @@ -254,22 +266,27 @@ namespace NTable { bool DoReverse(const TRowId row1, const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { + auto index = Index.TryLoadRaw(); + if (!index) { + return false; + } + auto startRow = row1; auto endRow = row2; // Page that contains row1 - auto first = Index.LookupRow(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(); + 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); + 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()); @@ -285,12 +302,17 @@ namespace NTable { const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { + auto index = Index.TryLoadRaw(); + if (!index) { + return { false, false }; + } + auto startRow = row1; auto endRow = row2; bool overshot = !key2; // +inf is always on the next slice // First page to precharge (contains row1) - auto first = Index.LookupRow(row1); + auto first = index->LookupRow(row1); if (Y_UNLIKELY(!first)) { return { true, true }; // already out of bounds, nothing to precharge } @@ -299,16 +321,16 @@ namespace NTable { auto firstExt = first; // Last page to precharge (contains row2) - auto last = Index.LookupRow(row2, first); + auto last = index->LookupRow(row2, first); if (Y_UNLIKELY(last < first)) { last = first; // will not go past the first page - endRow = Min(endRow, Index.GetLastRowId(last)); + endRow = Min(endRow, index->GetLastRowId(last)); } TIter key1Page; if (key1) { // First page to precharge (may contain key >= key1) - key1Page = Index.LookupKey(key1, Scheme.Groups[0], ESeek::Lower, &keyDefaults); + key1Page = index->LookupKey(key1, Scheme.Groups[0], ESeek::Lower, &keyDefaults); if (!key1Page || key1Page > last) { return { true, true }; // first key is outside of bounds } @@ -329,7 +351,7 @@ namespace NTable { if (key2) { // Last page to precharge (may contain key >= key2) // We actually use the next page since lookup is not exact - key2Page = Index.LookupKey(key2, Scheme.Groups[0], ESeek::Lower, &keyDefaults); + key2Page = index->LookupKey(key2, Scheme.Groups[0], ESeek::Lower, &keyDefaults); auto key2PageExt = key2Page + 1; if (key2PageExt && key2PageExt <= last) { last = Max(key2PageExt, firstExt); @@ -351,16 +373,21 @@ namespace NTable { const TRowId row2, const TKeyCellDefaults &keyDefaults, ui64 itemsLimit, ui64 bytesLimit) const noexcept { + auto index = Index.TryLoadRaw(); + if (!index) { + return { false, false }; + } + auto startRow = row1; auto endRow = row2; bool overshot = !key2; // +inf is always on the next slice // First page to precharge (contains row1) - auto first = Index.LookupRow(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(); + startRow = Min(row1, index->GetEndRowId() - 1); + first = --(*index)->End(); if (Y_UNLIKELY(!first)) { return { true, true }; // empty index? } @@ -370,7 +397,7 @@ namespace NTable { auto firstExt = first; // Last page to precharge (contains row2) - auto last = Index.LookupRow(row2, first); + 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()); @@ -379,14 +406,14 @@ namespace NTable { TIter key1Page; if (key1) { // First page to precharge (may contain key <= key1) - key1Page = Index.LookupKeyReverse(key1, Scheme.Groups[0], ESeek::Lower, &keyDefaults); + key1Page = index->LookupKeyReverse(key1, Scheme.Groups[0], ESeek::Lower, &keyDefaults); if (!key1Page || key1Page < last) { return { true, true }; // first key is outside of bounds } if (first >= key1Page) { first = key1Page; // use the minimum firstExt = key1Page - 1; // first key <= key1 might be on the next page - startRow = Min(startRow, Index.GetLastRowId(first)); + startRow = Min(startRow, index->GetLastRowId(first)); if (key1Page.Off() == 0 || last > firstExt) { firstExt = last; // never precharge past the last page overshot = true; // may have to touch the next slice @@ -400,11 +427,11 @@ namespace NTable { if (key2) { // Last page to precharge (may contain key <= key2) // We actually use the next page since lookup is not exact - key2Page = Index.LookupKeyReverse(key2, Scheme.Groups[0], ESeek::Lower, &keyDefaults); + key2Page = index->LookupKeyReverse(key2, Scheme.Groups[0], ESeek::Lower, &keyDefaults); auto key2PageExt = key2Page - 1; if (key2Page && key2Page.Off() != 0 && key2PageExt >= last) { last = Min(key2PageExt, firstExt); - endRow = Max(endRow, Index.GetLastRowId(last)); // may load the last row of key2PageExt + endRow = Max(endRow, index->GetLastRowId(last)); // may load the last row of key2PageExt } else { overshot = true; // may find first key < key2 on row < row2 } @@ -617,7 +644,10 @@ namespace NTable { private: bool DoPrechargeHistory(TRowId startRowId, TRowId endRowId) const noexcept { - using TCells = NPage::TCells; + auto index = HistoryIndex->TryLoadRaw(); + if (!index) { + return false; + } if (endRowId < startRowId) { using std::swap; @@ -651,12 +681,12 @@ namespace NTable { // Directly use the histroy key defaults with correct sort order const TKeyCellDefaults* keyDefaults = Part->Scheme->HistoryKeys.Get(); - auto first = HistoryIndex->LookupKey(startKey, scheme, ESeek::Lower, keyDefaults); + auto first = index->LookupKey(startKey, scheme, ESeek::Lower, keyDefaults); if (!first) { return true; } - auto last = HistoryIndex->LookupKey(endKey, scheme, ESeek::Lower, keyDefaults); + auto last = index->LookupKey(endKey, scheme, ESeek::Lower, keyDefaults); bool ready = true; bool hasItems = false; @@ -717,12 +747,12 @@ namespace NTable { private: struct TGroupState { - const NPage::TIndex& GroupIndex; + TPartIndexIt GroupIndex; TIter Index; TRowId LastRowId = Max<TRowId>(); const NPage::TGroupId GroupId; - TGroupState(const NPage::TIndex& groupIndex, NPage::TGroupId groupId) + TGroupState(TPartIndexIt&& groupIndex, NPage::TGroupId groupId) : GroupIndex(groupIndex) , GroupId(groupId) { } @@ -733,16 +763,25 @@ 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(); + if (!groupIndex) { + if (bytes) { + // Note: we can't continue if we have bytes limit + bytes = Max<ui64>(); + } + return false; + } + bool ready = true; if (!g.Index || row1 < g.Index->GetRowId() || row1 > g.LastRowId) { - g.Index = g.GroupIndex.LookupRow(row1, g.Index); + g.Index = groupIndex->LookupRow(row1, g.Index); if (Y_UNLIKELY(!g.Index)) { // Looks like row1 doesn't even exist g.LastRowId = Max<TRowId>(); return ready; } - g.LastRowId = g.GroupIndex.GetLastRowId(g.Index); + 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); @@ -754,7 +793,7 @@ namespace NTable { g.LastRowId = Max<TRowId>(); return ready; } - g.LastRowId = g.GroupIndex.GetLastRowId(g.Index); + 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); @@ -767,16 +806,25 @@ 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(); + if (!groupIndex) { + if (bytes) { + // Note: we can't continue if we have bytes limit + bytes = Max<ui64>(); + } + return false; + } + bool ready = true; if (!g.Index || row1 < g.Index->GetRowId() || row1 > g.LastRowId) { - g.Index = g.GroupIndex.LookupRow(row1, g.Index); + g.Index = groupIndex->LookupRow(row1, g.Index); if (Y_UNLIKELY(!g.Index)) { // Looks like row1 doesn't even exist g.LastRowId = Max<TRowId>(); return ready; } - g.LastRowId = g.GroupIndex.GetLastRowId(g.Index); + 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); @@ -826,8 +874,8 @@ namespace NTable { IPages * const Env = nullptr; const TPart * const Part = nullptr; const TPartScheme &Scheme; - const NPage::TIndex &Index; - const NPage::TIndex* const HistoryIndex; + mutable TPartIndexIt Index; + mutable std::optional<TPartIndexIt> HistoryIndex; mutable TSmallVec<TGroupState> Groups; mutable TSmallVec<TGroupState> HistoryGroups; }; diff --git a/ydb/core/tablet_flat/flat_part_index_iter.h b/ydb/core/tablet_flat/flat_part_index_iter.h index 979763cf45..db9d881f33 100644 --- a/ydb/core/tablet_flat/flat_part_index_iter.h +++ b/ydb/core/tablet_flat/flat_part_index_iter.h @@ -67,6 +67,7 @@ public: return EReady::Page; } if (Iter.Off() == 0) { + Iter = { }; return EReady::Gone; } Iter--; @@ -77,6 +78,11 @@ public: return bool(Iter); } + // for precharge only + TIndex* TryLoadRaw() { + return TryGetIndex(); + } + public: TRowId GetEndRowId() { return EndRowId; @@ -91,7 +97,7 @@ public: Y_VERIFY(Index); return Iter->GetRowId(); } - + TRowId GetNextRowId() { Y_VERIFY(Index); auto next = Iter + 1; diff --git a/ydb/core/tablet_flat/ut/ut_charge.cpp b/ydb/core/tablet_flat/ut/ut_charge.cpp index c7eb5e7a80..fceb7152b0 100644 --- a/ydb/core/tablet_flat/ut/ut_charge.cpp +++ b/ydb/core/tablet_flat/ut/ut_charge.cpp @@ -17,11 +17,12 @@ namespace { enum TPageIdFlags { IfIter = 1, IfFail = 2, - IfNoFail = 4 + IfNoFail = 4, + IfSticky = 8 }; struct TFlaggedPageId { TPageId Page; - TPageIdFlags Flags = static_cast<TPageIdFlags>(TPageIdFlags::IfIter | TPageIdFlags::IfFail | TPageIdFlags::IfNoFail); + TPageIdFlags Flags = static_cast<TPageIdFlags>(TPageIdFlags::IfIter | TPageIdFlags::IfFail | TPageIdFlags::IfNoFail | TPageIdFlags::IfSticky); TFlaggedPageId(TPageId page) : Page(page) {} @@ -46,21 +47,27 @@ namespace { } struct TTouchEnv : public NTest::TTestEnv { - TTouchEnv(bool fail) : Fail(fail) { } + TTouchEnv(bool fail, TSet<std::pair<TGroupId, TPageId>> sticky) + : Fail(fail) + , Sticky(std::move(sticky)) + { } const TSharedData* TryGetPage(const TPart *part, TPageId id, TGroupId groupId) override { - if (part->IndexPages.Has(groupId, id)) { - // TODO: delete after index precharge + Touched[groupId].insert(id); + + if (!Fail || Sticky.contains({groupId, id})) { return NTest::TTestEnv::TryGetPage(part, id, groupId); } - - Touched[groupId].insert(id); - return Fail ? nullptr : NTest::TTestEnv::TryGetPage(part, id, groupId); + + ToLoad[groupId].insert(id); + return nullptr; } const bool Fail = false; + TSet<std::pair<TGroupId, TPageId>> Sticky; TMap<TGroupId, TSet<TPageId>> Touched; + TMap<TGroupId, TSet<TPageId>> ToLoad; }; struct TCooker { @@ -141,29 +148,39 @@ namespace { void CheckByKeys(ui32 lower, ui32 upper, ui64 items, const TMap<TGroupId, TArr>& shouldPrecharge) const { - CheckPrechargeByKeys(lower, upper, items, false, shouldPrecharge, false); - CheckPrechargeByKeys(lower, upper, items, true, shouldPrecharge, false); + CheckPrechargeByKeys(lower, upper, items, TPageIdFlags::IfNoFail, shouldPrecharge, false, GetIndexPages()); + CheckPrechargeByKeys(lower, upper, items, TPageIdFlags::IfFail, shouldPrecharge, false, GetIndexPages()); CheckIterByKeys(lower, upper, items ? items : Max<ui32>(), shouldPrecharge); } void CheckByKeysReverse(ui32 lower, ui32 upper, ui64 items, const TMap<TGroupId, TArr>& shouldPrecharge) const { - CheckPrechargeByKeys(lower, upper, items, false, shouldPrecharge, true); - CheckPrechargeByKeys(lower, upper, items, true, shouldPrecharge, true); + CheckPrechargeByKeys(lower, upper, items, TPageIdFlags::IfNoFail, shouldPrecharge, true, GetIndexPages()); + CheckPrechargeByKeys(lower, upper, items, TPageIdFlags::IfFail, shouldPrecharge, true, GetIndexPages()); CheckIterByKeysReverse(lower, upper, items ? items : Max<ui32>(), shouldPrecharge); } - void CheckByRows(TPageId row1, TPageId row2, ui64 items, TMap<TGroupId, TArr> shouldPrecharge) const + void CheckByRows(TPageId row1, TPageId row2, ui64 items, const TMap<TGroupId, TArr>& shouldPrecharge) const { CheckPrechargeByRows(row1, row2, items, false, shouldPrecharge); CheckPrechargeByRows(row1, row2, items, true, shouldPrecharge); } - void CheckPrechargeByKeys(ui32 lower, ui32 upper, ui64 items, bool fail, const TMap<TGroupId, TArr>& shouldPrecharge, bool reverse) const + void CheckIndex(ui32 lower, ui32 upper, ui64 items, const TMap<TGroupId, TArr>& shouldPrecharge, TSet<TPageId> stickyIndex) const { + TSet<std::pair<TGroupId, TPageId>> sticky; + for (auto x : stickyIndex) { + sticky.insert({TGroupId{}, x}); + } + + CheckPrechargeByKeys(lower, upper, items, static_cast<TPageIdFlags>(TPageIdFlags::IfFail | TPageIdFlags::IfSticky), shouldPrecharge, false, sticky); + } + + void CheckPrechargeByKeys(ui32 lower, ui32 upper, ui64 items, TPageIdFlags flags, const TMap<TGroupId, TArr>& shouldPrecharge, bool reverse, TSet<std::pair<TGroupId, TPageId>> sticky) const { Y_VERIFY(lower < Mass.Saved.Size() && upper < Mass.Saved.Size()); - TTouchEnv env(fail); + bool fail(flags & TPageIdFlags::IfFail); + TTouchEnv env(fail, sticky); const auto &keyDefaults = *Tool.Scheme.Keys; const auto from = Tool.KeyCells(Mass.Saved[lower]); @@ -184,16 +201,17 @@ namespace { ? TCharge::Range(&env, from, to, run, keyDefaults, tags, items, Max<ui64>(), true) : TCharge::RangeReverse(&env, from, to, run, keyDefaults, tags, items, Max<ui64>(), true); - UNIT_ASSERT_VALUES_EQUAL_C(!fail || env.Touched.empty(), ready, AssertMesage(fail)); + UNIT_ASSERT_VALUES_EQUAL_C(!fail || env.ToLoad.empty(), ready, AssertMesage(fail)); - AssertEqual(env.Touched, shouldPrecharge, fail ? TPageIdFlags::IfFail : TPageIdFlags::IfNoFail); + CheckPrecharged(env.Touched, shouldPrecharge, sticky, flags); } void CheckPrechargeByRows(TPageId row1, TPageId row2, ui64 items, bool fail, TMap<TGroupId, TArr> shouldPrecharge) const { Y_VERIFY(row1 <= row2 && row2 < 3 * 9); - TTouchEnv env(fail); + auto sticky = GetIndexPages(); + TTouchEnv env(fail, sticky); const auto &keyDefaults = *Tool.Scheme.Keys; @@ -213,14 +231,15 @@ namespace { TCharge(&env, *run.begin()->Part, tags, false).Do(row1, row2, keyDefaults, items, Max<ui64>()), AssertMesage(fail)); - AssertEqual(env.Touched, shouldPrecharge, fail ? TPageIdFlags::IfFail : TPageIdFlags::IfNoFail); + CheckPrecharged(env.Touched, shouldPrecharge, sticky, fail ? TPageIdFlags::IfFail : TPageIdFlags::IfNoFail); } void CheckIterByKeys(ui32 lower, ui32 upper, ui64 items, const TMap<TGroupId, TArr>& precharged) const { Y_VERIFY(lower < Mass.Saved.Size() && upper < Mass.Saved.Size()); - NTest::TCheckIt wrap(Eggs, { new TTouchEnv(false) }); + auto sticky = GetIndexPages(); + NTest::TCheckIt wrap(Eggs, { new TTouchEnv(false, sticky) }); wrap.To(CurrentStep()); wrap.StopAfter(Tool.KeyCells(Mass.Saved[upper])); @@ -248,14 +267,15 @@ namespace { auto env = wrap.Displace<TTouchEnv>(nullptr); - AssertEqual(env->Touched, precharged, TPageIdFlags::IfIter); + CheckPrecharged(env->Touched, precharged, sticky, TPageIdFlags::IfIter); } void CheckIterByKeysReverse(ui32 lower, ui32 upper, ui64 items, const TMap<TGroupId, TArr>& precharged) const { Y_VERIFY(lower < Mass.Saved.Size() && upper < Mass.Saved.Size()); - NTest::TCheckReverseIt wrap(Eggs, { new TTouchEnv(false) }); + auto sticky = GetIndexPages(); + NTest::TCheckReverseIt wrap(Eggs, { new TTouchEnv(false, sticky) }); wrap.To(CurrentStep()); wrap.StopAfter(Tool.KeyCells(Mass.Saved[upper])); @@ -283,7 +303,7 @@ namespace { auto env = wrap.Displace<TTouchEnv>(nullptr); - AssertEqual(env->Touched, precharged, TPageIdFlags::IfIter); + CheckPrecharged(env->Touched, precharged, sticky, TPageIdFlags::IfIter); } const NTest::TMass Mass; @@ -291,7 +311,23 @@ namespace { const NTest::TRowTool Tool; private: - void AssertEqual(const TMap<TGroupId, TSet<TPageId>>& actual, const TMap<TGroupId, TArr>& expected, TPageIdFlags flags) const { + TSet<std::pair<TGroupId, TPageId>> GetIndexPages() const { + TSet<std::pair<TGroupId, TPageId>> result; + + auto &pages = Eggs.Lone()->IndexPages; + TGroupId mainGroupId{}; + + for (auto x : pages.Groups) { + result.insert({mainGroupId, x}); + } + for (auto x : pages.Historic) { + result.insert({mainGroupId, x}); + } + + return result; + } + + void CheckPrecharged(const TMap<TGroupId, TSet<TPageId>>& actual, const TMap<TGroupId, TArr>& expected, TSet<std::pair<TGroupId, TPageId>> sticky, TPageIdFlags flags) const { for (auto [groupId, arr] : expected) { if (groupId.IsHistoric() && flags == TPageIdFlags::IfIter) { // isn't supported @@ -304,11 +340,17 @@ namespace { absoluteId[absoluteId.size()] = it->GetPageId(); } - auto actualValue = actual.Value(groupId, TSet<TPageId>()); + TSet<TPageId> actualValue; + for (auto p : actual.Value(groupId, TSet<TPageId>())) { + if (flags & TPageIdFlags::IfSticky || !sticky.contains({groupId, p})) { + actualValue.insert(p); + } + } + auto expectedValue = TSet<TPageId>{}; for (auto p : arr) { if (flags & p.Flags) { - expectedValue.insert(absoluteId[p.Page]); + expectedValue.insert(absoluteId.Value(p.Page, p.Page)); } } UNIT_ASSERT_VALUES_EQUAL_C(expectedValue, actualValue, AssertMesage(groupId, flags)); @@ -920,6 +962,191 @@ Y_UNIT_TEST_SUITE(Charge) { }); } + Y_UNIT_TEST(ByKeysIndex) + { + { // index + TModel me(false, false); + auto &pages = me.Eggs.Lone()->IndexPages; + + // no index => touch index + me.To(100).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {pages.Groups[0]}}, + }, TSet<TPageId> { + + }); + + // index => touch pages + index + me.To(101).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0]}} + }, + TSet<TPageId> { + pages.Groups[0] + }); + } + + { // index + history index + TModel me(false, true); + auto &pages = me.Eggs.Lone()->IndexPages; + + // no index => touch index + me.To(200).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {pages.Groups[0]}}, + {TGroupId{0, true}, {}} + }, TSet<TPageId> { + + }); + + // no history index => touch main pages + index + history index + me.To(201).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], pages.Historic[0]}}, + {TGroupId{0, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0] + }); + + // history index => touch main pages + history pages + index + history index + me.To(202).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], pages.Historic[0]}}, + {TGroupId{0, true}, {1, 2, 3, 4}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Historic[0] + }); + } + + { // index + groups + TModel me(true, false); + auto &pages = me.Eggs.Lone()->IndexPages; + + // no index => touch index + me.To(300).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {pages.Groups[0]}}, + {TGroupId{1}, {}} + }, TSet<TPageId> { + + }); + + // no groups index => touch main pages + index + all groups indexes + me.To(301).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{1}, {}} + }, + TSet<TPageId> { + pages.Groups[0] + }); + + // groups index => touch all pages + index + all groups indexes + me.To(302).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{1}, {3, 4, 5, 6, 7}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Groups[1] + }); + } + + { // index + groups + history + TModel me(true, true); + auto &pages = me.Eggs.Lone()->IndexPages; + + // no index => touch index + me.To(400).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {pages.Groups[0]}}, + {TGroupId{0, true}, {}}, + {TGroupId{1}, {}}, + {TGroupId{1, true}, {}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, TSet<TPageId> { + + }); + + // only index => touch main pages + index + all groups indexes + history index + me.To(401).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], pages.Historic[0], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{0, true}, {}}, + {TGroupId{1}, {}}, + {TGroupId{1, true}, {}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0] + }); + + // history index => touch main pages + index + all groups indexes + main history pages + me.To(402).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], + pages.Historic[0], pages.Historic[1], pages.Historic[2], pages.Historic[3], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{0, true}, {1, 2, 3, 4}}, + {TGroupId{1}, {}}, + {TGroupId{1, true}, {}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Historic[0] + }); + + // main history and history => touch main pages + index + all groups indexes + history pages + history groups pages + me.To(403).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], + pages.Historic[0], pages.Historic[1], pages.Historic[2], pages.Historic[3], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{0, true}, {1, 2, 3, 4}}, + {TGroupId{1}, {}}, + {TGroupId{1, true}, {3, 4, 5}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Historic[0], pages.Historic[1] + }); + + // groups index => touch main pages + index + history index + all groups indexes + groups pages + me.To(404).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], + pages.Historic[0], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{0, true}, {}}, + {TGroupId{1}, {3, 4, 5, 6, 7}}, + {TGroupId{1, true}, {}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Groups[1] + }); + + // main history and groups => touch main pages + index + all groups indexes + groups pages + history main pages + me.To(405).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], + pages.Historic[0], pages.Historic[1], pages.Historic[2], pages.Historic[3], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{0, true}, {1, 2, 3, 4}}, + {TGroupId{1}, {3, 4, 5, 6, 7}}, + {TGroupId{1, true}, {}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Historic[0], pages.Groups[1] + }); + + // all indexes + me.To(406).CheckIndex(6, 22, 0, TMap<TGroupId, TArr>{ + {TGroupId{0}, {1, 2, 3, 4, 5, 6, pages.Groups[0], + pages.Historic[0], pages.Historic[1], pages.Historic[2], pages.Historic[3], pages.Groups[1], pages.Groups[2], pages.Groups[3]}}, + {TGroupId{0, true}, {1, 2, 3, 4}}, + {TGroupId{1}, {3, 4, 5, 6, 7}}, + {TGroupId{1, true}, {3, 4, 5}}, + {TGroupId{2}, {}}, + {TGroupId{2, true}, {}} + }, + TSet<TPageId> { + pages.Groups[0], pages.Historic[0], pages.Historic[1], pages.Groups[1] + }); + } + } + Y_UNIT_TEST(ByRows) { TModel me(true); diff --git a/ydb/core/tablet_flat/ut/ut_comp_shard.cpp b/ydb/core/tablet_flat/ut/ut_comp_shard.cpp index afc6642d0f..aa69db2495 100644 --- a/ydb/core/tablet_flat/ut/ut_comp_shard.cpp +++ b/ydb/core/tablet_flat/ut/ut_comp_shard.cpp @@ -43,11 +43,6 @@ namespace { info.Touched.insert(token); - if (part->IndexPages.Has(groupId, ref)) { - // TODO: delete after index precharge - return NTest::TTestEnv::TryGetPage(part, ref, groupId); - } - if (info.Loaded.contains(token)) { return TTestEnv::TryGetPage(part, ref, groupId); } @@ -286,12 +281,18 @@ Y_UNIT_TEST_SUITE(TShardedCompaction) { TSimpleConsumer consumer; TSliceSplitOp op(&consumer, &table, pshards, partView.Part, slice); + // load index bool ok1 = op.Execute(&env); UNIT_ASSERT_VALUES_EQUAL(ok1, false); - env.Load(); + + // load data bool ok2 = op.Execute(&env); - UNIT_ASSERT_VALUES_EQUAL(ok2, true); + UNIT_ASSERT_VALUES_EQUAL(ok2, false); + env.Load(); + + bool ok3 = op.Execute(&env); + UNIT_ASSERT_VALUES_EQUAL(ok3, true); auto& result = consumer.Result.value(); size_t pos = 0; @@ -370,12 +371,18 @@ Y_UNIT_TEST_SUITE(TShardedCompaction) { TSimpleConsumer consumer; TSliceSplitOp op(&consumer, &table, pshards, partView.Part, slice); + // load index bool ok1 = op.Execute(&env); UNIT_ASSERT_VALUES_EQUAL(ok1, false); - env.Load(); + + // load data bool ok2 = op.Execute(&env); - UNIT_ASSERT_VALUES_EQUAL(ok2, true); + UNIT_ASSERT_VALUES_EQUAL(ok2, false); + env.Load(); + + bool ok3 = op.Execute(&env); + UNIT_ASSERT_VALUES_EQUAL(ok3, true); auto& result = consumer.Result.value(); UNIT_ASSERT_VALUES_EQUAL(result.NewSlices.size(), 2u); @@ -436,12 +443,18 @@ Y_UNIT_TEST_SUITE(TShardedCompaction) { TSimpleConsumer consumer; TSliceSplitOp op(&consumer, &table, pshards, partView.Part, slice); + // load index bool ok1 = op.Execute(&env); UNIT_ASSERT_VALUES_EQUAL(ok1, false); - env.Load(); + + // load data bool ok2 = op.Execute(&env); - UNIT_ASSERT_VALUES_EQUAL(ok2, true); + UNIT_ASSERT_VALUES_EQUAL(ok2, false); + env.Load(); + + bool ok3 = op.Execute(&env); + UNIT_ASSERT_VALUES_EQUAL(ok3, true); auto& result = consumer.Result.value(); UNIT_ASSERT_VALUES_EQUAL(result.NewSlices.size(), 2u); @@ -1239,11 +1252,16 @@ Y_UNIT_TEST_SUITE(TShardedCompactionScenarios) { UNIT_ASSERT_VALUES_EQUAL(backend.PendingReads.size(), 2u); while (backend.PendingReads) { TStrictEnv env; + // load index auto first = backend.RunRead(&env); UNIT_ASSERT(!first.Completed); env.Load(); - auto second = backend.RunRead(first.ReadId, &env); - UNIT_ASSERT(second.Completed); + // load data + auto second = backend.RunRead(&env); + UNIT_ASSERT(!second.Completed); + env.Load(); + auto third = backend.RunRead(first.ReadId, &env); + UNIT_ASSERT(third.Completed); } UNIT_ASSERT(backend.CheckChangesFlag()); diff --git a/ydb/core/tablet_flat/ut/ut_part.cpp b/ydb/core/tablet_flat/ut/ut_part.cpp index d532f9e7ee..83d8eb8f43 100644 --- a/ydb/core/tablet_flat/ut/ut_part.cpp +++ b/ydb/core/tablet_flat/ut/ut_part.cpp @@ -59,11 +59,6 @@ namespace { struct TTouchEnv : public NTest::TTestEnv { const TSharedData* TryGetPage(const TPart *part, TPageId id, TGroupId groupId) override { - if (part->IndexPages.Has(groupId, id)) { - // TODO: delete after index precharge - return NTest::TTestEnv::TryGetPage(part, id, groupId); - } - if (PrechargePhase) { Precharged[groupId].insert(id); return NTest::TTestEnv::TryGetPage(part, id, groupId); |