diff --git a/cloud/blockstore/config/storage.proto b/cloud/blockstore/config/storage.proto index c7fd81f92d..73584b349c 100644 --- a/cloud/blockstore/config/storage.proto +++ b/cloud/blockstore/config/storage.proto @@ -1083,4 +1083,8 @@ message TStorageServiceConfig // percentage, then the rejection of such agents does not occur - we assume // a connectivity failure in the cluster. optional double DiskRegistryInitialAgentRejectionThreshold = 396; + + // When enabled, tag "use-intermediate-write-buffer" will be added + // after scrubbing finds a mismatch + optional bool AutomaticallyEnableBufferCopyingAfterChecksumMismatch = 397; } diff --git a/cloud/blockstore/libs/storage/api/service.h b/cloud/blockstore/libs/storage/api/service.h index c4557506bd..f56a9f9a4b 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 827ad3a8a0..2200212fed 100644 --- a/cloud/blockstore/libs/storage/core/config.cpp +++ b/cloud/blockstore/libs/storage/core/config.cpp @@ -521,6 +521,8 @@ TDuration MSeconds(ui32 value) xxx(EncryptionAtRestForDiskRegistryBasedDisksEnabled, bool, false )\ xxx(DisableFullPlacementGroupCountCalculation, bool, false )\ xxx(DiskRegistryInitialAgentRejectionThreshold, double, 50 )\ + \ + xxx(AutomaticallyEnableBufferCopyingAfterChecksumMismatch, bool, false )\ // BLOCKSTORE_STORAGE_CONFIG_RW #define BLOCKSTORE_STORAGE_CONFIG(xxx) \ diff --git a/cloud/blockstore/libs/storage/core/config.h b/cloud/blockstore/libs/storage/core/config.h index 96ed8b1968..30bf958d1d 100644 --- a/cloud/blockstore/libs/storage/core/config.h +++ b/cloud/blockstore/libs/storage/core/config.h @@ -622,6 +622,8 @@ class TStorageConfig [[nodiscard]] bool GetDisableFullPlacementGroupCountCalculation() const; [[nodiscard]] double GetDiskRegistryInitialAgentRejectionThreshold() 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 144a89a2a2..5c0dfa87f0 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.cpp +++ b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -204,6 +205,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, @@ -271,6 +277,25 @@ void TMirrorPartitionActor::StartResyncRange( BlockDigestGenerator); } +void TMirrorPartitionActor::AddTagForBufferCopying( + const NActors::TActorContext& ctx) +{ + auto requestInfo = CreateRequestInfo( + SelfId(), + 0, // cookie + MakeIntrusive() + ); + + TVector tags(1); + tags.emplace_back(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 7a769b49e0..9c2c3f1a90 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.h +++ b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_actor.h @@ -113,6 +113,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 76d6ce716c..fc1b0562d3 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_ut.cpp +++ b/cloud/blockstore/libs/storage/partition_nonrepl/part_mirror_ut.cpp @@ -257,6 +257,15 @@ struct TTestEnv ) ); + Runtime.AddLocalService( + MakeStorageServiceId(), + TActorSetupCmd( + new TStorageServiceMock(), + TMailboxType::Simple, + 0 + ) + ); + NKikimr::SetupTabletServices(Runtime); } @@ -1176,7 +1185,20 @@ 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) + { + tagEnabled = true; + } + + return false; + }); const auto range1 = TBlockRange64::WithLength(0, 2); env.WriteMirror(range1, 'A'); @@ -1197,6 +1219,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 fde71b6c40..a743a4c44d 100644 --- a/cloud/blockstore/libs/storage/partition_nonrepl/ut_env.h +++ b/cloud/blockstore/libs/storage/partition_nonrepl/ut_env.h @@ -234,6 +234,48 @@ 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.h b/cloud/blockstore/libs/storage/service/service_actor.h index fafda2279b..71b3775f3b 100644 --- a/cloud/blockstore/libs/storage/service/service_actor.h +++ b/cloud/blockstore/libs/storage/service/service_actor.h @@ -208,6 +208,10 @@ class TServiceActor final const TEvService::TEvRunVolumesLivenessCheckResponse::TPtr& ev, const NActors::TActorContext& ctx); + void HandleAddTagsRequest( + const TEvService::TEvAddTagsRequest::TPtr& ev, + const NActors::TActorContext& ctx); + bool HandleRequests(STFUNC_SIG); BLOCKSTORE_STORAGE_SERVICE(BLOCKSTORE_IMPLEMENT_REQUEST, TEvService) 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 242d38f162..64f5332e4d 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::HandleAddTagsRequest( + 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 a655665b38..859d983036 100644 --- a/cloud/blockstore/libs/storage/volume/volume_state.cpp +++ b/cloud/blockstore/libs/storage/volume/volume_state.cpp @@ -308,7 +308,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; } } diff --git a/cloud/blockstore/libs/storage/volume/volume_state.h b/cloud/blockstore/libs/storage/volume/volume_state.h index e2c4c0a320..2b2e516bfb 100644 --- a/cloud/blockstore/libs/storage/volume/volume_state.h +++ b/cloud/blockstore/libs/storage/volume/volume_state.h @@ -43,6 +43,11 @@ using TMigrations = google::protobuf::RepeatedPtrField //////////////////////////////////////////////////////////////////////////////// +constexpr TStringBuf IntermediateWriteBufferTagName = + "use-intermediate-write-buffer"; + +//////////////////////////////////////////////////////////////////////////////// + struct THistoryLogKey { TInstant Timestamp;