summaryrefslogtreecommitdiff
path: root/src/mongo/db/db_raii.cpp
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@mongodb.com>2022-03-09 22:18:59 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-09 23:41:25 +0000
commit0c242cb6ac5d61100cdcaee7f4533de7c2307d25 (patch)
treeeb7e9c89fcc9d4f9880be04d67b8783f99ac869f /src/mongo/db/db_raii.cpp
parentf65e8bc4c54cdb9de2358287d4824011729fde98 (diff)
downloadmongo-0c242cb6ac5d61100cdcaee7f4533de7c2307d25.tar.gz
SERVER-62457 Fix AutoGetCollectionForReadCommandLock bug wherein a request can come in with an UNSHARDED shard version, AutoGet*LockFree can find sharded state and then pass the SV check as unsharded, due to concurrent activities with the lock-free read state setup
Diffstat (limited to 'src/mongo/db/db_raii.cpp')
-rw-r--r--src/mongo/db/db_raii.cpp50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/mongo/db/db_raii.cpp b/src/mongo/db/db_raii.cpp
index 92dc19dc08e..b5a16af0306 100644
--- a/src/mongo/db/db_raii.cpp
+++ b/src/mongo/db/db_raii.cpp
@@ -40,9 +40,13 @@
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/s/collection_sharding_state.h"
#include "mongo/db/s/database_sharding_state.h"
+#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/storage/snapshot_helper.h"
#include "mongo/logv2/log.h"
+MONGO_FAIL_POINT_DEFINE(hangBeforeAutoGetShardVersionCheck);
+MONGO_FAIL_POINT_DEFINE(reachedAutoGetLockFreeShardConsistencyRetry);
+
namespace mongo {
namespace {
@@ -809,6 +813,13 @@ AutoGetCollectionForReadCommandBase<AutoGetCollectionForReadType>::
deadline,
secondaryNssOrUUIDs) {
+ hangBeforeAutoGetShardVersionCheck.executeIf(
+ [&](auto&) { hangBeforeAutoGetShardVersionCheck.pauseWhileSet(opCtx); },
+ [&](const BSONObj& data) {
+ return opCtx->getLogicalSessionId() &&
+ opCtx->getLogicalSessionId()->getId() == UUID::fromCDR(data["lsid"].uuid());
+ });
+
if (!_autoCollForRead.getView()) {
auto css =
CollectionShardingState::getSharedForLockFreeReads(opCtx, _autoCollForRead.getNss());
@@ -816,6 +827,45 @@ AutoGetCollectionForReadCommandBase<AutoGetCollectionForReadType>::
}
}
+AutoGetCollectionForReadCommandLockFree::AutoGetCollectionForReadCommandLockFree(
+ OperationContext* opCtx,
+ const NamespaceStringOrUUID& nsOrUUID,
+ AutoGetCollectionViewMode viewMode,
+ Date_t deadline,
+ AutoStatsTracker::LogMode logMode,
+ const std::vector<NamespaceStringOrUUID>& secondaryNssOrUUIDs) {
+ _autoCollForReadCommandBase.emplace(
+ opCtx, nsOrUUID, viewMode, deadline, logMode, secondaryNssOrUUIDs);
+ auto receivedShardVersion =
+ OperationShardingState::get(opCtx).getShardVersion(_autoCollForReadCommandBase->getNss());
+
+ while (_autoCollForReadCommandBase->getCollection() &&
+ _autoCollForReadCommandBase->getCollection().isSharded() && receivedShardVersion &&
+ receivedShardVersion.get() == ChunkVersion::UNSHARDED()) {
+ reachedAutoGetLockFreeShardConsistencyRetry.executeIf(
+ [&](auto&) { reachedAutoGetLockFreeShardConsistencyRetry.pauseWhileSet(opCtx); },
+ [&](const BSONObj& data) {
+ return opCtx->getLogicalSessionId() &&
+ opCtx->getLogicalSessionId()->getId() == UUID::fromCDR(data["lsid"].uuid());
+ });
+
+ // A request may arrive with an UNSHARDED shard version for the namespace, and then running
+ // lock-free it is possible that the lock-free state finds a sharded collection but
+ // subsequently the namespace was dropped and recreated UNSHARDED again, in time for the SV
+ // check performed in AutoGetCollectionForReadCommandBase. We must check here whether
+ // sharded state was found by the lock-free state setup, and make sure that the collection
+ // state in-use matches the shard version in the request. If there is an issue, we can
+ // simply retry: the scenario is very unlikely.
+ //
+ // It's possible for there to be no SV for the namespace in the command request. That's OK
+ // because shard versioning isn't needed in that case. See SERVER-63009 for more details.
+ _autoCollForReadCommandBase.emplace(
+ opCtx, nsOrUUID, viewMode, deadline, logMode, secondaryNssOrUUIDs);
+ receivedShardVersion = OperationShardingState::get(opCtx).getShardVersion(
+ _autoCollForReadCommandBase->getNss());
+ }
+}
+
OldClientContext::OldClientContext(OperationContext* opCtx, const std::string& ns, bool doVersion)
: _opCtx(opCtx) {
const auto dbName = nsToDatabaseSubstring(ns);