diff options
Diffstat (limited to 'src/mongo/db/commands/dbhash.cpp')
-rw-r--r-- | src/mongo/db/commands/dbhash.cpp | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp index c7aa1c64e14..29a7e1fb129 100644 --- a/src/mongo/db/commands/dbhash.cpp +++ b/src/mongo/db/commands/dbhash.cpp @@ -32,6 +32,7 @@ #include "mongo/platform/basic.h" +#include <boost/optional.hpp> #include <map> #include <string> @@ -62,6 +63,17 @@ public: return false; } + ReadWriteType getReadWriteType() const override { + return ReadWriteType::kRead; + } + + bool supportsReadConcern(const std::string& dbName, + const BSONObj& cmdObj, + repl::ReadConcernLevel level) const override { + return level == repl::ReadConcernLevel::kLocalReadConcern || + level == repl::ReadConcernLevel::kSnapshotReadConcern; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } @@ -101,7 +113,14 @@ public: // We lock the entire database in S-mode in order to ensure that the contents will not // change for the snapshot. - AutoGetDb autoDb(opCtx, ns, MODE_S); + auto lockMode = LockMode::MODE_S; + if (repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()) { + // However, if we are using "atClusterTime" to read from a consistent snapshot, then we + // only need to lock the database in intent mode to ensure that none of the collections + // get dropped. + lockMode = getLockModeForQuery(opCtx); + } + AutoGetDb autoDb(opCtx, ns, lockMode); Database* db = autoDb.getDb(); std::list<std::string> colls; if (db) { @@ -177,6 +196,30 @@ private: if (!collection) return ""; + boost::optional<Lock::CollectionLock> collLock; + if (repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime()) { + // When using "atClusterTime", we are only holding the database lock in intent mode. We + // need to also acquire the collection lock in intent mode to ensure reading from the + // consistent snapshot doesn't overlap with any catalog operations on the collection. + invariant(opCtx->lockState()->isDbLockedForMode(db->name(), MODE_IS)); + collLock.emplace(opCtx->lockState(), fullCollectionName, getLockModeForQuery(opCtx)); + + auto minSnapshot = collection->getMinimumVisibleSnapshot(); + auto mySnapshot = opCtx->recoveryUnit()->getPointInTimeReadTimestamp(); + invariant(mySnapshot); + + uassert(ErrorCodes::SnapshotUnavailable, + str::stream() << "Unable to read from a snapshot due to pending collection" + " catalog changes; please retry the operation. Snapshot" + " timestamp is " + << mySnapshot->toString() + << ". Collection minimum timestamp is " + << minSnapshot->toString(), + !minSnapshot || *mySnapshot >= *minSnapshot); + } else { + invariant(opCtx->lockState()->isDbLockedForMode(db->name(), MODE_S)); + } + IndexDescriptor* desc = collection->getIndexCatalog()->findIdIndex(opCtx); std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> exec; |