From 9527980f3f19a3dc7f94d17e04653dbfe5efc923 Mon Sep 17 00:00:00 2001 From: Cthulhu Date: Wed, 22 Jan 2025 18:14:55 +0300 Subject: [PATCH] Implement PDisk shred reaction to Harakiri and YardInit, #12483 (#13685) --- .../blobstorage/pdisk/blobstorage_pdisk.h | 7 + .../pdisk/blobstorage_pdisk_impl.cpp | 237 ++++++++++-------- .../pdisk/blobstorage_pdisk_impl.h | 15 +- .../pdisk/blobstorage_pdisk_state.h | 22 ++ .../pdisk/blobstorage_pdisk_ut.cpp | 94 ++++++- .../pdisk/blobstorage_pdisk_ut_env.h | 7 + ydb/library/services/services.proto | 1 + 7 files changed, 264 insertions(+), 119 deletions(-) diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h index 27efb9a752af..32d93975c411 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h @@ -1727,5 +1727,12 @@ struct TPDiskCtx { } \ } while (false) +#define S_LOG(LEVEL, MARKER, ...) \ + do { \ + if (PCtx && PCtx->ActorSystem) { \ + STLOGX(*PCtx->ActorSystem, LEVEL, BS_PDISK_SHRED, MARKER, __VA_ARGS__, (PDiskId, PCtx->PDiskId)); \ + } \ + } while (false) + } // NPDisk } // NKikimr diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp index 781a5e4472bf..f3c157bc116c 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp @@ -1803,6 +1803,8 @@ bool TPDisk::YardInitForKnownVDisk(TYardInit &evYardInit, TOwner owner) { ownerData.HasReadTheWholeLog = false; ownerData.LogStartPosition = TLogPosition{0, 0}; ownerData.Status = TOwnerData::VDISK_STATUS_SENT_INIT; + ownerData.LastShredGeneration = 0; + ownerData.ShredState = TOwnerData::VDISK_SHRED_STATE_NOT_REQUESTED; AddCbsSet(owner); @@ -1814,6 +1816,7 @@ bool TPDisk::YardInitForKnownVDisk(TYardInit &evYardInit, TOwner owner) { PCtx->ActorSystem->Send(evYardInit.Sender, result.Release()); Mon.YardInit.CountResponse(); AskVDisksToCutLogs(owner, false); + ProgressShredState(); return true; } @@ -2140,6 +2143,12 @@ void TPDisk::KillOwner(TOwner owner, TOwnerRound killOwnerRound, TCompletionEven ++it; } + bool isProgressShredStateNeeded = false; + if (OwnerData[owner].ShredState == TOwnerData::VDISK_SHRED_STATE_COMPACT_REQUESTED || + OwnerData[owner].ShredState == TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED) { + isProgressShredStateNeeded = true; + } + ReleaseUnusedLogChunks(completionAction); TVDiskID vDiskId = SysLogRecord.OwnerVDisks[owner]; @@ -2155,6 +2164,10 @@ void TPDisk::KillOwner(TOwner owner, TOwnerRound killOwnerRound, TCompletionEven OwnerData[owner].OwnerRound = ownerRound; VDiskOwners.erase(vDiskId); + if (isProgressShredStateNeeded) { + ProgressShredState(); + } + P_LOG(PRI_NOTICE, BPD12, "KillOwner", (ownerId, owner), (ownerRound, ownerRound), (VDiskId, vDiskId.ToStringWOGeneration()), (lastSeenLsn, lastSeenLsn)); } @@ -3900,110 +3913,102 @@ void TPDisk::AddCbsSet(ui32 ownerId) { SchedulerConfigure(conf); } -void TPDisk::SendPreShredCompactVDiskRequests() { - TGuard guard(StateMutex); - for (ui32 ownerId = 0; ownerId < OwnerData.size(); ++ownerId) { - TOwnerData &data = OwnerData[ownerId]; - if (data.VDiskId != TVDiskID::InvalidId) { - if (data.Status == TOwnerData::VDISK_STATUS_DEFAULT || data.Status == TOwnerData::VDISK_STATUS_HASNT_COME) { - data.ShredState = TOwnerData::VDISK_SHRED_STATE_NOT_REQUESTED; - } else { - if (data.LastShredGeneration < ShredGeneration) { - std::vector chunksToShred; - THolder compactRequest(new TEvPreShredCompactVDisk(ShredGeneration)); - LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, - "PDisk# " << PCtx->PDiskId - << " sends compact request to VDisk# " << data.VDiskId - << " ownerId# " << ownerId - << " request# " << compactRequest->ToString()); - PCtx->ActorSystem->Send(data.CutLogId, compactRequest.Release()); - ++PreShredCompactVDiskRequestsSent; - data.LastShredGeneration = ShredGeneration; - data.ShredState = TOwnerData::VDISK_SHRED_STATE_COMPACT_REQUESTED; - } - } - } - } -} - -void TPDisk::SendShredVDiskRequests() { - TGuard guard(StateMutex); - for (ui32 ownerId = 0; ownerId < OwnerData.size(); ++ownerId) { - TOwnerData &data = OwnerData[ownerId]; - if (data.VDiskId != TVDiskID::InvalidId && data.ShredState == TOwnerData::VDISK_SHRED_STATE_COMPACT_FINISHED) { - std::vector chunksToShred; - chunksToShred.reserve(ChunkState.size()); - for (TChunkIdx chunkIdx = 0; chunkIdx < ChunkState.size(); ++chunkIdx) { - if (ChunkState[chunkIdx].OwnerId == ownerId) { - // TODO(cthulhu): check if chunk is dirty - chunksToShred.push_back(chunkIdx); - } - } - THolder shredRequest(new TEvShredVDisk(ShredGeneration, chunksToShred)); - LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, - "PDisk# " << PCtx->PDiskId - << " sends shred request to VDisk# " << data.VDiskId - << " ownerId# " << ownerId - << " request# " << shredRequest->ToString()); - PCtx->ActorSystem->Send(data.CutLogId, shredRequest.Release()); - ++ShredRequestsSent; - data.ShredState = TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED; - } - } -} - void TPDisk::ProgressShredState() { + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "ProgressShredState at PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " ShredState# " << (ui32)ShredState); TGuard guard(StateMutex); if (ShredState == EShredStateSendPreShredCompactVDisk) { - // Check if all a PreShredCompactVDisk requests are sent + ui32 finishedCount = 0; for (ui32 ownerId = 0; ownerId < OwnerData.size(); ++ownerId) { TOwnerData &data = OwnerData[ownerId]; if (data.VDiskId != TVDiskID::InvalidId) { - if (data.ShredState != TOwnerData::VDISK_SHRED_STATE_COMPACT_REQUESTED && - data.ShredState != TOwnerData::VDISK_SHRED_STATE_COMPACT_FINISHED) { + if (data.Status == TOwnerData::VDISK_STATUS_DEFAULT || data.Status == TOwnerData::VDISK_STATUS_HASNT_COME) { + data.ShredState = TOwnerData::VDISK_SHRED_STATE_NOT_REQUESTED; + } else { + if (data.LastShredGeneration < ShredGeneration) { + std::vector chunksToShred; + THolder compactRequest(new TEvPreShredCompactVDisk(ShredGeneration)); + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "PDisk# " << PCtx->PDiskId + << " sends compact request to VDisk# " << data.VDiskId + << " ownerId# " << ownerId + << " request# " << compactRequest->ToString()); + PCtx->ActorSystem->Send(data.CutLogId, compactRequest.Release()); + data.LastShredGeneration = ShredGeneration; + data.ShredState = TOwnerData::VDISK_SHRED_STATE_COMPACT_REQUESTED; + } + } + if (data.ShredState != TOwnerData::VDISK_SHRED_STATE_COMPACT_FINISHED) { + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " is waiting for ownerId# " << ownerId + << " before finishing pre-shred compact" + << " VDiskId# " << data.VDiskId + << " VDiskStatus# " << data.GetStringStatus() + << " ShredState# " << data.GetStringShredState()); return; } + ++finishedCount; } } - LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "PDisk# " << PCtx->PDiskId - << " has sent all pre-shred compact VDisk requests" + << " has finished all pre-shred compact VDisk requests" << " ShredGeneration# " << ShredGeneration - << " PreShredCompactVDiskRequestsSent# " << PreShredCompactVDiskRequestsSent); - ShredState = EShredStateGatherPreShredCompactVDisksResponse; - } - if (ShredState == EShredStateGatherPreShredCompactVDisksResponse) { - if (PreShredCompactVDiskRequestsSent != PreShredCompactVDiskResponsesReceived) { - return; - } + << " finishedCount# " << finishedCount); ShredState = EShredStateSendShredVDisk; - SendShredVDiskRequests(); } if (ShredState == EShredStateSendShredVDisk) { - // Check if all a PreShredCompactVDisk requests are sent + ui32 finishedCount = 0; for (ui32 ownerId = 0; ownerId < OwnerData.size(); ++ownerId) { TOwnerData &data = OwnerData[ownerId]; if (data.VDiskId != TVDiskID::InvalidId) { - if (data.ShredState != TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED && - data.ShredState != TOwnerData::VDISK_SHRED_STATE_SHRED_FINISHED) { + if (data.Status == TOwnerData::VDISK_STATUS_DEFAULT || data.Status == TOwnerData::VDISK_STATUS_HASNT_COME) { + data.ShredState = TOwnerData::VDISK_SHRED_STATE_COMPACT_FINISHED; + } else if (data.ShredState != TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED + && data.ShredState != TOwnerData::VDISK_SHRED_STATE_SHRED_FINISHED) { + std::vector chunksToShred; + chunksToShred.reserve(ChunkState.size()); + for (TChunkIdx chunkIdx = 0; chunkIdx < ChunkState.size(); ++chunkIdx) { + if (ChunkState[chunkIdx].OwnerId == ownerId) { + // TODO(cthulhu): check if chunk is dirty + chunksToShred.push_back(chunkIdx); + } + } + THolder shredRequest(new TEvShredVDisk(ShredGeneration, chunksToShred)); + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "PDisk# " << PCtx->PDiskId + << " sends shred request to VDisk# " << data.VDiskId + << " ownerId# " << ownerId + << " request# " << shredRequest->ToString()); + PCtx->ActorSystem->Send(data.CutLogId, shredRequest.Release()); + data.ShredState = TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED; + data.LastShredGeneration = ShredGeneration; + } + if (data.ShredState != TOwnerData::VDISK_SHRED_STATE_SHRED_FINISHED) { + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " is waiting for ownerId# " << ownerId + << " VDiskId# " << data.VDiskId + << " ShredState# " << data.GetStringShredState() + << " before finishing shred"); return; } + ++finishedCount; } } - LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "PDisk# " << PCtx->PDiskId - << " has sent all shred requests" + << " has finished all shred requests" << " ShredGeneration# " << ShredGeneration - << " ShredRequestsSent# " << ShredRequestsSent); - ShredState = EShredStateGatherShredVDisksResponse; - } - if (ShredState == EShredStateGatherShredVDisksResponse) { - if (ShredRequestsSent != ShredResponsesReceived) { - return; - } + << " finishedCount# " << finishedCount); ShredState = EShredStateFinished; // TODO: send result to the requester after actual shred is done - LOG_NOTICE_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_NOTICE_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "Shred request is finished at PDisk# " << PCtx->PDiskId << " ShredGeneration# " << ShredGeneration); for (TActorId &requester : ShredRequesters) { @@ -4014,7 +4019,7 @@ void TPDisk::ProgressShredState() { } void TPDisk::ProcessShredPDisk(TShredPDisk& request) { - LOG_NOTICE_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_NOTICE_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "ProcessShredPDisk at PDisk# " << PCtx->PDiskId << " ShredGeneration# " << ShredGeneration << " request# " << request.ToString()); @@ -4046,24 +4051,18 @@ void TPDisk::ProcessShredPDisk(TShredPDisk& request) { ShredGeneration = request.ShredGeneration; ShredRequesters.push_back(request.Sender); ShredState = EShredStateSendPreShredCompactVDisk; - PreShredCompactVDiskRequestsSent = 0; - PreShredCompactVDiskResponsesReceived = 0; - ShredRequestsSent = 0; - ShredResponsesReceived = 0; - - SendPreShredCompactVDiskRequests(); ProgressShredState(); } void TPDisk::ProcessPreShredCompactVDiskResult(TPreShredCompactVDiskResult& request) { - LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "ProcessPreShredCompactVDiskResult at PDisk# " << PCtx->PDiskId << " ShredGeneration# " << ShredGeneration << " request# " << request.ToString()); TGuard guard(StateMutex); if (request.ShredGeneration != ShredGeneration) { // Ignore old results - LOG_WARN_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_WARN_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "Old PreShredCompactVDiskResult is ignored at PDisk# " << PCtx->PDiskId << " ShredGeneration# " << ShredGeneration << " for PreShredCompactVDiskResult generation# " << request.ShredGeneration @@ -4071,6 +4070,28 @@ void TPDisk::ProcessPreShredCompactVDiskResult(TPreShredCompactVDiskResult& requ << " ownerRound# " << request.OwnerRound); return; } + TStringStream err; + NKikimrProto::EReplyStatus errStatus = CheckOwnerAndRound(&request, err); + if (errStatus != NKikimrProto::OK) { + LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "Incorrect PreShredCompactVDiskResult is received at PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " owner# " << request.Owner + << " ownerRound# " << request.OwnerRound + << " " << err.Str()); + return; + } + if (OwnerData[request.Owner].ShredState != TOwnerData::VDISK_SHRED_STATE_COMPACT_REQUESTED) { + // Ignore incorrect state results + LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "Unexpected PreShredCompactVDiskResult is received at PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " for PreShredCompactVDiskResult generation# " << request.ShredGeneration + << " owner# " << request.Owner + << " ownerRound# " << request.OwnerRound + << " ownerShredState# " << OwnerData[request.Owner].ShredState); + return; + } if (request.Status != NKikimrProto::OK) { ShredState = EShredStateFailed; for (TActorId &requester : ShredRequesters) { @@ -4081,30 +4102,26 @@ void TPDisk::ProcessPreShredCompactVDiskResult(TPreShredCompactVDiskResult& requ << " ownerRound# " << request.OwnerRound << " replied with PreShredCompactVDiskResult status# " << request.Status << " and ErrorReason# " << request.ErrorReason; - LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, str.Str()); + LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, str.Str()); PCtx->ActorSystem->Send(requester, new TEvShredPDiskResult(NKikimrProto::ERROR, request.ShredGeneration, str.Str())); } ShredRequesters.clear(); return; } - // TODO(cthulhu): check if owner is valid - if (OwnerData[request.Owner].ShredState == TOwnerData::VDISK_SHRED_STATE_COMPACT_REQUESTED) { - OwnerData[request.Owner].ShredState = TOwnerData::VDISK_SHRED_STATE_COMPACT_FINISHED; - } - ++PreShredCompactVDiskResponsesReceived; + OwnerData[request.Owner].ShredState = TOwnerData::VDISK_SHRED_STATE_COMPACT_FINISHED; ProgressShredState(); } void TPDisk::ProcessShredVDiskResult(TShredVDiskResult& request) { - LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_DEBUG_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "ProcessShredPDisk at PDisk# " << PCtx->PDiskId << " ShredGeneration# " << ShredGeneration << " request# " << request.ToString()); TGuard guard(StateMutex); if (request.ShredGeneration != ShredGeneration) { // Ignore old results - LOG_WARN_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, + LOG_WARN_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, "Old ShredVDiskResult is ignored at PDisk# " << PCtx->PDiskId << " ShredGeneration# " << ShredGeneration << " for shredGeneration# " << request.ShredGeneration @@ -4112,6 +4129,28 @@ void TPDisk::ProcessShredVDiskResult(TShredVDiskResult& request) { << " ownerRound# " << request.OwnerRound); return; } + TStringStream err; + NKikimrProto::EReplyStatus errStatus = CheckOwnerAndRound(&request, err); + if (errStatus != NKikimrProto::OK) { + LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "Incorrect ShredVDiskResult is received at PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " owner# " << request.Owner + << " ownerRound# " << request.OwnerRound + << " " << err.Str()); + return; + } + if (OwnerData[request.Owner].ShredState != TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED) { + // Ignore incorrect state results + LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, + "Unexpected ShredVDiskResult is received at PDisk# " << PCtx->PDiskId + << " ShredGeneration# " << ShredGeneration + << " for ShredVDiskResult generation# " << request.ShredGeneration + << " owner# " << request.Owner + << " ownerRound# " << request.OwnerRound + << " ownerShredState# " << OwnerData[request.Owner].ShredState); + return; + } if (request.Status != NKikimrProto::OK) { ShredState = EShredStateFailed; for (TActorId &requester : ShredRequesters) { @@ -4122,18 +4161,14 @@ void TPDisk::ProcessShredVDiskResult(TShredVDiskResult& request) { << " ownerRound# " << request.OwnerRound << " replied with status# " << request.Status << " and ErrorReason# " << request.ErrorReason; - LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK, str.Str()); + LOG_ERROR_S(*PCtx->ActorSystem, NKikimrServices::BS_PDISK_SHRED, str.Str()); PCtx->ActorSystem->Send(requester, new TEvShredPDiskResult(NKikimrProto::ERROR, request.ShredGeneration, str.Str())); } ShredRequesters.clear(); return; } - // TODO(cthulhu): check if owner is valid - if (OwnerData[request.Owner].ShredState == TOwnerData::VDISK_SHRED_STATE_SHRED_REQUESTED) { - OwnerData[request.Owner].ShredState = TOwnerData::VDISK_SHRED_STATE_SHRED_FINISHED; - } - ++ShredResponsesReceived; + OwnerData[request.Owner].ShredState = TOwnerData::VDISK_SHRED_STATE_SHRED_FINISHED; ProgressShredState(); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h index b1ef56f08ba7..d0d9386b4f73 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h @@ -151,21 +151,14 @@ class TPDisk : public IPDisk { enum EShredState { EShredStateDefault = 0, EShredStateSendPreShredCompactVDisk = 1, - EShredStateGatherPreShredCompactVDisksResponse = 2, - EShredStateSendShredVDisk = 3, - EShredStateGatherShredVDisksResponse = 4, - EShredStateFinished = 5, - EShredStateFailed = 6, + EShredStateSendShredVDisk = 2, + EShredStateFinished = 3, + EShredStateFailed = 4, }; EShredState ShredState = EShredStateDefault; ui64 ShredGeneration = 0; std::deque ShredRequesters; - i64 PreShredCompactVDiskRequestsSent = 0; - i64 PreShredCompactVDiskResponsesReceived = 0; - i64 ShredRequestsSent = 0; - i64 ShredResponsesReceived = 0; - // Chunks that are owned by killed owner, but have operations InFlight TVector QuarantineChunks; TVector QuarantineOwners; @@ -406,8 +399,6 @@ class TPDisk : public IPDisk { void HandleNextWriteMetadata(); void ProcessWriteMetadataResult(TWriteMetadataResult& request); - void SendPreShredCompactVDiskRequests(); - void SendShredVDiskRequests(); void ProgressShredState(); void ProcessShredPDisk(TShredPDisk& request); void ProcessPreShredCompactVDiskResult(TPreShredCompactVDiskResult& request); diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h index 74f87226e845..86efd878642c 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h @@ -142,6 +142,26 @@ struct TOwnerData { return RenderStatus(Status); } + const char* GetStringShredState() const { + return RenderShredState(ShredState); + } + + static const char* RenderShredState(const EVDiskShredState shredState) { + switch(shredState) { + case EVDiskShredState::VDISK_SHRED_STATE_NOT_REQUESTED: + return "Not requested"; + case EVDiskShredState::VDISK_SHRED_STATE_COMPACT_REQUESTED: + return "Compact requested"; + case EVDiskShredState::VDISK_SHRED_STATE_COMPACT_FINISHED: + return "Compact finished"; + case EVDiskShredState::VDISK_SHRED_STATE_SHRED_REQUESTED: + return "Shred requested"; + case EVDiskShredState::VDISK_SHRED_STATE_SHRED_FINISHED: + return "Shred finished"; + } + return "Unexpected enum value"; + } + static const char* RenderStatus(const EVDiskStatus status) { switch(status) { case VDISK_STATUS_DEFAULT: @@ -230,6 +250,8 @@ struct TOwnerData { InFlight.Reset(TIntrusivePtr(new TOwnerInflight)); } OnQuarantine = quarantine; + LastShredGeneration = 0; + ShredState = VDISK_SHRED_STATE_NOT_REQUESTED; } }; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut.cpp index 116707899f02..f0e104abd600 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut.cpp @@ -1434,7 +1434,6 @@ Y_UNIT_TEST_SUITE(ReadOnlyPDisk) { Y_UNIT_TEST_SUITE(ShredPDisk) { Y_UNIT_TEST(EmptyShred) { ui64 shredGeneration = 1; - TActorTestContext testCtx{{}}; TVDiskMock vdisk(&testCtx); THolder res = testCtx.TestResponse(new NPDisk::TEvShredPDisk(shredGeneration), NKikimrProto::OK); @@ -1443,19 +1442,102 @@ Y_UNIT_TEST_SUITE(ShredPDisk) { } Y_UNIT_TEST(SimpleShred) { ui64 shredGeneration = 1; - TActorTestContext testCtx{{}}; TVDiskMock vdisk(&testCtx); vdisk.InitFull(); vdisk.SendEvLogSync(); - testCtx.Send(new NPDisk::TEvShredPDisk(shredGeneration)); - vdisk.RespondToPreShredCompact(shredGeneration, NKikimrProto::OK, ""); vdisk.RespondToShred(shredGeneration, NKikimrProto::OK, ""); - THolder res = testCtx.TestResponse(nullptr, NKikimrProto::OK); - + UNIT_ASSERT_VALUES_EQUAL(res->ErrorReason, ""); + UNIT_ASSERT_VALUES_EQUAL(res->ShredGeneration, shredGeneration); + } + Y_UNIT_TEST(KillVDiskWhilePreShredding) { + ui64 shredGeneration = 1; + TActorTestContext testCtx{{}}; + TVDiskMock vdisk(&testCtx); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + testCtx.Send(new NPDisk::TEvShredPDisk(shredGeneration)); + THolder evReq = testCtx.Recv(); + UNIT_ASSERT_VALUES_UNEQUAL(evReq.Get(), nullptr); + vdisk.PerformHarakiri(); + THolder res = testCtx.TestResponse( + nullptr, NKikimrProto::OK); + UNIT_ASSERT_VALUES_EQUAL(res->ErrorReason, ""); + UNIT_ASSERT_VALUES_EQUAL(res->ShredGeneration, shredGeneration); + } + Y_UNIT_TEST(KillVDiskWhileShredding) { + ui64 shredGeneration = 1; + TActorTestContext testCtx{{}}; + TVDiskMock vdisk(&testCtx); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + testCtx.Send(new NPDisk::TEvShredPDisk(shredGeneration)); + vdisk.RespondToPreShredCompact(shredGeneration, NKikimrProto::OK, ""); + THolder evReq = testCtx.Recv(); + UNIT_ASSERT_VALUES_UNEQUAL(evReq.Get(), nullptr); + vdisk.PerformHarakiri(); + THolder res = testCtx.TestResponse( + nullptr, NKikimrProto::OK); + UNIT_ASSERT_VALUES_EQUAL(res->ErrorReason, ""); + UNIT_ASSERT_VALUES_EQUAL(res->ShredGeneration, shredGeneration); + } + Y_UNIT_TEST(InitVDiskAfterShredding) { + ui64 shredGeneration = 1; + TActorTestContext testCtx{{}}; + TVDiskMock vdisk(&testCtx); + TVDiskMock vdisk2(&testCtx); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + vdisk2.InitFull(); + vdisk2.SendEvLogSync(); + testCtx.RestartPDiskSync(); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + testCtx.Send(new NPDisk::TEvShredPDisk(shredGeneration)); + vdisk.RespondToPreShredCompact(shredGeneration, NKikimrProto::OK, ""); + vdisk2.InitFull(); + vdisk2.SendEvLogSync(); + vdisk2.RespondToPreShredCompact(shredGeneration, NKikimrProto::OK, ""); + vdisk.RespondToShred(shredGeneration, NKikimrProto::OK, ""); + vdisk2.RespondToShred(shredGeneration, NKikimrProto::OK, ""); + THolder res = testCtx.TestResponse(nullptr, NKikimrProto::OK); + UNIT_ASSERT_VALUES_EQUAL(res->ErrorReason, ""); + UNIT_ASSERT_VALUES_EQUAL(res->ShredGeneration, shredGeneration); + } + Y_UNIT_TEST(ReinitVDiskWhilePreShredding) { + ui64 shredGeneration = 1; + TActorTestContext testCtx{{}}; + TVDiskMock vdisk(&testCtx); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + testCtx.Send(new NPDisk::TEvShredPDisk(shredGeneration)); + THolder evReq = testCtx.Recv(); + UNIT_ASSERT_VALUES_UNEQUAL(evReq.Get(), nullptr); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + vdisk.RespondToPreShredCompact(shredGeneration, NKikimrProto::OK, ""); + vdisk.RespondToShred(shredGeneration, NKikimrProto::OK, ""); + THolder res = testCtx.TestResponse(nullptr, NKikimrProto::OK); + UNIT_ASSERT_VALUES_EQUAL(res->ErrorReason, ""); + UNIT_ASSERT_VALUES_EQUAL(res->ShredGeneration, shredGeneration); + } + Y_UNIT_TEST(ReinitVDiskWhileShredding) { + ui64 shredGeneration = 1; + TActorTestContext testCtx{{}}; + TVDiskMock vdisk(&testCtx); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + testCtx.Send(new NPDisk::TEvShredPDisk(shredGeneration)); + vdisk.RespondToPreShredCompact(shredGeneration, NKikimrProto::OK, ""); + THolder evReq = testCtx.Recv(); + UNIT_ASSERT_VALUES_UNEQUAL(evReq.Get(), nullptr); + vdisk.InitFull(); + vdisk.SendEvLogSync(); + vdisk.RespondToShred(shredGeneration, NKikimrProto::OK, ""); + THolder res = testCtx.TestResponse(nullptr, NKikimrProto::OK); UNIT_ASSERT_VALUES_EQUAL(res->ErrorReason, ""); UNIT_ASSERT_VALUES_EQUAL(res->ShredGeneration, shredGeneration); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.h index ada1c77ba874..687dee85f941 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.h @@ -103,6 +103,7 @@ struct TActorTestContext { Runtime->SetLogPriority(NKikimrServices::BS_PDISK, NLog::PRI_NOTICE); Runtime->SetLogPriority(NKikimrServices::BS_PDISK_SYSLOG, NLog::PRI_NOTICE); Runtime->SetLogPriority(NKikimrServices::BS_PDISK_TEST, NLog::PRI_DEBUG); + Runtime->SetLogPriority(NKikimrServices::BS_PDISK_SHRED, NLog::PRI_DEBUG); Sender = Runtime->AllocateEdgeActor(); auto cfg = DefaultPDiskConfig(Settings.IsBad); @@ -348,6 +349,12 @@ struct TVDiskMock { return LastUsedLsn + 1 - FirstLsnToKeep; } + void PerformHarakiri() { + TestCtx->TestResponse( + new NPDisk::TEvHarakiri(PDiskParams->Owner, PDiskParams->OwnerRound), + NKikimrProto::OK); + } + void RespondToPreShredCompact(ui64 shredGeneration, NKikimrProto::EReplyStatus status, const TString& errorReason) { THolder evReq = TestCtx->Recv(); if (evReq) { diff --git a/ydb/library/services/services.proto b/ydb/library/services/services.proto index 75d3557e83c8..f573cccd412a 100644 --- a/ydb/library/services/services.proto +++ b/ydb/library/services/services.proto @@ -29,6 +29,7 @@ enum EServiceKikimr { BS_REPL = 273; BS_PDISK = 274; BS_PDISK_TEST = 1102; + BS_PDISK_SHRED = 1103; BS_YARD = 275; BS_PROXY = 276; BS_NODE = 277;