aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/time_provider
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2023-06-15 18:24:59 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2023-06-15 18:26:33 +0300
commit068d4453cf9fc68c875eee73f5c637bb076f6a71 (patch)
treeda3e83fdb9488ea08faa39d8b41916744f9acad7 /library/cpp/time_provider
parent7e7de263d4acbc6eacf92b618bcb5f9049bccc9b (diff)
downloadydb-068d4453cf9fc68c875eee73f5c637bb076f6a71.tar.gz
Create stable-23-2 branch
x-stable-origin-commit: 3fd4d58117c143ed9e6b21813ccd9e507d2cd4d3
Diffstat (limited to 'library/cpp/time_provider')
-rw-r--r--library/cpp/time_provider/monotonic.cpp83
-rw-r--r--library/cpp/time_provider/monotonic.h197
-rw-r--r--library/cpp/time_provider/monotonic_provider.cpp44
-rw-r--r--library/cpp/time_provider/monotonic_provider.h28
-rw-r--r--library/cpp/time_provider/time_provider.cpp2
5 files changed, 213 insertions, 141 deletions
diff --git a/library/cpp/time_provider/monotonic.cpp b/library/cpp/time_provider/monotonic.cpp
index 99126080e2..f9fb6c5e19 100644
--- a/library/cpp/time_provider/monotonic.cpp
+++ b/library/cpp/time_provider/monotonic.cpp
@@ -1,28 +1,81 @@
#include "monotonic.h"
#include <chrono>
+#include <optional>
+#include <system_error>
+#include <util/system/platform.h>
+
+#ifdef _linux_
+ #include <time.h>
+ #include <string.h>
+#endif
namespace NMonotonic {
-namespace {
-// Unfortunately time_since_epoch() is sometimes negative on wine
-// Remember initial time point at program start and use offsets from that
-std::chrono::steady_clock::time_point MonotonicOffset = std::chrono::steady_clock::now();
-}
+ namespace {
+#if defined(_linux_) && defined(CLOCK_BOOTTIME)
+ std::optional<ui64> GetClockBootTimeMicroSeconds() {
+ struct timespec t;
+ std::optional<ui64> r;
+ if (0 == ::clock_gettime(CLOCK_BOOTTIME, &t)) {
+ r.emplace(t.tv_nsec / 1000ULL + t.tv_sec * 1000000ULL);
+ }
+ return r;
+ }
+#endif
+
+ struct TMonotonicSupport {
+#if defined(_linux_) && defined(CLOCK_BOOTTIME)
+ // We remember initial offset to measure time relative to program
+ // start and so we never return a zero time.
+ std::optional<ui64> BootTimeOffset;
+#endif
+ // Unfortunately time_since_epoch() is sometimes negative on wine
+ // Remember initial time point at program start and use offsets from that
+ std::chrono::steady_clock::time_point SteadyClockOffset;
+
+ TMonotonicSupport() {
+#if defined(_linux_) && defined(CLOCK_BOOTTIME)
+ BootTimeOffset = GetClockBootTimeMicroSeconds();
+#endif
+ SteadyClockOffset = std::chrono::steady_clock::now();
+ }
+
+ ui64 GetMicroSeconds() const {
+#if defined(_linux_) && defined(CLOCK_BOOTTIME)
+ if (Y_LIKELY(BootTimeOffset)) {
+ auto r = GetClockBootTimeMicroSeconds();
+ if (Y_UNLIKELY(!r)) {
+ throw std::system_error(
+ std::error_code(errno, std::system_category()),
+ "clock_gettime(CLOCK_BOOTTIME) failed");
+ }
+ // Note: we add 1 so we never return zero
+ return *r - *BootTimeOffset + 1;
+ }
+#endif
+ auto elapsed = std::chrono::steady_clock::now() - SteadyClockOffset;
+ auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
+ // Steady clock is supposed to never jump backwards, but it's
+ // better to be safe in case of buggy implementations
+ if (Y_UNLIKELY(microseconds < 0)) {
+ microseconds = 0;
+ }
+ // Note: we add 1 so we never return zero
+ return ui64(microseconds) + 1;
+ }
+ };
-ui64 GetMonotonicMicroSeconds() {
- auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - MonotonicOffset).count();
- // Steady clock is supposed to never jump backwards, but it's better to be safe in case of buggy implementations
- if (Y_UNLIKELY(microseconds < 0)) {
- microseconds = 0;
+ TMonotonicSupport MonotonicSupport;
+ }
+
+ ui64 GetMonotonicMicroSeconds() {
+ return MonotonicSupport.GetMicroSeconds();
}
- // Add one so we never return zero
- return microseconds + 1;
-}
-} // namespace TMonotonic
+}
-template<>
+template <>
void Out<NMonotonic::TMonotonic>(
IOutputStream& o,
NMonotonic::TMonotonic t)
diff --git a/library/cpp/time_provider/monotonic.h b/library/cpp/time_provider/monotonic.h
index e36902d884..a1258e3342 100644
--- a/library/cpp/time_provider/monotonic.h
+++ b/library/cpp/time_provider/monotonic.h
@@ -1,111 +1,124 @@
#pragma once
#include <util/datetime/base.h>
-namespace NMonotonic {
-/**
- * Returns current monotonic time in microseconds
- */
-ui64 GetMonotonicMicroSeconds();
-
-/**
- * Similar to TInstant, but measuring monotonic time
- */
-class TMonotonic: public TTimeBase<TMonotonic> {
- using TBase = TTimeBase<TMonotonic>;
-
-private:
- constexpr explicit TMonotonic(TValue value) noexcept
- : TBase(value) {
- }
-
-public:
- constexpr TMonotonic() noexcept {
- }
-
- static constexpr TMonotonic FromValue(TValue value) noexcept {
- return TMonotonic(value);
- }
-
- static inline TMonotonic Now() {
- return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds());
- }
-
- using TBase::Days;
- using TBase::Hours;
- using TBase::MicroSeconds;
- using TBase::MilliSeconds;
- using TBase::Minutes;
- using TBase::Seconds;
- static constexpr TMonotonic Max() noexcept {
- return TMonotonic(::Max<ui64>());
- }
-
- static constexpr TMonotonic Zero() noexcept {
- return TMonotonic();
- }
-
- static constexpr TMonotonic MicroSeconds(ui64 us) noexcept {
- return TMonotonic(TInstant::MicroSeconds(us).GetValue());
- }
-
- static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept {
- return TMonotonic(TInstant::MilliSeconds(ms).GetValue());
- }
-
- static constexpr TMonotonic Seconds(ui64 s) noexcept {
- return TMonotonic(TInstant::Seconds(s).GetValue());
- }
-
- static constexpr TMonotonic Minutes(ui64 m) noexcept {
- return TMonotonic(TInstant::Minutes(m).GetValue());
- }
-
- static constexpr TMonotonic Hours(ui64 h) noexcept {
- return TMonotonic(TInstant::Hours(h).GetValue());
- }
-
- static constexpr TMonotonic Days(ui64 d) noexcept {
- return TMonotonic(TInstant::Days(d).GetValue());
- }
+namespace NMonotonic {
- template<class T>
- inline TMonotonic& operator+=(const T& t) noexcept {
- return (*this = (*this + t));
- }
+ /**
+ * Returns current monotonic time in microseconds
+ *
+ * On Linux uses CLOCK_BOOTTIME under the hood, so it includes time passed
+ * during suspend and makes it safe for measuring lease times.
+ */
+ ui64 GetMonotonicMicroSeconds();
+
+ /**
+ * Similar to TInstant, but measuring monotonic time
+ *
+ * On Linux uses CLOCK_BOOTTIME under the hood, so it includes time passed
+ * during suspend and makes it safe for measuring lease times.
+ */
+ class TMonotonic: public TTimeBase<TMonotonic> {
+ using TBase = TTimeBase<TMonotonic>;
+
+ protected:
+ constexpr explicit TMonotonic(TValue value) noexcept
+ : TBase(value)
+ {
+ }
+
+ public:
+ constexpr TMonotonic() noexcept {
+ }
+
+ static constexpr TMonotonic FromValue(TValue value) noexcept {
+ return TMonotonic(value);
+ }
+
+ static inline TMonotonic Now() {
+ return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds());
+ }
+
+ using TBase::Days;
+ using TBase::Hours;
+ using TBase::MicroSeconds;
+ using TBase::MilliSeconds;
+ using TBase::Minutes;
+ using TBase::Seconds;
+
+ static constexpr TMonotonic Max() noexcept {
+ return TMonotonic::FromValue(::Max<ui64>());
+ }
+
+ static constexpr TMonotonic Zero() noexcept {
+ return TMonotonic::FromValue(0);
+ }
+
+ static constexpr TMonotonic MicroSeconds(ui64 us) noexcept {
+ return TMonotonic::FromValue(TInstant::MicroSeconds(us).GetValue());
+ }
+
+ static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept {
+ return TMonotonic::FromValue(TInstant::MilliSeconds(ms).GetValue());
+ }
+
+ static constexpr TMonotonic Seconds(ui64 s) noexcept {
+ return TMonotonic::FromValue(TInstant::Seconds(s).GetValue());
+ }
+
+ static constexpr TMonotonic Minutes(ui64 m) noexcept {
+ return TMonotonic::FromValue(TInstant::Minutes(m).GetValue());
+ }
+
+ static constexpr TMonotonic Hours(ui64 h) noexcept {
+ return TMonotonic::FromValue(TInstant::Hours(h).GetValue());
+ }
+
+ static constexpr TMonotonic Days(ui64 d) noexcept {
+ return TMonotonic::FromValue(TInstant::Days(d).GetValue());
+ }
+
+ template <class T>
+ inline TMonotonic& operator+=(const T& t) noexcept {
+ return (*this = (*this + t));
+ }
+
+ template <class T>
+ inline TMonotonic& operator-=(const T& t) noexcept {
+ return (*this = (*this - t));
+ }
+ };
- template<class T>
- inline TMonotonic& operator-=(const T& t) noexcept {
- return (*this = (*this - t));
- }
-};
} // namespace NMonotonic
Y_DECLARE_PODTYPE(NMonotonic::TMonotonic);
-template<>
-struct THash<NMonotonic::TMonotonic> {
- size_t operator()(const NMonotonic::TMonotonic& key) const {
- return THash<NMonotonic::TMonotonic::TValue>()(key.GetValue());
- }
-};
+namespace std {
+ template <>
+ struct hash<NMonotonic::TMonotonic> {
+ size_t operator()(const NMonotonic::TMonotonic& key) const noexcept {
+ return hash<NMonotonic::TMonotonic::TValue>()(key.GetValue());
+ }
+ };
+}
namespace NMonotonic {
-constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) {
- return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue());
-}
+ constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) {
+ return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue());
+ }
-constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) {
- TInstant result = TInstant::FromValue(l.GetValue()) + r;
- return TMonotonic::FromValue(result.GetValue());
-}
+ constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) {
+ TInstant result = TInstant::FromValue(l.GetValue()) + r;
+ return TMonotonic::FromValue(result.GetValue());
+ }
-constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) {
- TInstant result = TInstant::FromValue(l.GetValue()) - r;
- return TMonotonic::FromValue(result.GetValue());
-}
+ constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) {
+ TInstant result = TInstant::FromValue(l.GetValue()) - r;
+ return TMonotonic::FromValue(result.GetValue());
+ }
} // namespace NMonotonic
+// TODO: remove, alias for compatibility
using TMonotonic = NMonotonic::TMonotonic;
diff --git a/library/cpp/time_provider/monotonic_provider.cpp b/library/cpp/time_provider/monotonic_provider.cpp
index 22937bd873..6b116a0e73 100644
--- a/library/cpp/time_provider/monotonic_provider.cpp
+++ b/library/cpp/time_provider/monotonic_provider.cpp
@@ -1,32 +1,32 @@
#include "monotonic_provider.h"
-namespace {
-TIntrusivePtr<IMonotonicTimeProvider> GlobalMonotonicTimeProvider;
-}
-
-void TMonotonicOperator::RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider) {
- GlobalMonotonicTimeProvider = provider;
-}
+namespace NMonotonic {
-NMonotonic::TMonotonic TMonotonicOperator::Now() {
- if (GlobalMonotonicTimeProvider) {
- return GlobalMonotonicTimeProvider->Now();
- } else {
- return TMonotonic::Now();
+ namespace {
+ TIntrusivePtr<IMonotonicTimeProvider> GlobalMonotonicTimeProvider;
}
-}
-namespace NMonotonic {
+ void TMonotonicOperator::RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider) {
+ GlobalMonotonicTimeProvider = provider;
+ }
-class TDefaultMonotonicTimeProvider: public IMonotonicTimeProvider {
-public:
- TMonotonic Now() override {
- return TMonotonic::Now();
+ NMonotonic::TMonotonic TMonotonicOperator::Now() {
+ if (GlobalMonotonicTimeProvider) {
+ return GlobalMonotonicTimeProvider->Now();
+ } else {
+ return TMonotonic::Now();
+ }
}
-};
-TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() {
- return TIntrusivePtr<IMonotonicTimeProvider>(new TDefaultMonotonicTimeProvider);
-}
+ class TDefaultMonotonicTimeProvider: public IMonotonicTimeProvider {
+ public:
+ TMonotonic Now() override {
+ return TMonotonic::Now();
+ }
+ };
+
+ TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() {
+ return TIntrusivePtr<IMonotonicTimeProvider>(new TDefaultMonotonicTimeProvider);
+ }
}
diff --git a/library/cpp/time_provider/monotonic_provider.h b/library/cpp/time_provider/monotonic_provider.h
index 966e2e496b..17b57e4075 100644
--- a/library/cpp/time_provider/monotonic_provider.h
+++ b/library/cpp/time_provider/monotonic_provider.h
@@ -3,19 +3,25 @@
#include <util/datetime/base.h>
#include "monotonic.h"
-class IMonotonicTimeProvider: public TThrRefBase {
-public:
- virtual TMonotonic Now() = 0;
-};
+namespace NMonotonic {
-class TMonotonicOperator {
-public:
- static void RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider);
- static TMonotonic Now();
-};
+ class IMonotonicTimeProvider: public TThrRefBase {
+ public:
+ virtual TMonotonic Now() = 0;
+ };
-namespace NMonotonic {
+ class TMonotonicOperator {
+ public:
+ static void RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider);
+ static TMonotonic Now();
+ };
-TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider();
+ TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider();
}
+
+// TODO: remove, alias for compatibility
+using IMonotonicTimeProvider = NMonotonic::IMonotonicTimeProvider;
+
+// TODO: remove, alias for compatibility
+using NMonotonic::CreateDefaultMonotonicTimeProvider;
diff --git a/library/cpp/time_provider/time_provider.cpp b/library/cpp/time_provider/time_provider.cpp
index 687681f1ff..e1045dae05 100644
--- a/library/cpp/time_provider/time_provider.cpp
+++ b/library/cpp/time_provider/time_provider.cpp
@@ -30,7 +30,7 @@ TIntrusivePtr<ITimeProvider> CreateDeterministicTimeProvider(ui64 seed) {
}
namespace {
-TIntrusivePtr<ITimeProvider> GlobalTimeProvider;
+ TIntrusivePtr<ITimeProvider> GlobalTimeProvider;
}
void TInstantOperator::RegisterProvider(TIntrusivePtr<ITimeProvider> provider) {