|
1 | 1 | #include <ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h>
|
2 | 2 | #include <ydb/core/blobstorage/dsproxy/dsproxy_strategy_restore.h>
|
| 3 | +#include <ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_restore.h> |
3 | 4 | #include <library/cpp/testing/unittest/registar.h>
|
4 | 5 | #include <util/stream/null.h>
|
| 6 | +#include <util/generic/overloaded.h> |
5 | 7 |
|
6 | 8 | using namespace NActors;
|
7 | 9 | using namespace NKikimr;
|
@@ -193,10 +195,153 @@ void RunStrategyTest(TBlobStorageGroupType type) {
|
193 | 195 | }
|
194 | 196 | }
|
195 | 197 |
|
| 198 | +struct TGetQuery { |
| 199 | + ui32 OrderNumber; |
| 200 | + TLogoBlobID Id; |
| 201 | + ui32 Shift; |
| 202 | + ui32 Size; |
| 203 | + |
| 204 | + friend bool operator ==(const TGetQuery& x, const TGetQuery& y) { |
| 205 | + return x.OrderNumber == y.OrderNumber && x.Id == y.Id && x.Shift == y.Shift && x.Size == y.Size; |
| 206 | + } |
| 207 | +}; |
| 208 | + |
| 209 | +struct TPutQuery { |
| 210 | + ui32 OrderNumber; |
| 211 | + TLogoBlobID Id; |
| 212 | + |
| 213 | + friend bool operator ==(const TPutQuery& x, const TPutQuery& y) { |
| 214 | + return x.OrderNumber == y.OrderNumber && x.Id == y.Id; |
| 215 | + } |
| 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 | + // see which operations we can add to the stock |
| 224 | + const size_t stockSizeOnEntry = stock.size(); |
| 225 | + auto& requests = blackboard.GroupDiskRequests.DiskRequestsForOrderNumber; |
| 226 | + for (ui32 i = 0; i < info.GetTotalVDisksNum(); ++i) { |
| 227 | + for (const auto& get : requests[i].GetsToSend) { |
| 228 | + stock.push_back(TGetQuery{i, get.Id, get.Shift, get.Size}); |
| 229 | + } |
| 230 | + requests[i].GetsToSend.clear(); |
| 231 | + for (const auto& put : requests[i].PutsToSend) { |
| 232 | + stock.push_back(TPutQuery{i, put.Id}); |
| 233 | + } |
| 234 | + requests[i].PutsToSend.clear(); |
| 235 | + } |
| 236 | + |
| 237 | + // try every single operation in stock |
| 238 | + for (size_t i = 0; i < stock.size(); ++i) { |
| 239 | + std::swap(stock[i], stock.back()); |
| 240 | + TOperation operation = std::move(stock.back()); |
| 241 | + stock.pop_back(); |
| 242 | + |
| 243 | + TBlackboard branch(blackboard); |
| 244 | + TSubgroupPartLayout myPresenceMask(presenceMask); |
| 245 | + |
| 246 | + std::visit(TOverloaded{ |
| 247 | + [&](const TGetQuery& op) { |
| 248 | + const ui32 idxInSubgroup = info.GetTopology().GetIdxInSubgroup(info.GetVDiskId(op.OrderNumber), id.Hash()); |
| 249 | + if (nonWorkingDomain && idxInSubgroup % 3 == 2) { |
| 250 | + branch.AddErrorResponse(op.Id, op.OrderNumber); |
| 251 | + } else if (myPresenceMask.GetDisksWithPart(op.Id.PartId() - 1) >> idxInSubgroup & 1) { |
| 252 | + const ui32 blobSize = op.Id.BlobSize(); |
| 253 | + const ui32 shift = Min(op.Shift, blobSize); |
| 254 | + const ui32 size = Min(op.Size ? op.Size : Max<ui32>(), blobSize - shift); |
| 255 | + branch.AddResponseData(op.Id, op.OrderNumber, shift, TRope(TString(size, 'X'))); |
| 256 | + } else { |
| 257 | + branch.AddNoDataResponse(op.Id, op.OrderNumber); |
| 258 | + } |
| 259 | + }, |
| 260 | + [&](const TPutQuery& op) { |
| 261 | + const ui32 idxInSubgroup = info.GetTopology().GetIdxInSubgroup(info.GetVDiskId(op.OrderNumber), id.Hash()); |
| 262 | + if (nonWorkingDomain && idxInSubgroup % 3 == 2) { |
| 263 | + branch.AddErrorResponse(op.Id, op.OrderNumber); |
| 264 | + } else { |
| 265 | + myPresenceMask.AddItem(idxInSubgroup, op.Id.PartId() - 1, info.Type); |
| 266 | + branch.AddPutOkResponse(op.Id, op.OrderNumber); |
| 267 | + } |
| 268 | + } |
| 269 | + }, operation); |
| 270 | + |
| 271 | + auto outcome = runStrategies(branch); |
| 272 | + UNIT_ASSERT(outcome != EStrategyOutcome::ERROR); |
| 273 | + if (outcome == EStrategyOutcome::DONE) { |
| 274 | + TBlobStorageGroupInfo::TOrderNums nums; |
| 275 | + info.GetTopology().PickSubgroup(id.Hash(), nums); |
| 276 | + UNIT_ASSERT(info.GetQuorumChecker().GetBlobState(myPresenceMask, {&info.GetTopology()}) == TBlobStorageGroupInfo::EBS_FULL); |
| 277 | + } else { |
| 278 | + RunTestLevel(info, branch, runStrategies, id, stock, myPresenceMask, nonWorkingDomain); |
| 279 | + } |
| 280 | + |
| 281 | + stock.push_back(std::move(operation)); |
| 282 | + std::swap(stock[i], stock.back()); |
| 283 | + } |
| 284 | + |
| 285 | + // revert stock |
| 286 | + stock.resize(stockSizeOnEntry); |
| 287 | +} |
| 288 | + |
196 | 289 | Y_UNIT_TEST_SUITE(DSProxyStrategyTest) {
|
197 | 290 |
|
198 | 291 | Y_UNIT_TEST(Restore_block42) {
|
199 | 292 | RunStrategyTest<TRestoreStrategy>(TBlobStorageGroupType::Erasure4Plus2Block);
|
200 | 293 | }
|
201 | 294 |
|
| 295 | + Y_UNIT_TEST(Restore_mirror3dc) { |
| 296 | + THPTimer timer; |
| 297 | + const TBlobStorageGroupType type(TBlobStorageGroupType::ErasureMirror3dc); |
| 298 | + |
| 299 | + TBlobStorageGroupInfo info(type, 1, 3, 3); |
| 300 | + info.Ref(); |
| 301 | + TGroupQueues groupQueues(info.GetTopology()); |
| 302 | + groupQueues.Ref(); |
| 303 | + |
| 304 | + std::vector<TOperation> stock; |
| 305 | + |
| 306 | + TLogContext logCtx(NKikimrServices::BS_PROXY, false); |
| 307 | + logCtx.SuppressLog = true; |
| 308 | + |
| 309 | + auto runStrategies = [&](TBlackboard& blackboard) { |
| 310 | + return blackboard.RunStrategy(logCtx, TMirror3dcGetWithRestoreStrategy()); |
| 311 | + }; |
| 312 | + |
| 313 | + const ui32 base = RandomNumber(512u); |
| 314 | + for (ui32 i = 0; i < 512; ++i) { |
| 315 | + const ui32 diskMask = (base + i) % 512; |
| 316 | + for (bool nonWorkingDomain : {false, true}) { |
| 317 | + Cerr << "diskMask# " << diskMask << " nonWorkingDomain# " << nonWorkingDomain << Endl; |
| 318 | + |
| 319 | + TBlackboard blackboard(&info, &groupQueues, NKikimrBlobStorage::UserData, NKikimrBlobStorage::FastRead); |
| 320 | + |
| 321 | + const TLogoBlobID id(1'000'000'000, 1, 1, 0, 1000, 0); |
| 322 | + TSubgroupPartLayout presenceMask; |
| 323 | + blackboard.AddNeeded(id, 0, id.BlobSize()); |
| 324 | + bool partsAvailable = false; |
| 325 | + for (ui32 idxInSubgroup = 0; idxInSubgroup < 9; ++idxInSubgroup) { |
| 326 | + if (diskMask >> idxInSubgroup & 1 && (!nonWorkingDomain || idxInSubgroup % 3 != 2)) { |
| 327 | + presenceMask.AddItem(idxInSubgroup, idxInSubgroup % 3, info.Type); |
| 328 | + partsAvailable = true; |
| 329 | + } |
| 330 | + } |
| 331 | + if (!partsAvailable) { |
| 332 | + continue; |
| 333 | + } |
| 334 | + |
| 335 | + auto outcome = runStrategies(blackboard); |
| 336 | + UNIT_ASSERT(outcome == EStrategyOutcome::IN_PROGRESS); |
| 337 | + |
| 338 | + RunTestLevel(info, blackboard, runStrategies, id, stock, presenceMask, nonWorkingDomain); |
| 339 | + |
| 340 | + if (TDuration::Seconds(timer.Passed()) >= TDuration::Minutes(5)) { |
| 341 | + break; |
| 342 | + } |
| 343 | + } |
| 344 | + } |
| 345 | + } |
| 346 | + |
202 | 347 | }
|
0 commit comments