diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2018-02-03 10:31:45 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2018-02-06 07:33:21 -0500 |
commit | 1f376bcf8824df1a6122c297d5205daa1e6ff8a7 (patch) | |
tree | 2d8a6c5d21a042e47ed702e5426851a54e314331 /src | |
parent | 0851ee0434ba5352561a204f368a062d660c8882 (diff) | |
download | mongo-1f376bcf8824df1a6122c297d5205daa1e6ff8a7.tar.gz |
SERVER-32367 Make AutoGetCollection throw if UUID cannot be resolved
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/catalog/catalog_raii.cpp | 57 | ||||
-rw-r--r-- | src/mongo/db/catalog/catalog_raii.h | 13 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/commands.h | 5 | ||||
-rw-r--r-- | src/mongo/db/commands/count_cmd.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/commands/distinct.cpp | 72 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/commands/parallel_collection_scan.cpp | 71 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.h | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline_d.cpp | 62 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline_d.h | 2 |
12 files changed, 169 insertions, 164 deletions
diff --git a/src/mongo/db/catalog/catalog_raii.cpp b/src/mongo/db/catalog/catalog_raii.cpp index 60c81373b79..fb1535f22df 100644 --- a/src/mongo/db/catalog/catalog_raii.cpp +++ b/src/mongo/db/catalog/catalog_raii.cpp @@ -37,12 +37,6 @@ namespace mongo { namespace { -StringData getDBNameToLock(const NamespaceStringOrUUID& nsOrUUID) { - if (nsOrUUID.nss()) - return nsOrUUID.nss()->db(); - return nsOrUUID.dbAndUUID()->dbName; -} - MONGO_FP_DECLARE(setAutoGetCollectionWait); } // namespace @@ -58,36 +52,33 @@ AutoGetCollection::AutoGetCollection(OperationContext* opCtx, LockMode modeDB, LockMode modeColl, ViewMode viewMode) - : AutoGetCollection(opCtx, - nsOrUUID, - Lock::DBLock(opCtx, getDBNameToLock(nsOrUUID), modeDB), - modeColl, - viewMode) {} + : AutoGetCollection( + opCtx, nsOrUUID, Lock::DBLock(opCtx, nsOrUUID.db(), modeDB), modeColl, viewMode) {} AutoGetCollection::AutoGetCollection(OperationContext* opCtx, const NamespaceStringOrUUID& nsOrUUID, Lock::DBLock dbLock, LockMode modeColl, ViewMode viewMode) - : _autoDb(opCtx, getDBNameToLock(nsOrUUID), std::move(dbLock)) { - if (nsOrUUID.nss()) { - _nsAndLock.emplace(NamespaceAndCollectionLock{ - Lock::CollectionLock(opCtx->lockState(), nsOrUUID.nss()->ns(), modeColl), - *nsOrUUID.nss()}); - } else { - UUIDCatalog& catalog = UUIDCatalog::get(opCtx); - auto resolvedNss = catalog.lookupNSSByUUID(nsOrUUID.dbAndUUID()->uuid); - - // If the collection UUID cannot be resolved, we can't obtain a collection or check for - // views - if (!resolvedNss.isValid()) - return; - - _nsAndLock.emplace(NamespaceAndCollectionLock{ - Lock::CollectionLock(opCtx->lockState(), resolvedNss.ns(), modeColl), - std::move(resolvedNss)}); - } - + : _autoDb(opCtx, nsOrUUID.db(), std::move(dbLock)), + _nsAndLock([&]() -> NamespaceAndCollectionLock { + if (nsOrUUID.nss()) { + return {Lock::CollectionLock(opCtx->lockState(), nsOrUUID.nss()->ns(), modeColl), + *nsOrUUID.nss()}; + } else { + UUIDCatalog& catalog = UUIDCatalog::get(opCtx); + auto resolvedNss = catalog.lookupNSSByUUID(nsOrUUID.dbAndUUID()->uuid); + + // If the collection UUID cannot be resolved, we can't obtain a collection or check + // for vews + uassert(ErrorCodes::NamespaceNotFound, + str::stream() << "Unable to resolve " << nsOrUUID.toString(), + resolvedNss.isValid()); + + return {Lock::CollectionLock(opCtx->lockState(), resolvedNss.ns(), modeColl), + std::move(resolvedNss)}; + } + }()) { // Wait for a configured amount of time after acquiring locks if the failpoint is enabled MONGO_FAIL_POINT_BLOCK(setAutoGetCollectionWait, customWait) { const BSONObj& data = customWait.getData(); @@ -100,7 +91,7 @@ AutoGetCollection::AutoGetCollection(OperationContext* opCtx, if (!db) return; - _coll = db->getCollection(opCtx, _nsAndLock->nss); + _coll = db->getCollection(opCtx, _nsAndLock.nss); // If the collection exists, there is no need to check for views and we must keep the collection // lock @@ -108,9 +99,9 @@ AutoGetCollection::AutoGetCollection(OperationContext* opCtx, return; } - _view = db->getViewCatalog()->lookup(opCtx, _nsAndLock->nss.ns()); + _view = db->getViewCatalog()->lookup(opCtx, _nsAndLock.nss.ns()); uassert(ErrorCodes::CommandNotSupportedOnView, - str::stream() << "Namespace " << _nsAndLock->nss.ns() << " is a view, not a collection", + str::stream() << "Namespace " << _nsAndLock.nss.ns() << " is a view, not a collection", !_view || viewMode == kViewsPermitted); } diff --git a/src/mongo/db/catalog/catalog_raii.h b/src/mongo/db/catalog/catalog_raii.h index 819d59f62ff..8c7bbb632f1 100644 --- a/src/mongo/db/catalog/catalog_raii.h +++ b/src/mongo/db/catalog/catalog_raii.h @@ -73,7 +73,7 @@ private: * RAII-style class, which acquires a locks on the specified database and collection in the * requested modes and obtains references to both. * - * NOTE: If the collection cannot be resolved to a name, the collection lock will not be held. + * NOTE: Throws NamespaceNotFound if the collection UUID cannot be resolved to a name. * * Any acquired locks may be released when this object goes out of scope, therefore the database * and the collection references returned by this class should not be retained. @@ -124,6 +124,13 @@ public: return _view.get(); } + /** + * Returns the resolved namespace of the collection or view. + */ + const NamespaceString& getNss() const { + return _nsAndLock.nss; + } + private: struct NamespaceAndCollectionLock { Lock::CollectionLock lock; @@ -131,9 +138,7 @@ private: }; AutoGetDb _autoDb; - - // This value will be initialized if the UUID can be resolved to a collection name - boost::optional<NamespaceAndCollectionLock> _nsAndLock; + const NamespaceAndCollectionLock _nsAndLock; Collection* _coll = nullptr; std::shared_ptr<ViewDefinition> _view; diff --git a/src/mongo/db/catalog/database_test.cpp b/src/mongo/db/catalog/database_test.cpp index 4610735077b..c82c7fc5897 100644 --- a/src/mongo/db/catalog/database_test.cpp +++ b/src/mongo/db/catalog/database_test.cpp @@ -228,7 +228,7 @@ TEST_F(DatabaseTest, // Replicated collection is renamed with a special drop-pending names in the <db>.system.drop.* // namespace. auto dpns = _nss.makeDropPendingNamespace(dropOpTime); - ASSERT_TRUE(mongo::AutoGetCollectionForRead(_opCtx.get(), dpns).getCollection()); + ASSERT_TRUE(AutoGetCollectionForRead(_opCtx.get(), dpns).getCollection()); // Reaper should have the drop optime of the collection. auto reaperEarliestDropOpTime = diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 762b87a87ca..b301df2d131 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -79,8 +79,10 @@ struct CommandHelpers { static void appendCommandStatus(BSONObjBuilder& result, bool ok, const std::string& errmsg = {}); + // @return s.isOK() static bool appendCommandStatus(BSONObjBuilder& result, const Status& status); + /** * Helper for setting a writeConcernError field in the command result object if * a writeConcern error occurs. @@ -95,15 +97,18 @@ struct CommandHelpers { static void appendCommandWCStatus(BSONObjBuilder& result, const Status& awaitReplicationStatus, const WriteConcernResult& wcResult = WriteConcernResult()); + /** * Appends passthrough fields from a cmdObj to a given request. */ static BSONObj appendPassthroughFields(const BSONObj& cmdObjWithPassthroughFields, const BSONObj& request); + /** * Returns a copy of 'cmdObj' with a majority writeConcern appended. */ static BSONObj appendMajorityWriteConcern(const BSONObj& cmdObj); + /** * Returns true if the provided argument is one that is handled by the command processing layer * and should generally be ignored by individual command implementations. In particular, diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index 129af8c89de..336bcad29e0 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -59,7 +59,11 @@ class CmdCount : public BasicCommand { public: CmdCount() : BasicCommand("count") {} - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + std::string help() const override { + return "count objects in collection"; + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } @@ -71,28 +75,24 @@ public: return Command::AllowedOnSecondary::kOptIn; } - virtual bool maintenanceOk() const { + bool maintenanceOk() const override { return false; } - virtual bool adminOnly() const { + bool adminOnly() const override { return false; } bool supportsReadConcern(const std::string& dbName, const BSONObj& cmdObj, - repl::ReadConcernLevel level) const final { + repl::ReadConcernLevel level) const override { return true; } - ReadWriteType getReadWriteType() const { + ReadWriteType getReadWriteType() const override { return ReadWriteType::kRead; } - std::string help() const override { - return "count objects in collection"; - } - Status checkAuthForOperation(OperationContext* opCtx, const std::string& dbname, const BSONObj& cmdObj) override { @@ -110,11 +110,11 @@ public: return Status::OK(); } - virtual Status explain(OperationContext* opCtx, - const std::string& dbname, - const BSONObj& cmdObj, - ExplainOptions::Verbosity verbosity, - BSONObjBuilder* out) const { + Status explain(OperationContext* opCtx, + const std::string& dbname, + const BSONObj& cmdObj, + ExplainOptions::Verbosity verbosity, + BSONObjBuilder* out) const override { const bool isExplain = true; Lock::DBLock dbLock(opCtx, dbname, MODE_IS); auto nss = CommandHelpers::parseNsOrUUID(opCtx, dbname, cmdObj); @@ -169,10 +169,10 @@ public: return Status::OK(); } - virtual bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + bool run(OperationContext* opCtx, + const string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { const bool isExplain = false; Lock::DBLock dbLock(opCtx, dbname, MODE_IS); auto nss = CommandHelpers::parseNsOrUUID(opCtx, dbname, cmdObj); diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index 50b05986912..99e42d567ae 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -64,32 +64,33 @@ #include "mongo/util/log.h" namespace mongo { +namespace { -using std::unique_ptr; -using std::string; -using std::stringstream; - -namespace dps = ::mongo::dotted_path_support; +namespace dps = dotted_path_support; class DistinctCommand : public BasicCommand { public: DistinctCommand() : BasicCommand("distinct") {} + std::string help() const override { + return "{ distinct : 'collection name' , key : 'a.b' , query : {} }"; + } + AllowedOnSecondary secondaryAllowed() const override { return AllowedOnSecondary::kOptIn; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } bool supportsReadConcern(const std::string& dbName, const BSONObj& cmdObj, - repl::ReadConcernLevel level) const final { + repl::ReadConcernLevel level) const override { return true; } - ReadWriteType getReadWriteType() const { + ReadWriteType getReadWriteType() const override { return ReadWriteType::kRead; } @@ -97,30 +98,24 @@ public: return FindCommon::kInitReplyBufferSize; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { + void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) override { ActionSet actions; actions.addAction(ActionType::find); out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); } - std::string help() const override { - return "{ distinct : 'collection name' , key : 'a.b' , query : {} }"; - } - - virtual Status explain(OperationContext* opCtx, - const std::string& dbname, - const BSONObj& cmdObj, - ExplainOptions::Verbosity verbosity, - BSONObjBuilder* out) const { + Status explain(OperationContext* opCtx, + const std::string& dbname, + const BSONObj& cmdObj, + ExplainOptions::Verbosity verbosity, + BSONObjBuilder* out) const override { const NamespaceString nss(CommandHelpers::parseNsCollectionRequired(dbname, cmdObj)); const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto parsedDistinct = ParsedDistinct::parse(opCtx, nss, cmdObj, extensionsCallback, true); - if (!parsedDistinct.isOK()) { - return parsedDistinct.getStatus(); - } + auto parsedDistinct = + uassertStatusOK(ParsedDistinct::parse(opCtx, nss, cmdObj, extensionsCallback, true)); AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); @@ -128,7 +123,7 @@ public: if (ctx.getView()) { ctx.releaseLocksForView(); - auto viewAggregation = parsedDistinct.getValue().asAggregationCommand(); + auto viewAggregation = parsedDistinct.asAggregationCommand(); if (!viewAggregation.isOK()) { return viewAggregation.getStatus(); } @@ -143,27 +138,22 @@ public: opCtx, nss, viewAggRequest.getValue(), viewAggregation.getValue(), *out); } - auto executor = getExecutorDistinct( - opCtx, collection, nss.ns(), &parsedDistinct.getValue(), PlanExecutor::YIELD_AUTO); - if (!executor.isOK()) { - return executor.getStatus(); - } + auto executor = uassertStatusOK(getExecutorDistinct( + opCtx, collection, nss.ns(), &parsedDistinct, PlanExecutor::YIELD_AUTO)); - Explain::explainStages(executor.getValue().get(), collection, verbosity, out); + Explain::explainStages(executor.get(), collection, verbosity, out); return Status::OK(); } bool run(OperationContext* opCtx, - const string& dbname, + const std::string& dbname, const BSONObj& cmdObj, - BSONObjBuilder& result) { + BSONObjBuilder& result) override { const NamespaceString nss(CommandHelpers::parseNsCollectionRequired(dbname, cmdObj)); const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto parsedDistinct = ParsedDistinct::parse(opCtx, nss, cmdObj, extensionsCallback, false); - if (!parsedDistinct.isOK()) { - return CommandHelpers::appendCommandStatus(result, parsedDistinct.getStatus()); - } + auto parsedDistinct = + uassertStatusOK(ParsedDistinct::parse(opCtx, nss, cmdObj, extensionsCallback, false)); AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); @@ -171,7 +161,7 @@ public: if (ctx.getView()) { ctx.releaseLocksForView(); - auto viewAggregation = parsedDistinct.getValue().asAggregationCommand(); + auto viewAggregation = parsedDistinct.asAggregationCommand(); if (!viewAggregation.isOK()) { return CommandHelpers::appendCommandStatus(result, viewAggregation.getStatus()); } @@ -183,7 +173,7 @@ public: } auto executor = getExecutorDistinct( - opCtx, collection, nss.ns(), &parsedDistinct.getValue(), PlanExecutor::YIELD_AUTO); + opCtx, collection, nss.ns(), &parsedDistinct, PlanExecutor::YIELD_AUTO); if (!executor.isOK()) { return CommandHelpers::appendCommandStatus(result, executor.getStatus()); } @@ -194,7 +184,7 @@ public: Explain::getPlanSummary(executor.getValue().get())); } - string key = cmdObj[ParsedDistinct::kKeyField].valuestrsafe(); + const auto key = cmdObj[ParsedDistinct::kKeyField].valuestrsafe(); int bufSize = BSONObjMaxUserSize - 4096; BufBuilder bb(bufSize); @@ -267,6 +257,8 @@ public: return true; } + } distinctCmd; +} // namespace } // namespace mongo diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 7139f52175f..494542a3279 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -143,8 +143,7 @@ public: } // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. - - ExtensionsCallbackReal extensionsCallback(opCtx, &nss); + const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, @@ -262,7 +261,7 @@ public: beginQueryOp(opCtx, nss, cmdObj, ntoreturn, ntoskip); // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. - ExtensionsCallbackReal extensionsCallback(opCtx, &nss); + const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); const boost::intrusive_ptr<ExpressionContext> expCtx; auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp index c9f36a820e4..8a79411fc44 100644 --- a/src/mongo/db/commands/parallel_collection_scan.cpp +++ b/src/mongo/db/commands/parallel_collection_scan.cpp @@ -51,28 +51,23 @@ namespace { class ParallelCollectionScanCmd : public BasicCommand { public: - struct ExtentInfo { - ExtentInfo(RecordId dl, size_t s) : diskLoc(dl), size(s) {} - RecordId diskLoc; - size_t size; - }; - ParallelCollectionScanCmd() : BasicCommand("parallelCollectionScan") {} - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } + AllowedOnSecondary secondaryAllowed() const override { return AllowedOnSecondary::kAlways; } bool supportsReadConcern(const std::string& dbName, const BSONObj& cmdObj, - repl::ReadConcernLevel level) const final { + repl::ReadConcernLevel level) const override { return true; } - ReadWriteType getReadWriteType() const { + ReadWriteType getReadWriteType() const override { return ReadWriteType::kCommand; } @@ -93,10 +88,10 @@ public: return Status::OK(); } - virtual bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& cmdObj, - BSONObjBuilder& result) { + bool run(OperationContext* opCtx, + const string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { Lock::DBLock dbSLock(opCtx, dbname, MODE_IS); const NamespaceString ns(CommandHelpers::parseNsOrUUID(opCtx, dbname, cmdObj)); @@ -156,36 +151,34 @@ public: mis->addIterator(std::move(iterators[i])); } - { - BSONArrayBuilder bucketsBuilder; - for (auto&& exec : execs) { - // Need to save state while yielding locks between now and getMore(). - exec->saveState(); - exec->detachFromOperationContext(); - - // Create and register a new ClientCursor. - auto pinnedCursor = collection->getCursorManager()->registerCursor( - opCtx, - {std::move(exec), - ns, - AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(), - opCtx->recoveryUnit()->isReadingFromMajorityCommittedSnapshot(), - cmdObj}); - pinnedCursor.getCursor()->setLeftoverMaxTimeMicros( - opCtx->getRemainingMaxTimeMicros()); - - BSONObjBuilder threadResult; - appendCursorResponseObject( - pinnedCursor.getCursor()->cursorid(), ns.ns(), BSONArray(), &threadResult); - threadResult.appendBool("ok", 1); - - bucketsBuilder.append(threadResult.obj()); - } - result.appendArray("cursors", bucketsBuilder.obj()); + BSONArrayBuilder bucketsBuilder; + for (auto&& exec : execs) { + // Need to save state while yielding locks between now and getMore(). + exec->saveState(); + exec->detachFromOperationContext(); + + // Create and register a new ClientCursor. + auto pinnedCursor = collection->getCursorManager()->registerCursor( + opCtx, + {std::move(exec), + ns, + AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(), + opCtx->recoveryUnit()->isReadingFromMajorityCommittedSnapshot(), + cmdObj}); + pinnedCursor.getCursor()->setLeftoverMaxTimeMicros(opCtx->getRemainingMaxTimeMicros()); + + BSONObjBuilder threadResult; + appendCursorResponseObject( + pinnedCursor.getCursor()->cursorid(), ns.ns(), BSONArray(), &threadResult); + threadResult.appendBool("ok", 1); + + bucketsBuilder.append(threadResult.obj()); } + result.appendArray("cursors", bucketsBuilder.obj()); return true; } + } parallelCollectionScanCmd; } // namespace diff --git a/src/mongo/db/namespace_string.cpp b/src/mongo/db/namespace_string.cpp index 19b35fec4cd..ba17dc66cc4 100644 --- a/src/mongo/db/namespace_string.cpp +++ b/src/mongo/db/namespace_string.cpp @@ -245,6 +245,12 @@ bool NamespaceString::isReplicated() const { return true; } +StringData NamespaceStringOrUUID::db() const { + if (_nss) + return _nss->db(); + return _dbAndUUID->dbName; +} + std::string NamespaceStringOrUUID::toString() const { if (_nss) return _nss->toString(); diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h index 13b13dda0f8..eb19a5dfb04 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -457,6 +457,8 @@ public: NamespaceStringOrUUID(NamespaceString nss) : _nss(std::move(nss)) {} NamespaceStringOrUUID(StringData dbName, UUID uuid) : _dbAndUUID({dbName.toString(), uuid}) {} + StringData db() const; + const boost::optional<NamespaceString>& nss() const { return _nss; } diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index fb6d6355efd..2441a0cc787 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -705,11 +705,14 @@ Status PipelineD::MongoDInterface::attachCursorSourceToPipeline( boost::optional<AutoGetCollectionForReadCommand> autoColl; if (expCtx->uuid) { - autoColl.emplace(expCtx->opCtx, expCtx->ns.db(), *expCtx->uuid); - if (autoColl->getCollection() == nullptr) { - // The UUID doesn't exist anymore. - return {ErrorCodes::NamespaceNotFound, - "No namespace with UUID " + expCtx->uuid->toString()}; + try { + autoColl.emplace(expCtx->opCtx, expCtx->ns.db(), *expCtx->uuid); + uassert(ErrorCodes::NamespaceNotFound, + "No namespace with UUID " + expCtx->uuid->toString(), + autoColl->getCollection()); + } catch (const ExceptionFor<ErrorCodes::NamespaceNotFound>& ex) { + // The UUID doesn't exist anymore + return ex.toStatus(); } } else { autoColl.emplace(expCtx->opCtx, expCtx->ns); @@ -864,14 +867,17 @@ boost::optional<Document> PipelineD::MongoDInterface::lookupSingleDocument( invariant(!readConcern); // We don't currently support a read concern on mongod - it's only // expected to be necessary on mongos. - // Be sure to do the lookup using the collection default collation. - auto foreignExpCtx = expCtx->copyWith( - nss, collectionUUID, _getCollectionDefaultCollator(expCtx->opCtx, nss, collectionUUID)); - auto swPipeline = makePipeline({BSON("$match" << documentKey)}, foreignExpCtx); - if (swPipeline == ErrorCodes::NamespaceNotFound) { + std::unique_ptr<Pipeline, PipelineDeleter> pipeline; + try { + // Be sure to do the lookup using the collection default collation + auto foreignExpCtx = expCtx->copyWith( + nss, + collectionUUID, + _getCollectionDefaultCollator(expCtx->opCtx, nss.db(), collectionUUID)); + pipeline = uassertStatusOK(makePipeline({BSON("$match" << documentKey)}, foreignExpCtx)); + } catch (const ExceptionFor<ErrorCodes::NamespaceNotFound>&) { return boost::none; } - auto pipeline = uassertStatusOK(std::move(swPipeline)); auto lookedUpDocument = pipeline->getNext(); if (auto next = pipeline->getNext()) { @@ -888,21 +894,27 @@ boost::optional<Document> PipelineD::MongoDInterface::lookupSingleDocument( } std::unique_ptr<CollatorInterface> PipelineD::MongoDInterface::_getCollectionDefaultCollator( - OperationContext* opCtx, const NamespaceString& nss, UUID collectionUUID) { - if (_collatorCache.find(collectionUUID) == _collatorCache.end()) { - AutoGetCollection autoColl(opCtx, NamespaceStringOrUUID(nss.db(), collectionUUID), MODE_IS); - if (!autoColl.getCollection()) { - // This collection doesn't exist - since we looked up by UUID, it will never exist in - // the future, so we cache a null pointer as the default collation. - _collatorCache[collectionUUID] = nullptr; - } else { - auto defaultCollator = autoColl.getCollection()->getDefaultCollator(); - // Clone the collator so that we can safely use the pointer if the collection - // disappears right after we release the lock. - _collatorCache[collectionUUID] = defaultCollator ? defaultCollator->clone() : nullptr; - } + OperationContext* opCtx, StringData dbName, UUID collectionUUID) { + auto it = _collatorCache.find(collectionUUID); + if (it == _collatorCache.end()) { + auto collator = [&]() -> std::unique_ptr<CollatorInterface> { + AutoGetCollection autoColl(opCtx, {dbName, collectionUUID}, MODE_IS); + if (!autoColl.getCollection()) { + // This collection doesn't exist, so assume a nullptr default collation + return nullptr; + } else { + auto defaultCollator = autoColl.getCollection()->getDefaultCollator(); + // Clone the collator so that we can safely use the pointer if the collection + // disappears right after we release the lock. + return defaultCollator ? defaultCollator->clone() : nullptr; + } + }(); + + it = _collatorCache.emplace(collectionUUID, std::move(collator)).first; } - return _collatorCache[collectionUUID] ? _collatorCache[collectionUUID]->clone() : nullptr; + + auto& collator = it->second; + return collator ? collator->clone() : nullptr; } } // namespace mongo diff --git a/src/mongo/db/pipeline/pipeline_d.h b/src/mongo/db/pipeline/pipeline_d.h index afbb6b8f73f..60ad684cc7b 100644 --- a/src/mongo/db/pipeline/pipeline_d.h +++ b/src/mongo/db/pipeline/pipeline_d.h @@ -123,7 +123,7 @@ public: * collation. */ std::unique_ptr<CollatorInterface> _getCollectionDefaultCollator(OperationContext* opCtx, - const NamespaceString& nss, + StringData dbName, UUID collectionUUID); DBDirectClient _client; |