diff options
author | Ian Boros <ian.boros@mongodb.com> | 2019-09-05 20:32:39 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-09-05 20:32:39 +0000 |
commit | afc3f0f7faa0417e6f5e46b45cd47eb3e838fb73 (patch) | |
tree | d8df3a2e166495bfe8679fdc4da957c1ea057831 | |
parent | 273ed84bc7eb6cc0e38eca16088fc1a454f1cb28 (diff) | |
download | mongo-afc3f0f7faa0417e6f5e46b45cd47eb3e838fb73.tar.gz |
SERVER-41863 make sleep command wait until server clock has advanced
-rw-r--r-- | src/mongo/db/commands/sleep_command.cpp | 86 |
1 files changed, 59 insertions, 27 deletions
diff --git a/src/mongo/db/commands/sleep_command.cpp b/src/mongo/db/commands/sleep_command.cpp index 08d126061b0..0653cdd5ece 100644 --- a/src/mongo/db/commands/sleep_command.cpp +++ b/src/mongo/db/commands/sleep_command.cpp @@ -86,39 +86,71 @@ public: const BSONObj& cmdObj, BSONObjBuilder& result) { log() << "test only command sleep invoked"; - long long millis = 0; - - if (cmdObj["secs"] || cmdObj["millis"]) { - if (cmdObj["secs"]) { - uassert(34344, "'secs' must be a number.", cmdObj["secs"].isNumber()); - millis += cmdObj["secs"].numberLong() * 1000; + long long msToSleep = 0; + + if (cmdObj["secs"] || cmdObj["seconds"] || cmdObj["millis"]) { + uassert(51153, + "Only one of 'secs' and 'seconds' may be specified", + !(cmdObj["secs"] && cmdObj["seconds"])); + + if (auto secsElem = cmdObj["secs"]) { + uassert(34344, "'secs' must be a number.", secsElem.isNumber()); + msToSleep += secsElem.numberLong() * 1000; + } else if (auto secondsElem = cmdObj["seconds"]) { + uassert(51154, "'seconds' must be a number.", secondsElem.isNumber()); + msToSleep += secondsElem.numberLong() * 1000; } - if (cmdObj["millis"]) { - uassert(34345, "'millis' must be a number.", cmdObj["millis"].isNumber()); - millis += cmdObj["millis"].numberLong(); + + if (auto millisElem = cmdObj["millis"]) { + uassert(34345, "'millis' must be a number.", millisElem.isNumber()); + msToSleep += millisElem.numberLong(); } } else { - millis = 10 * 1000; + msToSleep = 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"]); + auto now = opCtx->getServiceContext()->getFastClockSource()->now(); + auto deadline = now + Milliseconds(msToSleep); - std::string lock(cmdObj.getStringField("lock")); - if (lock == "none") { - opCtx->sleepFor(Milliseconds(millis)); - } else if (lock == "w") { - _sleepInWriteLock(opCtx, millis); + // 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.count() < msToSleep + threshold.count()); + + ON_BLOCK_EXIT( + [&now, opCtx] { now = opCtx->getServiceContext()->getFastClockSource()->now(); }); + + StringData lockTarget; + if (cmdObj["lockTarget"]) { + lockTarget = cmdObj["lockTarget"].checkAndGetStringData(); + } + 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()); + } } } @@ -130,4 +162,4 @@ public: }; MONGO_REGISTER_TEST_COMMAND(CmdSleep); -} // namespace +} // namespace mongo |