Skip to content

Commit 0456d4d

Browse files
authored
Merge 3ddc5ea into 81da9ab
2 parents 81da9ab + 3ddc5ea commit 0456d4d

11 files changed

+560
-261
lines changed

ydb/core/tablet_flat/flat_fwd_cache.h

Lines changed: 116 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,115 @@
11
#pragma once
22

33
#include "flat_part_iface.h"
4-
#include "flat_part_forward.h"
54
#include "flat_fwd_iface.h"
65
#include "flat_fwd_misc.h"
76
#include "flat_fwd_page.h"
7+
#include "flat_part_index_iter.h"
8+
#include "flat_part_index_iter_iface.h"
9+
#include "flat_table_part.h"
10+
#include "flat_part_slice.h"
811

912
namespace NKikimr {
1013
namespace NTable {
1114
namespace NFwd {
1215

13-
class TCache : public IPageLoadingLogic {
14-
using TGroupId = NPage::TGroupId;
15-
16-
template<size_t Items>
17-
struct TRound {
18-
const TSharedData* Get(TPageId pageId) const
19-
{
20-
if (pageId < Edge) {
21-
const auto pred = [pageId](const NPageCollection::TLoadedPage &page) {
22-
return page.PageId == pageId;
23-
};
24-
25-
auto it = std::find_if(Pages.begin(), Pages.end(), pred);
26-
27-
if (it == Pages.end()) {
28-
Y_ABORT("Failed to locate page within forward trace");
16+
template<size_t Capacity>
17+
class TLoadedPagesCircularBuffer {
18+
public:
19+
const TSharedData* Get(TPageId pageId) const
20+
{
21+
if (pageId < FirstUnseenPageId) {
22+
for (const auto& page : LoadedPages) {
23+
if (page.PageId == pageId) {
24+
return &page.Data;
2925
}
30-
31-
return &it->Data;
3226
}
3327

34-
return nullptr;
28+
Y_ABORT("Failed to locate page within forward trace");
3529
}
3630

37-
ui32 Emplace(TPage &page)
38-
{
39-
Y_ABORT_UNLESS(page, "Cannot push invalid page to trace cache");
31+
// next pages may be requested, ignore them
32+
return nullptr;
33+
}
34+
35+
// returns released data size
36+
ui64 Emplace(TPage &page)
37+
{
38+
Y_ABORT_UNLESS(page, "Cannot push invalid page to trace cache");
4039

41-
Offset = (Pages.size() + Offset - 1) % Pages.size();
40+
Offset = (Offset + 1) % Capacity;
4241

43-
const ui32 was = Pages[Offset].Data.size();
42+
const ui64 releasedDataSize = LoadedPages[Offset].Data.size();
4443

45-
Pages[Offset].Data = page.Release();
46-
Pages[Offset].PageId = page.PageId;
47-
Edge = Max(Edge, page.PageId + 1);
44+
LoadedPages[Offset].Data = page.Release();
45+
LoadedPages[Offset].PageId = page.PageId;
46+
FirstUnseenPageId = Max(FirstUnseenPageId, page.PageId + 1);
4847

49-
return was;
50-
}
48+
return releasedDataSize;
49+
}
5150

52-
private:
53-
std::array<NPageCollection::TLoadedPage, Items> Pages;
54-
TPageId Edge = 0;
55-
ui32 Offset = 0;
56-
};
51+
private:
52+
std::array<NPageCollection::TLoadedPage, Capacity> LoadedPages;
53+
ui32 Offset = 0;
54+
TPageId FirstUnseenPageId = 0;
55+
};
5756

57+
class TCache : public IPageLoadingLogic {
5858
public:
59+
using TGroupId = NPage::TGroupId;
60+
5961
TCache() = delete;
6062

6163
TCache(const TPart* part, IPages* env, TGroupId groupId, const TIntrusiveConstPtr<TSlices>& bounds = nullptr)
62-
: Index(part, env, groupId, 1, bounds)
63-
{ }
64+
: Index(MakeHolder<TPartIndexIt>(part, env, groupId)) // TODO: use CreateIndexIter(part, env, groupId)
65+
{
66+
if (bounds && !bounds->empty()) {
67+
BeginRowId = bounds->front().BeginRowId();
68+
EndRowId = bounds->back().EndRowId();
69+
} else {
70+
BeginRowId = 0;
71+
EndRowId = Index->GetEndRowId();
72+
}
73+
}
6474

6575
~TCache()
6676
{
67-
for (auto &it: Pages) it.Release();
77+
for (auto &it: Pages) {
78+
it.Release();
79+
}
6880
}
6981

7082
TResult Handle(IPageLoadingQueue *head, TPageId pageId, ui64 lower) noexcept override
7183
{
72-
Y_ABORT_UNLESS(pageId != Max<TPageId>(), "Invalid requested pageId");
84+
Y_ABORT_UNLESS(pageId != Max<TPageId>(), "Requested page is invalid");
7385

74-
if (auto *page = Trace.Get(pageId))
86+
if (auto *page = Trace.Get(pageId)) {
7587
return { page, false, true };
88+
}
7689

77-
Rewind(pageId).Shrink(); /* points Offset to pageId */
90+
DropPagesBefore(pageId);
91+
Shrink();
92+
93+
bool grow = OnHold + OnFetch <= lower;
7894

79-
bool more = Grow && (OnHold + OnFetch <= lower);
95+
if (Offset == Pages.size()) { // isn't processed yet
96+
SyncIndex(pageId);
97+
AddToQueue(head, pageId);
98+
}
8099

81-
return { Preload(head, 0).Touch(pageId, Stat), more, true };
100+
grow &= Index->IsValid() && Index->GetRowId() < EndRowId;
101+
102+
return {Pages.at(Offset).Touch(pageId, Stat), grow, true};
82103
}
83104

84105
void Forward(IPageLoadingQueue *head, ui64 upper) noexcept override
85106
{
86-
Preload(head, upper);
107+
Y_ABORT_UNLESS(Started, "Couldn't be called before Handle returns grow");
108+
109+
while (OnHold + OnFetch < upper && Index->IsValid() && Index->GetRowId() < EndRowId) {
110+
AddToQueue(head, Index->GetPageId());
111+
Y_ABORT_UNLESS(Index->Next() != EReady::Page);
112+
}
87113
}
88114

89115
void Apply(TArrayRef<NPageCollection::TLoadedPage> loaded) noexcept override
@@ -105,7 +131,7 @@ namespace NFwd {
105131

106132
Stat.Saved += one.Data.size();
107133
OnFetch -= one.Data.size();
108-
OnHold += it->Settle(one);
134+
OnHold += it->Settle(one); // settle of a dropped page returns 0 and releases its data
109135

110136
++it;
111137
}
@@ -114,65 +140,72 @@ namespace NFwd {
114140
}
115141

116142
private:
117-
TPage& Preload(IPageLoadingQueue *head, ui64 upper) noexcept
143+
void DropPagesBefore(TPageId pageId) noexcept
118144
{
119-
auto until = [this, upper]() {
120-
return OnHold + OnFetch < upper ? Max<TPageId>() : 0;
121-
};
145+
while (Offset < Pages.size()) {
146+
auto &page = Pages.at(Offset);
122147

123-
while (auto more = Index.More(until())) {
124-
auto size = head->AddToQueue(more, EPage::DataPage);
148+
if (page.PageId >= pageId) {
149+
break;
150+
}
125151

126-
Stat.Fetch += size;
127-
OnFetch += size;
152+
if (page.Size == 0) {
153+
Y_ABORT("Dropping page that has not been touched");
154+
} else if (page.Usage == EUsage::Keep && page) {
155+
OnHold -= Trace.Emplace(page);
156+
} else {
157+
OnHold -= page.Release().size();
158+
*(page.Ready() ? &Stat.After : &Stat.Before) += page.Size;
159+
}
128160

129-
Pages.emplace_back(more, size, 0, Max<TPageId>());
130-
Pages.back().Fetch = EFetch::Wait;
161+
// keep pending pages but increment offset
162+
Offset++;
131163
}
132-
133-
Grow = Grow && Index.On(true) < Max<TPageId>();
134-
135-
return Pages.at(Offset);
136164
}
137165

138-
TCache& Rewind(TPageId pageId) noexcept
166+
void Shrink() noexcept
139167
{
140-
while (auto drop = Index.Clean(pageId)) {
141-
auto &page = Pages.at(Offset);
142-
143-
if (!Pages || page.PageId != drop.PageId) {
144-
Y_ABORT("Dropping page that is not exist in cache");
145-
} else if (page.Size == 0) {
146-
Y_ABORT("Dropping page that has not been touched");
147-
} else if (page.Usage == EUsage::Keep) {
148-
OnHold -= Trace.Emplace(page);
149-
} else if (auto size = page.Release().size()) {
150-
OnHold -= size;
168+
for (; Offset && Pages[0].Ready(); Offset--) {
169+
Pages.pop_front();
170+
}
171+
}
151172

152-
*(page.Ready() ? &Stat.After : &Stat.Before) += size;
153-
}
173+
void SyncIndex(TPageId pageId) noexcept
174+
{
175+
if (!Started) {
176+
Y_ABORT_UNLESS(Index->Seek(BeginRowId) == EReady::Data);
177+
Y_ABORT_UNLESS(Index->GetPageId() <= pageId, "Requested page is out of slice bounds");
178+
Started = true;
179+
}
154180

155-
Offset++;
181+
while (Index->IsValid() && Index->GetPageId() < pageId) {
182+
Y_ABORT_UNLESS(Index->Next() == EReady::Data);
183+
Y_ABORT_UNLESS(Index->GetRowId() < EndRowId, "Requested page is out of slice bounds");
156184
}
157185

158-
return *this;
186+
Y_ABORT_UNLESS(Index->GetPageId() == pageId, "Requested page doesn't belong to the part");
187+
Y_ABORT_UNLESS(Index->Next() != EReady::Page);
159188
}
160189

161-
TCache& Shrink() noexcept
190+
void AddToQueue(IPageLoadingQueue *head, TPageId pageId) noexcept
162191
{
163-
for (; Offset && Pages[0].Ready(); Offset--)
164-
Pages.pop_front();
192+
auto size = head->AddToQueue(pageId, EPage::DataPage);
193+
194+
Stat.Fetch += size;
195+
OnFetch += size;
165196

166-
return *this;
197+
Y_ABORT_UNLESS(!Pages || Pages.back().PageId < pageId);
198+
Pages.emplace_back(pageId, size, 0, Max<TPageId>());
199+
Pages.back().Fetch = EFetch::Wait;
167200
}
168201

169202
private:
170-
bool Grow = true; /* Have some pages for Forward(...) */
171-
TForward Index;
172-
TRound<TPart::Trace> Trace;
203+
THolder<IIndexIter> Index; /* Points on next to load page */
204+
bool Started = false;
205+
TRowId BeginRowId, EndRowId;
206+
TLoadedPagesCircularBuffer<TPart::Trace> Trace;
173207

174208
/*_ Forward cache line state */
175-
176209
ui64 OnHold = 0;
177210
ui64 OnFetch = 0;
178211
ui32 Offset = 0;

ydb/core/tablet_flat/flat_fwd_env.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
#include "flat_table_subset.h"
1111
#include "flat_part_iface.h"
1212
#include "flat_part_store.h"
13-
#include "flat_sausage_packet.h"
1413
#include "flat_sausage_fetch.h"
1514
#include "util_fmt_abort.h"
16-
#include "util_basics.h"
1715
#include <util/generic/deque.h>
1816
#include <util/random/random.h>
1917
#include <util/generic/intrlist.h>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "flat_fwd_misc.h"
2+
3+
Y_DECLARE_OUT_SPEC(, NKikimr::NTable::NFwd::TStat, stream, value) {
4+
value.Describe(stream);
5+
}

ydb/core/tablet_flat/flat_fwd_misc.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ namespace NFwd {
1818
{
1919
out
2020
<< "TFwd{"
21-
<< Fetch << "b"
22-
<< " > " << Saved << "b"
23-
<< " > " << Usage << "b"
24-
<< " +" << After << "b"
25-
<< " ~" << Before << "b"
21+
<< "fetch=" << Fetch
22+
<< ",saved=" << Saved
23+
<< ",usage=" << Usage
24+
<< ",after=" << After
25+
<< ",before=" << Before
2626
<< "}";
2727
}
2828

@@ -37,6 +37,8 @@ namespace NFwd {
3737
return *this;
3838
}
3939

40+
auto operator<=>(const TStat&) const = default;
41+
4042
ui64 Fetch = 0; /* Requested to load by cache */
4143
ui64 Saved = 0; /* Obtained by cache with DoSave() */
4244
ui64 Usage = 0; /* Actually was used by client */

ydb/core/tablet_flat/flat_fwd_page.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ namespace NFwd {
7575
const TSharedData* Touch(TPageId pageId, TStat &stat) noexcept
7676
{
7777
if (PageId != pageId || (!Data && Fetch == EFetch::Done)) {
78-
Y_ABORT("Touching page thatd doesn't fits to this action");
78+
Y_ABORT("Touching page that doesn't fit to this action");
7979
} else {
8080
auto to = Fetch == EFetch::None ? EUsage::Seen : EUsage::Keep;
8181

ydb/core/tablet_flat/flat_page_other.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace NPage {
2828
Tags.resize(TagsCount + (TagsCount & 1), 0);
2929
Cook.reserve(tags);
3030

31-
Y_ABORT_UNLESS(tags <= ui32(-Min<i16>()), "Too many columnt tags");
31+
Y_ABORT_UNLESS(tags <= ui32(-Min<i16>()), "Too many column tags");
3232
}
3333

3434
void Put(TRowId row, ui16 tag, ui32 bytes) noexcept

0 commit comments

Comments
 (0)