summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-03-21 18:30:52 -0400
committerMathias Stearn <mathias@10gen.com>2017-03-22 19:15:21 -0400
commitd55eaad5cdfcfbe8458658d39f8c57102c3b3504 (patch)
tree85657a3a7d2f38c6c2059786a51062437561d377 /src/mongo/util
parent86bc5bdac397909e246f0ea19f5414387bb6b0a9 (diff)
downloadmongo-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.cpp10
-rw-r--r--src/mongo/util/background_thread_clock_source.h7
-rw-r--r--src/mongo/util/background_thread_clock_source_test.cpp73
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