summaryrefslogtreecommitdiff
path: root/src/mongo/db/curop.cpp
diff options
context:
space:
mode:
authorJason Rassi <rassi@10gen.com>2013-07-26 15:37:21 -0400
committerJason Rassi <rassi@10gen.com>2013-07-26 16:37:53 -0400
commit950d8deb486b4608828e0c4f7e9caa3e7d84fed8 (patch)
tree69ad420cc19713899697bf1c86c020789983c696 /src/mongo/db/curop.cpp
parent6f8b9d5515591beaaa6f58c8fdabb9ddd2b2450f (diff)
downloadmongo-950d8deb486b4608828e0c4f7e9caa3e7d84fed8.tar.gz
SERVER-2212 Ability for CurOp objects to be "timer-interruptible"
- New public methods introduced to CurOp for requesting op interruption after a given time period. - KillCurrentOp objects now additionally tasked with interrupting CurOp objects that have exceeded their time limit, during the "interrupt check".
Diffstat (limited to 'src/mongo/db/curop.cpp')
-rw-r--r--src/mongo/db/curop.cpp91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
index 8544e47ab26..41f6df82604 100644
--- a/src/mongo/db/curop.cpp
+++ b/src/mongo/db/curop.cpp
@@ -48,6 +48,7 @@ namespace mongo {
_command = false;
_dbprofile = 0;
_end = 0;
+ _maxTimeTracker.reset();
_message = "";
_progressMeter.finished();
_killPending.store(0);
@@ -256,6 +257,24 @@ namespace mongo {
}
}
+ void CurOp::setMaxTimeMicros(uint64_t maxTimeMicros) {
+ if (maxTimeMicros == 0) {
+ // 0 is "allow to run indefinitely".
+ return;
+ }
+
+ // Note that calling startTime() will set CurOp::_start if it hasn't been set yet.
+ _maxTimeTracker.setTimeLimit(startTime(), maxTimeMicros);
+ }
+
+ bool CurOp::maxTimeHasExpired() {
+ return _maxTimeTracker.checkTimeLimit();
+ }
+
+ uint64_t CurOp::getRemainingMaxTimeMicros() const {
+ return _maxTimeTracker.getRemainingMicros();
+ }
+
AtomicUInt CurOp::_nextOpNum;
static Counter64 returnedCounter;
@@ -297,4 +316,76 @@ namespace mongo {
if ( fastmod )
fastmodCounter.increment();
}
+
+ CurOp::MaxTimeTracker::MaxTimeTracker() {
+ reset();
+ }
+
+ void CurOp::MaxTimeTracker::reset() {
+ _enabled = false;
+ _targetEpochMicros = 0;
+ _approxTargetServerMillis = 0;
+ }
+
+ void CurOp::MaxTimeTracker::setTimeLimit(uint64_t startEpochMicros, uint64_t durationMicros) {
+ dassert(durationMicros != 0);
+
+ _enabled = true;
+
+ _targetEpochMicros = startEpochMicros + durationMicros;
+
+ uint64_t now = curTimeMicros64();
+ // If our accurate time source thinks time is not up yet, calculate the next target for
+ // our approximate time source.
+ if (_targetEpochMicros > now) {
+ _approxTargetServerMillis = Listener::getElapsedTimeMillis() +
+ static_cast<int64_t>((_targetEpochMicros - now) / 1000);
+ }
+ // Otherwise, set our approximate time source target such that it thinks time is already
+ // up.
+ else {
+ _approxTargetServerMillis = Listener::getElapsedTimeMillis();
+ }
+ }
+
+ bool CurOp::MaxTimeTracker::checkTimeLimit() {
+ if (!_enabled) {
+ return false;
+ }
+
+ // Does our approximate time source think time is not up yet? If so, return early.
+ if (_approxTargetServerMillis > Listener::getElapsedTimeMillis()) {
+ return false;
+ }
+
+ uint64_t now = curTimeMicros64();
+ // Does our accurate time source think time is not up yet? If so, readjust the target for
+ // our approximate time source and return early.
+ if (_targetEpochMicros > now) {
+ _approxTargetServerMillis = Listener::getElapsedTimeMillis() +
+ static_cast<int64_t>((_targetEpochMicros - now) / 1000);
+ return false;
+ }
+
+ // Otherwise, time is up.
+ return true;
+ }
+
+ uint64_t CurOp::MaxTimeTracker::getRemainingMicros() const {
+ if (!_enabled) {
+ // 0 is "allow to run indefinitely".
+ return 0;
+ }
+
+ // Does our accurate time source think time is up? If so, claim there is 1 microsecond
+ // left for this operation.
+ uint64_t now = curTimeMicros64();
+ if (_targetEpochMicros <= now) {
+ return 1;
+ }
+
+ // Otherwise, calculate remaining time.
+ return _targetEpochMicros - now;
+ }
+
}