summaryrefslogtreecommitdiff
path: root/src/mongo/db/db_raii.cpp
diff options
context:
space:
mode:
authormatt dannenberg <matt.dannenberg@10gen.com>2015-08-20 06:23:21 -0400
committermatt dannenberg <matt.dannenberg@10gen.com>2015-08-26 04:29:12 -0400
commit6fbd22f5f812885002b5d4cdd23a8bfec843ce82 (patch)
treedd470a98ad95df7d1a13b257a139bdbf19c18e45 /src/mongo/db/db_raii.cpp
parent9c1a9128384e6cead43ecf7fef38e76363a1213f (diff)
downloadmongo-6fbd22f5f812885002b5d4cdd23a8bfec843ce82.tar.gz
SERVER-20052 yield when waiting/blocking for read committed
Diffstat (limited to 'src/mongo/db/db_raii.cpp')
-rw-r--r--src/mongo/db/db_raii.cpp80
1 files changed, 52 insertions, 28 deletions
diff --git a/src/mongo/db/db_raii.cpp b/src/mongo/db/db_raii.cpp
index a987062b11b..5a0c9f964bd 100644
--- a/src/mongo/db/db_raii.cpp
+++ b/src/mongo/db/db_raii.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/stats/top.h"
#include "mongo/s/d_state.h"
+#include "mongo/util/scopeguard.h"
namespace mongo {
@@ -73,40 +74,63 @@ AutoGetCollectionForRead::AutoGetCollectionForRead(OperationContext* txn, const
AutoGetCollectionForRead::AutoGetCollectionForRead(OperationContext* txn,
const NamespaceString& nss)
: _txn(txn), _transaction(txn, MODE_IS), _autoColl(txn, nss, MODE_IS) {
- // We have both the DB and collection locked, which the prerequisite to do a stable shard
- // version check
- ensureShardVersionOKOrThrow(_txn, nss.ns());
+ {
+ auto curOp = CurOp::get(_txn);
+ stdx::lock_guard<Client> lk(*_txn->getClient());
- auto curOp = CurOp::get(_txn);
- stdx::lock_guard<Client> lk(*_txn->getClient());
+ // TODO: OldClientContext legacy, needs to be removed
+ curOp->ensureStarted();
+ curOp->setNS_inlock(nss.ns());
+
+ // At this point, we are locked in shared mode for the database by the DB lock in the
+ // constructor, so it is safe to load the DB pointer.
+ if (_autoColl.getDb()) {
+ // TODO: OldClientContext legacy, needs to be removed
+ curOp->enter_inlock(nss.ns().c_str(), _autoColl.getDb()->getProfilingLevel());
+ }
+ }
- // TODO: OldClientContext legacy, needs to be removed
- curOp->ensureStarted();
- curOp->setNS_inlock(nss.ns());
+ // We have both the DB and collection locked, which is the prerequisite to do a stable shard
+ // version check, but we'd like to do the check after we have a satisfactory snapshot.
+ ON_BLOCK_EXIT([&]() { ensureShardVersionOKOrThrow(_txn, nss.ns()); });
- // At this point, we are locked in shared mode for the database by the DB lock in the
- // constructor, so it is safe to load the DB pointer.
- if (_autoColl.getDb()) {
- // TODO: OldClientContext legacy, needs to be removed
- curOp->enter_inlock(nss.ns().c_str(), _autoColl.getDb()->getProfilingLevel());
+ if (!getCollection()) {
+ return;
+ }
+ auto minSnapshot = getCollection()->getMinimumVisibleSnapshot();
+ if (!minSnapshot) {
+ return;
+ }
+ auto mySnapshot = _txn->recoveryUnit()->getMajorityCommittedSnapshot();
+ if (!mySnapshot) {
+ return;
+ }
+ if (mySnapshot > minSnapshot) {
+ return;
}
- if (getCollection()) {
- if (auto minSnapshot = getCollection()->getMinimumVisibleSnapshot()) {
- if (auto mySnapshot = _txn->recoveryUnit()->getMajorityCommittedSnapshot()) {
- while (mySnapshot < minSnapshot) {
- // Wait until a snapshot is available.
- repl::ReplicationCoordinator::get(_txn)->waitForNewSnapshot(_txn);
-
- Status status = _txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot();
- uassert(28786,
- "failed to set read from majority-committed snapshot",
- status.isOK());
- mySnapshot = _txn->recoveryUnit()->getMajorityCommittedSnapshot();
- }
- }
- }
+ // Save lock state for yielding.
+ Locker* locker = _txn->lockState();
+ Locker::LockSnapshot lockStateBackup;
+ massert(28795,
+ str::stream() << "Unable to yield to wait for readConcern=majority "
+ << "snapshot to be available for " << nss.ns(),
+ locker->saveLockStateAndUnlock(&lockStateBackup));
+ ON_BLOCK_EXIT([&]() { locker->restoreLockState(lockStateBackup); });
+
+ // Wait until a snapshot is available.
+ while (mySnapshot < minSnapshot) {
+ repl::ReplicationCoordinator::get(_txn)->waitForNewSnapshot(_txn);
+
+ Status status = _txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot();
+ uassert(28786,
+ "failed to set read from majority-committed snapshot",
+ status.isOK());
+ mySnapshot = _txn->recoveryUnit()->getMajorityCommittedSnapshot();
}
+
+ stdx::lock_guard<Client> lk(*_txn->getClient());
+ CurOp::get(_txn)->yielded();
}
AutoGetCollectionForRead::~AutoGetCollectionForRead() {