summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Heppenstall <jamie.heppenstall@mongodb.com>2020-05-08 16:52:12 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-05-12 20:26:53 +0000
commit02ceb3f342d4295aef49b3b1d5479930496186f0 (patch)
treebaca4a4374e455af7499aa6237c0a50c3910fca5
parentc4c5768798b72027a7b40eb0bbf4455f7e9564b9 (diff)
downloadmongo-02ceb3f342d4295aef49b3b1d5479930496186f0.tar.gz
SERVER-46698 Invariant that operations holding open an oplog hole cannot call blocking functions
-rw-r--r--src/mongo/db/concurrency/lock_state.cpp10
-rw-r--r--src/mongo/db/concurrency/locker.h2
-rw-r--r--src/mongo/db/storage/recovery_unit.h8
-rw-r--r--src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h4
4 files changed, 23 insertions, 1 deletions
diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp
index 5a2871a563b..e668bcd1cc2 100644
--- a/src/mongo/db/concurrency/lock_state.cpp
+++ b/src/mongo/db/concurrency/lock_state.cpp
@@ -353,6 +353,12 @@ bool LockerImpl::_acquireTicket(OperationContext* opCtx, LockMode mode, Date_t d
// If the ticket wait is interrupted, restore the state of the client.
auto restoreStateOnErrorGuard = makeGuard([&] { _clientState.store(kInactive); });
+ // Acquiring a ticket is a potentially blocking operation. This must not be called after a
+ // transaction timestamp has been set, indicating this transaction has created an oplog
+ // hole.
+ if (opCtx)
+ invariant(!opCtx->recoveryUnit()->isTimestamped());
+
OperationContext* interruptible = _uninterruptibleLocksRequested ? nullptr : opCtx;
if (deadline == Date_t::max()) {
holder->waitForTicket(interruptible);
@@ -1002,6 +1008,10 @@ void LockerImpl::getFlowControlTicket(OperationContext* opCtx, LockMode lockMode
// tracking whether other resources need to be released.
_clientState.store(kQueuedWriter);
auto restoreState = makeGuard([&] { _clientState.store(kInactive); });
+ // Acquiring a ticket is a potentially blocking operation. This must not be called after a
+ // transaction timestamp has been set, indicating this transaction has created an oplog
+ // hole.
+ invariant(!opCtx->recoveryUnit()->isTimestamped());
ticketholder->getTicket(opCtx, &_flowControlStats);
}
}
diff --git a/src/mongo/db/concurrency/locker.h b/src/mongo/db/concurrency/locker.h
index 48674103bd5..34ac15d8586 100644
--- a/src/mongo/db/concurrency/locker.h
+++ b/src/mongo/db/concurrency/locker.h
@@ -71,7 +71,7 @@ public:
* Require global lock attempts to obtain tickets from 'reading' (for MODE_S and MODE_IS),
* and from 'writing' (for MODE_IX), which must have static lifetimes. There is no throttling
* for MODE_X, as there can only ever be a single locker using this mode. The throttling is
- * intended to defend against arge drops in throughput under high load due to too much
+ * intended to defend against large drops in throughput under high load due to too much
* concurrency.
*/
static void setGlobalThrottling(class TicketHolder* reading, class TicketHolder* writing);
diff --git a/src/mongo/db/storage/recovery_unit.h b/src/mongo/db/storage/recovery_unit.h
index eeddfafd624..b2e5aefa051 100644
--- a/src/mongo/db/storage/recovery_unit.h
+++ b/src/mongo/db/storage/recovery_unit.h
@@ -292,6 +292,14 @@ public:
}
/**
+ * Returns true if a commit timestamp has been assigned to writes in this transaction.
+ * Otherwise, returns false.
+ */
+ virtual bool isTimestamped() const {
+ return false;
+ }
+
+ /**
* Sets a timestamp that will be assigned to all future writes on this RecoveryUnit until
* clearCommitTimestamp() is called. This must be called either outside of a WUOW or on a
* prepared transaction after setPrepareTimestamp() is called. setTimestamp() must not be called
diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h
index 19c67fcfe62..373794582a2 100644
--- a/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h
+++ b/src/mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h
@@ -117,6 +117,10 @@ public:
Status setTimestamp(Timestamp timestamp) override;
+ bool isTimestamped() const override {
+ return _isTimestamped;
+ }
+
void setCommitTimestamp(Timestamp timestamp) override;
void clearCommitTimestamp() override;