Skip to content

Commit 526ec53

Browse files
authored
DS proxy mirror-3-dc restoration strategy test (#1238)
1 parent 899f3dd commit 526ec53

File tree

3 files changed

+180
-4
lines changed

3 files changed

+180
-4
lines changed

ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ struct TBlobState {
108108
};
109109

110110
struct TDiskGetRequest {
111-
const TLogoBlobID Id;
112-
const ui32 Shift;
113-
const ui32 Size;
111+
TLogoBlobID Id;
112+
ui32 Shift;
113+
ui32 Size;
114114
ssize_t PartMapIndex = -1;
115115

116116
TDiskGetRequest(const TLogoBlobID &id, const ui32 shift, const ui32 size)
@@ -127,7 +127,7 @@ struct TDiskPutRequest {
127127
ReasonInitial,
128128
ReasonAccelerate
129129
};
130-
const TLogoBlobID Id;
130+
TLogoBlobID Id;
131131
TRope Buffer;
132132
EPutReason Reason;
133133
bool IsHandoff;

ydb/core/blobstorage/dsproxy/ut_strategy/strategy_ut.cpp

+174
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include <ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h>
22
#include <ydb/core/blobstorage/dsproxy/dsproxy_strategy_restore.h>
3+
#include <ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_restore.h>
34
#include <library/cpp/testing/unittest/registar.h>
45
#include <util/stream/null.h>
6+
#include <util/generic/overloaded.h>
57

68
using namespace NActors;
79
using namespace NKikimr;
@@ -193,10 +195,182 @@ void RunStrategyTest(TBlobStorageGroupType type) {
193195
}
194196
}
195197

198+
struct TGetQuery {
199+
ui32 OrderNumber;
200+
TLogoBlobID Id;
201+
ui32 Shift;
202+
ui32 Size;
203+
204+
auto AsTuple() const { return std::make_tuple(OrderNumber, Id, Shift, Size); }
205+
friend bool operator ==(const TGetQuery& x, const TGetQuery& y) { return x.AsTuple() == y.AsTuple(); }
206+
friend bool operator <(const TGetQuery& x, const TGetQuery& y) { return x.AsTuple() < y.AsTuple(); }
207+
};
208+
209+
struct TPutQuery {
210+
ui32 OrderNumber;
211+
TLogoBlobID Id;
212+
213+
auto AsTuple() const { return std::make_tuple(OrderNumber, Id); }
214+
friend bool operator ==(const TPutQuery& x, const TPutQuery& y) { return x.AsTuple() == y.AsTuple(); }
215+
friend bool operator <(const TPutQuery& x, const TPutQuery& y) { return x.AsTuple() < y.AsTuple(); }
216+
};
217+
218+
using TOperation = std::variant<TGetQuery, TPutQuery>;
219+
220+
void RunTestLevel(const TBlobStorageGroupInfo& info, TBlackboard& blackboard,
221+
const std::function<EStrategyOutcome(TBlackboard&)>& runStrategies, const TLogoBlobID& id,
222+
std::vector<TOperation>& stock, TSubgroupPartLayout presenceMask, bool nonWorkingDomain,
223+
std::set<TOperation>& context, ui32& terminals) {
224+
// see which operations we can add to the stock
225+
const size_t stockSizeOnEntry = stock.size();
226+
auto& requests = blackboard.GroupDiskRequests.DiskRequestsForOrderNumber;
227+
for (ui32 i = 0; i < info.GetTotalVDisksNum(); ++i) {
228+
for (auto& j = requests[i].FirstUnsentRequestIdx; j < requests[i].GetsToSend.size(); ++j) {
229+
auto& get = requests[i].GetsToSend[j];
230+
stock.push_back(TGetQuery{i, get.Id, get.Shift, get.Size});
231+
const bool inserted = context.insert(stock.back()).second;
232+
UNIT_ASSERT(inserted);
233+
}
234+
for (auto& j = requests[i].FirstUnsentPutIdx; j < requests[i].PutsToSend.size(); ++j) {
235+
auto& put = requests[i].PutsToSend[j];
236+
stock.push_back(TPutQuery{i, put.Id});
237+
const bool inserted = context.insert(stock.back()).second;
238+
UNIT_ASSERT(inserted);
239+
}
240+
}
241+
UNIT_ASSERT(!stock.empty());
242+
243+
bool canIssuePuts = true;
244+
for (size_t i = 0; i < stock.size(); ++i) {
245+
if (std::holds_alternative<TGetQuery>(stock[i])) {
246+
canIssuePuts = false;
247+
break;
248+
}
249+
}
250+
251+
// try every single operation in stock
252+
for (size_t i = 0; i < stock.size(); ++i) {
253+
if (!canIssuePuts && std::holds_alternative<TPutQuery>(stock[i])) {
254+
continue;
255+
}
256+
if (auto *get = std::get_if<TGetQuery>(&stock[i]); get && context.contains(TPutQuery{get->OrderNumber, get->Id})) {
257+
continue;
258+
}
259+
260+
std::swap(stock[i], stock.back());
261+
TOperation operation = std::move(stock.back());
262+
stock.pop_back();
263+
264+
TBlackboard branch(blackboard);
265+
TSubgroupPartLayout myPresenceMask(presenceMask);
266+
267+
std::visit(TOverloaded{
268+
[&](const TGetQuery& op) {
269+
const ui32 idxInSubgroup = info.GetTopology().GetIdxInSubgroup(info.GetVDiskId(op.OrderNumber), id.Hash());
270+
if (nonWorkingDomain && idxInSubgroup % 3 == 2) {
271+
branch.AddErrorResponse(op.Id, op.OrderNumber);
272+
} else if (myPresenceMask.GetDisksWithPart(op.Id.PartId() - 1) >> idxInSubgroup & 1) {
273+
const ui32 blobSize = op.Id.BlobSize();
274+
const ui32 shift = Min(op.Shift, blobSize);
275+
const ui32 size = Min(op.Size ? op.Size : Max<ui32>(), blobSize - shift);
276+
branch.AddResponseData(op.Id, op.OrderNumber, shift, TRope(TString(size, 'X')));
277+
} else {
278+
branch.AddNoDataResponse(op.Id, op.OrderNumber);
279+
}
280+
},
281+
[&](const TPutQuery& op) {
282+
const ui32 idxInSubgroup = info.GetTopology().GetIdxInSubgroup(info.GetVDiskId(op.OrderNumber), id.Hash());
283+
if (nonWorkingDomain && idxInSubgroup % 3 == 2) {
284+
branch.AddErrorResponse(op.Id, op.OrderNumber);
285+
} else {
286+
myPresenceMask.AddItem(idxInSubgroup, op.Id.PartId() - 1, info.Type);
287+
branch.AddPutOkResponse(op.Id, op.OrderNumber);
288+
}
289+
}
290+
}, operation);
291+
292+
auto outcome = runStrategies(branch);
293+
UNIT_ASSERT(outcome != EStrategyOutcome::ERROR);
294+
if (outcome == EStrategyOutcome::DONE) {
295+
TBlobStorageGroupInfo::TOrderNums nums;
296+
info.GetTopology().PickSubgroup(id.Hash(), nums);
297+
UNIT_ASSERT(info.GetQuorumChecker().GetBlobState(myPresenceMask, {&info.GetTopology()}) == TBlobStorageGroupInfo::EBS_FULL);
298+
++terminals;
299+
} else {
300+
RunTestLevel(info, branch, runStrategies, id, stock, myPresenceMask, nonWorkingDomain, context, terminals);
301+
}
302+
303+
stock.push_back(std::move(operation));
304+
std::swap(stock[i], stock.back());
305+
}
306+
307+
// revert stock
308+
for (size_t i = stockSizeOnEntry; i < stock.size(); ++i) {
309+
const size_t n = context.erase(stock[i]);
310+
UNIT_ASSERT(n);
311+
}
312+
stock.resize(stockSizeOnEntry);
313+
}
314+
196315
Y_UNIT_TEST_SUITE(DSProxyStrategyTest) {
197316

198317
Y_UNIT_TEST(Restore_block42) {
199318
RunStrategyTest<TRestoreStrategy>(TBlobStorageGroupType::Erasure4Plus2Block);
200319
}
201320

321+
Y_UNIT_TEST(Restore_mirror3dc) {
322+
THPTimer timer;
323+
const TBlobStorageGroupType type(TBlobStorageGroupType::ErasureMirror3dc);
324+
325+
TBlobStorageGroupInfo info(type, 1, 3, 3);
326+
info.Ref();
327+
TGroupQueues groupQueues(info.GetTopology());
328+
groupQueues.Ref();
329+
330+
std::vector<TOperation> stock;
331+
332+
TLogContext logCtx(NKikimrServices::BS_PROXY, false);
333+
logCtx.SuppressLog = true;
334+
335+
auto runStrategies = [&](TBlackboard& blackboard) {
336+
return blackboard.RunStrategy(logCtx, TMirror3dcGetWithRestoreStrategy());
337+
};
338+
339+
const ui32 base = RandomNumber(512u);
340+
for (ui32 i = 0; i < 512; ++i) {
341+
const ui32 diskMask = (base + i) % 512;
342+
for (bool nonWorkingDomain : {false, true}) {
343+
TBlackboard blackboard(&info, &groupQueues, NKikimrBlobStorage::UserData, NKikimrBlobStorage::FastRead);
344+
345+
const TLogoBlobID id(1'000'000'000, 1, 1, 0, 1000, 0);
346+
TSubgroupPartLayout presenceMask;
347+
blackboard.AddNeeded(id, 0, id.BlobSize());
348+
bool partsAvailable = false;
349+
for (ui32 idxInSubgroup = 0; idxInSubgroup < 9; ++idxInSubgroup) {
350+
if (diskMask >> idxInSubgroup & 1 && (!nonWorkingDomain || idxInSubgroup % 3 != 2)) {
351+
presenceMask.AddItem(idxInSubgroup, idxInSubgroup % 3, info.Type);
352+
partsAvailable = true;
353+
}
354+
}
355+
if (!partsAvailable) {
356+
continue;
357+
}
358+
359+
Cerr << "diskMask# " << diskMask << " nonWorkingDomain# " << nonWorkingDomain;
360+
361+
auto outcome = runStrategies(blackboard);
362+
UNIT_ASSERT(outcome == EStrategyOutcome::IN_PROGRESS);
363+
364+
std::set<TOperation> context;
365+
ui32 terminals = 0;
366+
RunTestLevel(info, blackboard, runStrategies, id, stock, presenceMask, nonWorkingDomain, context, terminals);
367+
Cerr << " " << terminals << Endl;
368+
369+
if (TDuration::Seconds(timer.Passed()) >= TDuration::Minutes(5)) {
370+
return;
371+
}
372+
}
373+
}
374+
}
375+
202376
}

ydb/core/blobstorage/dsproxy/ut_strategy/ya.make

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
UNITTEST()
22

3+
FORK_SUBTESTS()
4+
35
TIMEOUT(600)
46
SIZE(MEDIUM)
57

0 commit comments

Comments
 (0)