summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Boros <puppyofkosh@gmail.com>2019-07-05 12:59:44 -0400
committerIan Boros <puppyofkosh@gmail.com>2019-07-08 12:25:56 -0400
commitb0770322568c42ab8480be6a220bd5349349af23 (patch)
treec2a3cb2917bfda0e805c825e8a33a3ca220e4486
parentaf3b8d9af0ee9a8d16d68d4f09feb9696a15c35d (diff)
downloadmongo-b0770322568c42ab8480be6a220bd5349349af23.tar.gz
SERVER-41863 sleep command waits for server clock to advance by duration requested
-rw-r--r--src/mongo/db/commands/test_commands.cpp67
1 files changed, 44 insertions, 23 deletions
diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp
index 359e97292c5..86c94971c92 100644
--- a/src/mongo/db/commands/test_commands.cpp
+++ b/src/mongo/db/commands/test_commands.cpp
@@ -47,6 +47,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 {
@@ -155,51 +156,71 @@ public:
}
CmdSleep() : Command("sleep") {}
- bool run(OperationContext* txn,
+ bool run(OperationContext* opCtx,
const string& ns,
BSONObj& cmdObj,
int,
string& errmsg,
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(txn, millis);
- } else {
- _sleepInReadLock(txn, millis);
- }
- } else {
- uassert(34346, "Only one of 'w' and 'lock' may be set.", !cmdObj["w"]);
-
- std::string lock(cmdObj.getStringField("lock"));
- if (lock == "none") {
- sleepmillis(millis);
- } else if (lock == "w") {
- _sleepInWriteLock(txn, 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(txn, millis);
+ uassert(34346, "Only one of 'w' and 'lock' may be set.", !cmdObj["w"]);
+
+ std::string lock(cmdObj.getStringField("lock"));
+ if (lock == "none") {
+ sleepmillis(msRemaining.count());
+ } 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());
+ }
}
}
// Interrupt point for testing (e.g. maxTimeMS).
- txn->checkForInterrupt();
+ opCtx->checkForInterrupt();
return true;
}