diff --git a/cloud/blockstore/config/storage.proto b/cloud/blockstore/config/storage.proto index aa25381fb06..ad82a894ac7 100644 --- a/cloud/blockstore/config/storage.proto +++ b/cloud/blockstore/config/storage.proto @@ -1103,4 +1103,8 @@ message TStorageServiceConfig optional uint32 ForcedCompactionRangeCountPerRun = 401; optional bool YdbViewerServiceEnabled = 402; + + // When enabled, tag "use-intermediate-write-buffer" will be added + // after scrubbing finds a mismatch + optional bool AutomaticallyEnableBufferCopyingAfterChecksumMismatch = 403; } diff --git a/cloud/blockstore/libs/storage/api/public.h b/cloud/blockstore/libs/storage/api/public.h index ea53c0cd95e..b54d57410b0 100644 --- a/cloud/blockstore/libs/storage/api/public.h +++ b/cloud/blockstore/libs/storage/api/public.h @@ -6,6 +6,11 @@ namespace NCloud::NBlockStore::NStorage { +//////////////////////////////////////////////////////////////////////////////// + +constexpr TStringBuf IntermediateWriteBufferTagName = + "use-intermediate-write-buffer"; + //////////////////////////////////////////////////////////////////////////////// // BackpressureReport event descriptor diff --git a/cloud/blockstore/libs/storage/api/service.h b/cloud/blockstore/libs/storage/api/service.h index c4557506bd2..f56a9f9a4b0 100644 --- a/cloud/blockstore/libs/storage/api/service.h +++ b/cloud/blockstore/libs/storage/api/service.h @@ -19,6 +19,7 @@ namespace NCloud::NBlockStore::NStorage { xxx(ChangeVolumeBinding, __VA_ARGS__) \ xxx(GetVolumeStats, __VA_ARGS__) \ xxx(RunVolumesLivenessCheck, __VA_ARGS__) \ + xxx(AddTags, __VA_ARGS__) \ // BLOCKSTORE_SERVICE_REQUESTS //////////////////////////////////////////////////////////////////////////////// @@ -160,6 +161,28 @@ struct TEvService {} }; + // + // AddTags + // + + struct TAddTagsRequest + { + const TString DiskId; + const TVector Tags; + + TAddTagsRequest() = default; + + TAddTagsRequest( + TString diskId, + TVector tags) + : DiskId(std::move(diskId)) + , Tags(std::move(tags)) + {} + }; + + struct TAddTagsResponse + {}; + // // VolumeMountStateChanged // @@ -317,6 +340,9 @@ struct TEvService EvQueryAgentsInfoRequest = EvBegin + 89, EvQueryAgentsInfoResponse = EvBegin + 90, + EvAddTagsRequest = EvBegin + 91, + EvAddTagsResponse = EvBegin + 92, + EvEnd }; diff --git a/cloud/blockstore/libs/storage/core/config.cpp b/cloud/blockstore/libs/storage/core/config.cpp index ab3be9af149..2df913d52bf 100644 --- a/cloud/blockstore/libs/storage/core/config.cpp +++ b/cloud/blockstore/libs/storage/core/config.cpp @@ -512,6 +512,7 @@ TDuration MSeconds(ui32 value) xxx(ScrubbingBandwidth, ui64, 20 )\ xxx(MaxScrubbingBandwidth, ui64, 50 )\ xxx(MinScrubbingBandwidth, ui64, 5 )\ + xxx(AutomaticallyEnableBufferCopyingAfterChecksumMismatch, bool, false )\ \ xxx(OptimizeVoidBuffersTransferForReadsEnabled, bool, false )\ xxx(VolumeHistoryCleanupItemCount, ui32, 100'000 )\ diff --git a/cloud/blockstore/libs/storage/core/config.h b/cloud/blockstore/libs/storage/core/config.h index 94f5fe3b970..440b68ef0ae 100644 --- a/cloud/blockstore/libs/storage/core/config.h +++ b/cloud/blockstore/libs/storage/core/config.h @@ -631,6 +631,8 @@ class TStorageConfig [[nodiscard]] bool GetCalculateSplittedUsedQuotaMetric() const; bool GetYdbViewerServiceEnabled() const; + + bool GetAutomaticallyEnableBufferCopyingAfterChecksumMismatch() const; }; ui64 GetAllocationUnit( diff --git a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.cpp b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.cpp index f120d037ae4..1931a9da47f 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.cpp +++ b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.cpp @@ -208,6 +208,11 @@ void TMirrorPartitionActor::CompareChecksums(const TActorContext& ctx) DiskId.c_str(), DescribeRange(GetScrubbingRange()).c_str()); + if (Config->GetAutomaticallyEnableBufferCopyingAfterChecksumMismatch()) + { + AddTagForBufferCopying(ctx); + } + for (size_t i = 0; i < checksums.size(); i++) { LOG_ERROR( ctx, @@ -275,6 +280,22 @@ void TMirrorPartitionActor::StartResyncRange( BlockDigestGenerator); } +void TMirrorPartitionActor::AddTagForBufferCopying( + const NActors::TActorContext& ctx) +{ + auto requestInfo = CreateRequestInfo( + SelfId(), + 0, // cookie + MakeIntrusive()); + + TVector tags({TString(IntermediateWriteBufferTagName)}); + auto request = std::make_unique( + DiskId, + std::move(tags)); + + ctx.Send(MakeStorageServiceId(), std::move(request)); +} + void TMirrorPartitionActor::ReplyAndDie(const TActorContext& ctx) { NCloud::Reply(ctx, *Poisoner, std::make_unique()); diff --git a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.h b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.h index 60106832fcd..8679a972908 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.h +++ b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.h @@ -116,6 +116,7 @@ class TMirrorPartitionActor final const NActors::TActorContext& ctx, ui64 scrubbingRangeId); void StartResyncRange(const NActors::TActorContext& ctx); + void AddTagForBufferCopying(const NActors::TActorContext& ctx); private: STFUNC(StateWork); diff --git a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_ut.cpp b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_ut.cpp index ad9e6c31f5f..f2637a694be 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_ut.cpp +++ b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_ut.cpp @@ -259,6 +259,10 @@ struct TTestEnv ) ); + Runtime.AddLocalService( + MakeStorageServiceId(), + TActorSetupCmd(new TStorageServiceMock(), TMailboxType::Simple, 0)); + NKikimr::SetupTabletServices(Runtime); } @@ -1179,7 +1183,25 @@ Y_UNIT_TEST_SUITE(TMirrorPartitionTest) TDynamicCountersPtr critEventsCounters = new TDynamicCounters(); InitCriticalEventsCounter(critEventsCounters); - TTestEnv env(runtime); + NProto::TStorageServiceConfig config; + config.SetAutomaticallyEnableBufferCopyingAfterChecksumMismatch(true); + TTestEnv env(runtime, config); + + bool tagEnabled = false; + runtime.SetEventFilter([&] (auto& runtime, auto& event) { + Y_UNUSED(runtime); + if (event->GetTypeRewrite() == TEvService::EvAddTagsRequest) + { + using TRequest = + TEvService::TEvAddTagsRequest; + const auto& tags = event->template Get()->Tags; + UNIT_ASSERT_VALUES_EQUAL(1, tags.size()); + UNIT_ASSERT_VALUES_EQUAL(IntermediateWriteBufferTagName, tags[0]); + tagEnabled = true; + } + + return false; + }); const auto range1 = TBlockRange64::WithLength(0, 2); env.WriteMirror(range1, 'A'); @@ -1200,6 +1222,7 @@ Y_UNIT_TEST_SUITE(TMirrorPartitionTest) UNIT_ASSERT_VALUES_EQUAL(2, mirroredDiskMinorityChecksumMismatch->Val()); UNIT_ASSERT_VALUES_EQUAL(2, counters.Simple.ChecksumMismatches.Value); + UNIT_ASSERT(tagEnabled); const auto range3 = TBlockRange64::WithLength(1025, 50); env.WriteMirror(range3, 'A'); diff --git a/cloud/blockstore/libs/storage/partition_nonrepl/ut_env.h b/cloud/blockstore/libs/storage/partition_nonrepl/ut_env.h index 1994bf4e812..09b35fdbe05 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/ut_env.h +++ b/cloud/blockstore/libs/storage/partition_nonrepl/ut_env.h @@ -236,6 +236,47 @@ class TDummyActor final //////////////////////////////////////////////////////////////////////////////// +class TStorageServiceMock final: public NActors::TActor +{ +public: + TStorageServiceMock() + : TActor(&TThis::StateWork) + { + } + +private: + STFUNC(StateWork) + { + switch (ev->GetTypeRewrite()) { + HFunc(NActors::TEvents::TEvPoisonPill, HandlePoisonPill); + + HFunc(TEvService::TEvAddTagsRequest, HandleAddTagsRequest); + + default: + Y_ABORT("Unexpected event %x", ev->GetTypeRewrite()); + } + } + + void HandlePoisonPill( + const NActors::TEvents::TEvPoisonPill::TPtr& ev, + const NActors::TActorContext& ctx) + { + Y_UNUSED(ev); + + Die(ctx); + } + + void HandleAddTagsRequest( + const TEvService::TEvAddTagsRequest::TPtr& ev, + const NActors::TActorContext& ctx) + { + Y_UNUSED(ev); + Y_UNUSED(ctx); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + class TPartitionClient { private: diff --git a/cloud/blockstore/libs/storage/service/service_actor_actions_modify_tags.cpp b/cloud/blockstore/libs/storage/service/service_actor_actions_modify_tags.cpp index 242d38f162a..46f652a072c 100644 --- a/cloud/blockstore/libs/storage/service/service_actor_actions_modify_tags.cpp +++ b/cloud/blockstore/libs/storage/service/service_actor_actions_modify_tags.cpp @@ -352,6 +352,35 @@ STFUNC(TModifyTagsActionActor::StateWaitReady) //////////////////////////////////////////////////////////////////////////////// +void TServiceActor::HandleAddTags( + const TEvService::TEvAddTagsRequest::TPtr& ev, + const NActors::TActorContext& ctx) +{ + auto* msg = ev->Get(); + + auto requestInfo = CreateRequestInfo( + SelfId(), + 0, // cookie + MakeIntrusive()); + + NPrivateProto::TModifyTagsRequest modifyTagsRequest; + modifyTagsRequest.SetDiskId(msg->DiskId); + for (const auto& tag: msg->Tags) { + modifyTagsRequest.AddTagsToAdd(tag); + } + + TString input; + google::protobuf::util::MessageToJsonString(modifyTagsRequest, &input); + + NCloud::Register( + ctx, + std::make_unique( + std::move(requestInfo), + std::move(input))); +} + +//////////////////////////////////////////////////////////////////////////////// + TResultOrError TServiceActor::CreateModifyTagsActionActor( TRequestInfoPtr requestInfo, TString input) diff --git a/cloud/blockstore/libs/storage/volume/volume_state.cpp b/cloud/blockstore/libs/storage/volume/volume_state.cpp index 2a8fbd0d8ec..8d9cbd8ea9c 100644 --- a/cloud/blockstore/libs/storage/volume/volume_state.cpp +++ b/cloud/blockstore/libs/storage/volume/volume_state.cpp @@ -310,7 +310,7 @@ void TVolumeState::Reset() TDuration::TryParse(value, MaxTimedOutDeviceStateDuration); } else if (tag == "use-fastpath") { UseFastPath = true; - } else if (tag == "use-intermediate-write-buffer") { + } else if (tag == IntermediateWriteBufferTagName) { UseIntermediateWriteBuffer = true; } }