summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Boros <ian.boros@mongodb.com>2019-09-06 16:21:27 +0000
committerevergreen <evergreen@mongodb.com>2019-09-06 16:21:27 +0000
commit0d9d438513643d95fba019080f3fc605afdf255d (patch)
tree3656856aa9835951da4ae1b8ec927a0d86ab4f17
parentb2d1b22788c295d247482cf2b19631585a10ad19 (diff)
downloadmongo-0d9d438513643d95fba019080f3fc605afdf255d.tar.gz
SERVER-41863 make sleep command wait until server clock has advanced
-rw-r--r--src/mongo/db/commands/test_commands.cpp63
1 files changed, 42 insertions, 21 deletions
diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp
index 8f6046e9ffb..10275031ddb 100644
--- a/src/mongo/db/commands/test_commands.cpp
+++ b/src/mongo/db/commands/test_commands.cpp
@@ -49,6 +49,7 @@
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/service_context.h"
#include "mongo/util/log.h"
+#include "mongo/util/scopeguard.h"
namespace mongo {
@@ -156,39 +157,59 @@ public:
const BSONObj& cmdObj,
BSONObjBuilder& result) {
log() << "test only command sleep invoked";
- long long millis = 0;
+ Milliseconds msToSleep(0);
if (cmdObj["secs"] || cmdObj["millis"]) {
if (cmdObj["secs"]) {
uassert(34344, "'secs' must be a number.", cmdObj["secs"].isNumber());
- millis += cmdObj["secs"].numberLong() * 1000;
+ msToSleep += Milliseconds(cmdObj["secs"].numberLong() * 1000);
}
if (cmdObj["millis"]) {
uassert(34345, "'millis' must be a number.", cmdObj["millis"].isNumber());
- millis += cmdObj["millis"].numberLong();
+ msToSleep += Milliseconds(cmdObj["millis"].numberLong());
}
} else {
- millis = 10 * 1000;
+ msToSleep = Milliseconds(10 * 1000);
}
- if (!cmdObj["lock"]) {
- // Legacy implementation
- if (cmdObj.getBoolField("w")) {
- _sleepInWriteLock(opCtx, millis);
- } else {
- _sleepInReadLock(opCtx, millis);
- }
- } else {
- uassert(34346, "Only one of 'w' and 'lock' may be set.", !cmdObj["w"]);
-
- std::string lock(cmdObj.getStringField("lock"));
- if (lock == "none") {
- opCtx->sleepFor(Milliseconds(millis));
- } else if (lock == "w") {
- _sleepInWriteLock(opCtx, millis);
+ auto now = opCtx->getServiceContext()->getFastClockSource()->now();
+ auto deadline = now + Milliseconds(msToSleep);
+
+ // Note that if the system clock moves _backwards_ (which has been known to happen), this
+ // could result in a much longer sleep than requested. Since this command is only used for
+ // testing, we're okay with this imprecision.
+ while (deadline > now) {
+ Milliseconds msRemaining = deadline - now;
+
+ // If the clock moves back by an absurd amount then uassert.
+ Milliseconds threshold(10000);
+ uassert(31173,
+ str::stream() << "Clock must have moved backwards by at least " << threshold
+ << " ms during sleep command",
+ msRemaining < msToSleep + threshold);
+
+ ON_BLOCK_EXIT(
+ [&now, opCtx] { now = opCtx->getServiceContext()->getFastClockSource()->now(); });
+
+ if (!cmdObj["lock"]) {
+ // Legacy implementation
+ if (cmdObj.getBoolField("w")) {
+ _sleepInWriteLock(opCtx, msRemaining.count());
+ } else {
+ _sleepInReadLock(opCtx, msRemaining.count());
+ }
} else {
- uassert(34347, "'lock' must be one of 'r', 'w', 'none'.", lock == "r");
- _sleepInReadLock(opCtx, millis);
+ uassert(34346, "Only one of 'w' and 'lock' may be set.", !cmdObj["w"]);
+
+ std::string lock(cmdObj.getStringField("lock"));
+ if (lock == "none") {
+ opCtx->sleepFor(msRemaining);
+ } else if (lock == "w") {
+ _sleepInWriteLock(opCtx, msRemaining.count());
+ } else {
+ uassert(34347, "'lock' must be one of 'r', 'w', 'none'.", lock == "r");
+ _sleepInReadLock(opCtx, msRemaining.count());
+ }
}
}