diff options
author | Mathias Stearn <mathias@10gen.com> | 2017-03-21 18:30:52 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2017-03-22 19:15:21 -0400 |
commit | d55eaad5cdfcfbe8458658d39f8c57102c3b3504 (patch) | |
tree | 85657a3a7d2f38c6c2059786a51062437561d377 /src/mongo/util | |
parent | 86bc5bdac397909e246f0ea19f5414387bb6b0a9 (diff) | |
download | mongo-d55eaad5cdfcfbe8458658d39f8c57102c3b3504.tar.gz |
SERVER-21538 Use mockable cv wait in background_thread_clock_source_test
This both makes the test run much faster and avoids spurious failures when
the system scheduler decides not to run a thread for over a second.
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/background_thread_clock_source.cpp | 10 | ||||
-rw-r--r-- | src/mongo/util/background_thread_clock_source.h | 7 | ||||
-rw-r--r-- | src/mongo/util/background_thread_clock_source_test.cpp | 73 |
3 files changed, 55 insertions, 35 deletions
diff --git a/src/mongo/util/background_thread_clock_source.cpp b/src/mongo/util/background_thread_clock_source.cpp index d55e046a845..b533d52b8ea 100644 --- a/src/mongo/util/background_thread_clock_source.cpp +++ b/src/mongo/util/background_thread_clock_source.cpp @@ -46,6 +46,7 @@ BackgroundThreadClockSource::BackgroundThreadClockSource(std::unique_ptr<ClockSo Milliseconds granularity) : _clockSource(std::move(clockSource)), _granularity(granularity) { _startTimerThread(); + _tracksSystemClock = _clockSource->tracksSystemClock(); } BackgroundThreadClockSource::~BackgroundThreadClockSource() { @@ -62,6 +63,10 @@ Milliseconds BackgroundThreadClockSource::getPrecision() { return _granularity; } +Status BackgroundThreadClockSource::setAlarm(Date_t when, stdx::function<void()> action) { + return _clockSource->setAlarm(when, action); +} + Date_t BackgroundThreadClockSource::now() { // Since this is called very frequently by many threads, the common case should not write to // shared memory. @@ -112,8 +117,9 @@ void BackgroundThreadClockSource::_startTimerThread() { _condition.wait(lock, [this] { return _inShutdown || _current.load() != 0; }); } - _condition.wait_for( - lock, _granularity.toSystemDuration(), [this] { return _inShutdown; }); + const auto sleepUntil = Date_t::fromMillisSinceEpoch(_current.load()) + _granularity; + _clockSource->waitForConditionUntil( + _condition, lock, sleepUntil, [this] { return _inShutdown; }); } }); diff --git a/src/mongo/util/background_thread_clock_source.h b/src/mongo/util/background_thread_clock_source.h index 55d0096f58c..03e9e4e302f 100644 --- a/src/mongo/util/background_thread_clock_source.h +++ b/src/mongo/util/background_thread_clock_source.h @@ -56,12 +56,15 @@ public: ~BackgroundThreadClockSource() override; Milliseconds getPrecision() override; Date_t now() override; + Status setAlarm(Date_t when, stdx::function<void()> action) override; /** * Doesn't count as a call to now() for determining whether this ClockSource is idle. + * + * Unlike now(), returns Date_t() if the thread is currently paused. */ - int64_t peekNowForTest() const { - return _current.load(); + Date_t peekNowForTest() const { + return Date_t::fromMillisSinceEpoch(_current.load()); } private: diff --git a/src/mongo/util/background_thread_clock_source_test.cpp b/src/mongo/util/background_thread_clock_source_test.cpp index fe8b1b22c5e..0d293a0f28c 100644 --- a/src/mongo/util/background_thread_clock_source_test.cpp +++ b/src/mongo/util/background_thread_clock_source_test.cpp @@ -53,6 +53,16 @@ public: } protected: + void waitForIdleDetection() { + auto start = _csMock->now(); + while (_btcs->peekNowForTest() != Date_t()) { + // If the bg thread doesn't notice idleness within a minute, something is wrong. + ASSERT_LT(_csMock->now() - start, Minutes(1)); + _csMock->advance(Milliseconds(1)); + sleepFor(Milliseconds(1)); + } + } + std::unique_ptr<BackgroundThreadClockSource> _btcs; ClockSourceMock* _csMock; }; @@ -69,8 +79,8 @@ TEST_F(BTCSTest, TimeKeeping) { setUpClocks(Milliseconds(1)); ASSERT_EQUALS(_btcs->now(), _csMock->now()); - _csMock->advance(Milliseconds(100)); - sleepFor(Seconds(1)); // give the _btcs opportunity to read the new time + waitForIdleDetection(); + ASSERT_EQUALS(_btcs->now(), _csMock->now()); } @@ -81,69 +91,70 @@ TEST_F(BTCSTest, GetPrecision) { TEST_F(BTCSTest, StartsPaused) { setUpClocks(Milliseconds(1)); - ASSERT_EQUALS(_btcs->peekNowForTest(), 0); + ASSERT_EQUALS(_btcs->peekNowForTest(), Date_t()); } TEST_F(BTCSTest, PausesAfterRead) { - setUpClocks(Milliseconds(100)); + const auto kGranularity = Milliseconds(5); + setUpClocks(kGranularity); // Wake it up. - auto now = _btcs->now().toMillisSinceEpoch(); - ASSERT_NE(now, 0); + const auto now = _btcs->now(); + ASSERT_NE(now, Date_t()); ASSERT_EQ(_btcs->peekNowForTest(), now); - _csMock->advance(Milliseconds(100)); - ASSERT_EQ(_btcs->now().toMillisSinceEpoch(), now); + _csMock->advance(kGranularity - Milliseconds(1)); + ASSERT_EQ(_btcs->now(), now); - sleepFor(Seconds(1)); // give the _btcs opportunity to detect idleness. - ASSERT_EQ(_btcs->peekNowForTest(), 0); + waitForIdleDetection(); // Only returns when the thread is paused. } TEST_F(BTCSTest, DoesntPauseWhenInUse) { - setUpClocks(Milliseconds(100)); + const auto kGranularity = Milliseconds(5); + setUpClocks(kGranularity); - auto lastTime = _btcs->now().toMillisSinceEpoch(); - ASSERT_NE(lastTime, 0); - ASSERT_EQ(lastTime, _btcs->now().toMillisSinceEpoch()); // Mark the timer as still in use. - auto ticks = 0; // Count of when times change. + auto lastTime = _btcs->now(); + ASSERT_NE(lastTime, Date_t()); + ASSERT_EQ(lastTime, _btcs->now()); // Mark the timer as still in use. + auto ticks = 0; // Count of when times change. while (ticks < 10) { if (_btcs->peekNowForTest() == lastTime) { _csMock->advance(Milliseconds(1)); - ASSERT_LT(_csMock->now().toMillisSinceEpoch() - lastTime, 1000); + ASSERT_LT(_csMock->now() - lastTime, Minutes(1)); sleepFor(Milliseconds(1)); continue; } ticks++; - ASSERT_NE(_btcs->peekNowForTest(), 0); - lastTime = _btcs->now().toMillisSinceEpoch(); - ASSERT_NE(lastTime, 0); + ASSERT_NE(_btcs->peekNowForTest(), Date_t()); + lastTime = _btcs->now(); + ASSERT_NE(lastTime, Date_t()); ASSERT_EQ(lastTime, _btcs->peekNowForTest()); } } TEST_F(BTCSTest, WakesAfterPause) { - setUpClocks(Milliseconds(10)); + const auto kGranularity = Milliseconds(5); + setUpClocks(kGranularity); // Wake it up. - auto now = _btcs->now().toMillisSinceEpoch(); - ASSERT_NE(now, 0); + const auto now = _btcs->now(); + ASSERT_NE(now, Date_t()); ASSERT_EQ(_btcs->peekNowForTest(), now); - _csMock->advance(Milliseconds(10)); - ASSERT_EQ(_btcs->now().toMillisSinceEpoch(), now); + _csMock->advance(kGranularity - Milliseconds(1)); + ASSERT_EQ(_btcs->now(), now); - sleepFor(Seconds(1)); // give the _btcs opportunity to detect idleness. - ASSERT_EQ(_btcs->peekNowForTest(), 0); + waitForIdleDetection(); // Wake it up again and ensure it ticks at least once. - auto lastTime = _btcs->now().toMillisSinceEpoch(); - ASSERT_NE(lastTime, 0); - ASSERT_EQ(lastTime, _btcs->now().toMillisSinceEpoch()); // Mark the timer as still in use. + const auto lastTime = _btcs->now(); + ASSERT_NE(lastTime, Date_t()); + ASSERT_EQ(lastTime, _btcs->now()); // Mark the timer as still in use. while (_btcs->peekNowForTest() == lastTime) { _csMock->advance(Milliseconds(1)); - ASSERT_LT(_csMock->now().toMillisSinceEpoch() - lastTime, 1000); + ASSERT_LT(_csMock->now() - lastTime, Minutes(1)); sleepFor(Milliseconds(1)); } - ASSERT_NE(_btcs->peekNowForTest(), 0); + ASSERT_NE(_btcs->peekNowForTest(), Date_t()); } } // namespace |