Skip to content

Commit d8fc0d3

Browse files
authored
add implementation for common cases in local partition reader (#6692)
1 parent 0bf2ed6 commit d8fc0d3

File tree

2 files changed

+199
-46
lines changed

2 files changed

+199
-46
lines changed

ydb/core/backup/impl/local_partition_reader.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111
using namespace NActors;
1212
using namespace NKikimr::NReplication::NService;
1313

14+
namespace {
15+
1416
constexpr static char OFFLOAD_ACTOR_CLIENT_ID[] = "__OFFLOAD_ACTOR__";
17+
constexpr static ui64 READ_TIMEOUT_MS = 1000;
18+
constexpr static ui64 READ_LIMIT_BYTES = 1_MB;
19+
20+
} // anonymous namespace
1521

1622
namespace NKikimr::NBackup::NImpl {
1723

@@ -50,6 +56,10 @@ class TLocalPartitionReader
5056
return request;
5157
}
5258

59+
void HandleInit() {
60+
Send(PQTablet, CreateGetOffsetRequest().Release());
61+
}
62+
5363
void HandleInit(TEvWorker::TEvHandshake::TPtr& ev) {
5464
Worker = ev->Sender;
5565
LOG_D("Handshake"
@@ -62,8 +72,8 @@ class TLocalPartitionReader
6272
LOG_D("Handle " << ev->Get()->ToString());
6373
auto& record = ev->Get()->Record;
6474
if (record.GetErrorCode() == NPersQueue::NErrorCode::INITIALIZING) {
65-
// TODO reschedule
66-
Y_ABORT("Unimplemented!");
75+
Schedule(TDuration::Seconds(1), new NActors::TEvents::TEvWakeup);
76+
return;
6777
}
6878
Y_VERIFY_S(record.GetErrorCode() == NPersQueue::NErrorCode::OK, "Unimplemented!");
6979
Y_VERIFY_S(record.HasPartitionResponse() && record.GetPartitionResponse().HasCmdGetClientOffsetResult(), "Unimplemented!");
@@ -85,8 +95,8 @@ class TLocalPartitionReader
8595
auto& read = *req.MutableCmdRead();
8696
read.SetOffset(Offset);
8797
read.SetClientId(OFFLOAD_ACTOR_CLIENT_ID);
88-
read.SetTimeoutMs(0);
89-
read.SetBytes(1_MB);
98+
read.SetTimeoutMs(READ_TIMEOUT_MS);
99+
read.SetBytes(READ_LIMIT_BYTES);
90100

91101
return request;
92102
}
@@ -114,6 +124,12 @@ class TLocalPartitionReader
114124

115125
const auto& readResult = record.GetPartitionResponse().GetCmdReadResult();
116126

127+
if (!readResult.ResultSize()) {
128+
Y_ABORT_UNLESS(PQTablet);
129+
Send(PQTablet, CreateReadRequest().Release());
130+
return;
131+
}
132+
117133
auto gotOffset = Offset;
118134
TVector<TEvWorker::TEvData::TRecord> records(::Reserve(readResult.ResultSize()));
119135

@@ -147,6 +163,7 @@ class TLocalPartitionReader
147163
switch (ev->GetTypeRewrite()) {
148164
hFunc(TEvWorker::TEvHandshake, HandleInit);
149165
hFunc(TEvPersQueue::TEvResponse, HandleInit);
166+
sFunc(TEvents::TEvWakeup, HandleInit);
150167
sFunc(TEvents::TEvPoison, PassAway);
151168
default:
152169
Y_VERIFY_S(false, "Unhandled event type: " << ev->GetTypeRewrite()

ydb/core/backup/impl/local_partition_reader_ut.cpp

Lines changed: 178 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,90 @@ using namespace NReplication::NService;
1515
using namespace NPersQueue;
1616

1717
Y_UNIT_TEST_SUITE(LocalPartitionReader) {
18+
constexpr static ui64 INITIAL_OFFSET = 3;
19+
constexpr static ui64 PARTITION = 7;
20+
constexpr static const char* PARTITION_STR = "7";
21+
constexpr static const char* OFFLOAD_ACTOR_NAME = "__OFFLOAD_ACTOR__";
22+
23+
void GrabInitialPQRequest(TTestActorRuntime& runtime) {
24+
TAutoPtr<IEventHandle> handle;
25+
auto getOffset = runtime.GrabEdgeEventRethrow<TEvPersQueue::TEvRequest>(handle);
26+
UNIT_ASSERT(getOffset->Record.HasPartitionRequest());
27+
UNIT_ASSERT_VALUES_EQUAL(getOffset->Record.GetPartitionRequest().GetPartition(), PARTITION);
28+
UNIT_ASSERT(getOffset->Record.GetPartitionRequest().HasCmdGetClientOffset());
29+
auto getOffsetCmd = getOffset->Record.GetPartitionRequest().GetCmdGetClientOffset();
30+
UNIT_ASSERT_VALUES_EQUAL(getOffsetCmd.GetClientId(), OFFLOAD_ACTOR_NAME);
31+
}
32+
33+
void GrabReadPQRequest(TTestActorRuntime& runtime, ui32 expectedOffset) {
34+
TAutoPtr<IEventHandle> handle;
35+
auto read = runtime.GrabEdgeEventRethrow<TEvPersQueue::TEvRequest>(handle);
36+
UNIT_ASSERT(read->Record.HasPartitionRequest());
37+
UNIT_ASSERT_VALUES_EQUAL(read->Record.GetPartitionRequest().GetPartition(), PARTITION);
38+
UNIT_ASSERT(read->Record.GetPartitionRequest().HasCmdRead());
39+
auto readCmd = read->Record.GetPartitionRequest().GetCmdRead();
40+
UNIT_ASSERT_VALUES_EQUAL(readCmd.GetClientId(), OFFLOAD_ACTOR_NAME);
41+
UNIT_ASSERT_VALUES_EQUAL(readCmd.GetOffset(), expectedOffset);
42+
}
43+
44+
void GrabDataEvent(TTestActorRuntime& runtime, ui32 dataPatternCookie) {
45+
TAutoPtr<IEventHandle> handle;
46+
auto data = runtime.GrabEdgeEventRethrow<TEvWorker::TEvData>(handle);
47+
UNIT_ASSERT_VALUES_EQUAL(data->Source, PARTITION_STR);
48+
UNIT_ASSERT_VALUES_EQUAL(data->Records.size(), 2);
49+
UNIT_ASSERT_VALUES_EQUAL(data->Records[0].Offset, INITIAL_OFFSET + dataPatternCookie * 2);
50+
UNIT_ASSERT_VALUES_EQUAL(data->Records[0].Data, Sprintf("1-%d", dataPatternCookie));
51+
UNIT_ASSERT_VALUES_EQUAL(data->Records[1].Offset, INITIAL_OFFSET + dataPatternCookie * 2 + 1);
52+
UNIT_ASSERT_VALUES_EQUAL(data->Records[1].Data, Sprintf("2-%d", dataPatternCookie));
53+
}
54+
55+
TEvPersQueue::TEvResponse* GenerateData(ui32 dataPatternCookie) {
56+
auto* readResponse = new TEvPersQueue::TEvResponse;
57+
readResponse->Record.SetErrorCode(NPersQueue::NErrorCode::OK);
58+
auto& cmdReadResult = *readResponse->Record.MutablePartitionResponse()->MutableCmdReadResult();
59+
auto& readResult1 = *cmdReadResult.AddResult();
60+
NKikimrPQClient::TDataChunk msg1;
61+
msg1.SetData(Sprintf("1-%d", dataPatternCookie));
62+
TString msg1Str;
63+
UNIT_ASSERT(msg1.SerializeToString(&msg1Str));
64+
readResult1.SetOffset(INITIAL_OFFSET + dataPatternCookie * 2);
65+
readResult1.SetData(msg1Str);
66+
auto& readResult2 = *cmdReadResult.AddResult();
67+
NKikimrPQClient::TDataChunk msg2;
68+
msg2.SetData(Sprintf("2-%d", dataPatternCookie));
69+
TString msg2Str;
70+
UNIT_ASSERT(msg2.SerializeToString(&msg2Str));
71+
readResult2.SetOffset(INITIAL_OFFSET + dataPatternCookie * 2 + 1);
72+
readResult2.SetData(msg2Str);
73+
74+
return readResponse;
75+
}
76+
77+
TEvPersQueue::TEvResponse* GenerateEmptyData() {
78+
auto* readResponse = new TEvPersQueue::TEvResponse;
79+
readResponse->Record.SetErrorCode(NPersQueue::NErrorCode::OK);
80+
readResponse->Record.MutablePartitionResponse()->MutableCmdReadResult();
81+
82+
return readResponse;
83+
}
84+
1885
Y_UNIT_TEST(Simple) {
1986
TTestActorRuntime runtime;
2087
runtime.Initialize(NKikimr::TAppPrepare().Unwrap());
2188

2289
TActorId pqtablet = runtime.AllocateEdgeActor();
23-
TActorId reader = runtime.Register(CreateLocalPartitionReader(pqtablet, 7));
90+
TActorId reader = runtime.Register(CreateLocalPartitionReader(pqtablet, PARTITION));
91+
runtime.EnableScheduleForActor(reader);
2492
TActorId worker = runtime.AllocateEdgeActor();
2593
TAutoPtr<IEventHandle> handle;
2694

2795
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvHandshake));
2896

29-
auto getOffset = runtime.GrabEdgeEventRethrow<TEvPersQueue::TEvRequest>(handle);
30-
UNIT_ASSERT(getOffset->Record.HasPartitionRequest());
31-
UNIT_ASSERT_VALUES_EQUAL(getOffset->Record.GetPartitionRequest().GetPartition(), 7);
32-
UNIT_ASSERT(getOffset->Record.GetPartitionRequest().HasCmdGetClientOffset());
33-
auto getOffsetCmd = getOffset->Record.GetPartitionRequest().GetCmdGetClientOffset();
34-
UNIT_ASSERT_VALUES_EQUAL(getOffsetCmd.GetClientId(), "__OFFLOAD_ACTOR__"); // hardcoded for now
97+
GrabInitialPQRequest(runtime);
3598

3699
auto* getOffsetResponse = new TEvPersQueue::TEvResponse;
37100
getOffsetResponse->Record.SetErrorCode(NPersQueue::NErrorCode::OK);
38-
getOffsetResponse->Record.MutablePartitionResponse()->MutableCmdGetClientOffsetResult()->SetOffset(3);
101+
getOffsetResponse->Record.MutablePartitionResponse()->MutableCmdGetClientOffsetResult()->SetOffset(INITIAL_OFFSET);
39102
runtime.Send(new IEventHandle(reader, pqtablet, getOffsetResponse));
40103

41104
auto handshake = runtime.GrabEdgeEventRethrow<TEvWorker::TEvHandshake>(handle);
@@ -44,40 +107,113 @@ Y_UNIT_TEST_SUITE(LocalPartitionReader) {
44107
for (auto i = 0; i < 3; ++i) {
45108
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvPoll));
46109

47-
auto read = runtime.GrabEdgeEventRethrow<TEvPersQueue::TEvRequest>(handle);
48-
UNIT_ASSERT(read->Record.HasPartitionRequest());
49-
UNIT_ASSERT_VALUES_EQUAL(read->Record.GetPartitionRequest().GetPartition(), 7);
50-
UNIT_ASSERT(read->Record.GetPartitionRequest().HasCmdRead());
51-
auto readCmd = read->Record.GetPartitionRequest().GetCmdRead();
52-
UNIT_ASSERT_VALUES_EQUAL(readCmd.GetClientId(), "__OFFLOAD_ACTOR__"); // hardcoded for now
53-
UNIT_ASSERT_VALUES_EQUAL(readCmd.GetOffset(), 3 + i * 2);
54-
55-
auto* readResponse = new TEvPersQueue::TEvResponse;
56-
readResponse->Record.SetErrorCode(NPersQueue::NErrorCode::OK);
57-
auto& cmdReadResult = *readResponse->Record.MutablePartitionResponse()->MutableCmdReadResult();
58-
auto& readResult1 = *cmdReadResult.AddResult();
59-
NKikimrPQClient::TDataChunk msg1;
60-
msg1.SetData(Sprintf("1-%d", i));
61-
TString msg1Str;
62-
UNIT_ASSERT(msg1.SerializeToString(&msg1Str));
63-
readResult1.SetOffset(3 + i * 2);
64-
readResult1.SetData(msg1Str);
65-
auto& readResult2 = *cmdReadResult.AddResult();
66-
NKikimrPQClient::TDataChunk msg2;
67-
msg2.SetData(Sprintf("2-%d", i));
68-
TString msg2Str;
69-
UNIT_ASSERT(msg2.SerializeToString(&msg2Str));
70-
readResult2.SetOffset(3 + i * 2 + 1);
71-
readResult2.SetData(msg2Str);
72-
runtime.Send(new IEventHandle(reader, pqtablet, readResponse));
73-
74-
auto data = runtime.GrabEdgeEventRethrow<TEvWorker::TEvData>(handle);
75-
UNIT_ASSERT_VALUES_EQUAL(data->Source, "7");
76-
UNIT_ASSERT_VALUES_EQUAL(data->Records.size(), 2);
77-
UNIT_ASSERT_VALUES_EQUAL(data->Records[0].Offset, 3 + i * 2);
78-
UNIT_ASSERT_VALUES_EQUAL(data->Records[0].Data, Sprintf("1-%d", i));
79-
UNIT_ASSERT_VALUES_EQUAL(data->Records[1].Offset, 3 + i * 2 + 1);
80-
UNIT_ASSERT_VALUES_EQUAL(data->Records[1].Data, Sprintf("2-%d", i));
110+
GrabReadPQRequest(runtime, INITIAL_OFFSET + i * 2);
111+
112+
runtime.Send(new IEventHandle(reader, pqtablet, GenerateData(i)));
113+
114+
GrabDataEvent(runtime, i);
115+
116+
// TODO check commit
117+
}
118+
}
119+
120+
Y_UNIT_TEST(Booting) {
121+
TTestActorRuntime runtime;
122+
runtime.Initialize(NKikimr::TAppPrepare().Unwrap());
123+
124+
TActorId pqtablet = runtime.AllocateEdgeActor();
125+
TActorId reader = runtime.Register(CreateLocalPartitionReader(pqtablet, PARTITION));
126+
runtime.EnableScheduleForActor(reader);
127+
TActorId worker = runtime.AllocateEdgeActor();
128+
TAutoPtr<IEventHandle> handle;
129+
130+
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvHandshake));
131+
132+
for (int i = 0; i < 5; ++i) {
133+
GrabInitialPQRequest(runtime);
134+
135+
auto* getOffsetResponse = new TEvPersQueue::TEvResponse;
136+
getOffsetResponse->Record.SetErrorCode(NPersQueue::NErrorCode::INITIALIZING);
137+
runtime.Send(new IEventHandle(reader, pqtablet, getOffsetResponse));
138+
}
139+
140+
GrabInitialPQRequest(runtime);
141+
142+
auto* getOffsetResponse = new TEvPersQueue::TEvResponse;
143+
getOffsetResponse->Record.SetErrorCode(NPersQueue::NErrorCode::OK);
144+
getOffsetResponse->Record.MutablePartitionResponse()->MutableCmdGetClientOffsetResult()->SetOffset(INITIAL_OFFSET);
145+
runtime.Send(new IEventHandle(reader, pqtablet, getOffsetResponse));
146+
147+
auto handshake = runtime.GrabEdgeEventRethrow<TEvWorker::TEvHandshake>(handle);
148+
Y_UNUSED(handshake);
149+
}
150+
151+
Y_UNIT_TEST(FeedSlowly) {
152+
TTestActorRuntime runtime;
153+
runtime.Initialize(NKikimr::TAppPrepare().Unwrap());
154+
155+
TActorId pqtablet = runtime.AllocateEdgeActor();
156+
TActorId reader = runtime.Register(CreateLocalPartitionReader(pqtablet, PARTITION));
157+
runtime.EnableScheduleForActor(reader);
158+
TActorId worker = runtime.AllocateEdgeActor();
159+
TAutoPtr<IEventHandle> handle;
160+
161+
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvHandshake));
162+
163+
GrabInitialPQRequest(runtime);
164+
165+
auto* getOffsetResponse = new TEvPersQueue::TEvResponse;
166+
getOffsetResponse->Record.SetErrorCode(NPersQueue::NErrorCode::OK);
167+
getOffsetResponse->Record.MutablePartitionResponse()->MutableCmdGetClientOffsetResult()->SetOffset(INITIAL_OFFSET);
168+
runtime.Send(new IEventHandle(reader, pqtablet, getOffsetResponse));
169+
170+
auto handshake = runtime.GrabEdgeEventRethrow<TEvWorker::TEvHandshake>(handle);
171+
Y_UNUSED(handshake);
172+
173+
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvPoll));
174+
175+
for (auto i = 0; i < 3; ++i) {
176+
GrabReadPQRequest(runtime, INITIAL_OFFSET);
177+
178+
runtime.SimulateSleep(TDuration::Seconds(1));
179+
180+
runtime.Send(new IEventHandle(reader, pqtablet, GenerateEmptyData()));
181+
}
182+
183+
for (auto i = 0; i < 3; ++i) {
184+
if (i != 0) {
185+
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvPoll));
186+
}
187+
188+
GrabReadPQRequest(runtime, INITIAL_OFFSET + i * 2);
189+
190+
runtime.Send(new IEventHandle(reader, pqtablet, GenerateData(i)));
191+
192+
GrabDataEvent(runtime, i);
193+
194+
// TODO check commit
195+
}
196+
197+
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvPoll));
198+
199+
for (auto i = 0; i < 2; ++i) {
200+
GrabReadPQRequest(runtime, 9);
201+
202+
runtime.SimulateSleep(TDuration::Seconds(1));
203+
204+
runtime.Send(new IEventHandle(reader, pqtablet, GenerateEmptyData()));
205+
}
206+
207+
for (auto i = 3; i < 5; ++i) {
208+
if (i != 3) {
209+
runtime.Send(new IEventHandle(reader, worker, new TEvWorker::TEvPoll));
210+
}
211+
212+
GrabReadPQRequest(runtime, INITIAL_OFFSET + i * 2);
213+
214+
runtime.Send(new IEventHandle(reader, pqtablet, GenerateData(i)));
215+
216+
GrabDataEvent(runtime, i);
81217

82218
// TODO check commit
83219
}

0 commit comments

Comments
 (0)