diff --git a/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor.cpp b/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor.cpp index eda96d8f559..df564becf8c 100644 --- a/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor.cpp +++ b/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor.cpp @@ -233,7 +233,7 @@ TStringBuf NormalizeMirrorId(TStringBuf diskId) { bool CheckMirrorDiskId( const TSet& disksInSS, - const TVector disksInBackup, + const TVector& disksInBackup, const NProto::TDiskConfig& disk) { const TString& diskId = disk.GetDiskId(); @@ -532,12 +532,21 @@ void TRestoreValidationActor::HandleListVolumesResponse( ValidSnapshot.DisksToCleanup, NormalizeMirrorId(itr->GetDiskId()))) { - LOG_WARN_S( - ctx, - Component, - RESTORE_PREFIX - << " DiskID " << itr->GetDiskId().Quote() - << " is found in backup but not in SS"); + const bool isShadowDisk = + !itr->GetCheckpointReplica().GetCheckpointId().empty(); + if (isShadowDisk) { + LOG_WARN_S( + ctx, + Component, + RESTORE_PREFIX << " ShadowDisk " << itr->GetDiskId().Quote() + << " is found in backup"); + } else { + LOG_WARN_S( + ctx, + Component, + RESTORE_PREFIX << " DiskID " << itr->GetDiskId().Quote() + << " is found in backup, but not in SS"); + } SetErrorDevicesInBackup(itr->GetDeviceUUIDs(), ctx.Now()); DisksInBackup.erase(itr->GetDiskId()); itr = ValidSnapshot.Disks.erase(itr); diff --git a/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor_ut.cpp b/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor_ut.cpp index 4b8e58c9a40..02e0d5b96b9 100644 --- a/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor_ut.cpp +++ b/cloud/blockstore/libs/storage/disk_registry/actors/restore_validator_actor_ut.cpp @@ -790,6 +790,86 @@ Y_UNIT_TEST_SUITE(TRestoreValidatorActorTest) UNIT_ASSERT_EQUAL( state.Disks[4].GetDiskId(), "Disk 4/1"); } + + Y_UNIT_TEST_F(CheckSkipRestoreShadowDisk, TSetupEnvironment) + { + TDiskRegistryStateSnapshot backup; + { // Source disk + auto& diskConfig = backup.Disks.emplace_back(); + diskConfig.SetDiskId("Disk 1"); + diskConfig.SetFolderId("Folder 1"); + diskConfig.SetCloudId("Cloud 1"); + diskConfig.SetBlockSize(41); + } + { // checkpoint disk + auto& diskConfig = backup.Disks.emplace_back(); + diskConfig.SetDiskId("Disk 1-cp1"); + diskConfig.SetFolderId("Folder 1"); + diskConfig.SetCloudId("Cloud 1"); + diskConfig.SetBlockSize(41); + auto* checkpoint = diskConfig.MutableCheckpointReplica(); + checkpoint->SetSourceDiskId("Disk 1"); + checkpoint->SetCheckpointId("cp1"); + } + + auto validatorId = ActorSystem.Register( + new TRestoreValidationActor(EdgeActor, {}, 0, backup)); + + ActorSystem.GrabEdgeEvent(); + + auto volumeListResponse = + std::make_unique(); + volumeListResponse->Record.AddVolumes("Disk 1"); + + ActorSystem.Send(new NActors::IEventHandle( + validatorId, + EdgeActor, + volumeListResponse.release())); + + ActorSystem.GrabEdgeEvent(); + { + NKikimrSchemeOp::TPathDescription description; + auto* mutableVolumeConfig = + description.MutableBlockStoreVolumeDescription() + ->MutableVolumeConfig(); + mutableVolumeConfig->SetDiskId("Disk 1"); + mutableVolumeConfig->SetBlockSize(41); + mutableVolumeConfig->SetFolderId("Folder 1"); + mutableVolumeConfig->SetCloudId("Cloud 1"); + auto describeVolumeResponse = + std::make_unique( + "", + std::move(description)); + + ActorSystem.Send(new NActors::IEventHandle( + validatorId, + EdgeActor, + describeVolumeResponse.release())); + } + + { + UNIT_ASSERT_EQUAL( + ActorSystem.GrabEdgeEvent() + ->Record.GetDiskId(), + "Disk 1"); + + auto volumeInfoResponse = + std::make_unique(); + auto& volume = *volumeInfoResponse->Record.MutableVolume(); + volume.SetDiskId("Disk 1"); + + ActorSystem.Send(new NActors::IEventHandle( + validatorId, + EdgeActor, + volumeInfoResponse.release())); + } + + auto response = ActorSystem.GrabEdgeEvent< + TEvDiskRegistryPrivate::TEvRestoreDiskRegistryValidationResponse>(); + auto& state = response->LoadDBState; + UNIT_ASSERT_EQUAL(state.Disks.size(), 1); + UNIT_ASSERT_EQUAL(state.Disks[0].GetDiskId(), "Disk 1"); + } } } // namespace NDiskRegistry diff --git a/cloud/blockstore/libs/storage/volume/actors/shadow_disk_actor.cpp b/cloud/blockstore/libs/storage/volume/actors/shadow_disk_actor.cpp index c546e44e47f..24c85d8d182 100644 --- a/cloud/blockstore/libs/storage/volume/actors/shadow_disk_actor.cpp +++ b/cloud/blockstore/libs/storage/volume/actors/shadow_disk_actor.cpp @@ -775,7 +775,9 @@ void TShadowDiskActor::HandleShadowDiskAcquired( } if (HasError(msg->Error)) { - if (acquireReason != EAcquireReason::PeriodicalReAcquire) { + if (msg->Error.GetCode() == E_NOT_FOUND || + acquireReason != EAcquireReason::PeriodicalReAcquire) + { SetErrorState(ctx); } return; diff --git a/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp b/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp index 5387277b656..0b430ef75ee 100644 --- a/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp +++ b/cloud/blockstore/libs/storage/volume/volume_ut_checkpoint.cpp @@ -3725,6 +3725,60 @@ Y_UNIT_TEST_SUITE(TVolumeCheckpointTest) } } + Y_UNIT_TEST(ShouldStopAcquiringAfterENotFound) + { + NProto::TStorageServiceConfig config; + config.SetUseShadowDisksForNonreplDiskCheckpoints(true); + config.SetMaxAcquireShadowDiskTotalTimeoutWhenNonBlocked(2000); + + auto runtime = PrepareTestActorRuntime(config); + + auto describeDiskRequestsFilter = [&](TAutoPtr& event) + { + if (event->GetTypeRewrite() == + TEvDiskRegistry::EvDescribeDiskResponse) + { // Simulate response with E_NOT_FOUND error from DiskRegistry. + auto* msg = + event->Get(); + msg->Record.MutableError()->SetCode(E_NOT_FOUND); + } + return TTestActorRuntime::DefaultObserverFunc(event); + }; + runtime->SetObserverFunc(describeDiskRequestsFilter); + + // Create volume. + TVolumeClient volume(*runtime); + volume.UpdateVolumeConfig( + 0, + 0, + 0, + 0, + false, + 1, + NCloud::NProto::STORAGE_MEDIA_SSD_NONREPLICATED, + 32768); + + volume.WaitReady(); + + auto clientInfo = CreateVolumeClientInfo( + NProto::VOLUME_ACCESS_READ_WRITE, + NProto::VOLUME_MOUNT_LOCAL, + 0); + volume.AddClient(clientInfo); + + // Create checkpoint. + volume.CreateCheckpoint("c1"); + + // Reconnect pipe since partition has restarted. + volume.ReconnectPipe(); + + // Shadow disk entered the error state. + auto status = + volume.GetCheckpointStatus("c1")->Record.GetCheckpointStatus(); + + UNIT_ASSERT_EQUAL(NProto::ECheckpointStatus::ERROR, status); + } + Y_UNIT_TEST(ShouldBlockWritesWhenReAcquire) { NProto::TStorageServiceConfig config;