diff options
author | Ben Caimano <ben.caimano@10gen.com> | 2020-07-23 21:59:46 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-28 20:57:56 +0000 |
commit | 214379825c248f5a5e5f0a01ad9863b900faaf30 (patch) | |
tree | 077a4844ec0daaf1a738933920525cde7d440131 /src | |
parent | 6dd301449ec7a48e35a7114e93b888df9958217f (diff) | |
download | mongo-214379825c248f5a5e5f0a01ad9863b900faaf30.tar.gz |
SERVER-48650 Gave the ClockSourceMock a global impl
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/repl/initial_syncer_test.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_test_fixture.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/service_context_test_fixture.cpp | 7 | ||||
-rw-r--r-- | src/mongo/executor/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_mock.cpp | 22 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_mock.h | 29 | ||||
-rw-r--r-- | src/mongo/s/mongos_topology_coordinator_test.cpp | 35 | ||||
-rw-r--r-- | src/mongo/util/clock_source_mock.cpp | 96 | ||||
-rw-r--r-- | src/mongo/util/clock_source_mock.h | 16 |
10 files changed, 115 insertions, 104 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 0fbabb87582..2f5aad83e4c 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1697,6 +1697,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ 'op_observer', + '$BUILD_DIR/mongo/util/clock_source_mock', ], ) diff --git a/src/mongo/db/repl/initial_syncer_test.cpp b/src/mongo/db/repl/initial_syncer_test.cpp index 4180a2a5b74..455dfd10d6a 100644 --- a/src/mongo/db/repl/initial_syncer_test.cpp +++ b/src/mongo/db/repl/initial_syncer_test.cpp @@ -67,6 +67,7 @@ #include "mongo/executor/network_interface_mock.h" #include "mongo/executor/thread_pool_task_executor_test_fixture.h" #include "mongo/platform/mutex.h" +#include "mongo/util/clock_source_mock.h" #include "mongo/util/concurrency/thread_name.h" #include "mongo/util/concurrency/thread_pool.h" #include "mongo/util/fail_point.h" @@ -340,10 +341,8 @@ protected: }; auto* service = getGlobalServiceContext(); - service->setFastClockSource( - std::make_unique<executor::NetworkInterfaceMockClockSource>(getNet())); - service->setPreciseClockSource( - std::make_unique<executor::NetworkInterfaceMockClockSource>(getNet())); + service->setFastClockSource(std::make_unique<ClockSourceMock>()); + service->setPreciseClockSource(std::make_unique<ClockSourceMock>()); ThreadPool::Options dbThreadPoolOptions; dbThreadPoolOptions.poolName = "dbthread"; dbThreadPoolOptions.minThreads = 1U; diff --git a/src/mongo/db/repl/replication_coordinator_test_fixture.cpp b/src/mongo/db/repl/replication_coordinator_test_fixture.cpp index f2147923ed9..e54eda1b6f1 100644 --- a/src/mongo/db/repl/replication_coordinator_test_fixture.cpp +++ b/src/mongo/db/repl/replication_coordinator_test_fixture.cpp @@ -153,9 +153,8 @@ void ReplCoordTest::init() { replicationProcess, _storageInterface, seed); - service->setFastClockSource(std::make_unique<executor::NetworkInterfaceMockClockSource>(_net)); - service->setPreciseClockSource( - std::make_unique<executor::NetworkInterfaceMockClockSource>(_net)); + service->setFastClockSource(std::make_unique<ClockSourceMock>()); + service->setPreciseClockSource(std::make_unique<ClockSourceMock>()); } void ReplCoordTest::init(const ReplSettings& settings) { diff --git a/src/mongo/db/service_context_test_fixture.cpp b/src/mongo/db/service_context_test_fixture.cpp index 3a1a8b4edb5..3ba046db3de 100644 --- a/src/mongo/db/service_context_test_fixture.cpp +++ b/src/mongo/db/service_context_test_fixture.cpp @@ -37,11 +37,18 @@ #include "mongo/db/client.h" #include "mongo/db/op_observer_registry.h" #include "mongo/util/assert_util.h" +#include "mongo/util/clock_source_mock.h" #include "mongo/util/diagnostic_info.h" namespace mongo { ScopedGlobalServiceContextForTest::ScopedGlobalServiceContextForTest() { + { + // Reset the global clock source + ClockSourceMock clkSource; + clkSource.reset(); + } + auto serviceContext = [] { auto serviceContext = ServiceContext::make(); auto serviceContextPtr = serviceContext.get(); diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript index 80ee3174a12..da4acd722ab 100644 --- a/src/mongo/executor/SConscript +++ b/src/mongo/executor/SConscript @@ -74,6 +74,7 @@ env.Library('network_interface_mock', LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/rpc/metadata', + '$BUILD_DIR/mongo/util/clock_source_mock', '$BUILD_DIR/mongo/util/net/network', 'network_interface', 'task_executor_interface', diff --git a/src/mongo/executor/network_interface_mock.cpp b/src/mongo/executor/network_interface_mock.cpp index ab1fcceb126..ed9e7fe1d4d 100644 --- a/src/mongo/executor/network_interface_mock.cpp +++ b/src/mongo/executor/network_interface_mock.cpp @@ -50,9 +50,9 @@ using CallbackHandle = TaskExecutor::CallbackHandle; using ResponseStatus = TaskExecutor::ResponseStatus; NetworkInterfaceMock::NetworkInterfaceMock() - : _waitingToRunMask(0), + : _clkSource(std::make_unique<ClockSourceMock>()), + _waitingToRunMask(0), _currentlyRunning(kNoThread), - _now(fassert(18653, dateFromISOString("2014-08-01T00:00:00Z"))), _hasStarted(false), _inShutdown(false), _executorNextWakeupDate(Date_t::max()) {} @@ -416,8 +416,11 @@ Date_t NetworkInterfaceMock::runUntil(Date_t until) { if (until < newNow) { newNow = until; } - invariant(_now_inlock() <= newNow); - _now = newNow; + + auto duration = newNow - _now_inlock(); + invariant(duration >= Milliseconds{0}); + _clkSource->advance(duration); + _waitingToRunMask |= kExecutorThread; } _runReadyNetworkOperations_inlock(&lk); @@ -427,8 +430,10 @@ Date_t NetworkInterfaceMock::runUntil(Date_t until) { void NetworkInterfaceMock::advanceTime(Date_t newTime) { stdx::unique_lock<stdx::mutex> lk(_mutex); invariant(_currentlyRunning == kNetworkThread); - invariant(newTime > _now_inlock()); - _now = newTime; + + auto duration = newTime - _now_inlock(); + invariant(duration > Milliseconds{0}); + _clkSource->advance(duration); _waitingToRunMask |= kExecutorThread; _runReadyNetworkOperations_inlock(&lk); @@ -720,10 +725,5 @@ NetworkInterfaceMock* NetworkInterfaceMock::InNetworkGuard::operator->() const { return _net; } -NetworkInterfaceMockClockSource::NetworkInterfaceMockClockSource(NetworkInterfaceMock* net) - : _net(net) { - _tracksSystemClock = false; -} - } // namespace executor } // namespace mongo diff --git a/src/mongo/executor/network_interface_mock.h b/src/mongo/executor/network_interface_mock.h index 8781101329d..911917523fc 100644 --- a/src/mongo/executor/network_interface_mock.h +++ b/src/mongo/executor/network_interface_mock.h @@ -42,6 +42,7 @@ #include "mongo/stdx/unordered_map.h" #include "mongo/stdx/unordered_set.h" #include "mongo/util/clock_source.h" +#include "mongo/util/clock_source_mock.h" #include "mongo/util/time_support.h" namespace mongo { @@ -319,7 +320,7 @@ private: * Returns the current virtualized time. */ Date_t _now_inlock() const { - return _now; + return _clkSource->now(); } /** @@ -364,6 +365,9 @@ private: // in multi-threaded execution, and so unsynchronized, are labeled (R). stdx::mutex _mutex; // NOLINT + // A mocked clock source. + std::unique_ptr<ClockSourceMock> _clkSource; // (M) + // Condition signaled to indicate that the network processing thread should wake up. stdx::condition_variable _shouldWakeNetworkCondition; // (M) @@ -376,9 +380,6 @@ private: // Indicator of which thread, if any, is currently running. ThreadType _currentlyRunning; // (M) - // The current time reported by this instance of NetworkInterfaceMock. - Date_t _now; // (M) - // Set to true by "startUp()" bool _hasStarted; // (M) @@ -556,25 +557,5 @@ private: bool _callExitNetwork = true; }; -class NetworkInterfaceMockClockSource : public ClockSource { -public: - explicit NetworkInterfaceMockClockSource(NetworkInterfaceMock* net); - - Milliseconds getPrecision() override { - return Milliseconds{1}; - } - Date_t now() override { - return _net->now(); - } - Status setAlarm(Date_t when, unique_function<void()> action) override { - return _net->setAlarm(TaskExecutor::CallbackHandle(), - when, - [action = std::move(action)](Status) { action(); }); - } - -private: - NetworkInterfaceMock* _net; -}; - } // namespace executor } // namespace mongo diff --git a/src/mongo/s/mongos_topology_coordinator_test.cpp b/src/mongo/s/mongos_topology_coordinator_test.cpp index 012dd4d9b41..5959e939754 100644 --- a/src/mongo/s/mongos_topology_coordinator_test.cpp +++ b/src/mongo/s/mongos_topology_coordinator_test.cpp @@ -49,18 +49,15 @@ public: virtual void setUp() { _topo = std::make_unique<MongosTopologyCoordinator>(); - getServiceContext()->setFastClockSource(std::make_unique<ClockSourceMock>()); - _fastClock = dynamic_cast<ClockSourceMock*>(getServiceContext()->getFastClockSource()); - - getServiceContext()->setPreciseClockSource(std::make_unique<ClockSourceMock>()); - _preciseClock = - dynamic_cast<ClockSourceMock*>(getServiceContext()->getPreciseClockSource()); + // The fast clock is used by OperationContext::hasDeadlineExpired. + getServiceContext()->setFastClockSource( + std::make_unique<SharedClockSourceAdapter>(_clkSource)); + // The precise clock is used by waitForConditionOrInterruptNoAssertUntil. + getServiceContext()->setPreciseClockSource( + std::make_unique<SharedClockSourceAdapter>(_clkSource)); } - virtual void tearDown() { - _fastClock = nullptr; - _preciseClock = nullptr; - } + virtual void tearDown() {} protected: /** @@ -74,24 +71,19 @@ protected: * Advance the time by millis on both clock source mocks. */ void advanceTime(Milliseconds millis) { - _fastClock->advance(millis); - _preciseClock->advance(millis); + _clkSource->advance(millis); } /** * Assumes that the times on both clock source mocks is the same. */ Date_t now() { - invariant(_fastClock->now() == _preciseClock->now()); - return _fastClock->now(); + return _clkSource->now(); } private: - unique_ptr<MongosTopologyCoordinator> _topo; - // The fast clock is used by OperationContext::hasDeadlineExpired. - ClockSourceMock* _fastClock; - // The precise clock is used by waitForConditionOrInterruptNoAssertUntil. - ClockSourceMock* _preciseClock; + std::unique_ptr<MongosTopologyCoordinator> _topo; + std::shared_ptr<ClockSourceMock> _clkSource = std::make_shared<ClockSourceMock>(); }; TEST_F(MongosTopoCoordTest, MongosTopologyVersionCounterInitializedAtStartup) { @@ -120,7 +112,6 @@ TEST_F(MongosTopoCoordTest, AwaitIsMasterResponseReturnsCurrentMongosTopologyVer auto opCtx = makeOperationContext(); auto maxAwaitTime = Milliseconds(5000); auto halfwayToMaxAwaitTime = maxAwaitTime / 2; - auto halfwayToDeadline = now() + halfwayToMaxAwaitTime; auto deadline = now() + maxAwaitTime; // isMaster request with the current TopologyVersion should attempt to wait for maxAwaitTimeMS. @@ -141,12 +132,10 @@ TEST_F(MongosTopoCoordTest, AwaitIsMasterResponseReturnsCurrentMongosTopologyVer // Advance the clocks halfway and make sure awaitIsMasterResponse did not return yet. advanceTime(halfwayToMaxAwaitTime); - ASSERT_EQUALS(halfwayToDeadline, now()); ASSERT_FALSE(isMasterReturned); // Advance the clocks the rest of the way so that awaitIsMasterResponse times out. advanceTime(halfwayToMaxAwaitTime); - ASSERT_EQUALS(deadline, now()); getIsMasterThread.join(); ASSERT_TRUE(isMasterReturned); } @@ -300,4 +289,4 @@ TEST_F(MongosTopoCoordTest, IsMasterReturnsErrorOnEnteringQuiesceMode) { } } // namespace -} // namespace mongo
\ No newline at end of file +} // namespace mongo diff --git a/src/mongo/util/clock_source_mock.cpp b/src/mongo/util/clock_source_mock.cpp index 0319e67b481..c50aca29a82 100644 --- a/src/mongo/util/clock_source_mock.cpp +++ b/src/mongo/util/clock_source_mock.cpp @@ -31,55 +31,91 @@ #include "mongo/platform/mutex.h" #include "mongo/util/clock_source_mock.h" +#include "mongo/util/static_immortal.h" #include <algorithm> namespace mongo { +namespace { +/** + * This is a synchronized global mocked ClockSource. + * + * For ease of use, this is the underlying source behind *every* clock source. + **/ +class ClockSourceMockImpl { +public: + using Alarm = std::pair<Date_t, unique_function<void()>>; + + static ClockSourceMockImpl* get() noexcept { + static auto clkSource = StaticImmortal<ClockSourceMockImpl>(); + return &clkSource.value(); + } + + Date_t now() { + stdx::lock_guard<stdx::mutex> lk(_mutex); + return _now; + } + + void advance(Milliseconds ms) { + stdx::unique_lock<stdx::mutex> lk(_mutex); + _now += ms; + _processAlarms(std::move(lk)); + } + void reset(Date_t newNow) { + stdx::unique_lock<stdx::mutex> lk(_mutex); + _now = newNow; + _processAlarms(std::move(lk)); + } + + Status setAlarm(Date_t when, unique_function<void()> action) { + stdx::unique_lock<stdx::mutex> lk(_mutex); + if (when <= _now) { + lk.unlock(); + action(); + return Status::OK(); + } + _alarms.emplace_back(when, std::move(action)); + return Status::OK(); + } + +private: + void _processAlarms(stdx::unique_lock<stdx::mutex> lk) { + invariant(lk.owns_lock()); + std::vector<Alarm> readyAlarms; + auto alarmIsNotExpired = [&](const Alarm& alarm) { return alarm.first > _now; }; + auto expiredAlarmsBegin = std::partition(_alarms.begin(), _alarms.end(), alarmIsNotExpired); + std::move(expiredAlarmsBegin, _alarms.end(), std::back_inserter(readyAlarms)); + _alarms.erase(expiredAlarmsBegin, _alarms.end()); + lk.unlock(); + for (const auto& alarm : readyAlarms) { + alarm.second(); + } + } + + stdx::mutex _mutex; // NOLINT + Date_t _now = ClockSourceMock::kInitialNow; + std::vector<Alarm> _alarms; +}; +} // namespace Milliseconds ClockSourceMock::getPrecision() { return Milliseconds(1); } Date_t ClockSourceMock::now() { - stdx::lock_guard<stdx::mutex> lk(_mutex); - return _now; + return ClockSourceMockImpl::get()->now(); } void ClockSourceMock::advance(Milliseconds ms) { - stdx::unique_lock<stdx::mutex> lk(_mutex); - _now += ms; - _processAlarms(std::move(lk)); + ClockSourceMockImpl::get()->advance(ms); } void ClockSourceMock::reset(Date_t newNow) { - stdx::unique_lock<stdx::mutex> lk(_mutex); - _now = newNow; - _processAlarms(std::move(lk)); + ClockSourceMockImpl::get()->reset(newNow); } Status ClockSourceMock::setAlarm(Date_t when, unique_function<void()> action) { - stdx::unique_lock<stdx::mutex> lk(_mutex); - if (when <= _now) { - lk.unlock(); - action(); - return Status::OK(); - } - _alarms.emplace_back(std::make_pair(when, std::move(action))); - return Status::OK(); -} - -void ClockSourceMock::_processAlarms(stdx::unique_lock<stdx::mutex> lk) { - using std::swap; - invariant(lk.owns_lock()); - std::vector<Alarm> readyAlarms; - auto alarmIsNotExpired = [&](const Alarm& alarm) { return alarm.first > _now; }; - auto expiredAlarmsBegin = std::partition(_alarms.begin(), _alarms.end(), alarmIsNotExpired); - std::move(expiredAlarmsBegin, _alarms.end(), std::back_inserter(readyAlarms)); - _alarms.erase(expiredAlarmsBegin, _alarms.end()); - lk.unlock(); - for (const auto& alarm : readyAlarms) { - alarm.second(); - } + return ClockSourceMockImpl::get()->setAlarm(when, std::move(action)); } } // namespace mongo diff --git a/src/mongo/util/clock_source_mock.h b/src/mongo/util/clock_source_mock.h index 689a03832f7..44f3eb13283 100644 --- a/src/mongo/util/clock_source_mock.h +++ b/src/mongo/util/clock_source_mock.h @@ -41,9 +41,13 @@ namespace mongo { /** * Mock clock source that returns a fixed time until explicitly advanced. + * + * Each ClockSourceMock that is constructed tracks the same shared global understanding of time. */ class ClockSourceMock : public ClockSource { public: + static constexpr auto kInitialNow = Date_t::fromMillisSinceEpoch(1); + /** * Constructs a ClockSourceMock with the current time set to the Unix epoch. */ @@ -51,6 +55,8 @@ public: _tracksSystemClock = false; } + static ClockSourceMock* get() noexcept; + Milliseconds getPrecision() override; Date_t now() override; Status setAlarm(Date_t when, unique_function<void()> action) override; @@ -63,15 +69,7 @@ public: /** * Resets the current time to the given value. */ - void reset(Date_t newNow); - -private: - using Alarm = std::pair<Date_t, unique_function<void()>>; - void _processAlarms(stdx::unique_lock<stdx::mutex> lk); - - stdx::mutex _mutex; // NOLINT - Date_t _now{Date_t::fromMillisSinceEpoch(1)}; - std::vector<Alarm> _alarms; + void reset(Date_t newNow = kInitialNow); }; /** |