diff --git a/cloud/blockstore/libs/storage/volume/testlib/test_env.cpp b/cloud/blockstore/libs/storage/volume/testlib/test_env.cpp index c2a563fb7c4..700385cd934 100644 --- a/cloud/blockstore/libs/storage/volume/testlib/test_env.cpp +++ b/cloud/blockstore/libs/storage/volume/testlib/test_env.cpp @@ -369,11 +369,18 @@ std::unique_ptr TVolumeClient::CreateDescri std::unique_ptr TVolumeClient::CreateCreateCheckpointRequest( const TString& checkpointId, - bool isLight) + bool isLight, + bool withoutData) { auto request = std::make_unique(); request->Record.SetCheckpointId(checkpointId); - request->Record.SetIsLight(isLight); + if (withoutData) { + request->Record.SetCheckpointType(NProto::ECheckpointType::WITHOUT_DATA); + } else if (isLight) { + request->Record.SetCheckpointType(NProto::ECheckpointType::LIGHT); + } else { + request->Record.SetCheckpointType(NProto::ECheckpointType::NORMAL); + } return request; } diff --git a/cloud/blockstore/libs/storage/volume/testlib/test_env.h b/cloud/blockstore/libs/storage/volume/testlib/test_env.h index d6e0b57f2cd..4c470bc57fb 100644 --- a/cloud/blockstore/libs/storage/volume/testlib/test_env.h +++ b/cloud/blockstore/libs/storage/volume/testlib/test_env.h @@ -393,7 +393,8 @@ class TVolumeClient std::unique_ptr CreateCreateCheckpointRequest( const TString& checkpointId, - bool isLight = false); + bool isLight = false, + bool withoutData = false); std::unique_ptr CreateDeleteCheckpointRequest( const TString& checkpointId); diff --git a/cloud/blockstore/libs/storage/volume/volume_actor_checkpoint.cpp b/cloud/blockstore/libs/storage/volume/volume_actor_checkpoint.cpp index 04d9e870a1c..c2ab0b20ed9 100644 --- a/cloud/blockstore/libs/storage/volume/volume_actor_checkpoint.cpp +++ b/cloud/blockstore/libs/storage/volume/volume_actor_checkpoint.cpp @@ -138,6 +138,7 @@ class TCheckpointActor final const TActorId VolumeActorId; const TPartitionDescrs PartitionDescrs; const TRequestTraceInfo TraceInfo; + const ECheckpointRequestType RequestType; const bool CreateCheckpointShadowDisk; ui32 DrainResponses = 0; @@ -156,6 +157,7 @@ class TCheckpointActor final TActorId volumeActorId, TPartitionDescrs partitionDescrs, TRequestTraceInfo traceInfo, + ECheckpointRequestType requestType, bool createCheckpointShadowDisk); void Bootstrap(const TActorContext& ctx); @@ -228,6 +230,7 @@ TCheckpointActor::TCheckpointActor( TActorId volumeActorId, TPartitionDescrs partitionDescrs, TRequestTraceInfo traceInfo, + ECheckpointRequestType requestType, bool createCheckpointShadowDisk) : RequestInfo(std::move(requestInfo)) , RequestId(requestId) @@ -237,6 +240,7 @@ TCheckpointActor::TCheckpointActor( , VolumeActorId(volumeActorId) , PartitionDescrs(std::move(partitionDescrs)) , TraceInfo(std::move(traceInfo)) + , RequestType(requestType) , CreateCheckpointShadowDisk(createCheckpointShadowDisk) , ChildCallContexts(Reserve(PartitionDescrs.size())) {} @@ -687,6 +691,13 @@ void TCheckpointActor::DoActionForBlobStorageBasedPartition( const auto selfId = TBase::SelfId(); auto request = std::make_unique(); request->Record.SetCheckpointId(CheckpointId); + if constexpr (std::is_same_v) { + request->Record.SetCheckpointType( + RequestType == ECheckpointRequestType::CreateWithoutData + ? NProto::ECheckpointType::WITHOUT_DATA + : NProto::ECheckpointType::NORMAL + ); + } ForkTraces(request->CallContext); @@ -1155,6 +1166,7 @@ void TVolumeActor::ProcessNextCheckpointRequest(const TActorContext& ctx) requestInfo->IsTraced, requestInfo->TraceTs, TraceSerializer), + request.ReqType, Config->GetUseShadowDisksForNonreplDiskCheckpoints()); break; } @@ -1179,6 +1191,7 @@ void TVolumeActor::ProcessNextCheckpointRequest(const TActorContext& ctx) requestInfo->IsTraced, requestInfo->TraceTs, TraceSerializer), + request.ReqType, Config->GetUseShadowDisksForNonreplDiskCheckpoints()); break; } @@ -1197,6 +1210,7 @@ void TVolumeActor::ProcessNextCheckpointRequest(const TActorContext& ctx) requestInfo->IsTraced, requestInfo->TraceTs, TraceSerializer), + request.ReqType, Config->GetUseShadowDisksForNonreplDiskCheckpoints()); break; } diff --git a/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp b/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp index 71fc7f205e5..329924d22bd 100644 --- a/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp +++ b/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp @@ -1884,6 +1884,74 @@ Y_UNIT_TEST_SUITE(TVolumeCheckpointTest) } } + Y_UNIT_TEST(ShouldNotReadFromCheckpointWithoutData) + { + NProto::TStorageServiceConfig config; + auto runtime = PrepareTestActorRuntime(config); + + TVolumeClient volume(*runtime); + volume.UpdateVolumeConfig(); + + volume.WaitReady(); + + auto clientInfo = CreateVolumeClientInfo( + NProto::VOLUME_ACCESS_READ_WRITE, + NProto::VOLUME_MOUNT_LOCAL, + 0); + volume.AddClient(clientInfo); + + volume.WriteBlocks( + TBlockRange64::WithLength(0, 1024), + clientInfo.GetClientId(), + 1); + volume.CreateCheckpoint("c1", false, true); + volume.WriteBlocks( + TBlockRange64::WithLength(0, 1024), + clientInfo.GetClientId(), + 2); + + { + // Read from checkpoint without data failed + volume.SendReadBlocksRequest( + GetBlockRangeById(0), + clientInfo.GetClientId(), + "c1"); + + auto response = volume.RecvReadBlocksResponse(); + UNIT_ASSERT_VALUES_EQUAL(E_NOT_FOUND, response->GetStatus()); + UNIT_ASSERT_VALUES_EQUAL( + "checkpoint not found: \"c1\"", + response->GetError().GetMessage()); + UNIT_ASSERT(HasProtoFlag( + response->GetError().GetFlags(), + NProto::EF_SILENT)); + } + + volume.CreateCheckpoint("c2"); + volume.DeleteCheckpointData("c2"); + volume.WriteBlocks( + TBlockRange64::WithLength(0, 1024), + clientInfo.GetClientId(), + 2); + + { + // Read from checkpoint without data failed + volume.SendReadBlocksRequest( + GetBlockRangeById(0), + clientInfo.GetClientId(), + "c2"); + + auto response = volume.RecvReadBlocksResponse(); + UNIT_ASSERT_VALUES_EQUAL(E_NOT_FOUND, response->GetStatus()); + UNIT_ASSERT_VALUES_EQUAL( + "checkpoint not found: \"c2\"", + response->GetError().GetMessage()); + UNIT_ASSERT(HasProtoFlag( + response->GetError().GetFlags(), + NProto::EF_SILENT)); + } + } + Y_UNIT_TEST(ShouldNotRejectRZRequestsDuringSinglePartionCheckpointCreation) { NProto::TStorageServiceConfig config;