summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/dbhash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/commands/dbhash.cpp')
-rw-r--r--src/mongo/db/commands/dbhash.cpp45
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;