diff options
author | Jennifer Peshansky <jennifer.peshansky@mongodb.com> | 2022-11-03 16:13:20 +0000 |
---|---|---|
committer | Jennifer Peshansky <jennifer.peshansky@mongodb.com> | 2022-11-03 16:13:20 +0000 |
commit | e74d2910bbe76790ad131d53fee277829cd95982 (patch) | |
tree | cabe148764529c9623652374fbc36323a550cd44 /src/mongo/util | |
parent | 280145e9940729480bb8a35453d4056afac87641 (diff) | |
parent | ba467f46cc1bc49965e1d72b541eff0cf1d7b22e (diff) | |
download | mongo-e74d2910bbe76790ad131d53fee277829cd95982.tar.gz |
Merge branch 'master' into jenniferpeshansky/SERVER-70854jenniferpeshansky/SERVER-70854
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/concurrency/ticketholder.cpp | 4 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_apple.cpp | 11 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_openssl.cpp | 14 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager_windows.cpp | 10 | ||||
-rw-r--r-- | src/mongo/util/pair_map.h | 204 | ||||
-rw-r--r-- | src/mongo/util/system_tick_source.cpp | 136 | ||||
-rw-r--r-- | src/mongo/util/system_tick_source.h | 23 | ||||
-rw-r--r-- | src/mongo/util/tick_source.h | 13 | ||||
-rw-r--r-- | src/mongo/util/tick_source_test.cpp | 72 | ||||
-rw-r--r-- | src/mongo/util/timer.cpp | 2 |
10 files changed, 298 insertions, 191 deletions
diff --git a/src/mongo/util/concurrency/ticketholder.cpp b/src/mongo/util/concurrency/ticketholder.cpp index a9c44467536..2e9e90eeec1 100644 --- a/src/mongo/util/concurrency/ticketholder.cpp +++ b/src/mongo/util/concurrency/ticketholder.cpp @@ -51,7 +51,7 @@ void updateQueueStatsOnRelease(ServiceContext* serviceContext, queueStats.totalFinishedProcessing.fetchAndAddRelaxed(1); auto startTime = admCtx->getStartProcessingTime(); auto tickSource = serviceContext->getTickSource(); - auto delta = tickSource->spanTo<Microseconds>(startTime, tickSource->getTicks()); + auto delta = tickSource->ticksTo<Microseconds>(tickSource->getTicks() - startTime); queueStats.totalTimeProcessingMicros.fetchAndAddRelaxed(delta.count()); } @@ -163,7 +163,7 @@ boost::optional<Ticket> TicketHolderWithQueueingStats::waitForTicketUntil(Operat auto currentWaitTime = tickSource->getTicks(); auto updateQueuedTime = [&]() { auto oldWaitTime = std::exchange(currentWaitTime, tickSource->getTicks()); - auto waitDelta = tickSource->spanTo<Microseconds>(oldWaitTime, currentWaitTime).count(); + auto waitDelta = tickSource->ticksTo<Microseconds>(currentWaitTime - oldWaitTime).count(); queueStats.totalTimeQueuedMicros.fetchAndAddRelaxed(waitDelta); }; queueStats.totalAddedQueue.fetchAndAddRelaxed(1); diff --git a/src/mongo/util/net/ssl_manager_apple.cpp b/src/mongo/util/net/ssl_manager_apple.cpp index 832e0b54262..98024421e5a 100644 --- a/src/mongo/util/net/ssl_manager_apple.cpp +++ b/src/mongo/util/net/ssl_manager_apple.cpp @@ -1675,11 +1675,12 @@ Future<SSLPeerInfo> SSLManagerApple::parseAndValidatePeerCertificate( // The cipher will be presented as a number. ::SSLCipherSuite cipher; uassertOSStatusOK(::SSLGetNegotiatedCipher(ssl, &cipher)); - - LOGV2_INFO(6723803, - "Accepted TLS connection from peer", - "peerSubjectName"_attr = peerSubjectName, - "cipher"_attr = cipher); + if (!serverGlobalParams.quiet.load()) { + LOGV2_INFO(6723803, + "Accepted TLS connection from peer", + "peerSubjectName"_attr = peerSubjectName, + "cipher"_attr = cipher); + } // Server side. if (remoteHost.empty()) { diff --git a/src/mongo/util/net/ssl_manager_openssl.cpp b/src/mongo/util/net/ssl_manager_openssl.cpp index a8418eed3fa..606dd1e8868 100644 --- a/src/mongo/util/net/ssl_manager_openssl.cpp +++ b/src/mongo/util/net/ssl_manager_openssl.cpp @@ -771,6 +771,10 @@ Future<UniqueOCSPResponse> retrieveOCSPResponse(const std::string& host, return getSSLFailure("Could not convert type OCSP Response to DER encoded object."); } + if (!OCSPManager::get(getGlobalServiceContext())) { + return getSSLFailure("OCSP fetch could not complete, server is in shutdown mode."); + } + // Query the OCSP responder return OCSPManager::get(getGlobalServiceContext()) ->requestStatus(buffer, host, purpose) @@ -3309,10 +3313,12 @@ Future<SSLPeerInfo> SSLManagerOpenSSL::parseAndValidatePeerCertificate( // TODO: check optional cipher restriction, using cert. auto peerSubject = getCertificateSubjectX509Name(peerCert.get()); const auto cipher = SSL_get_current_cipher(conn); - LOGV2_INFO(6723801, - "Accepted TLS connection from peer", - "peerSubject"_attr = peerSubject, - "cipher"_attr = SSL_CIPHER_get_name(cipher)); + if (!serverGlobalParams.quiet.load()) { + LOGV2_INFO(6723801, + "Accepted TLS connection from peer", + "peerSubject"_attr = peerSubject, + "cipher"_attr = SSL_CIPHER_get_name(cipher)); + } StatusWith<stdx::unordered_set<RoleName>> swPeerCertificateRoles = _parsePeerRoles(peerCert.get()); diff --git a/src/mongo/util/net/ssl_manager_windows.cpp b/src/mongo/util/net/ssl_manager_windows.cpp index 782ff15d417..760b81b4e07 100644 --- a/src/mongo/util/net/ssl_manager_windows.cpp +++ b/src/mongo/util/net/ssl_manager_windows.cpp @@ -2067,10 +2067,12 @@ Future<SSLPeerInfo> SSLManagerWindows::parseAndValidatePeerCertificate( } const auto cipher = std::wstring(cipherInfo.szCipherSuite); - LOGV2_INFO(6723802, - "Accepted TLS connection from peer", - "peerSubjectName"_attr = peerSubjectName, - "cipher"_attr = toUtf8String(cipher)); + if (!serverGlobalParams.quiet.load()) { + LOGV2_INFO(6723802, + "Accepted TLS connection from peer", + "peerSubjectName"_attr = peerSubjectName, + "cipher"_attr = toUtf8String(cipher)); + } // If this is a server and client and server certificate are the same, log a warning. if (remoteHost.empty() && _sslConfiguration.serverSubjectName() == peerSubjectName) { diff --git a/src/mongo/util/pair_map.h b/src/mongo/util/pair_map.h new file mode 100644 index 00000000000..6271fb9ae6d --- /dev/null +++ b/src/mongo/util/pair_map.h @@ -0,0 +1,204 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include <absl/container/flat_hash_map.h> +#include <absl/container/flat_hash_set.h> + +#include "mongo/base/string_data.h" +#include "mongo/util/assert_util.h" + +namespace mongo { + +template <typename T> +class PairMapTraits { +public: + using OwnedType = T; + using ViewType = T; + using HashableType = T; + + static const T& toOwned(const T& t) { + return t; + } + static const T& toView(const T& t) { + return t; + } + static const T& toHashable(const T& t) { + return t; + } +}; + +template <> +class PairMapTraits<StringData> { +public: + using OwnedType = std::string; + using ViewType = StringData; + using HashableType = absl::string_view; + + static std::string toOwned(const StringData& t) { + return t.toString(); + } + static const StringData& toView(const StringData& t) { + return t; + } + static absl::string_view toHashable(const StringData& t) { + // Use the default absl string hasher. + return absl::string_view(t.rawData(), t.size()); + } +}; + +template <> +class PairMapTraits<std::string> { +public: + using OwnedType = std::string; + using ViewType = StringData; + using HashableType = absl::string_view; + + static const std::string& toOwned(const std::string& t) { + return t; + } + static StringData toView(const std::string& t) { + return StringData(t); + } + static absl::string_view toHashable(const std::string& t) { + // Use the default absl string hasher. + return absl::string_view(t.data(), t.size()); + } +}; + +/** + * Type that bundles a hashed key with the actual pair value so that hashing can be performed + * outside of insert() call. This is needed to facilitate heterogeneous lookup. + */ +template <typename T1, typename T2> +class PairMapHashedKey { +public: + using OwnedType1 = typename PairMapTraits<T1>::OwnedType; + using OwnedType2 = typename PairMapTraits<T2>::OwnedType; + using OwnedPairType = std::pair<OwnedType1, OwnedType2>; + using ViewType1 = typename PairMapTraits<T1>::ViewType; + using ViewType2 = typename PairMapTraits<T2>::ViewType; + using ViewPairType = std::pair<ViewType1, ViewType2>; + + explicit PairMapHashedKey(ViewPairType key, std::size_t hash) + : _key(std::move(key)), _hash(hash) {} + + explicit operator OwnedPairType() const { + return {PairMapTraits<ViewType1>::toOwned(_key.first), + PairMapTraits<ViewType2>::toOwned(_key.second)}; + } + + const ViewPairType& key() const { + return _key; + } + + std::size_t hash() const { + return _hash; + } + +private: + ViewPairType _key; + std::size_t _hash; +}; + +/** + * Hasher to support heterogeneous lookup. + */ +template <typename T1, typename T2> +class PairMapHasher { +public: + using OwnedType1 = typename PairMapTraits<T1>::OwnedType; + using OwnedType2 = typename PairMapTraits<T2>::OwnedType; + using OwnedPairType = std::pair<OwnedType1, OwnedType2>; + using ViewType1 = typename PairMapTraits<T1>::ViewType; + using ViewType2 = typename PairMapTraits<T2>::ViewType; + using ViewPairType = std::pair<ViewType1, ViewType2>; + using HashableType1 = typename PairMapTraits<T1>::HashableType; + using HashableType2 = typename PairMapTraits<T2>::HashableType; + using HashablePairType = std::pair<HashableType1, HashableType2>; + + // This using directive activates heterogeneous lookup in the hash table. + using is_transparent = void; + + std::size_t operator()(const ViewPairType& sd) const { + return absl::Hash<HashablePairType>{}( + std::make_pair(PairMapTraits<ViewType1>::toHashable(sd.first), + PairMapTraits<ViewType2>::toHashable(sd.second))); + } + + std::size_t operator()(const OwnedPairType& s) const { + return operator()(std::make_pair(PairMapTraits<OwnedType1>::toView(s.first), + PairMapTraits<OwnedType2>::toView(s.second))); + } + + std::size_t operator()(const PairMapHashedKey<T1, T2>& key) const { + return key.hash(); + } + + PairMapHashedKey<T1, T2> hashed_key(const ViewPairType& sd) const { + return PairMapHashedKey<T1, T2>(sd, operator()(sd)); + } +}; + +template <typename T1, typename T2> +class PairMapEq { +public: + using ViewType1 = typename PairMapTraits<T1>::ViewType; + using ViewType2 = typename PairMapTraits<T2>::ViewType; + using ViewPairType = std::pair<ViewType1, ViewType2>; + + // This using directive activates heterogeneous lookup in the hash table. + using is_transparent = void; + + bool operator()(const ViewPairType& lhs, const ViewPairType& rhs) const { + return lhs == rhs; + } + + bool operator()(const PairMapHashedKey<T1, T2>& lhs, const ViewPairType& rhs) const { + return lhs.key() == rhs; + } + + bool operator()(const ViewPairType& lhs, const PairMapHashedKey<T1, T2>& rhs) const { + return lhs == rhs.key(); + } + + bool operator()(const PairMapHashedKey<T1, T2>& lhs, + const PairMapHashedKey<T1, T2>& rhs) const { + return lhs.key() == rhs.key(); + } +}; + +template <typename K1, typename K2, typename V> +using PairMap = absl::flat_hash_map<std::pair<K1, K2>, V, PairMapHasher<K1, K2>, PairMapEq<K1, K2>>; + +template <typename K1, typename K2> +using PairSet = absl::flat_hash_set<std::pair<K1, K2>, PairMapHasher<K1, K2>, PairMapEq<K1, K2>>; + +} // namespace mongo diff --git a/src/mongo/util/system_tick_source.cpp b/src/mongo/util/system_tick_source.cpp index ee5f24d4e83..293b072f079 100644 --- a/src/mongo/util/system_tick_source.cpp +++ b/src/mongo/util/system_tick_source.cpp @@ -27,132 +27,32 @@ * it in the license file. */ -#include "mongo/platform/basic.h" - #include "mongo/util/system_tick_source.h" -#include "mongo/config.h" - -#include <ctime> -#include <limits> -#if defined(MONGO_CONFIG_HAVE_HEADER_UNISTD_H) -#include <unistd.h> -#endif +#include <chrono> // NOLINT #include <memory> -#include "mongo/base/init.h" -#include "mongo/util/assert_util.h" #include "mongo/util/tick_source.h" -#include "mongo/util/time_support.h" namespace mongo { -namespace { - -const int64_t kMillisPerSecond = 1000; -const int64_t kMicrosPerSecond = 1000 * kMillisPerSecond; -const int64_t kNanosPerSecond = 1000 * kMicrosPerSecond; - -/** - * Internally, the timer counts platform-dependent ticks of some sort, and - * must then convert those ticks to microseconds and their ilk. This field - * stores the frequency of the platform-dependent counter. - * - * Define ticksPerSecond before init to ensure correct relative sequencing - * regardless of how it is initialized (static or dynamic). - */ -TickSource::Tick ticksPerSecond = kMicrosPerSecond; - -// "Generic" implementation for _timerNow. -TickSource::Tick _timerNowGeneric() { - return curTimeMicros64(); -} - -// Function pointer to timer implementation. -// Overridden in initTickSource() with better implementation where available. -TickSource::Tick (*_timerNow)() = &_timerNowGeneric; - -#if defined(_WIN32) - -/** - * Windows-specific implementation of the - * Timer class. Windows selects the best available timer, in its estimation, for - * measuring time at high resolution. This may be the HPET of the TSC on x86 systems, - * but is promised to be synchronized across processors, barring BIOS errors. - */ -TickSource::Tick timerNowWindows() { - LARGE_INTEGER i; - fassert(16161, QueryPerformanceCounter(&i)); - return i.QuadPart; -} - -void initTickSource() { - LARGE_INTEGER x; - bool ok = QueryPerformanceFrequency(&x); - verify(ok); - ticksPerSecond = x.QuadPart; - _timerNow = &timerNowWindows; -} - -#elif defined(MONGO_CONFIG_HAVE_POSIX_MONOTONIC_CLOCK) - -/** - * Implementation for timer on systems that support the - * POSIX clock API and CLOCK_MONOTONIC clock. - */ -TickSource::Tick timerNowPosixMonotonicClock() { - timespec the_time; - long long result; - - fassert(16160, !clock_gettime(CLOCK_MONOTONIC, &the_time)); - - // Safe for 292 years after the clock epoch, even if we switch to a signed time value. - // On Linux, the monotonic clock's epoch is the UNIX epoch. - result = static_cast<long long>(the_time.tv_sec); - result *= kNanosPerSecond; - result += static_cast<long long>(the_time.tv_nsec); - return result; -} - -void initTickSource() { - // If the monotonic clock is not available at runtime (sysconf() returns 0 or -1), - // do not override the generic implementation or modify ticksPerSecond. - if (sysconf(_SC_MONOTONIC_CLOCK) <= 0) { - return; - } - - ticksPerSecond = kNanosPerSecond; - _timerNow = &timerNowPosixMonotonicClock; - - // Make sure that the current time relative to the (unspecified) epoch isn't already too - // big to represent as a 64-bit count of nanoseconds. - long long maxSecs = std::numeric_limits<long long>::max() / kNanosPerSecond; - timespec the_time; - fassert(16162, !clock_gettime(CLOCK_MONOTONIC, &the_time)); - fassert(16163, static_cast<long long>(the_time.tv_sec) < maxSecs); -} -#else -void initTickSource() {} -#endif - -} // unnamed namespace - -MONGO_INITIALIZER(SystemTickSourceInit)(InitializerContext* context) { - initTickSource(); - SystemTickSource::get(); -} - -TickSource::Tick SystemTickSource::getTicks() { - return _timerNow(); -} - -TickSource::Tick SystemTickSource::getTicksPerSecond() { - return ticksPerSecond; -} - -SystemTickSource* SystemTickSource::get() { - static const auto globalSystemTickSource = std::make_unique<SystemTickSource>(); - return globalSystemTickSource.get(); +std::unique_ptr<TickSource> makeSystemTickSource() { + class Steady : public TickSource { + using C = std::chrono::steady_clock; // NOLINT + Tick getTicksPerSecond() override { + static_assert(C::period::num == 1, "Fractional frequency disallowed"); + return C::period::den; + } + Tick getTicks() override { + return C::now().time_since_epoch().count(); + } + }; + return std::make_unique<Steady>(); +} + +TickSource* globalSystemTickSource() { + static const auto p = makeSystemTickSource().release(); + return p; } } // namespace mongo diff --git a/src/mongo/util/system_tick_source.h b/src/mongo/util/system_tick_source.h index df59541fcee..360b38616f0 100644 --- a/src/mongo/util/system_tick_source.h +++ b/src/mongo/util/system_tick_source.h @@ -31,25 +31,14 @@ #include "mongo/util/tick_source.h" +#include <memory> + namespace mongo { -/** - * Tick source based on platform specific clock ticks. Should be of reasonably high - * performance. The maximum span measurable by the counter and convertible to microseconds - * is about 10 trillion ticks. As long as there are fewer than 100 ticks per nanosecond, - * timer durations of 2.5 years will be supported. Since a typical tick duration will be - * under 10 per nanosecond, if not below 1 per nanosecond, this should not be an issue. - */ -class SystemTickSource final : public TickSource { -public: - TickSource::Tick getTicks() override; +/** Tick source based on `std:::chrono::steady_clock`. Monotonic, cheap, and high-precision. */ +std::unique_ptr<TickSource> makeSystemTickSource(); - TickSource::Tick getTicksPerSecond() override; +/** Accesses a singleton instance made by `makeSystemTickSource`. Safe to call at any time. */ +TickSource* globalSystemTickSource(); - /** - * Gets the singleton instance of SystemTickSource. Should not be called before - * the global initializers are done. - */ - static SystemTickSource* get(); -}; } // namespace mongo diff --git a/src/mongo/util/tick_source.h b/src/mongo/util/tick_source.h index 5b0abc88aca..759a6354ed1 100644 --- a/src/mongo/util/tick_source.h +++ b/src/mongo/util/tick_source.h @@ -65,18 +65,5 @@ public: static_cast<double>(getTicksPerSecond()) * D::period::num / D::period::den; return D(static_cast<int64_t>(ticks / ticksPerD)); } - - /** - * Measures the length of the span from the start tick to the end tick and returns the result - * using duration type D. - * If the start tick is after (greater than) the end tick, returns a duration equivalent to 0 - * ticks. - * - * e.g. tickSource->spanTo<Milliseconds>(start, end); - */ - template <typename D> - D spanTo(Tick start, Tick end) { - return ticksTo<D>(std::max((end - start), Tick{0})); - } }; } // namespace mongo diff --git a/src/mongo/util/tick_source_test.cpp b/src/mongo/util/tick_source_test.cpp index 9cfd907677a..b0fd6e43cb3 100644 --- a/src/mongo/util/tick_source_test.cpp +++ b/src/mongo/util/tick_source_test.cpp @@ -27,10 +27,10 @@ * it in the license file. */ -#include "mongo/platform/basic.h" - +#include "mongo/unittest/assert_that.h" #include "mongo/unittest/unittest.h" -#include "mongo/util/clock_source_mock.h" +#include "mongo/util/duration.h" +#include "mongo/util/system_tick_source.h" #include "mongo/util/tick_source.h" #include "mongo/util/tick_source_mock.h" #include "mongo/util/time_support.h" @@ -38,35 +38,53 @@ namespace mongo { namespace { +namespace m = unittest::match; + +template <typename SourceDuration, typename OutDuration> +auto tickToDuration(int ticks) { + TickSourceMock<SourceDuration> ts; + ts.reset(ticks); + return ts.template ticksTo<OutDuration>(ts.getTicks()).count(); +} + TEST(TickSourceTest, TicksToDurationConversion) { - TickSourceMock<Seconds> tsSecs; - tsSecs.reset(1); - ASSERT_EQ(tsSecs.ticksTo<Seconds>(tsSecs.getTicks()).count(), 1); - ASSERT_EQ(tsSecs.ticksTo<Milliseconds>(tsSecs.getTicks()).count(), 1000); - ASSERT_EQ(tsSecs.ticksTo<Microseconds>(tsSecs.getTicks()).count(), 1000 * 1000); + ASSERT_EQ((tickToDuration<Seconds, Seconds>(1)), 1); + ASSERT_EQ((tickToDuration<Seconds, Milliseconds>(1)), 1'000); + ASSERT_EQ((tickToDuration<Seconds, Microseconds>(1)), 1'000'000); + ASSERT_EQ((tickToDuration<Milliseconds, Milliseconds>(1)), 1); + ASSERT_EQ((tickToDuration<Milliseconds, Microseconds>(1)), 1'000); + ASSERT_EQ((tickToDuration<Microseconds, Microseconds>(1)), 1); +} - TickSourceMock<Milliseconds> tsMillis; - tsMillis.reset(1); - ASSERT_EQ(tsMillis.ticksTo<Milliseconds>(tsMillis.getTicks()).count(), 1); - ASSERT_EQ(tsMillis.ticksTo<Microseconds>(tsMillis.getTicks()).count(), 1000); +TEST(SystemTickSourceTest, TicksPerSecond) { + ASSERT_EQ(makeSystemTickSource()->getTicksPerSecond(), 1'000'000'000); +} - TickSourceMock<Microseconds> tsMicros; - tsMicros.reset(1); - ASSERT_EQ(tsMicros.ticksTo<Microseconds>(tsMicros.getTicks()).count(), 1); +TEST(SystemTickSourceTest, GetTicks) { + auto ts = makeSystemTickSource(); + auto t0 = ts->getTicks(); + for (int reps = 20; reps--;) { + static constexpr Milliseconds delay{200}; + static constexpr Milliseconds err{20}; + sleepFor(delay); + auto t1 = ts->getTicks(); + ASSERT_THAT(ts->ticksTo<Milliseconds>(t1 - t0), + m::AllOf(m::Ge(delay - err), m::Le(delay + err))); + t0 = t1; + } } -TEST(TickSourceTest, SpansToDurationConversion) { - TickSourceMock<Seconds> tsSecs; - tsSecs.reset(0); - TickSource::Tick zero = tsSecs.getTicks(); - tsSecs.reset(10); - TickSource::Tick ten = tsSecs.getTicks(); - ASSERT_EQ(tsSecs.spanTo<Seconds>(zero, ten).count(), 10); - ASSERT_EQ(tsSecs.spanTo<Seconds>(ten, zero).count(), 0); - ASSERT_EQ(tsSecs.spanTo<Milliseconds>(zero, ten).count(), 10 * 1000); - ASSERT_EQ(tsSecs.spanTo<Milliseconds>(ten, zero).count(), 0); - ASSERT_EQ(tsSecs.spanTo<Microseconds>(zero, ten).count(), 10 * 1000 * 1000); - ASSERT_EQ(tsSecs.spanTo<Microseconds>(ten, zero).count(), 0); +TEST(SystemTickSourceTest, Monotonic) { + auto ts = makeSystemTickSource(); + auto t0 = ts->getTicks(); + std::vector<TickSource::Tick> samples; + samples.reserve(1'000'000); + do { + samples.clear(); + for (size_t i = 0; i < 1'000'000; ++i) + samples.push_back(ts->getTicks()); + ASSERT_TRUE(std::is_sorted(samples.begin(), samples.end())); + } while (ts->ticksTo<Milliseconds>(ts->getTicks() - t0) < Seconds{5}); } } // namespace } // namespace mongo diff --git a/src/mongo/util/timer.cpp b/src/mongo/util/timer.cpp index f69bfc4cbb8..7992cd0788c 100644 --- a/src/mongo/util/timer.cpp +++ b/src/mongo/util/timer.cpp @@ -42,7 +42,7 @@ const int64_t kMicrosPerSecond = 1000 * 1000; } // unnamed namespace -Timer::Timer() : Timer(SystemTickSource::get()) {} +Timer::Timer() : Timer(globalSystemTickSource()) {} Timer::Timer(TickSource* tickSource) : _tickSource(tickSource), |