diff options
| author | babenko <[email protected]> | 2026-04-12 13:31:27 +0300 |
|---|---|---|
| committer | babenko <[email protected]> | 2026-04-12 14:03:33 +0300 |
| commit | 2f678ac94fa0e9aeffde6130e9015786e7ea4ed3 (patch) | |
| tree | 7355bafd4df46c0670182161ef2c25980436e764 | |
| parent | 1dd39b59f3963c032eba42bffb547d849e33502e (diff) | |
YT-27910: Make some more fields in TServiceContext atomic
commit_hash:24a87198c8fc53da983f9678679b990070e329b8
| -rw-r--r-- | library/cpp/yt/containers/sentinel_optional-inl.h | 118 | ||||
| -rw-r--r-- | library/cpp/yt/containers/sentinel_optional.h | 114 | ||||
| -rw-r--r-- | library/cpp/yt/containers/unittests/sentinel_optional_ut.cpp | 291 | ||||
| -rw-r--r-- | library/cpp/yt/containers/unittests/ya.make | 1 | ||||
| -rw-r--r-- | yt/yt/core/rpc/service_detail.cpp | 90 |
5 files changed, 581 insertions, 33 deletions
diff --git a/library/cpp/yt/containers/sentinel_optional-inl.h b/library/cpp/yt/containers/sentinel_optional-inl.h new file mode 100644 index 00000000000..c16f843f8a6 --- /dev/null +++ b/library/cpp/yt/containers/sentinel_optional-inl.h @@ -0,0 +1,118 @@ +#ifndef SENTINEL_OPTIONAL_INL_H_ +#error "Direct inclusion of this file is not allowed, include sentinel_optional.h" +// For the sake of sane code completion. +#include "sentinel_optional.h" +#endif + +#include <library/cpp/yt/assert/assert.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>::TSentinelOptional(std::nullopt_t) noexcept + : Value_(TSentinel::Sentinel) +{ } + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>::TSentinelOptional(T value) noexcept + : Value_(value) +{ } + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>::TSentinelOptional(std::optional<T> opt) noexcept + : Value_(opt.has_value() ? *opt : TSentinel::Sentinel) +{ } + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>& TSentinelOptional<T, TSentinel>::operator=(std::nullopt_t) noexcept +{ + Value_ = TSentinel::Sentinel; + return *this; +} + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>& TSentinelOptional<T, TSentinel>::operator=(T value) noexcept +{ + Value_ = value; + return *this; +} + +template <class T, class TSentinel> +constexpr bool TSentinelOptional<T, TSentinel>::has_value() const noexcept +{ + return Value_ != TSentinel::Sentinel; +} + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>::operator bool() const noexcept +{ + return has_value(); +} + +template <class T, class TSentinel> +constexpr T& TSentinelOptional<T, TSentinel>::operator*() noexcept +{ + return Value_; +} + +template <class T, class TSentinel> +constexpr const T& TSentinelOptional<T, TSentinel>::operator*() const noexcept +{ + return Value_; +} + +template <class T, class TSentinel> +constexpr T* TSentinelOptional<T, TSentinel>::operator->() noexcept +{ + return &Value_; +} + +template <class T, class TSentinel> +constexpr const T* TSentinelOptional<T, TSentinel>::operator->() const noexcept +{ + return &Value_; +} + +template <class T, class TSentinel> +T& TSentinelOptional<T, TSentinel>::value() noexcept +{ + YT_ASSERT(has_value()); + return Value_; +} + +template <class T, class TSentinel> +const T& TSentinelOptional<T, TSentinel>::value() const noexcept +{ + YT_ASSERT(has_value()); + return Value_; +} + +template <class T, class TSentinel> +constexpr T TSentinelOptional<T, TSentinel>::value_or(T default_value) const noexcept +{ + return has_value() ? Value_ : default_value; +} + +template <class T, class TSentinel> +constexpr void TSentinelOptional<T, TSentinel>::reset() noexcept +{ + Value_ = TSentinel::Sentinel; +} + +template <class T, class TSentinel> +constexpr TSentinelOptional<T, TSentinel>::operator std::optional<T>() const noexcept +{ + return has_value() ? std::optional<T>(Value_) : std::nullopt; +} + +template <class T, class TSentinel> +constexpr bool TSentinelOptional<T, TSentinel>::operator==(std::nullopt_t) const noexcept +{ + return !has_value(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/containers/sentinel_optional.h b/library/cpp/yt/containers/sentinel_optional.h new file mode 100644 index 00000000000..1d573550db9 --- /dev/null +++ b/library/cpp/yt/containers/sentinel_optional.h @@ -0,0 +1,114 @@ +#pragma once + +#include <optional> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +//! Convenience sentinel traits for structural types (integers, enums, pointers). +/*! + * Usage: |TSentinelOptional<int, TValueSentinel<-1>>| + */ +template <auto V> +struct TValueSentinel +{ + static constexpr auto Sentinel = V; +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! A compact alternative to |std::optional<T>| that uses a sentinel value +//! to represent the null state rather than an additional boolean field. +/*! + * The null state is represented by |TSentinel::Sentinel| of type |T|. + * The stored representation is exactly one |T|, so: + * sizeof(TSentinelOptional<T, TSentinel>) == sizeof(T) + * alignof(TSentinelOptional<T, TSentinel>) == alignof(T) + * + * Whenever |T| is trivially copyable the class is also trivially copyable, + * which guarantees that |std::atomic<TSentinelOptional<T, TSentinel>>| is lock-free + * if and only if |std::atomic<T>| is lock-free. + * + * The interface is a drop-in replacement for |std::optional<T>|. + * + * |TSentinel| must provide a |static constexpr T Sentinel| member. + * For structural types, use |TValueSentinel<V>| as a convenience. + */ +template <class T, class TSentinel> +class TSentinelOptional +{ +public: + using value_type = T; + + //! Constructs a null optional (stores the sentinel value). + constexpr TSentinelOptional() = default; + + //! Constructs a null optional. + constexpr TSentinelOptional(std::nullopt_t) noexcept; + + //! Constructs an optional holding |value|. + /*! + * \note The behavior is undefined if |value == TSentinel::Sentinel|. + */ + constexpr TSentinelOptional(T value) noexcept; + + //! Converts from |std::optional<T>|; nullopt maps to the null state. + constexpr TSentinelOptional(std::optional<T> opt) noexcept; + + constexpr TSentinelOptional(const TSentinelOptional&) = default; + constexpr TSentinelOptional(TSentinelOptional&&) = default; + + constexpr TSentinelOptional& operator=(const TSentinelOptional&) = default; + constexpr TSentinelOptional& operator=(TSentinelOptional&&) = default; + + //! Resets to null. + constexpr TSentinelOptional& operator=(std::nullopt_t) noexcept; + + //! Assigns |value|. + /*! + * \note The behavior is undefined if |value == TSentinel::Sentinel|. + */ + constexpr TSentinelOptional& operator=(T value) noexcept; + + //! Returns |true| iff the optional holds a value (i.e., the stored value differs from the sentinel). + [[nodiscard]] constexpr bool has_value() const noexcept; + + //! Returns |true| iff the optional holds a value. + constexpr explicit operator bool() const noexcept; + + //! Returns a reference to the held value; behavior is undefined if null. + constexpr T& operator*() noexcept; + constexpr const T& operator*() const noexcept; + + //! Returns a pointer to the held value; behavior is undefined if null. + constexpr T* operator->() noexcept; + constexpr const T* operator->() const noexcept; + + //! Returns a reference to the held value; aborts if null. + T& value() noexcept; + const T& value() const noexcept; + + //! Returns the held value if present, otherwise |default_value|. + constexpr T value_or(T default_value) const noexcept; + + //! Resets to null (equivalent to assigning |std::nullopt|). + constexpr void reset() noexcept; + + //! Converts to |std::optional<T>|; the null state maps to nullopt. + constexpr operator std::optional<T>() const noexcept; + + constexpr bool operator==(const TSentinelOptional& other) const = default; + [[nodiscard]] constexpr bool operator==(std::nullopt_t) const noexcept; + +private: + T Value_ = TSentinel::Sentinel; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define SENTINEL_OPTIONAL_INL_H_ +#include "sentinel_optional-inl.h" +#undef SENTINEL_OPTIONAL_INL_H_ diff --git a/library/cpp/yt/containers/unittests/sentinel_optional_ut.cpp b/library/cpp/yt/containers/unittests/sentinel_optional_ut.cpp new file mode 100644 index 00000000000..64ec5a04367 --- /dev/null +++ b/library/cpp/yt/containers/unittests/sentinel_optional_ut.cpp @@ -0,0 +1,291 @@ +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/containers/sentinel_optional.h> + +#include <atomic> +#include <type_traits> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +using TIntOpt = TSentinelOptional<int, TValueSentinel<-1>>; + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TSentinelOptionalTest, DefaultConstructNull) +{ + TIntOpt opt; + EXPECT_FALSE(opt.has_value()); + EXPECT_FALSE(static_cast<bool>(opt)); + EXPECT_EQ(opt, std::nullopt); +} + +TEST(TSentinelOptionalTest, NulloptConstruct) +{ + TIntOpt opt(std::nullopt); + EXPECT_FALSE(opt.has_value()); + EXPECT_EQ(opt, std::nullopt); +} + +TEST(TSentinelOptionalTest, ValueConstruct) +{ + TIntOpt opt(42); + EXPECT_TRUE(opt.has_value()); + EXPECT_TRUE(static_cast<bool>(opt)); + EXPECT_EQ(*opt, 42); +} + +TEST(TSentinelOptionalTest, ZeroIsNotNull) +{ + TIntOpt opt(0); + EXPECT_TRUE(opt.has_value()); + EXPECT_EQ(*opt, 0); +} + +TEST(TSentinelOptionalTest, AssignValue) +{ + TIntOpt opt; + opt = 7; + EXPECT_TRUE(opt.has_value()); + EXPECT_EQ(*opt, 7); +} + +TEST(TSentinelOptionalTest, AssignNullopt) +{ + TIntOpt opt(7); + opt = std::nullopt; + EXPECT_FALSE(opt.has_value()); +} + +TEST(TSentinelOptionalTest, Reset) +{ + TIntOpt opt(7); + opt.reset(); + EXPECT_FALSE(opt.has_value()); + EXPECT_EQ(opt, std::nullopt); +} + +TEST(TSentinelOptionalTest, Dereference) +{ + TIntOpt opt(99); + EXPECT_EQ(*opt, 99); + *opt = 100; + EXPECT_EQ(*opt, 100); +} + +TEST(TSentinelOptionalTest, ArrowOperator) +{ + TSentinelOptional<int, TValueSentinel<0>> opt(42); + EXPECT_EQ(*opt.operator->(), 42); +} + +TEST(TSentinelOptionalTest, ValueChecked) +{ + TIntOpt opt(5); + EXPECT_EQ(opt.value(), 5); + opt.value() = 10; + EXPECT_EQ(opt.value(), 10); +} + +TEST(TSentinelOptionalTest, ValueOr) +{ + TIntOpt opt; + EXPECT_EQ(opt.value_or(42), 42); + + opt = 7; + EXPECT_EQ(opt.value_or(42), 7); +} + +TEST(TSentinelOptionalTest, EqualityBetweenOptionals) +{ + TIntOpt a; + TIntOpt b; + EXPECT_EQ(a, b); + + a = 5; + EXPECT_NE(a, b); + + b = 5; + EXPECT_EQ(a, b); + + b = 6; + EXPECT_NE(a, b); +} + +TEST(TSentinelOptionalTest, EqualityWithNullopt) +{ + TIntOpt opt; + EXPECT_EQ(opt, std::nullopt); + EXPECT_EQ(std::nullopt, opt); + + opt = 1; + EXPECT_NE(opt, std::nullopt); + EXPECT_NE(std::nullopt, opt); +} + +TEST(TSentinelOptionalTest, CopyConstruct) +{ + TIntOpt a(3); + TIntOpt b = a; + EXPECT_EQ(*b, 3); + *a = 4; + EXPECT_EQ(*b, 3); // b is independent +} + +TEST(TSentinelOptionalTest, CopyAssign) +{ + TIntOpt a(3); + TIntOpt b; + b = a; + EXPECT_EQ(*b, 3); +} + +TEST(TSentinelOptionalTest, ConstAccess) +{ + const TIntOpt opt(77); + EXPECT_EQ(*opt, 77); + EXPECT_EQ(opt.value(), 77); + EXPECT_EQ(*opt.operator->(), 77); +} + +//////////////////////////////////////////////////////////////////////////////// +// Pointer sentinel. + +using TPtrOpt = TSentinelOptional<int*, TValueSentinel<nullptr>>; + +TEST(TSentinelOptionalTest, PointerSentinel) +{ + TPtrOpt opt; + EXPECT_FALSE(opt.has_value()); + + int x = 42; + opt = &x; + EXPECT_TRUE(opt.has_value()); + EXPECT_EQ(*opt, &x); + EXPECT_EQ(**opt, 42); +} + +//////////////////////////////////////////////////////////////////////////////// +// Enum sentinel. + +enum class EColor +{ + Red, + Green, + Blue, + Unknown, +}; + +using TColorOpt = TSentinelOptional<EColor, TValueSentinel<EColor::Unknown>>; + +TEST(TSentinelOptionalTest, EnumSentinel) +{ + TColorOpt opt; + EXPECT_FALSE(opt.has_value()); + + opt = EColor::Red; + EXPECT_TRUE(opt.has_value()); + EXPECT_EQ(*opt, EColor::Red); + + opt.reset(); + EXPECT_FALSE(opt.has_value()); +} + +//////////////////////////////////////////////////////////////////////////////// +// Layout and atomic guarantees. + +TEST(TSentinelOptionalTest, SizeEqualsUnderlyingType) +{ + static_assert(sizeof(TIntOpt) == sizeof(int)); + static_assert(sizeof(TPtrOpt) == sizeof(int*)); + static_assert(sizeof(TColorOpt) == sizeof(EColor)); +} + +TEST(TSentinelOptionalTest, TriviallyCopyable) +{ + static_assert(std::is_trivially_copyable_v<TIntOpt>); + static_assert(std::is_trivially_copyable_v<TPtrOpt>); + static_assert(std::is_trivially_copyable_v<TColorOpt>); +} + +TEST(TSentinelOptionalTest, AtomicLockFree) +{ + // std::atomic<TSentinelOptional<T, S>> must be lock-free whenever + // std::atomic<T> is lock-free. + if (std::atomic<int>{}.is_lock_free()) { + EXPECT_TRUE((std::atomic<TIntOpt>{}.is_lock_free())); + } + if (std::atomic<int*>{}.is_lock_free()) { + EXPECT_TRUE((std::atomic<TPtrOpt>{}.is_lock_free())); + } + if (std::atomic<EColor>{}.is_lock_free()) { + EXPECT_TRUE((std::atomic<TColorOpt>{}.is_lock_free())); + } +} + +TEST(TSentinelOptionalTest, AtomicStoreLoad) +{ + std::atomic<TIntOpt> a; + a.store(TIntOpt{}); + EXPECT_FALSE(a.load().has_value()); + + a.store(TIntOpt{42}); + EXPECT_EQ(*a.load(), 42); + + a.store(std::nullopt); + EXPECT_FALSE(a.load().has_value()); +} + +//////////////////////////////////////////////////////////////////////////////// +// std::optional conversions. + +TEST(TSentinelOptionalTest, FromStdOptionalNull) +{ + TIntOpt opt = std::optional<int>{}; + EXPECT_FALSE(opt.has_value()); + EXPECT_EQ(opt, std::nullopt); +} + +TEST(TSentinelOptionalTest, FromStdOptionalValue) +{ + TIntOpt opt = std::optional<int>{42}; + EXPECT_TRUE(opt.has_value()); + EXPECT_EQ(*opt, 42); +} + +TEST(TSentinelOptionalTest, ToStdOptionalNull) +{ + TIntOpt opt; + std::optional<int> stdOpt = opt; + EXPECT_FALSE(stdOpt.has_value()); +} + +TEST(TSentinelOptionalTest, ToStdOptionalValue) +{ + TIntOpt opt(7); + std::optional<int> stdOpt = opt; + EXPECT_TRUE(stdOpt.has_value()); + EXPECT_EQ(*stdOpt, 7); +} + +TEST(TSentinelOptionalTest, RoundTripThroughStdOptional) +{ + TIntOpt original(99); + TIntOpt roundTripped = std::optional<int>(original); + EXPECT_TRUE(roundTripped.has_value()); + EXPECT_EQ(*roundTripped, 99); +} + +TEST(TSentinelOptionalTest, RoundTripNullThroughStdOptional) +{ + TIntOpt original; + TIntOpt roundTripped = std::optional<int>(original); + EXPECT_FALSE(roundTripped.has_value()); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/containers/unittests/ya.make b/library/cpp/yt/containers/unittests/ya.make index 232fa2e0e5b..aa5aac875c8 100644 --- a/library/cpp/yt/containers/unittests/ya.make +++ b/library/cpp/yt/containers/unittests/ya.make @@ -9,6 +9,7 @@ SRCS( expiring_set_ut.cpp non_empty_ut.cpp ordered_hash_map_ut.cpp + sentinel_optional_ut.cpp sharded_set_ut.cpp ) diff --git a/yt/yt/core/rpc/service_detail.cpp b/yt/yt/core/rpc/service_detail.cpp index 9a502c57314..f51de7ae1f1 100644 --- a/yt/yt/core/rpc/service_detail.cpp +++ b/yt/yt/core/rpc/service_detail.cpp @@ -7,7 +7,6 @@ #include "helpers.h" #include "message.h" #include "request_queue_provider.h" -#include "response_keeper.h" #include "server_detail.h" #include "stream.h" @@ -34,6 +33,8 @@ #include <library/cpp/yt/misc/tls.h> +#include <library/cpp/yt/containers/sentinel_optional.h> + namespace NYT::NRpc { using namespace NBus; @@ -542,7 +543,7 @@ public: AbortStreamsUnlessClosed(TError(NYT::EErrorCode::Canceled, "Request canceled")); } - CancelInstant_ = NProfiling::GetInstant(); + CancelInstant_.store(NProfiling::GetInstant(), std::memory_order::release); MethodPerformanceCounters_->CanceledRequestCounter.Increment(); } @@ -587,15 +588,15 @@ public: std::optional<TInstant> GetRunInstant() const override { - return RunInstant_; + return RunInstant_.load(std::memory_order::acquire); } std::optional<TInstant> GetFinishInstant() const override { - if (ReplyInstant_) { - return ReplyInstant_; - } else if (CancelInstant_) { - return CancelInstant_; + if (auto replyInstant = ReplyInstant_.load(std::memory_order::acquire)) { + return replyInstant; + } else if (auto cancelInstant = CancelInstant_.load(std::memory_order::acquire)) { + return cancelInstant; } else { return std::nullopt; } @@ -603,19 +604,20 @@ public: std::optional<TDuration> GetWaitDuration() const override { - return LocalWaitTime_; + return LocalWaitTime_.load(std::memory_order::acquire); } std::optional<TDuration> GetExecutionDuration() const override { - return ExecutionTime_; + return ExecutionTime_.load(std::memory_order::acquire); } void RecordThrottling(TDuration throttleDuration) override { - ThrottlingTime_ = ThrottlingTime_ + throttleDuration; - if (ExecutionTime_) { - *ExecutionTime_ -= throttleDuration; + ThrottlingTime_.store(ThrottlingTime_.load(std::memory_order::acquire) + + throttleDuration, std::memory_order::release); + if (auto executionTime = ExecutionTime_.load(std::memory_order::acquire)) { + ExecutionTime_.store(*executionTime - throttleDuration, std::memory_order::release); } } @@ -738,15 +740,27 @@ private: bool Cancelable_ = false; TSingleShotCallbackList<void(const TError&)> CanceledList_; + struct TInstantSentinel + { + static constexpr auto Sentinel = TInstant::Zero(); + }; + using TSentinelOptionalInstant = TSentinelOptional<TInstant, TInstantSentinel>; + + struct TDurationSentinel + { + static constexpr auto Sentinel = TDuration::Max(); + }; + using TSentinelOptionalDuration = TSentinelOptional<TDuration, TDurationSentinel>; + const TInstant ArriveInstant_; - std::optional<TInstant> RunInstant_; - std::optional<TInstant> ReplyInstant_; - std::optional<TInstant> CancelInstant_; - TDuration ThrottlingTime_; + std::atomic<TSentinelOptionalInstant> RunInstant_; + std::atomic<TSentinelOptionalInstant> ReplyInstant_; + std::atomic<TSentinelOptionalInstant> CancelInstant_; + std::atomic<TDuration> ThrottlingTime_; - std::optional<TDuration> ExecutionTime_; - std::optional<TDuration> TotalTime_; - std::optional<TDuration> LocalWaitTime_; + std::atomic<TSentinelOptionalDuration> ExecutionTime_; + std::atomic<TSentinelOptionalDuration> TotalTime_; + std::atomic<TSentinelOptionalDuration> LocalWaitTime_; std::atomic<bool> CompletedLatch_ = false; std::atomic<bool> TimedOutLatch_ = false; @@ -888,9 +902,13 @@ private: void DoRun(const TLiteHandler& handler) { - RunInstant_ = NProfiling::GetInstant(); - LocalWaitTime_ = *RunInstant_ - ArriveInstant_; - MethodPerformanceCounters_->LocalWaitTimeCounter.Record(*LocalWaitTime_); + auto runInstant = NProfiling::GetInstant(); + auto localWaitTime = runInstant - ArriveInstant_; + + RunInstant_.store(runInstant, std::memory_order::release); + LocalWaitTime_.store(localWaitTime, std::memory_order::release); + + MethodPerformanceCounters_->LocalWaitTimeCounter.Record(localWaitTime); try { TCurrentTraceContextGuard guard(TraceContext_); @@ -915,7 +933,8 @@ private: } if (auto timeout = GetTimeout()) { - auto remainingTimeout = *timeout - (*RunInstant_ - ArriveInstant_); + auto runInstant = RunInstant_.load(std::memory_order::acquire); + auto remainingTimeout = *timeout - (*runInstant - ArriveInstant_); if (remainingTimeout == TDuration::Zero()) { if (!TimedOutLatch_.exchange(true)) { Reply(TError(NYT::EErrorCode::Timeout, "Request dropped due to timeout before being run")); @@ -1026,15 +1045,20 @@ private: MethodPerformanceCounters_->TraceContextTimeCounter.Add(*traceContextTime); } - ReplyInstant_ = NProfiling::GetInstant(); - ExecutionTime_ = RunInstant_ ? *ReplyInstant_ - *RunInstant_ : TDuration(); - if (RunInstant_) { - *ExecutionTime_ -= ThrottlingTime_; + auto replyInstant = NProfiling::GetInstant(); + ReplyInstant_.store(replyInstant, std::memory_order::release); + + TDuration executionTime; + if (auto runInstant = RunInstant_.load(std::memory_order::acquire)) { + executionTime = (replyInstant - *runInstant) - ThrottlingTime_.load(std::memory_order::acquire); } - TotalTime_ = *ReplyInstant_ - ArriveInstant_; + ExecutionTime_.store(executionTime, std::memory_order::release); + + auto totalTime = replyInstant - ArriveInstant_; + TotalTime_.store(replyInstant - ArriveInstant_, std::memory_order::release); - MethodPerformanceCounters_->ExecutionTimeCounter.Record(*ExecutionTime_); - MethodPerformanceCounters_->TotalTimeCounter.Record(*TotalTime_); + MethodPerformanceCounters_->ExecutionTimeCounter.Record(executionTime); + MethodPerformanceCounters_->TotalTimeCounter.Record(totalTime); if (!Error_.IsOK()) { if (Service_->EnableErrorCodeCounter_.load()) { const auto* counter = MethodPerformanceCounters_->ErrorCodeCounters.GetCounter(Error_.GetNonTrivialCode()); @@ -1070,7 +1094,7 @@ private: ? FromProto<TDuration>(RequestHeader_->logging_suppression_timeout()) : RuntimeInfo_->LoggingSuppressionTimeout.load(std::memory_order::relaxed); - if (*TotalTime_ >= timeout) { + if (*TotalTime_.load(std::memory_order::acquire) >= timeout) { return; } @@ -1173,8 +1197,8 @@ private: } delimitedBuilder->AppendFormat("ExecutionTime: %v, TotalTime: %v", - *ExecutionTime_, - *TotalTime_); + *ExecutionTime_.load(std::memory_order::acquire), + *TotalTime_.load(std::memory_order::acquire)); if (auto traceContextTime = GetTraceContextTime()) { delimitedBuilder->AppendFormat("CpuTime: %v", traceContextTime); |
