aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkungasc <kungasc@yandex-team.com>2023-09-18 23:34:46 +0300
committerkungasc <kungasc@yandex-team.com>2023-09-18 23:53:56 +0300
commit55d8ae0f29a754250bb75958428dfe3b543cdaf9 (patch)
tree0837d0292cfd0a27d1cf4740b3ea9d12bc288fcd
parentc8409f20e76dba22a1e9928a4bdaa9595cf91e46 (diff)
downloadydb-55d8ae0f29a754250bb75958428dfe3b543cdaf9.tar.gz
KIKIMR-19139 Load index in Precharge
-rw-r--r--ydb/core/tablet_flat/flat_part_charge.h134
-rw-r--r--ydb/core/tablet_flat/flat_part_index_iter.h8
-rw-r--r--ydb/core/tablet_flat/ut/ut_charge.cpp279
-rw-r--r--ydb/core/tablet_flat/ut/ut_comp_shard.cpp44
-rw-r--r--ydb/core/tablet_flat/ut/ut_part.cpp5
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);