diff options
author | Dianna Hohensee <dianna.hohensee@mongodb.com> | 2022-03-09 22:18:59 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-03-09 23:41:25 +0000 |
commit | 0c242cb6ac5d61100cdcaee7f4533de7c2307d25 (patch) | |
tree | eb7e9c89fcc9d4f9880be04d67b8783f99ac869f /src/mongo/db/db_raii.cpp | |
parent | f65e8bc4c54cdb9de2358287d4824011729fde98 (diff) | |
download | mongo-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.cpp | 50 |
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); |