diff options
author | jannaerin <golden.janna@gmail.com> | 2023-03-29 16:29:36 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-03-29 19:13:28 +0000 |
commit | 4326f194dcd67e1053e7e57dae003831aacc5f2c (patch) | |
tree | b8926e345b61498d7628cd340cc224cc610bc11b | |
parent | 6759d92c8cd619d00bd522bb5ebd688a4d685fd0 (diff) | |
download | mongo-4326f194dcd67e1053e7e57dae003831aacc5f2c.tar.gz |
SERVER-73112 Make NamespaceString constructors private
128 files changed, 571 insertions, 314 deletions
diff --git a/buildscripts/resmokeconfig/suites/serverless.yml b/buildscripts/resmokeconfig/suites/serverless.yml index 884947a11a0..079496d45fb 100644 --- a/buildscripts/resmokeconfig/suites/serverless.yml +++ b/buildscripts/resmokeconfig/suites/serverless.yml @@ -4,7 +4,9 @@ selector: roots: - jstests/serverless/*.js - jstests/serverless/change_streams/**/*.js - - src/mongo/db/modules/*/jstests/serverless/**/*.js + # TODO SERVER-74888 Re-enable once the encrypted shell can handle tenantIds regardless of + # multitenancySupport. + # - src/mongo/db/modules/*/jstests/serverless/**/*.js executor: config: diff --git a/jstests/auth/change_stream_change_collection_role_auth.js b/jstests/auth/change_stream_change_collection_role_auth.js index 7ea4be1ffb1..4d174543d66 100644 --- a/jstests/auth/change_stream_change_collection_role_auth.js +++ b/jstests/auth/change_stream_change_collection_role_auth.js @@ -6,6 +6,7 @@ * assumes_read_preference_unchanged, * requires_replication, * requires_fcv_62, + * __TEMPORARILY_DISABLED__ * ] */ (function() { diff --git a/jstests/serverless/native_tenant_data_isolation_basic_dollar_tenant.js b/jstests/serverless/native_tenant_data_isolation_basic_dollar_tenant.js index c56362a6db8..aff88c405b1 100644 --- a/jstests/serverless/native_tenant_data_isolation_basic_dollar_tenant.js +++ b/jstests/serverless/native_tenant_data_isolation_basic_dollar_tenant.js @@ -402,15 +402,13 @@ const testColl = testDb.getCollection(kCollName); "collMod": kCollName, "index": {"keyPattern": {c: 1}, expireAfterSeconds: 100}, }); - assert.commandFailedWithCode(res, ErrorCodes.NamespaceNotFound); - // TODO SERVER-73025 Uncomment out this conditional below, and remove the assertion above in - // favor of the assertion in the conditional. - /* if (featureFlagRequireTenantId) { - assert.commandFailedWithCode(res, 7005300); + if (featureFlagRequireTenantId) { + // When the feature flag is enabled, the server will assert that all requests contain a + // tenantId. + assert.commandFailedWithCode(res, 6972100); } else { assert.commandFailedWithCode(res, ErrorCodes.NamespaceNotFound); } - */ // Modify the index with the tenantId res = assert.commandWorked(testDb.runCommand({ diff --git a/src/mongo/db/auth/auth_op_observer.cpp b/src/mongo/db/auth/auth_op_observer.cpp index bc1091f2dae..1a61ba188dd 100644 --- a/src/mongo/db/auth/auth_op_observer.cpp +++ b/src/mongo/db/auth/auth_op_observer.cpp @@ -126,7 +126,7 @@ void AuthOpObserver::onCollMod(OperationContext* opCtx, } void AuthOpObserver::onDropDatabase(OperationContext* opCtx, const DatabaseName& dbName) { - const NamespaceString cmdNss{dbName, "$cmd"}; + const NamespaceString cmdNss(NamespaceString::makeCommandNamespace(dbName)); const auto cmdObj = BSON("dropDatabase" << 1); AuthorizationManager::get(opCtx->getServiceContext()) @@ -206,7 +206,7 @@ void AuthOpObserver::onImportCollection(OperationContext* opCtx, void AuthOpObserver::onApplyOps(OperationContext* opCtx, const DatabaseName& dbName, const BSONObj& applyOpCmd) { - const NamespaceString cmdNss{dbName, "$cmd"}; + const NamespaceString cmdNss(NamespaceString::makeCommandNamespace(dbName)); AuthorizationManager::get(opCtx->getServiceContext()) ->logOp(opCtx, "c", cmdNss, applyOpCmd, nullptr); diff --git a/src/mongo/db/auth/authorization_checks.cpp b/src/mongo/db/auth/authorization_checks.cpp index 6af135d0ee2..5e1f9ad1987 100644 --- a/src/mongo/db/auth/authorization_checks.cpp +++ b/src/mongo/db/auth/authorization_checks.cpp @@ -225,7 +225,8 @@ Status checkAuthForCreate(OperationContext* opCtx, // Parse the viewOn namespace and the pipeline. If no pipeline was specified, use the empty // pipeline. - NamespaceString viewOnNs(ns.db(), optViewOn.value()); + NamespaceString viewOnNs( + NamespaceStringUtil::parseNamespaceFromRequest(ns.dbName(), optViewOn.value())); auto pipeline = cmd.getPipeline().get_value_or(std::vector<BSONObj>()); BSONArrayBuilder pipelineArray; for (const auto& stage : pipeline) { @@ -266,7 +267,8 @@ Status checkAuthForCollMod(OperationContext* opCtx, "Must specify both 'viewOn' and 'pipeline' when modifying a view and auth is enabled"); } if (hasViewOn) { - NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData()); + NamespaceString viewOnNs(NamespaceStringUtil::parseNamespaceFromRequest( + ns.dbName(), cmdObj["viewOn"].checkAndGetStringData())); auto viewPipeline = BSONArray(cmdObj["pipeline"].Obj()); return checkAuthForCreateOrModifyView( opCtx, authSession, ns, viewOnNs, viewPipeline, isMongos); diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp index 007ab381646..f799c2fb1ba 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp @@ -105,11 +105,11 @@ Status AuthzManagerExternalStateLocal::getStoredAuthorizationVersion(OperationCo namespace { NamespaceString getUsersCollection(const boost::optional<TenantId>& tenant) { - return NamespaceString(tenant, DatabaseName::kAdmin.db(), NamespaceString::kSystemUsers); + return NamespaceString::makeTenantUsersCollection(tenant); } NamespaceString getRolesCollection(const boost::optional<TenantId>& tenant) { - return NamespaceString(tenant, DatabaseName::kAdmin.db(), NamespaceString::kSystemRoles); + return NamespaceString::makeTenantRolesCollection(tenant); } void serializeResolvedRoles(BSONObjBuilder* user, @@ -253,10 +253,8 @@ void handleAuthLocalGetUserFailPoint(const std::vector<RoleName>& directRoles) { Status AuthzManagerExternalStateLocal::hasAnyUserDocuments( OperationContext* opCtx, const boost::optional<TenantId>& tenantId) { BSONObj userBSONObj; - return findOne(opCtx, - NamespaceString(tenantId, NamespaceString::kAdminUsersNamespace.ns()), - BSONObj(), - &userBSONObj); + return findOne( + opCtx, NamespaceString::makeTenantUsersCollection(tenantId), BSONObj(), &userBSONObj); } // If tenantId is none, we're checking whether to enable localhost auth bypass which by definition diff --git a/src/mongo/db/auth/privilege_parser.cpp b/src/mongo/db/auth/privilege_parser.cpp index d240328a4bd..801e731af08 100644 --- a/src/mongo/db/auth/privilege_parser.cpp +++ b/src/mongo/db/auth/privilege_parser.cpp @@ -500,8 +500,9 @@ Status ParsedPrivilege::parsedPrivilegeToPrivilege(const ParsedPrivilege& parsed } else { if (parsedResource.isDbSet() && !parsedResource.getDb().empty()) { if (parsedResource.isCollectionSet() && !parsedResource.getCollection().empty()) { - resource = ResourcePattern::forExactNamespace(NamespaceString( - boost::none, parsedResource.getDb(), parsedResource.getCollection())); + resource = ResourcePattern::forExactNamespace( + NamespaceString::createNamespaceStringForAuth( + boost::none, parsedResource.getDb(), parsedResource.getCollection())); } else { resource = ResourcePattern::forDatabaseName(parsedResource.getDb()); } diff --git a/src/mongo/db/auth/resource_pattern.h b/src/mongo/db/auth/resource_pattern.h index e289ca97049..036c12df655 100644 --- a/src/mongo/db/auth/resource_pattern.h +++ b/src/mongo/db/auth/resource_pattern.h @@ -79,8 +79,9 @@ public: * "ns" for which ns.isSystem() is false and ns.db() == dbname. */ static ResourcePattern forDatabaseName(StringData dbName) { - return ResourcePattern(MatchTypeEnum::kMatchDatabaseName, - NamespaceString(boost::none, dbName, "")); + return ResourcePattern( + MatchTypeEnum::kMatchDatabaseName, + NamespaceString::createNamespaceStringForAuth(boost::none, dbName, "")); } /** @@ -88,8 +89,9 @@ public: * collectionName. */ static ResourcePattern forCollectionName(StringData collectionName) { - return ResourcePattern(MatchTypeEnum::kMatchCollectionName, - NamespaceString(boost::none, "", collectionName)); + return ResourcePattern( + MatchTypeEnum::kMatchCollectionName, + NamespaceString::createNamespaceStringForAuth(boost::none, "", collectionName)); } /** @@ -112,8 +114,9 @@ public: * "db". */ static ResourcePattern forAnySystemBucketsInDatabase(StringData dbName) { - return ResourcePattern(MatchTypeEnum::kMatchAnySystemBucketInDBResource, - NamespaceString(boost::none, dbName, "")); + return ResourcePattern( + MatchTypeEnum::kMatchAnySystemBucketInDBResource, + NamespaceString::createNamespaceStringForAuth(boost::none, dbName, "")); } /** @@ -121,8 +124,9 @@ public: * in any database. */ static ResourcePattern forAnySystemBucketsInAnyDatabase(StringData collectionName) { - return ResourcePattern(MatchTypeEnum::kMatchSystemBucketInAnyDBResource, - NamespaceString(boost::none, "", collectionName)); + return ResourcePattern( + MatchTypeEnum::kMatchSystemBucketInAnyDBResource, + NamespaceString::createNamespaceStringForAuth(boost::none, "", collectionName)); } /** @@ -132,8 +136,9 @@ public: static ResourcePattern forExactSystemBucketsCollection(StringData dbName, StringData collectionName) { invariant(!collectionName.startsWith("system.buckets.")); - return ResourcePattern(MatchTypeEnum::kMatchExactSystemBucketResource, - NamespaceString(boost::none, dbName, collectionName)); + return ResourcePattern( + MatchTypeEnum::kMatchExactSystemBucketResource, + NamespaceString::createNamespaceStringForAuth(boost::none, dbName, collectionName)); } /** diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index daa52908254..3881b2dfba0 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -838,7 +838,7 @@ Status _collModInternal(OperationContext* opCtx, view->setPipeline(*cmd.getPipeline()); if (!viewOn.empty()) - view->setViewOn(NamespaceString(dbName, viewOn)); + view->setViewOn(NamespaceStringUtil::parseNamespaceFromRequest(dbName, viewOn)); BSONArrayBuilder pipeline; for (auto& item : view->pipeline()) { diff --git a/src/mongo/db/catalog/index_builds_manager.cpp b/src/mongo/db/catalog/index_builds_manager.cpp index 90821c2b484..4233138c744 100644 --- a/src/mongo/db/catalog/index_builds_manager.cpp +++ b/src/mongo/db/catalog/index_builds_manager.cpp @@ -258,7 +258,7 @@ StatusWith<std::pair<long long, long long>> IndexBuildsManager::startBuildingInd long long bytesRemoved = 0; const NamespaceString lostAndFoundNss = - NamespaceString(DatabaseName::kLocal, "lost_and_found." + coll->uuid().toString()); + NamespaceString::makeLocalCollection("lost_and_found." + coll->uuid().toString()); // Delete duplicate record and insert it into local lost and found. Status status = [&] { diff --git a/src/mongo/db/catalog/index_consistency.cpp b/src/mongo/db/catalog/index_consistency.cpp index 7875d7d13d8..186b3a61ae2 100644 --- a/src/mongo/db/catalog/index_consistency.cpp +++ b/src/mongo/db/catalog/index_consistency.cpp @@ -212,9 +212,8 @@ void KeyStringIndexConsistency::repairIndexEntries(OperationContext* opCtx, << " missing index entries."); } if (results->numDocumentsMovedToLostAndFound > 0) { - const NamespaceString lostAndFoundNss = - NamespaceString(DatabaseName::kLocal, - "lost_and_found." + _validateState->getCollection()->uuid().toString()); + const NamespaceString lostAndFoundNss = NamespaceString::makeLocalCollection( + "lost_and_found." + _validateState->getCollection()->uuid().toString()); results->warnings.push_back(str::stream() << "Removed " << results->numDocumentsMovedToLostAndFound << " duplicate documents to resolve " diff --git a/src/mongo/db/catalog/index_repair.cpp b/src/mongo/db/catalog/index_repair.cpp index 8ed4bb76a48..96fca0781dc 100644 --- a/src/mongo/db/catalog/index_repair.cpp +++ b/src/mongo/db/catalog/index_repair.cpp @@ -181,7 +181,7 @@ int repairMissingIndexEntry(OperationContext* opCtx, if (coll->findDoc(opCtx, ridToMove, &doc)) { const NamespaceString lostAndFoundNss = - NamespaceString(DatabaseName::kLocal, "lost_and_found." + coll->uuid().toString()); + NamespaceString::makeLocalCollection("lost_and_found." + coll->uuid().toString()); auto moveStatus = moveRecordToLostAndFound(opCtx, nss, lostAndFoundNss, ridToMove); diff --git a/src/mongo/db/catalog/uncommitted_catalog_updates.cpp b/src/mongo/db/catalog/uncommitted_catalog_updates.cpp index c98f88725ae..751c0b25f6f 100644 --- a/src/mongo/db/catalog/uncommitted_catalog_updates.cpp +++ b/src/mongo/db/catalog/uncommitted_catalog_updates.cpp @@ -216,7 +216,7 @@ void UncommittedCatalogUpdates::replaceViewsForDatabase(const DatabaseName& dbNa ViewsForDatabase&& vfdb) { _entries.push_back({Entry::Action::kReplacedViewsForDatabase, nullptr, - NamespaceString{dbName, ""}, + NamespaceString{dbName}, boost::none, {}, std::move(vfdb)}); diff --git a/src/mongo/db/catalog/unique_collection_name.cpp b/src/mongo/db/catalog/unique_collection_name.cpp index 2096bed3820..a5efa4b22df 100644 --- a/src/mongo/db/catalog/unique_collection_name.cpp +++ b/src/mongo/db/catalog/unique_collection_name.cpp @@ -81,7 +81,7 @@ StatusWith<NamespaceString> makeUniqueCollectionName(OperationContext* opCtx, collectionName.begin(), replacePercentSign); - NamespaceString nss(dbName, collectionName); + NamespaceString nss(NamespaceStringUtil::parseNamespaceFromDoc(dbName, collectionName)); if (!CollectionCatalog::get(opCtx)->lookupCollectionByNamespace(opCtx, nss)) { return nss; } diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 0fb0013dfb4..d470a767036 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -297,7 +297,8 @@ NamespaceString CommandHelpers::parseNsCollectionRequired(const DatabaseName& db uassert(ErrorCodes::InvalidNamespace, str::stream() << "collection name has invalid type " << typeName(first.type()), first.canonicalType() == canonicalizeBSONType(mongo::String)); - const NamespaceString nss(dbName, first.valueStringData()); + const NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, first.valueStringData())); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid namespace specified '" << nss.ns() << "'", nss.isValid()); @@ -328,7 +329,8 @@ NamespaceString CommandHelpers::parseNsFromCommand(const DatabaseName& dbName, BSONElement first = cmdObj.firstElement(); if (first.type() != mongo::String) return NamespaceString(dbName); - return NamespaceString(dbName, cmdObj.firstElement().valueStringData()); + return NamespaceStringUtil::parseNamespaceFromRequest(dbName, + cmdObj.firstElement().valueStringData()); } ResourcePattern CommandHelpers::resourcePatternForNamespace(const std::string& ns) { diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index 2796e297e61..fd5bf446270 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -73,7 +73,8 @@ public: uassert(ErrorCodes::TypeMismatch, "'toCollection' must be of type String", nssElt.type() == BSONType::String); - const NamespaceString nss(dbName, nssElt.valueStringData()); + const NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, nssElt.valueStringData())); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid target namespace: " << nss.ns(), nss.isValid()); @@ -116,8 +117,8 @@ public: uassert(ErrorCodes::InvalidOptions, "invalid command spec", size != 0); - NamespaceString fromNs(dbName, from); - NamespaceString toNs(dbName, to); + NamespaceString fromNs(NamespaceStringUtil::parseNamespaceFromRequest(dbName, from)); + NamespaceString toNs(NamespaceStringUtil::parseNamespaceFromRequest(dbName, to)); AutoGetCollection autoColl(opCtx, fromNs, MODE_X); Lock::CollectionLock collLock(opCtx, toNs, MODE_X); diff --git a/src/mongo/db/commands/connection_status.cpp b/src/mongo/db/commands/connection_status.cpp index 8e32d25f87e..152b9b69478 100644 --- a/src/mongo/db/commands/connection_status.cpp +++ b/src/mongo/db/commands/connection_status.cpp @@ -109,7 +109,7 @@ public: } NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/create_command.cpp b/src/mongo/db/commands/create_command.cpp index d91ec734f08..78573ff879a 100644 --- a/src/mongo/db/commands/create_command.cpp +++ b/src/mongo/db/commands/create_command.cpp @@ -115,7 +115,8 @@ void checkCollectionOptions(OperationContext* opCtx, MONGO_UNREACHABLE; } - auto fullNewNamespace = NamespaceString(ns.dbName(), options.viewOn); + auto fullNewNamespace = + NamespaceStringUtil::parseNamespaceFromRequest(ns.dbName(), options.viewOn); uassert(ErrorCodes::NamespaceExists, str::stream() << "namespace " << ns.ns() << " already exists, but is a view on " << view->viewOn() << " rather than " << fullNewNamespace, diff --git a/src/mongo/db/commands/dbcheck.cpp b/src/mongo/db/commands/dbcheck.cpp index c55f42df246..cf90ec8ba73 100644 --- a/src/mongo/db/commands/dbcheck.cpp +++ b/src/mongo/db/commands/dbcheck.cpp @@ -156,7 +156,8 @@ using DbCheckRun = std::vector<DbCheckCollectionInfo>; std::unique_ptr<DbCheckRun> singleCollectionRun(OperationContext* opCtx, const DatabaseName& dbName, const DbCheckSingleInvocation& invocation) { - NamespaceString nss(dbName, invocation.getColl()); + NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, invocation.getColl())); AutoGetCollectionForRead agc(opCtx, nss); uassert(ErrorCodes::NamespaceNotFound, diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index a0269f2ccc4..6216f7a7b22 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -255,9 +255,7 @@ public: } NamespaceString ns() const final { - const auto& tenant = request().getDbName().tenantId(); - const auto& nss = request().getCommandParameter(); - return NamespaceString(tenant, nss.db(), nss.coll()); + return request().getCommandParameter(); } Reply typedRun(OperationContext* opCtx) { diff --git a/src/mongo/db/commands/dbcommands_d.cpp b/src/mongo/db/commands/dbcommands_d.cpp index 370f6861778..96b1058599c 100644 --- a/src/mongo/db/commands/dbcommands_d.cpp +++ b/src/mongo/db/commands/dbcommands_d.cpp @@ -165,7 +165,7 @@ protected: // Accessing system.profile collection should not conflict with oplog application. ShouldNotConflictWithSecondaryBatchApplicationBlock shouldNotConflictBlock( opCtx->lockState()); - NamespaceString nss{dbName, NamespaceString::kSystemDotProfileCollectionName}; + NamespaceString nss(NamespaceString::makeSystemDotProfileNamespace(dbName)); AutoGetCollection ctx(opCtx, nss, dbMode); Database* db = ctx.getDb(); @@ -236,7 +236,7 @@ public: if (collectionName.empty()) collectionName = "fs"; collectionName += ".chunks"; - return NamespaceString(dbName, collectionName); + return NamespaceStringUtil::parseNamespaceFromRequest(dbName, collectionName); } Status checkAuthForOperation(OperationContext* opCtx, diff --git a/src/mongo/db/commands/fail_point_cmd.cpp b/src/mongo/db/commands/fail_point_cmd.cpp index a067522d6fe..04eda7ad215 100644 --- a/src/mongo/db/commands/fail_point_cmd.cpp +++ b/src/mongo/db/commands/fail_point_cmd.cpp @@ -144,7 +144,7 @@ public: // The command parameter happens to be string so it's historically been interpreted // by parseNs as a collection. Continuing to do so here for unexamined compatibility. NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } // No auth needed because it only works when enabled via command line. diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp index 9bc1717f6e8..43ff09312ad 100644 --- a/src/mongo/db/commands/generic.cpp +++ b/src/mongo/db/commands/generic.cpp @@ -285,7 +285,7 @@ public: } NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/generic_servers.cpp b/src/mongo/db/commands/generic_servers.cpp index 46276bb285b..a565f4924f5 100644 --- a/src/mongo/db/commands/generic_servers.cpp +++ b/src/mongo/db/commands/generic_servers.cpp @@ -81,7 +81,7 @@ public: } NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/get_cluster_parameter_command.cpp b/src/mongo/db/commands/get_cluster_parameter_command.cpp index 40eca042887..2e11ef26363 100644 --- a/src/mongo/db/commands/get_cluster_parameter_command.cpp +++ b/src/mongo/db/commands/get_cluster_parameter_command.cpp @@ -96,7 +96,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; } getClusterParameterCommand; diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index bb35a065a73..194f44a9092 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -322,7 +322,8 @@ public: Invocation(Command* cmd, const OpMsgRequest& request) : CommandInvocation(cmd), _cmd(GetMoreCommandRequest::parse(IDLParserContext{"getMore"}, request)) { - NamespaceString nss(_cmd.getDbName(), _cmd.getCollection()); + NamespaceString nss(NamespaceStringUtil::parseNamespaceFromRequest( + _cmd.getDbName(), _cmd.getCollection())); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid namespace for getMore: " << nss.ns(), nss.isValid()); @@ -347,7 +348,8 @@ public: } NamespaceString ns() const override { - return NamespaceString(_cmd.getDbName(), _cmd.getCollection()); + return NamespaceStringUtil::parseNamespaceFromRequest(_cmd.getDbName(), + _cmd.getCollection()); } void doCheckAuthorization(OperationContext* opCtx) const override { @@ -481,7 +483,8 @@ public: // the stats twice. boost::optional<AutoGetCollectionForReadMaybeLockFree> readLock; boost::optional<AutoStatsTracker> statsTracker; - NamespaceString nss(_cmd.getDbName(), _cmd.getCollection()); + NamespaceString nss(NamespaceStringUtil::parseNamespaceFromRequest( + _cmd.getDbName(), _cmd.getCollection())); const bool disableAwaitDataFailpointActive = MONGO_unlikely(disableAwaitDataForGetMoreCmd.shouldFail()); diff --git a/src/mongo/db/commands/http_client.cpp b/src/mongo/db/commands/http_client.cpp index 7ff14d644c9..fe67aa7b889 100644 --- a/src/mongo/db/commands/http_client.cpp +++ b/src/mongo/db/commands/http_client.cpp @@ -127,7 +127,7 @@ public: void doCheckAuthorization(OperationContext*) const final {} NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/killoperations_common.h b/src/mongo/db/commands/killoperations_common.h index 22060c28d64..c4542e84857 100644 --- a/src/mongo/db/commands/killoperations_common.h +++ b/src/mongo/db/commands/killoperations_common.h @@ -70,7 +70,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(Base::request().getDbName(), ""); + return NamespaceString(Base::request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index 74895ba0322..d8c7ead1291 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -351,7 +351,8 @@ public: if (DatabaseHolder::get(opCtx)->dbExists(opCtx, dbName)) { if (auto collNames = _getExactNameMatches(matcher.get())) { for (auto&& collName : *collNames) { - auto nss = NamespaceString(dbName, collName); + auto nss = + NamespaceStringUtil::parseNamespaceFromRequest(dbName, collName); // Only validate on a per-collection basis if the user requested // a list of authorized collections diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp index ecb4694e57d..3ad19b1d236 100644 --- a/src/mongo/db/commands/list_databases.cpp +++ b/src/mongo/db/commands/list_databases.cpp @@ -85,7 +85,7 @@ public: void doCheckAuthorization(OperationContext*) const final {} NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } ListDatabasesReply typedRun(OperationContext* opCtx) final { diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index f0648835437..1ceae347f2e 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -233,7 +233,7 @@ public: auto nss = request().getNamespaceOrUUID(); if (nss.uuid()) { // UUID requires opCtx to resolve, settle on just the dbname. - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } invariant(nss.nss()); return nss.nss().value(); diff --git a/src/mongo/db/commands/profile_common.cpp b/src/mongo/db/commands/profile_common.cpp index 94875fcbd70..6a33e66a561 100644 --- a/src/mongo/db/commands/profile_common.cpp +++ b/src/mongo/db/commands/profile_common.cpp @@ -56,7 +56,9 @@ Status ProfileCmdBase::checkAuthForOperation(OperationContext* opCtx, // If the user just wants to view the current values of 'slowms' and 'sampleRate', they // only need read rights on system.profile, even if they can't change the profiling level. if (authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace({dbName, "system.profile"}), ActionType::find)) { + ResourcePattern::forExactNamespace( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, "system.profile")), + ActionType::find)) { return Status::OK(); } } diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index 7c4166b8bf3..5e14d4c6549 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -374,8 +374,8 @@ StatusWith<StringMap<ExpressionContext::ResolvedNamespace>> resolveInvolvedNames // collection name references a view on the aggregation request's database. Note // that the inverse scenario (mistaking a view for a collection) is not an issue // because $merge/$out cannot target a view. - auto nssToCheck = - NamespaceString(request.getNamespace().dbName(), involvedNs.coll()); + auto nssToCheck = NamespaceStringUtil::parseNamespaceFromRequest( + request.getNamespace().dbName(), involvedNs.coll()); if (catalog->lookupView(opCtx, nssToCheck)) { auto status = resolveViewDefinition(nssToCheck); if (!status.isOK()) { diff --git a/src/mongo/db/commands/rwc_defaults_commands.cpp b/src/mongo/db/commands/rwc_defaults_commands.cpp index 8e1f1cb16cc..1a39456b35c 100644 --- a/src/mongo/db/commands/rwc_defaults_commands.cpp +++ b/src/mongo/db/commands/rwc_defaults_commands.cpp @@ -167,7 +167,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; } setDefaultRWConcernCommand; @@ -219,7 +219,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; } getDefaultRWConcernCommand; diff --git a/src/mongo/db/commands/shutdown.h b/src/mongo/db/commands/shutdown.h index 446c78632e0..373eb4a007e 100644 --- a/src/mongo/db/commands/shutdown.h +++ b/src/mongo/db/commands/shutdown.h @@ -86,7 +86,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(Base::request().getDbName(), ""); + return NamespaceString(Base::request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp index c1b73eb3ac8..ddd1dc50afa 100644 --- a/src/mongo/db/commands/tenant_migration_donor_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_donor_cmds.cpp @@ -150,7 +150,7 @@ public: return false; } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -225,7 +225,7 @@ public: return false; } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -309,7 +309,7 @@ public: return false; } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp index ff7c94df325..684d9c35624 100644 --- a/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp +++ b/src/mongo/db/commands/tenant_migration_recipient_cmds.cpp @@ -181,7 +181,7 @@ public: return false; } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -248,7 +248,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { @@ -404,7 +404,7 @@ public: } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/traffic_recording_cmds.cpp b/src/mongo/db/commands/traffic_recording_cmds.cpp index 143175c7301..b82157eb082 100644 --- a/src/mongo/db/commands/traffic_recording_cmds.cpp +++ b/src/mongo/db/commands/traffic_recording_cmds.cpp @@ -75,7 +75,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -110,7 +110,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index 233c9772a46..3741db51431 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -225,7 +225,7 @@ Status checkOkayToGrantPrivilegesToRole(const RoleName& role, const PrivilegeVec NamespaceString usersNSS(const boost::optional<TenantId>& tenant) { if (tenant) { - return NamespaceString(tenant, DatabaseName::kAdmin.db(), NamespaceString::kSystemUsers); + return NamespaceString::makeTenantUsersCollection(tenant); } else { return NamespaceString::kAdminUsersNamespace; } @@ -233,7 +233,7 @@ NamespaceString usersNSS(const boost::optional<TenantId>& tenant) { NamespaceString rolesNSS(const boost::optional<TenantId>& tenant) { if (tenant) { - return NamespaceString(tenant, DatabaseName::kAdmin.db(), NamespaceString::kSystemRoles); + return NamespaceString::makeTenantRolesCollection(tenant); } else { return NamespaceString::kAdminRolesNamespace; } @@ -961,9 +961,10 @@ public: NamespaceString ns() const final { const auto& cmd = request(); if constexpr (hasGetCmdParamStringData<RequestT>) { - return NamespaceString(cmd.getDbName(), cmd.getCommandParameter()); + return NamespaceStringUtil::parseNamespaceFromRequest(cmd.getDbName(), + cmd.getCommandParameter()); } - return NamespaceString(cmd.getDbName(), ""); + return NamespaceString(cmd.getDbName()); } }; @@ -2138,7 +2139,7 @@ public: } NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/commands/validate_db_metadata_cmd.cpp b/src/mongo/db/commands/validate_db_metadata_cmd.cpp index 785236f2e5b..ea4a72feb8d 100644 --- a/src/mongo/db/commands/validate_db_metadata_cmd.cpp +++ b/src/mongo/db/commands/validate_db_metadata_cmd.cpp @@ -134,8 +134,9 @@ public: } if (validateCmdRequest.getCollection()) { - if (!_validateNamespace( - opCtx, NamespaceString(dbName, *validateCmdRequest.getCollection()))) { + if (!_validateNamespace(opCtx, + NamespaceStringUtil::parseNamespaceFromRequest( + dbName, *validateCmdRequest.getCollection()))) { return; } continue; diff --git a/src/mongo/db/commands/vote_abort_index_build_command.cpp b/src/mongo/db/commands/vote_abort_index_build_command.cpp index e5577f60da8..c5e76436073 100644 --- a/src/mongo/db/commands/vote_abort_index_build_command.cpp +++ b/src/mongo/db/commands/vote_abort_index_build_command.cpp @@ -104,7 +104,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/commands/vote_commit_index_build_command.cpp b/src/mongo/db/commands/vote_commit_index_build_command.cpp index 475d23dddf1..2deaa460163 100644 --- a/src/mongo/db/commands/vote_commit_index_build_command.cpp +++ b/src/mongo/db/commands/vote_commit_index_build_command.cpp @@ -103,7 +103,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 8c909acffdf..d6d167893ae 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -140,7 +140,8 @@ public: return false; } - const NamespaceString nss(dbName, collElt.String()); + const NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, collElt.String())); uassert(ErrorCodes::InvalidNamespace, str::stream() << nss.toString() << " is not a valid namespace", nss.isValid()); diff --git a/src/mongo/db/fle_crud.cpp b/src/mongo/db/fle_crud.cpp index 885a8e60b6d..b5f93148306 100644 --- a/src/mongo/db/fle_crud.cpp +++ b/src/mongo/db/fle_crud.cpp @@ -614,7 +614,8 @@ void processFieldsForInsertV1(FLEQueryInterface* queryImpl, int32_t* pStmtId, bool bypassDocumentValidation) { - const NamespaceString nssEsc(edcNss.dbName(), efc.getEscCollection().value()); + const NamespaceString nssEsc = NamespaceStringUtil::parseNamespaceFromRequest( + edcNss.dbName(), efc.getEscCollection().value()); auto docCount = queryImpl->countDocuments(nssEsc); @@ -676,7 +677,8 @@ void processFieldsForInsertV1(FLEQueryInterface* queryImpl, checkWriteErrors(escInsertReply); - const NamespaceString nssEcoc(edcNss.dbName(), efc.getEcocCollection().value()); + const NamespaceString nssEcoc = NamespaceStringUtil::parseNamespaceFromRequest( + edcNss.dbName(), efc.getEcocCollection().value()); // TODO - should we make this a batch of ECOC updates? const auto ecocInsertReply = uassertStatusOK(queryImpl->insertDocuments( @@ -708,12 +710,12 @@ void processFieldsForInsertV2(FLEQueryInterface* queryImpl, const EncryptedFieldConfig& efc, int32_t* pStmtId, bool bypassDocumentValidation) { - if (serverPayload.empty()) { return; } - const NamespaceString nssEsc(edcNss.dbName(), efc.getEscCollection().value()); + const NamespaceString nssEsc = NamespaceStringUtil::parseNamespaceFromRequest( + edcNss.dbName(), efc.getEscCollection().value()); uint32_t totalTokens = 0; @@ -775,7 +777,8 @@ void processFieldsForInsertV2(FLEQueryInterface* queryImpl, uassertStatusOK(queryImpl->insertDocuments(nssEsc, escDocuments, pStmtId, true)); checkWriteErrors(escInsertReply); - NamespaceString nssEcoc(edcNss.dbName(), efc.getEcocCollection().value()); + NamespaceString nssEcoc = NamespaceStringUtil::parseNamespaceFromRequest( + edcNss.dbName(), efc.getEcocCollection().value()); std::vector<BSONObj> ecocDocuments; ecocDocuments.reserve(totalTokens); @@ -864,7 +867,8 @@ void processRemovedFieldsHelper(FLEQueryInterface* queryImpl, true)); checkWriteErrors(eccInsertReply); - const NamespaceString nssEcoc(edcNss.dbName(), efc.getEcocCollection().value()); + const NamespaceString nssEcoc = NamespaceStringUtil::parseNamespaceFromRequest( + edcNss.dbName(), efc.getEcocCollection().value()); // TODO - make this a batch of ECOC updates? EncryptedStateCollectionTokens tokens(esc, ecc); @@ -884,7 +888,8 @@ void processRemovedFields(FLEQueryInterface* queryImpl, const std::vector<EDCIndexedFields>& deletedFields, int32_t* pStmtId) { - const NamespaceString eccNss(edcNss.dbName(), efc.getEccCollection().value()); + const NamespaceString eccNss = NamespaceStringUtil::parseNamespaceFromRequest( + edcNss.dbName(), efc.getEccCollection().value()); auto docCount = queryImpl->countDocuments(eccNss); diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp index 3d236fe7524..6e9cf7bfbfe 100644 --- a/src/mongo/db/introspect.cpp +++ b/src/mongo/db/introspect.cpp @@ -112,8 +112,7 @@ void profile(OperationContext* opCtx, NetworkOp op) { opCtx->getClient()->swapLockState(std::move(oldCtxLocker)); }); AlternativeClientRegion acr(newClient); - const auto dbProfilingNS = - NamespaceString(ns.dbName(), NamespaceString::kSystemDotProfileCollectionName); + const auto dbProfilingNS = NamespaceString::makeSystemDotProfileNamespace(ns.dbName()); AutoGetCollection autoColl(newCtx.get(), dbProfilingNS, MODE_IX); Database* const db = autoColl.getDb(); if (!db) { @@ -149,8 +148,7 @@ void profile(OperationContext* opCtx, NetworkOp op) { Status createProfileCollection(OperationContext* opCtx, Database* db) { invariant(opCtx->lockState()->isDbLockedForMode(db->name(), MODE_IX)); - const auto dbProfilingNS = - NamespaceString(db->name(), NamespaceString::kSystemDotProfileCollectionName); + const auto dbProfilingNS = NamespaceString::makeSystemDotProfileNamespace(db->name()); // Checking the collection exists must also be done in the WCE retry loop. Only retrying // collection creation would endlessly throw errors because the collection exists: must check diff --git a/src/mongo/db/namespace_string.cpp b/src/mongo/db/namespace_string.cpp index 3fd5a88f4cc..157e02cb3c6 100644 --- a/src/mongo/db/namespace_string.cpp +++ b/src/mongo/db/namespace_string.cpp @@ -189,6 +189,10 @@ NamespaceString NamespaceString::makeSystemDotViewsNamespace(const DatabaseName& return NamespaceString(dbName, kSystemDotViewsCollectionName); } +NamespaceString NamespaceString::makeSystemDotProfileNamespace(const DatabaseName& dbName) { + return NamespaceString(dbName, kSystemDotProfileCollectionName); +} + NamespaceString NamespaceString::makeListCollectionsNSS(const DatabaseName& dbName) { NamespaceString nss(dbName, listCollectionsCursorCol); dassert(nss.isValid()); @@ -200,6 +204,10 @@ NamespaceString NamespaceString::makeGlobalConfigCollection(StringData collName) return NamespaceString(DatabaseName::kConfig, collName); } +NamespaceString NamespaceString::makeLocalCollection(StringData collName) { + return NamespaceString(DatabaseName::kLocal, collName); +} + NamespaceString NamespaceString::makeCollectionlessAggregateNSS(const DatabaseName& dbName) { NamespaceString nss(dbName, collectionlessAggregateCursorCol); dassert(nss.isValid()); @@ -241,11 +249,24 @@ NamespaceString NamespaceString::makeReshardingLocalConflictStashNSS( donorShardId); } +NamespaceString NamespaceString::makeTenantUsersCollection( + const boost::optional<TenantId>& tenantId) { + return NamespaceString(tenantId, DatabaseName::kAdmin.db(), NamespaceString::kSystemUsers); +} + +NamespaceString NamespaceString::makeTenantRolesCollection( + const boost::optional<TenantId>& tenantId) { + return NamespaceString(tenantId, DatabaseName::kAdmin.db(), NamespaceString::kSystemRoles); +} + +NamespaceString NamespaceString::makeCommandNamespace(const DatabaseName& dbName) { + return NamespaceString(dbName, "$cmd"); +} + NamespaceString NamespaceString::makeDummyNamespace(const boost::optional<TenantId>& tenantId) { return NamespaceString(tenantId, DatabaseName::kConfig.db(), "dummy.namespace"); } - std::string NamespaceString::getSisterNS(StringData local) const { verify(local.size() && local[0] != '.'); return db().toString() + "." + local.toString(); diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h index 2acb9d556fb..06a40dc1b44 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -47,6 +47,8 @@ #include "mongo/util/uuid.h" namespace mongo { +class NamespaceStringUtil; +class IDLParserContext; class NamespaceString { public: @@ -208,23 +210,6 @@ public: NamespaceString() = default; /** - * Constructs a NamespaceString from the fully qualified namespace named in "ns" and the - * tenantId. "ns" is NOT expected to contain the tenantId. - */ - explicit NamespaceString(boost::optional<TenantId> tenantId, StringData ns) { - _dotIndex = ns.find("."); - - uassert(ErrorCodes::InvalidNamespace, - "namespaces cannot have embedded null characters", - ns.find('\0') == std::string::npos); - - StringData db = ns.substr(0, _dotIndex); - _dbName = DatabaseName(std::move(tenantId), db); - _ns = ns.toString(); - } - - - /** * Constructs a NamespaceString for the given database. */ explicit NamespaceString(DatabaseName dbName) : _dbName(std::move(dbName)), _ns(_dbName.db()) {} @@ -234,37 +219,6 @@ public: explicit NamespaceString(StringData ns, boost::optional<TenantId> tenantId = boost::none) : NamespaceString(std::move(tenantId), ns) {} - /** - * Constructs a NamespaceString for the given database and collection names. - * "dbName" must not contain a ".", and "collectionName" must not start with one. - */ - NamespaceString(DatabaseName dbName, StringData collectionName) - : _dbName(std::move(dbName)), _ns(str::stream() << _dbName.db() << '.' << collectionName) { - const auto& db = _dbName.db(); - - uassert(ErrorCodes::InvalidNamespace, - "'.' is an invalid character in the database name: " + db, - db.find('.') == std::string::npos); - uassert(ErrorCodes::InvalidNamespace, - "Collection names cannot start with '.': " + collectionName, - collectionName.empty() || collectionName[0] != '.'); - - _dotIndex = db.size(); - dassert(_ns[_dotIndex] == '.'); - - uassert(ErrorCodes::InvalidNamespace, - "namespaces cannot have embedded null characters", - _ns.find('\0') == std::string::npos); - } - - /** - * Constructs a NamespaceString for the given db name, collection name, and tenantId. - * "db" must not contain a ".", and "collectionName" must not start with one. "dbName" is - * NOT expected to contain a tenantId. - */ - NamespaceString(boost::optional<TenantId> tenantId, StringData db, StringData collectionName) - : NamespaceString(DatabaseName(std::move(tenantId), db), collectionName) {} - // TODO SERVER-65920 Remove this constructor once all constructor call sites have been updated // to pass tenantId explicitly NamespaceString(StringData db, @@ -286,6 +240,11 @@ public: static NamespaceString makeGlobalConfigCollection(StringData collName); /** + * Constructs a NamespaceString in the local db, "local.<collName>". + */ + static NamespaceString makeLocalCollection(StringData collName); + + /** * These functions construct a NamespaceString without checking for presence of TenantId. * * MUST only be used for tests. @@ -319,6 +278,24 @@ public: } /** + * These functions construct a NamespaceString without checking for presence of TenantId. These + * must only be used by auth systems which are not yet tenant aware. + * + * TODO SERVER-74896 Remove this function. Any remaining call sites must be changed to use a + * function on NamespaceStringUtil. + */ + static NamespaceString createNamespaceStringForAuth(const boost::optional<TenantId>& tenantId, + StringData db, + StringData coll) { + return NamespaceString(tenantId, db, coll); + } + + static NamespaceString createNamespaceStringForAuth(const boost::optional<TenantId>& tenantId, + StringData ns) { + return NamespaceString(tenantId, ns); + } + + /** * Constructs the namespace '<dbName>.$cmd.aggregate', which we use as the namespace for * aggregation commands with the format {aggregate: 1}. */ @@ -358,6 +335,11 @@ public: static NamespaceString makeSystemDotViewsNamespace(const DatabaseName& dbName); /** + * Constructs the system.profile NamespaceString for the specified DatabaseName. + */ + static NamespaceString makeSystemDotProfileNamespace(const DatabaseName& dbName); + + /** * Constructs a NamespaceString representing a BulkWrite namespace. The format for this * namespace is admin.$cmd.bulkWrite". */ @@ -381,6 +363,23 @@ public: const std::string& donorShardId); /** + * Constructs the tenant-specific admin.system.users NamespaceString for the given tenant, + * "tenant_admin.system.users". + */ + static NamespaceString makeTenantUsersCollection(const boost::optional<TenantId>& tenantId); + + /** + * Constructs the tenant-specific admin.system.roles NamespaceString for the given tenant, + * "tenant_admin.system.roles". + */ + static NamespaceString makeTenantRolesCollection(const boost::optional<TenantId>& tenantId); + + /** + * Constructs the command NamespaceString, "<dbName>.$cmd". + */ + static NamespaceString makeCommandNamespace(const DatabaseName& dbName); + + /** * Constructs a dummy NamespaceString, "<tenantId>.config.dummy.namespace", to be used where a * placeholder NamespaceString is needed. It must be acceptable for tenantId to be empty, so we * use "config" as the db. @@ -468,6 +467,10 @@ public: bool isSystemDotViews() const { return coll() == kSystemDotViewsCollectionName; } + static bool resolvesToSystemDotViews(StringData ns) { + auto nss = NamespaceString(boost::none, ns); + return nss.isSystemDotViews(); + } bool isSystemDotJavascript() const { return coll() == kSystemDotJavascriptCollectionName; } @@ -768,6 +771,64 @@ public: } private: + friend NamespaceStringUtil; + // TODO SERVER-74897 IDLParserContext should no longer be a friend once IDL generated commands + // call into NamespaceStringUtil directly to construct NamespaceStrings. + friend IDLParserContext; + + /** + * In order to construct NamespaceString objects, use NamespaceStringUtil. The functions + * on NamespaceStringUtil make assertions necessary when running in Serverless. + */ + + /** + * Constructs a NamespaceString from the fully qualified namespace named in "ns" and the + * tenantId. "ns" is NOT expected to contain the tenantId. + */ + explicit NamespaceString(boost::optional<TenantId> tenantId, StringData ns) { + _dotIndex = ns.find("."); + + uassert(ErrorCodes::InvalidNamespace, + "namespaces cannot have embedded null characters", + ns.find('\0') == std::string::npos); + + StringData db = ns.substr(0, _dotIndex); + _dbName = DatabaseName(std::move(tenantId), db); + _ns = ns.toString(); + } + + /** + * Constructs a NamespaceString for the given database and collection names. + * "dbName" must not contain a ".", and "collectionName" must not start with one. + */ + NamespaceString(DatabaseName dbName, StringData collectionName) + : _dbName(std::move(dbName)), _ns(str::stream() << _dbName.db() << '.' << collectionName) { + const auto& db = _dbName.db(); + + uassert(ErrorCodes::InvalidNamespace, + "'.' is an invalid character in the database name: " + db, + db.find('.') == std::string::npos); + uassert(ErrorCodes::InvalidNamespace, + "Collection names cannot start with '.': " + collectionName, + collectionName.empty() || collectionName[0] != '.'); + + _dotIndex = db.size(); + dassert(_ns[_dotIndex] == '.'); + + uassert(ErrorCodes::InvalidNamespace, + "namespaces cannot have embedded null characters", + _ns.find('\0') == std::string::npos); + } + + /** + * Constructs a NamespaceString for the given db name, collection name, and tenantId. + * "db" must not contain a ".", and "collectionName" must not start with one. "db" is + * NOT expected to contain a tenantId. + */ + NamespaceString(boost::optional<TenantId> tenantId, StringData db, StringData collectionName) + : NamespaceString(DatabaseName(std::move(tenantId), db), collectionName) {} + + std::tuple<const boost::optional<TenantId>&, const std::string&> _lens() const { return std::tie(tenantId(), ns()); } diff --git a/src/mongo/db/namespace_string_test.cpp b/src/mongo/db/namespace_string_test.cpp index 231c14f6083..0d8e25255d4 100644 --- a/src/mongo/db/namespace_string_test.cpp +++ b/src/mongo/db/namespace_string_test.cpp @@ -375,21 +375,32 @@ TEST(NamespaceStringTest, CompareNSSWithTenantId) { TenantId tenantIdMin(OID("000000000000000000000000")); TenantId tenantIdMax(OID::max()); - ASSERT(NamespaceString(tenantIdMin, "foo.bar") == NamespaceString(tenantIdMin, "foo.bar")); - - ASSERT(NamespaceString(tenantIdMin, "foo.bar") != NamespaceString(tenantIdMax, "foo.bar")); - ASSERT(NamespaceString(tenantIdMin, "foo.bar") != NamespaceString(tenantIdMin, "zoo.bar")); - - ASSERT(NamespaceString(tenantIdMin, "foo.bar") < NamespaceString(tenantIdMax, "foo.bar")); - ASSERT(NamespaceString(tenantIdMin, "foo.bar") < NamespaceString(tenantIdMin, "zoo.bar")); - ASSERT(NamespaceString(tenantIdMin, "zoo.bar") < NamespaceString(tenantIdMax, "foo.bar")); - - ASSERT(NamespaceString(tenantIdMax, "foo.bar") > NamespaceString(tenantIdMin, "foo.bar")); - ASSERT(NamespaceString(tenantIdMin, "zoo.bar") > NamespaceString(tenantIdMin, "foo.bar")); - ASSERT(NamespaceString(tenantIdMax, "foo.bar") > NamespaceString(tenantIdMin, "zoo.bar")); - - ASSERT(NamespaceString(tenantIdMin, "foo.bar") <= NamespaceString(tenantIdMin, "foo.bar")); - ASSERT(NamespaceString(tenantIdMin, "foo.bar") >= NamespaceString(tenantIdMin, "foo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") == + NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar")); + + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") != + NamespaceString::createNamespaceString_forTest(tenantIdMax, "foo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") != + NamespaceString::createNamespaceString_forTest(tenantIdMin, "zoo.bar")); + + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") < + NamespaceString::createNamespaceString_forTest(tenantIdMax, "foo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") < + NamespaceString::createNamespaceString_forTest(tenantIdMin, "zoo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "zoo.bar") < + NamespaceString::createNamespaceString_forTest(tenantIdMax, "foo.bar")); + + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMax, "foo.bar") > + NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "zoo.bar") > + NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMax, "foo.bar") > + NamespaceString::createNamespaceString_forTest(tenantIdMin, "zoo.bar")); + + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") <= + NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar")); + ASSERT(NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar") >= + NamespaceString::createNamespaceString_forTest(tenantIdMin, "foo.bar")); } } // namespace diff --git a/src/mongo/db/op_observer/op_observer_impl.cpp b/src/mongo/db/op_observer/op_observer_impl.cpp index f9c4cf02b2e..9e242aee14a 100644 --- a/src/mongo/db/op_observer/op_observer_impl.cpp +++ b/src/mongo/db/op_observer/op_observer_impl.cpp @@ -691,7 +691,8 @@ void OpObserverImpl::onInserts(OperationContext* opCtx, opCtx, NamespaceStringUtil::deserialize(nss.dbName().tenantId(), it->doc.getStringField("_id")), - {nss.dbName(), it->doc.getStringField("viewOn")}, + NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + it->doc.getStringField("viewOn")), BSONArray{it->doc.getObjectField("pipeline")}, view_catalog_helpers::validatePipeline, it->doc.getObjectField("collation"), @@ -1282,7 +1283,7 @@ void OpObserverImpl::onDropDatabase(OperationContext* opCtx, const DatabaseName& oplogEntry.setOpType(repl::OpTypeEnum::kCommand); oplogEntry.setTid(dbName.tenantId()); - oplogEntry.setNss({dbName, "$cmd"}); + oplogEntry.setNss(NamespaceString::makeCommandNamespace(dbName)); oplogEntry.setObject(BSON("dropDatabase" << 1)); auto opTime = logOperation(opCtx, &oplogEntry, true /*assignWallClockTime*/, _oplogWriter.get()); @@ -1538,7 +1539,7 @@ void OpObserverImpl::onApplyOps(OperationContext* opCtx, oplogEntry.setOpType(repl::OpTypeEnum::kCommand); oplogEntry.setTid(dbName.tenantId()); - oplogEntry.setNss({dbName, "$cmd"}); + oplogEntry.setNss(NamespaceString::makeCommandNamespace(dbName)); oplogEntry.setObject(applyOpCmd); logOperation(opCtx, &oplogEntry, true /*assignWallClockTime*/, _oplogWriter.get()); } diff --git a/src/mongo/db/op_observer/op_observer_impl_test.cpp b/src/mongo/db/op_observer/op_observer_impl_test.cpp index 64a636974d4..f9d12984f34 100644 --- a/src/mongo/db/op_observer/op_observer_impl_test.cpp +++ b/src/mongo/db/op_observer/op_observer_impl_test.cpp @@ -348,7 +348,8 @@ protected: const UUID uuid3{UUID::gen()}; const TenantId kTenantId = TenantId(OID::gen()); - const NamespaceString kNssUnderTenantId{boost::none, kTenantId.toString() + "_db", "testColl"}; + const NamespaceString kNssUnderTenantId = NamespaceString::createNamespaceString_forTest( + boost::none, kTenantId.toString() + "_db", "testColl"); const UUID kNssUnderTenantIdUUID{UUID::gen()}; ReadWriteConcernDefaultsLookupMock _lookupMock; diff --git a/src/mongo/db/op_observer/user_write_block_mode_op_observer.cpp b/src/mongo/db/op_observer/user_write_block_mode_op_observer.cpp index 6330d195585..d9158099dca 100644 --- a/src/mongo/db/op_observer/user_write_block_mode_op_observer.cpp +++ b/src/mongo/db/op_observer/user_write_block_mode_op_observer.cpp @@ -223,7 +223,7 @@ void UserWriteBlockModeOpObserver::onCollMod(OperationContext* opCtx, void UserWriteBlockModeOpObserver::onDropDatabase(OperationContext* opCtx, const DatabaseName& dbName) { - _checkWriteAllowed(opCtx, NamespaceString(dbName, "")); + _checkWriteAllowed(opCtx, NamespaceString(dbName)); } repl::OpTime UserWriteBlockModeOpObserver::onDropCollection(OperationContext* opCtx, diff --git a/src/mongo/db/pipeline/aggregation_request_helper.cpp b/src/mongo/db/pipeline/aggregation_request_helper.cpp index 29a5fe90cd8..43d0c0491a7 100644 --- a/src/mongo/db/pipeline/aggregation_request_helper.cpp +++ b/src/mongo/db/pipeline/aggregation_request_helper.cpp @@ -136,7 +136,8 @@ NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) { << typeName(firstElement.type()), firstElement.type() == BSONType::String); - const NamespaceString nss(dbName, firstElement.valueStringData()); + const NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, firstElement.valueStringData())); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid namespace specified '" << nss.ns() << "'", diff --git a/src/mongo/db/pipeline/change_stream_event_transform.cpp b/src/mongo/db/pipeline/change_stream_event_transform.cpp index 9a54ec6b042..df965830b9d 100644 --- a/src/mongo/db/pipeline/change_stream_event_transform.cpp +++ b/src/mongo/db/pipeline/change_stream_event_transform.cpp @@ -243,7 +243,8 @@ Document ChangeStreamDefaultEventTransformation::applyTransformation(const Docum operationType = DocumentSourceChangeStream::kDropCollectionOpType; // The "o.drop" field will contain the actual collection name. - nss = NamespaceString(nss.dbName(), nssField.getStringData()); + nss = NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + nssField.getStringData()); } else if (auto nssField = oField.getField("renameCollection"); !nssField.missing()) { operationType = DocumentSourceChangeStream::kRenameCollectionOpType; @@ -270,32 +271,37 @@ Document ChangeStreamDefaultEventTransformation::applyTransformation(const Docum // Extract the database name from the namespace field and leave the collection name // empty. - nss = NamespaceString(nss.tenantId(), nss.dbName().db()); + nss = NamespaceString(nss.dbName()); } else if (auto nssField = oField.getField("create"); !nssField.missing()) { operationType = DocumentSourceChangeStream::kCreateOpType; - nss = NamespaceString(nss.dbName(), nssField.getStringData()); + nss = NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + nssField.getStringData()); operationDescription = Value(copyDocExceptFields(oField, {"create"_sd})); } else if (auto nssField = oField.getField("createIndexes"); !nssField.missing()) { operationType = DocumentSourceChangeStream::kCreateIndexesOpType; - nss = NamespaceString(nss.dbName(), nssField.getStringData()); + nss = NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + nssField.getStringData()); // Wrap the index spec in an "indexes" array for consistency with commitIndexBuild. auto indexSpec = Value(copyDocExceptFields(oField, {"createIndexes"_sd})); operationDescription = Value(Document{{"indexes", std::vector<Value>{indexSpec}}}); } else if (auto nssField = oField.getField("commitIndexBuild"); !nssField.missing()) { operationType = DocumentSourceChangeStream::kCreateIndexesOpType; - nss = NamespaceString(nss.dbName(), nssField.getStringData()); + nss = NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + nssField.getStringData()); operationDescription = Value(Document{{"indexes", oField.getField("indexes")}}); } else if (auto nssField = oField.getField("dropIndexes"); !nssField.missing()) { const auto o2Field = input[repl::OplogEntry::kObject2FieldName].getDocument(); operationType = DocumentSourceChangeStream::kDropIndexesOpType; - nss = NamespaceString(nss.dbName(), nssField.getStringData()); + nss = NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + nssField.getStringData()); // Wrap the index spec in an "indexes" array for consistency with createIndexes // and commitIndexBuild. auto indexSpec = Value(copyDocExceptFields(o2Field, {"dropIndexes"_sd})); operationDescription = Value(Document{{"indexes", std::vector<Value>{indexSpec}}}); } else if (auto nssField = oField.getField("collMod"); !nssField.missing()) { operationType = DocumentSourceChangeStream::kModifyOpType; - nss = NamespaceString(nss.dbName(), nssField.getStringData()); + nss = NamespaceStringUtil::parseNamespaceFromDoc(nss.dbName(), + nssField.getStringData()); operationDescription = Value(copyDocExceptFields(oField, {"collMod"_sd})); const auto o2Field = input[repl::OplogEntry::kObject2FieldName].getDocument(); @@ -552,13 +558,14 @@ ChangeStreamEventTransformer::ChangeStreamEventTransformer( ChangeStreamEventTransformation* ChangeStreamEventTransformer::getBuilder( const Document& oplog) const { - // 'nss' is only used here determine which type of transformation to use. This is not dependent - // on the tenantId, so it is safe to ignore the tenantId in the oplog entry. It is useful to - // avoid extracting the tenantId because we must make this determination for every change stream - // event, and the check should therefore be as optimized as possible. - auto nss = NamespaceString(boost::none, oplog[repl::OplogEntry::kNssFieldName].getStringData()); - - if (!_isSingleCollStream && nss.isSystemDotViews()) { + // The nss from the entry is only used here determine which type of transformation to use. This + // is not dependent on the tenantId, so it is safe to ignore the tenantId in the oplog entry. + // It is useful to avoid extracting the tenantId because we must make this determination for + // every change stream event, and the check should therefore be as optimized as possible. + + if (!_isSingleCollStream && + NamespaceString::resolvesToSystemDotViews( + oplog[repl::OplogEntry::kNssFieldName].getStringData())) { return _viewNsEventBuilder.get(); } return _defaultEventBuilder.get(); diff --git a/src/mongo/db/pipeline/change_stream_test_helpers.h b/src/mongo/db/pipeline/change_stream_test_helpers.h index 9e472042a25..a1bc916d2a0 100644 --- a/src/mongo/db/pipeline/change_stream_test_helpers.h +++ b/src/mongo/db/pipeline/change_stream_test_helpers.h @@ -42,7 +42,8 @@ namespace mongo::change_stream_test_helper { static const Timestamp kDefaultTs(100, 1); static const repl::OpTime kDefaultOpTime(kDefaultTs, 1); -static const NamespaceString nss(boost::none, "unittests.change_stream"); +static const NamespaceString nss = + NamespaceString::createNamespaceString_forTest(boost::none, "unittests.change_stream"); static const BSONObj kDefaultSpec = fromjson("{$changeStream: {}}"); static const BSONObj kShowExpandedEventsSpec = fromjson("{$changeStream: {showExpandedEvents: true}}"); diff --git a/src/mongo/db/pipeline/document_source_change_stream_add_post_image.cpp b/src/mongo/db/pipeline/document_source_change_stream_add_post_image.cpp index f6e655ea79e..217518bc20e 100644 --- a/src/mongo/db/pipeline/document_source_change_stream_add_post_image.cpp +++ b/src/mongo/db/pipeline/document_source_change_stream_add_post_image.cpp @@ -112,7 +112,8 @@ NamespaceString DocumentSourceChangeStreamAddPostImage::assertValidNamespace( .getDocument(); auto dbName = assertFieldHasType(namespaceObject, "db"_sd, BSONType::String); auto collectionName = assertFieldHasType(namespaceObject, "coll"_sd, BSONType::String); - NamespaceString nss(pExpCtx->ns.tenantId(), dbName.getString(), collectionName.getString()); + NamespaceString nss(NamespaceStringUtil::parseNamespaceFromDoc( + pExpCtx->ns.tenantId(), dbName.getString(), collectionName.getString())); // Change streams on an entire database only need to verify that the database names match. If // the database is 'admin', then this is a cluster-wide $changeStream and we are permitted to diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp index f8a7244b03a..244939c2d61 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp @@ -71,7 +71,8 @@ NamespaceString parseGraphLookupFromAndResolveNamespace(const BSONElement& elem, elem.type() == String || elem.type() == Object); if (elem.type() == BSONType::String) { - NamespaceString fromNss(defaultDb, elem.valueStringData()); + NamespaceString fromNss( + NamespaceStringUtil::parseNamespaceFromRequest(defaultDb, elem.valueStringData())); uassert(ErrorCodes::InvalidNamespace, str::stream() << "invalid $graphLookup namespace: " << fromNss.ns(), fromNss.isValid()); @@ -82,8 +83,9 @@ NamespaceString parseGraphLookupFromAndResolveNamespace(const BSONElement& elem, auto spec = NamespaceSpec::parse( IDLParserContext{elem.fieldNameStringData(), false /* apiStrict */, defaultDb.tenantId()}, elem.embeddedObject()); - // TODO SERVER-62491 Use system tenantId to construct nss. - auto nss = NamespaceString(spec.getDb().value_or(DatabaseName()), spec.getColl().value_or("")); + + auto nss = NamespaceStringUtil::parseNamespaceFromRequest(spec.getDb().value_or(DatabaseName()), + spec.getColl().value_or("")); uassert(ErrorCodes::FailedToParse, str::stream() diff --git a/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp b/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp index 9f571b8a26a..11938238198 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp @@ -892,7 +892,8 @@ TEST_F(DocumentSourceGraphLookupServerlessTest, auto tenantId = expCtx->ns.tenantId(); ASSERT(tenantId); - NamespaceString graphLookupNs(expCtx->ns.dbName(), "foo"); + NamespaceString graphLookupNs( + NamespaceString::createNamespaceString_forTest(expCtx->ns.dbName(), "foo")); expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{ {graphLookupNs.coll().toString(), {graphLookupNs, std::vector<BSONObj>()}}}); diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index 9dee46e0326..976ce9c78e5 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -105,15 +105,15 @@ NamespaceString parseLookupFromAndResolveNamespace(const BSONElement& elem, elem.type() == BSONType::String || elem.type() == BSONType::Object); if (elem.type() == BSONType::String) { - return NamespaceString(defaultDb, elem.valueStringData()); + return NamespaceStringUtil::parseNamespaceFromRequest(defaultDb, elem.valueStringData()); } // Valdate the db and coll names. auto spec = NamespaceSpec::parse( IDLParserContext{elem.fieldNameStringData(), false /* apiStrict */, defaultDb.tenantId()}, elem.embeddedObject()); - // TODO SERVER-62491 Use system tenantId to construct nss if running in serverless. - auto nss = NamespaceString(spec.getDb().value_or(DatabaseName()), spec.getColl().value_or("")); + auto nss = NamespaceStringUtil::parseNamespaceFromRequest(spec.getDb().value_or(DatabaseName()), + spec.getColl().value_or("")); uassert( ErrorCodes::FailedToParse, str::stream() << "$lookup with syntax {from: {db:<>, coll:<>},..} is not supported for db: " diff --git a/src/mongo/db/pipeline/document_source_merge.cpp b/src/mongo/db/pipeline/document_source_merge.cpp index 48052af235f..00b033a5b34 100644 --- a/src/mongo/db/pipeline/document_source_merge.cpp +++ b/src/mongo/db/pipeline/document_source_merge.cpp @@ -286,7 +286,8 @@ DocumentSourceMergeSpec parseMergeSpecAndResolveTargetNamespace(const BSONElemen // database name using the shortcut syntax (to match the semantics of the $out stage), the // target database will use the default name provided. if (spec.type() == BSONType::String) { - targetNss = {defaultDb, spec.valueStringData()}; + targetNss = + NamespaceStringUtil::parseNamespaceFromRequest(defaultDb, spec.valueStringData()); } else { mergeSpec = DocumentSourceMergeSpec::parse( IDLParserContext(kStageName, false /* apiStrict */, defaultDb.tenantId()), @@ -299,10 +300,10 @@ DocumentSourceMergeSpec parseMergeSpecAndResolveTargetNamespace(const BSONElemen // from the NamespaceString semantics which treats it as a database name. So, if the // target namespace collection is empty, we'll use the default database name as a target // database, and the provided namespace value as a collection name. - targetNss = {defaultDb, targetNss.ns()}; + targetNss = NamespaceStringUtil::parseNamespaceFromRequest(defaultDb, targetNss.ns()); } else if (targetNss.dbName().db().empty()) { // Use the default database name if it wasn't specified explicilty. - targetNss = {defaultDb, targetNss.coll()}; + targetNss = NamespaceStringUtil::parseNamespaceFromRequest(defaultDb, targetNss.coll()); } } diff --git a/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp b/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp index b0c6fff8037..9829838aba8 100644 --- a/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp +++ b/src/mongo/db/pipeline/document_source_merge_cursors_test.cpp @@ -83,7 +83,8 @@ const CursorId kExhaustedCursorID = 0; class DocumentSourceMergeCursorsTest : public ShardingTestFixture { public: - DocumentSourceMergeCursorsTest() : _nss(boost::none, kMergeCursorNsStr) { + DocumentSourceMergeCursorsTest() + : _nss(NamespaceString::createNamespaceString_forTest(boost::none, kMergeCursorNsStr)) { TimeZoneDatabase::set(getServiceContext(), std::make_unique<TimeZoneDatabase>()); } diff --git a/src/mongo/db/pipeline/document_source_merge_spec.cpp b/src/mongo/db/pipeline/document_source_merge_spec.cpp index 7518c8e2df0..d98b567f5c5 100644 --- a/src/mongo/db/pipeline/document_source_merge_spec.cpp +++ b/src/mongo/db/pipeline/document_source_merge_spec.cpp @@ -53,7 +53,7 @@ NamespaceString mergeTargetNssParseFromBSON(boost::optional<TenantId> tenantId, uassert(5786800, "{} 'into' field cannot be an empty string"_format(DocumentSourceMerge::kStageName), !elem.valueStringData().empty()); - return NamespaceString(tenantId, "", elem.valueStringData()); + return NamespaceStringUtil::parseNamespaceFromRequest(tenantId, "", elem.valueStringData()); } auto spec = NamespaceSpec::parse( IDLParserContext( @@ -65,7 +65,8 @@ NamespaceString mergeTargetNssParseFromBSON(boost::optional<TenantId> tenantId, DocumentSourceMerge::kStageName), coll && !coll->empty()); - return {spec.getDb().value_or(DatabaseName(tenantId, "")), *coll}; + return NamespaceStringUtil::parseNamespaceFromRequest( + spec.getDb().value_or(DatabaseName(tenantId, "")), *coll); } void mergeTargetNssSerializeToBSON(const NamespaceString& targetNss, diff --git a/src/mongo/db/pipeline/document_source_out.cpp b/src/mongo/db/pipeline/document_source_out.cpp index 12abd30a6b7..bd2eddac692 100644 --- a/src/mongo/db/pipeline/document_source_out.cpp +++ b/src/mongo/db/pipeline/document_source_out.cpp @@ -85,14 +85,15 @@ DocumentSourceOut::~DocumentSourceOut() { NamespaceString DocumentSourceOut::parseNsFromElem(const BSONElement& spec, const DatabaseName& defaultDB) { if (spec.type() == BSONType::String) { - return NamespaceString(defaultDB, spec.valueStringData()); + return NamespaceStringUtil::parseNamespaceFromRequest(defaultDB, spec.valueStringData()); } else if (spec.type() == BSONType::Object) { auto nsObj = spec.Obj(); uassert(16994, str::stream() << "If an object is passed to " << kStageName << " it must have exactly 2 fields: 'db' and 'coll'", nsObj.nFields() == 2 && nsObj.hasField("coll") && nsObj.hasField("db")); - return NamespaceString(defaultDB.tenantId(), nsObj["db"].String(), nsObj["coll"].String()); + return NamespaceStringUtil::parseNamespaceFromRequest( + defaultDB.tenantId(), nsObj["db"].String(), nsObj["coll"].String()); } else { uassert(16990, "{} only supports a string or object argument, but found {}"_format( @@ -104,7 +105,6 @@ NamespaceString DocumentSourceOut::parseNsFromElem(const BSONElement& spec, std::unique_ptr<DocumentSourceOut::LiteParsed> DocumentSourceOut::LiteParsed::parse( const NamespaceString& nss, const BSONElement& spec) { - NamespaceString targetNss = parseNsFromElem(spec, nss.dbName()); uassert(ErrorCodes::InvalidNamespace, "Invalid {} target namespace, {}"_format(kStageName, targetNss.ns()), @@ -120,9 +120,9 @@ void DocumentSourceOut::initialize() { // to be the target collection once we are done. // Note that this temporary collection name is used by MongoMirror and thus should not be // changed without consultation. - _tempNs = NamespaceString(outputNs.tenantId(), - str::stream() << outputNs.dbName().toString() << ".tmp.agg_out." - << UUID::gen()); + _tempNs = NamespaceStringUtil::parseNamespaceFromRequest( + outputNs.tenantId(), + str::stream() << outputNs.dbName().toString() << ".tmp.agg_out." << UUID::gen()); // Save the original collection options and index specs so we can check they didn't change // during computation. diff --git a/src/mongo/db/pipeline/document_source_union_with.cpp b/src/mongo/db/pipeline/document_source_union_with.cpp index f8d61a9e061..3506561f46a 100644 --- a/src/mongo/db/pipeline/document_source_union_with.cpp +++ b/src/mongo/db/pipeline/document_source_union_with.cpp @@ -127,12 +127,14 @@ std::unique_ptr<DocumentSourceUnionWith::LiteParsed> DocumentSourceUnionWith::Li NamespaceString unionNss; boost::optional<LiteParsedPipeline> liteParsedPipeline; if (spec.type() == BSONType::String) { - unionNss = NamespaceString(nss.dbName(), spec.valueStringData()); + unionNss = + NamespaceStringUtil::parseNamespaceFromRequest(nss.dbName(), spec.valueStringData()); } else { auto unionWithSpec = UnionWithSpec::parse(IDLParserContext(kStageName), spec.embeddedObject()); if (unionWithSpec.getColl()) { - unionNss = NamespaceString(nss.dbName(), *unionWithSpec.getColl()); + unionNss = NamespaceStringUtil::parseNamespaceFromRequest(nss.dbName(), + *unionWithSpec.getColl()); } else { // If no collection specified, it must have $documents as first field in pipeline. validateUnionWithCollectionlessPipeline(unionWithSpec.getPipeline()); @@ -185,12 +187,14 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceUnionWith::createFromBson( NamespaceString unionNss; std::vector<BSONObj> pipeline; if (elem.type() == BSONType::String) { - unionNss = NamespaceString(expCtx->ns.dbName(), elem.valueStringData()); + unionNss = NamespaceStringUtil::parseNamespaceFromRequest(expCtx->ns.dbName(), + elem.valueStringData()); } else { auto unionWithSpec = UnionWithSpec::parse(IDLParserContext(kStageName), elem.embeddedObject()); if (unionWithSpec.getColl()) { - unionNss = NamespaceString(expCtx->ns.dbName(), *unionWithSpec.getColl()); + unionNss = NamespaceStringUtil::parseNamespaceFromRequest(expCtx->ns.dbName(), + *unionWithSpec.getColl()); } else { // if no collection specified, it must have $documents as first field in pipeline validateUnionWithCollectionlessPipeline(unionWithSpec.getPipeline()); diff --git a/src/mongo/db/pipeline/process_interface/common_mongod_process_interface.cpp b/src/mongo/db/pipeline/process_interface/common_mongod_process_interface.cpp index 4bcd1db560b..f4d8e02d896 100644 --- a/src/mongo/db/pipeline/process_interface/common_mongod_process_interface.cpp +++ b/src/mongo/db/pipeline/process_interface/common_mongod_process_interface.cpp @@ -296,7 +296,8 @@ std::deque<BSONObj> CommonMongodProcessInterface::listCatalog(OperationContext* NamespaceString ns(NamespaceStringUtil::deserialize((*svns.nss()).tenantId(), obj.getStringField("_id"))); - NamespaceString viewOnNs(ns.dbName(), obj.getStringField("viewOn")); + NamespaceString viewOnNs(NamespaceStringUtil::parseNamespaceFromDoc( + ns.dbName(), obj.getStringField("viewOn"))); BSONObjBuilder builder; builder.append("db", DatabaseNameUtil::serialize(ns.dbName())); diff --git a/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp b/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp index 6dc8109420c..16473b19bda 100644 --- a/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp +++ b/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp @@ -152,7 +152,7 @@ void ReplicaSetNodeProcessInterface::renameIfOptionsAndIndexesHaveNotChanged( void ReplicaSetNodeProcessInterface::createCollection(OperationContext* opCtx, const DatabaseName& dbName, const BSONObj& cmdObj) { - NamespaceString dbNs = NamespaceString(dbName, StringData("")); + NamespaceString dbNs = NamespaceString(dbName); if (_canWriteLocally(opCtx, dbNs)) { return NonShardServerProcessInterface::createCollection(opCtx, dbName, cmdObj); } diff --git a/src/mongo/db/query/fle/server_rewrite.cpp b/src/mongo/db/query/fle/server_rewrite.cpp index f0f0db0da1e..a48ad5d7789 100644 --- a/src/mongo/db/query/fle/server_rewrite.cpp +++ b/src/mongo/db/query/fle/server_rewrite.cpp @@ -256,7 +256,8 @@ void doFLERewriteInTxn(OperationContext* opCtx, // if breaks us off of the current optctx readconcern and other settings // if (!opCtx->inMultiDocumentTransaction()) { - NamespaceString nssEsc(sharedBlock->dbName, sharedBlock->esc); + NamespaceString nssEsc(NamespaceStringUtil::parseNamespaceFromRequest( + sharedBlock->dbName, sharedBlock->esc)); NamespaceString nssEcc; // Ignored in V2 FLETagNoTXNQuery queryInterface(opCtx); @@ -268,17 +269,18 @@ void doFLERewriteInTxn(OperationContext* opCtx, auto txn = getTxn(opCtx); auto swCommitResult = txn->runNoThrow( opCtx, [sharedBlock](const txn_api::TransactionClient& txnClient, auto txnExec) { - NamespaceString nssEsc(sharedBlock->dbName, sharedBlock->esc); + NamespaceString nssEsc(NamespaceStringUtil::parseNamespaceFromRequest( + sharedBlock->dbName, sharedBlock->esc)); // Construct FLE rewriter from the transaction client and encryptionInformation. auto queryInterface = FLEQueryInterfaceImpl(txnClient, getGlobalServiceContext()); // Rewrite the MatchExpression. if (sharedBlock->ecc) { - sharedBlock->doRewrite( - &queryInterface, - nssEsc, - NamespaceString(sharedBlock->dbName, sharedBlock->ecc.get())); + sharedBlock->doRewrite(&queryInterface, + nssEsc, + NamespaceStringUtil::parseNamespaceFromRequest( + sharedBlock->dbName, sharedBlock->ecc.get())); } else { sharedBlock->doRewrite(&queryInterface, nssEsc); } @@ -298,10 +300,12 @@ BSONObj rewriteEncryptedFilterInsideTxn(FLETagQueryInterface* queryImpl, boost::intrusive_ptr<ExpressionContext> expCtx, BSONObj filter, EncryptedCollScanModeAllowed mode) { - NamespaceString nssEsc(dbName, efc.getEscCollection().value()); + NamespaceString nssEsc( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, efc.getEscCollection().value())); if (!gFeatureFlagFLE2ProtocolVersion2.isEnabled(serverGlobalParams.featureCompatibility)) { - NamespaceString nssEcc(dbName, efc.getEccCollection().value()); + NamespaceString nssEcc( + NamespaceStringUtil::parseNamespaceFromRequest(dbName, efc.getEccCollection().value())); return rewriteEncryptedFilter(queryImpl, nssEsc, nssEcc, expCtx, filter, mode); } diff --git a/src/mongo/db/repl/collection_cloner_test.cpp b/src/mongo/db/repl/collection_cloner_test.cpp index 5332d05ec4d..c51b32e7c89 100644 --- a/src/mongo/db/repl/collection_cloner_test.cpp +++ b/src/mongo/db/repl/collection_cloner_test.cpp @@ -60,7 +60,8 @@ const std::string kTestNs = "testDb.testColl"; class CollectionClonerTest : public InitialSyncClonerTestFixture { public: - CollectionClonerTest() : _nss(boost::none, kTestNs) {} + CollectionClonerTest() + : _nss(NamespaceString::createNamespaceString_forTest(boost::none, kTestNs)) {} protected: void setUp() override { @@ -1013,7 +1014,8 @@ TEST_F(CollectionClonerTestResumable, ResumableQueryTwoResumes) { class CollectionClonerMultitenancyTest : public CollectionClonerTestResumable { public: - CollectionClonerMultitenancyTest() : _nss(TenantId(OID::gen()), kTestNs) {} + CollectionClonerMultitenancyTest() + : _nss(NamespaceString::createNamespaceString_forTest(TenantId(OID::gen()), kTestNs)) {} protected: void setUp() final { diff --git a/src/mongo/db/repl/database_cloner.cpp b/src/mongo/db/repl/database_cloner.cpp index b19708702d1..5d600993f32 100644 --- a/src/mongo/db/repl/database_cloner.cpp +++ b/src/mongo/db/repl/database_cloner.cpp @@ -89,7 +89,8 @@ BaseCloner::AfterStageBehavior DatabaseCloner::listCollectionsStage() { .reason()); } - NamespaceString collectionNamespace(_dbName, result.getName()); + NamespaceString collectionNamespace( + NamespaceStringUtil::parseNamespaceFromResponse(_dbName, result.getName())); if (collectionNamespace.isSystem() && !collectionNamespace.isReplicated()) { LOGV2_DEBUG(21146, 1, diff --git a/src/mongo/db/repl/idempotency_test_fixture.h b/src/mongo/db/repl/idempotency_test_fixture.h index 33d4f1c4ffa..9412aac9aa9 100644 --- a/src/mongo/db/repl/idempotency_test_fixture.h +++ b/src/mongo/db/repl/idempotency_test_fixture.h @@ -89,7 +89,8 @@ StringBuilder& operator<<(StringBuilder& sb, const CollectionState& state); class IdempotencyTest : public OplogApplierImplTest { public: - IdempotencyTest() : _nss(boost::none, "test.foo") { + IdempotencyTest() + : _nss(NamespaceString::createNamespaceString_forTest(boost::none, "test.foo")) { globalFailPointRegistry() .find("doUntimestampedWritesForIdempotencyTests") ->setMode(FailPoint::alwaysOn); diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 98c57c1496f..04f92aeb17b 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -841,7 +841,7 @@ NamespaceString extractNs(DatabaseName dbName, const BSONObj& cmdObj) { first.canonicalType() == canonicalizeBSONType(mongo::String)); StringData coll = first.valueStringData(); uassert(28635, "no collection name specified", !coll.empty()); - return NamespaceString(dbName, coll); + return NamespaceStringUtil::parseNamespaceFromDoc(dbName, coll); } NamespaceString extractNsFromUUID(OperationContext* opCtx, const UUID& uuid) { diff --git a/src/mongo/db/repl/oplog_applier_impl_test.cpp b/src/mongo/db/repl/oplog_applier_impl_test.cpp index e55ef97dffa..337c8f14075 100644 --- a/src/mongo/db/repl/oplog_applier_impl_test.cpp +++ b/src/mongo/db/repl/oplog_applier_impl_test.cpp @@ -1685,8 +1685,8 @@ class MultiOplogEntryOplogApplierImplTestMultitenant : public OplogApplierImplTe public: MultiOplogEntryOplogApplierImplTestMultitenant() : _tenantId(OID::gen()), - _nss(_tenantId, "test.preptxn"), - _cmdNss(_tenantId, "admin", "$cmd"), + _nss(NamespaceString::createNamespaceString_forTest(_tenantId, "test.preptxn")), + _cmdNss(NamespaceString::createNamespaceString_forTest(_tenantId, "admin", "$cmd")), _txnNum(1) {} protected: diff --git a/src/mongo/db/repl/repl_set_test_egress.cpp b/src/mongo/db/repl/repl_set_test_egress.cpp index c3c5b9861eb..6fad40ebb51 100644 --- a/src/mongo/db/repl/repl_set_test_egress.cpp +++ b/src/mongo/db/repl/repl_set_test_egress.cpp @@ -139,7 +139,7 @@ public: void doCheckAuthorization(OperationContext*) const final {} NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/repl/rollback_impl_test.cpp b/src/mongo/db/repl/rollback_impl_test.cpp index bafd638b045..5ffbb4edf96 100644 --- a/src/mongo/db/repl/rollback_impl_test.cpp +++ b/src/mongo/db/repl/rollback_impl_test.cpp @@ -2068,8 +2068,8 @@ TEST_F(RollbackImplObserverInfoTest, RAIIServerParameterControllerForTest multitenancyController("multitenancySupport", true); boost::optional<TenantId> tid(OID::gen()); - auto fromNss = NamespaceString(tid, "test", "source"); - auto toNss = NamespaceString(tid, "test", "dest"); + auto fromNss = NamespaceString::createNamespaceString_forTest(tid, "test", "source"); + auto toNss = NamespaceString::createNamespaceString_forTest(tid, "test", "dest"); auto cmdObj = BSON("renameCollection" << NamespaceStringUtil::serialize(fromNss) << "to" << NamespaceStringUtil::serialize(toNss)); @@ -2089,8 +2089,8 @@ TEST_F(RollbackImplObserverInfoTest, RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true); boost::optional<TenantId> tid(OID::gen()); - auto fromNss = NamespaceString(tid, "test", "source"); - auto toNss = NamespaceString(tid, "test", "dest"); + auto fromNss = NamespaceString::createNamespaceString_forTest(tid, "test", "source"); + auto toNss = NamespaceString::createNamespaceString_forTest(tid, "test", "dest"); auto cmdObj = BSON("renameCollection" << NamespaceStringUtil::serialize(fromNss) << "to" << NamespaceStringUtil::serialize(toNss)); diff --git a/src/mongo/db/repl/shard_merge_recipient_service.cpp b/src/mongo/db/repl/shard_merge_recipient_service.cpp index 8e362697ee3..7bd286b4b7f 100644 --- a/src/mongo/db/repl/shard_merge_recipient_service.cpp +++ b/src/mongo/db/repl/shard_merge_recipient_service.cpp @@ -97,7 +97,8 @@ constexpr int kCheckpointTsBackupCursorErrorCode = 6929900; constexpr int kCloseCursorBeforeOpenErrorCode = 50886; NamespaceString getOplogBufferNs(const UUID& migrationUUID) { - return NamespaceString(DatabaseName::kConfig, kOplogBufferPrefix + migrationUUID.toString()); + return NamespaceString::makeGlobalConfigCollection(kOplogBufferPrefix + + migrationUUID.toString()); } boost::intrusive_ptr<ExpressionContext> makeExpressionContext(OperationContext* opCtx) { diff --git a/src/mongo/db/repl/tenant_migration_recipient_service.cpp b/src/mongo/db/repl/tenant_migration_recipient_service.cpp index e02202bfcb4..77829e61f4f 100644 --- a/src/mongo/db/repl/tenant_migration_recipient_service.cpp +++ b/src/mongo/db/repl/tenant_migration_recipient_service.cpp @@ -100,7 +100,8 @@ constexpr int kCheckpointTsBackupCursorErrorCode = 6929900; constexpr int kCloseCursorBeforeOpenErrorCode = 50886; NamespaceString getOplogBufferNs(const UUID& migrationUUID) { - return NamespaceString(DatabaseName::kConfig, kOplogBufferPrefix + migrationUUID.toString()); + return NamespaceString::makeGlobalConfigCollection(kOplogBufferPrefix + + migrationUUID.toString()); } bool isMigrationCompleted(TenantMigrationRecipientStateEnum state) { diff --git a/src/mongo/db/repl/tenant_migration_shard_merge_util.h b/src/mongo/db/repl/tenant_migration_shard_merge_util.h index 4950d392bf9..203fe094fc2 100644 --- a/src/mongo/db/repl/tenant_migration_shard_merge_util.h +++ b/src/mongo/db/repl/tenant_migration_shard_merge_util.h @@ -58,7 +58,8 @@ inline bool isDonatedFilesCollection(const NamespaceString& ns) { } inline NamespaceString getDonatedFilesNs(const UUID& migrationUUID) { - return NamespaceString(DatabaseName::kConfig, kDonatedFilesPrefix + migrationUUID.toString()); + return NamespaceString::makeGlobalConfigCollection(kDonatedFilesPrefix + + migrationUUID.toString()); } inline boost::filesystem::path fileClonerTempDir(const UUID& migrationId) { diff --git a/src/mongo/db/s/add_shard_cmd.cpp b/src/mongo/db/s/add_shard_cmd.cpp index 6682c51df21..b5505c4371c 100644 --- a/src/mongo/db/s/add_shard_cmd.cpp +++ b/src/mongo/db/s/add_shard_cmd.cpp @@ -95,7 +95,7 @@ public: // The command parameter happens to be string so it's historically been interpreted // by parseNs as a collection. Continuing to do so here for unexamined compatibility. NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } void doCheckAuthorization(OperationContext* opCtx) const override { diff --git a/src/mongo/db/s/analyze_shard_key_cmd_util.cpp b/src/mongo/db/s/analyze_shard_key_cmd_util.cpp index e0ba2487254..6dac0d170f2 100644 --- a/src/mongo/db/s/analyze_shard_key_cmd_util.cpp +++ b/src/mongo/db/s/analyze_shard_key_cmd_util.cpp @@ -619,11 +619,11 @@ CollStatsMetrics calculateCollStats(OperationContext* opCtx, const NamespaceStri * Generates the namespace for the temporary collection storing the split points. */ NamespaceString makeSplitPointsNss(const UUID& origCollUuid, const UUID& tempCollUuid) { - return NamespaceString(DatabaseName::kConfig, - fmt::format("{}{}.{}", - NamespaceString::kAnalyzeShardKeySplitPointsCollectionPrefix, - origCollUuid.toString(), - tempCollUuid.toString())); + return NamespaceString::makeGlobalConfigCollection( + fmt::format("{}{}.{}", + NamespaceString::kAnalyzeShardKeySplitPointsCollectionPrefix, + origCollUuid.toString(), + tempCollUuid.toString())); } /** diff --git a/src/mongo/db/s/check_sharding_index_command.cpp b/src/mongo/db/s/check_sharding_index_command.cpp index 9da41e79384..b1094698bde 100644 --- a/src/mongo/db/s/check_sharding_index_command.cpp +++ b/src/mongo/db/s/check_sharding_index_command.cpp @@ -72,7 +72,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool errmsgRun(OperationContext* opCtx, diff --git a/src/mongo/db/s/config/configsvr_ensure_chunk_version_is_greater_than_command.cpp b/src/mongo/db/s/config/configsvr_ensure_chunk_version_is_greater_than_command.cpp index 9acbfb2f107..7d2f659703e 100644 --- a/src/mongo/db/s/config/configsvr_ensure_chunk_version_is_greater_than_command.cpp +++ b/src/mongo/db/s/config/configsvr_ensure_chunk_version_is_greater_than_command.cpp @@ -64,7 +64,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/s/config/configsvr_remove_chunks_command.cpp b/src/mongo/db/s/config/configsvr_remove_chunks_command.cpp index f91f0b312df..5da8491410d 100644 --- a/src/mongo/db/s/config/configsvr_remove_chunks_command.cpp +++ b/src/mongo/db/s/config/configsvr_remove_chunks_command.cpp @@ -112,7 +112,7 @@ public: private: NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/s/config/configsvr_repair_sharded_collection_chunks_history_command.cpp b/src/mongo/db/s/config/configsvr_repair_sharded_collection_chunks_history_command.cpp index 2017fc4e8f9..1524ec36138 100644 --- a/src/mongo/db/s/config/configsvr_repair_sharded_collection_chunks_history_command.cpp +++ b/src/mongo/db/s/config/configsvr_repair_sharded_collection_chunks_history_command.cpp @@ -69,7 +69,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } Status checkAuthForOperation(OperationContext* opCtx, diff --git a/src/mongo/db/s/config/configsvr_split_chunk_command.cpp b/src/mongo/db/s/config/configsvr_split_chunk_command.cpp index 60d96eb8901..48eb421a579 100644 --- a/src/mongo/db/s/config/configsvr_split_chunk_command.cpp +++ b/src/mongo/db/s/config/configsvr_split_chunk_command.cpp @@ -106,7 +106,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/s/get_database_version_command.cpp b/src/mongo/db/s/get_database_version_command.cpp index 6d23fc2782d..f47466b361f 100644 --- a/src/mongo/db/s/get_database_version_command.cpp +++ b/src/mongo/db/s/get_database_version_command.cpp @@ -62,7 +62,8 @@ public: // The command parameter happens to be string so it's historically been interpreted // by parseNs as a collection. Continuing to do so here for unexamined compatibility. NamespaceString ns() const override { - return NamespaceString(request().getDbName(), _targetDb()); + return NamespaceStringUtil::parseNamespaceFromRequest(request().getDbName(), + _targetDb()); } void doCheckAuthorization(OperationContext* opCtx) const override { diff --git a/src/mongo/db/s/get_shard_version_command.cpp b/src/mongo/db/s/get_shard_version_command.cpp index 57906f8aaae..6bfbf1fc308 100644 --- a/src/mongo/db/s/get_shard_version_command.cpp +++ b/src/mongo/db/s/get_shard_version_command.cpp @@ -78,7 +78,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/s/migration_destination_manager_commands.cpp b/src/mongo/db/s/migration_destination_manager_commands.cpp index 7af69307659..6e289ccf0cd 100644 --- a/src/mongo/db/s/migration_destination_manager_commands.cpp +++ b/src/mongo/db/s/migration_destination_manager_commands.cpp @@ -85,7 +85,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } Status checkAuthForOperation(OperationContext* opCtx, diff --git a/src/mongo/db/s/move_primary/move_primary_recipient_cmds.cpp b/src/mongo/db/s/move_primary/move_primary_recipient_cmds.cpp index a99cf7f6299..6f3faeb2043 100644 --- a/src/mongo/db/s/move_primary/move_primary_recipient_cmds.cpp +++ b/src/mongo/db/s/move_primary/move_primary_recipient_cmds.cpp @@ -93,7 +93,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -161,7 +161,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -232,7 +232,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/s/move_primary_coordinator.cpp b/src/mongo/db/s/move_primary_coordinator.cpp index 5f34c64cbfe..1b695aafc45 100644 --- a/src/mongo/db/s/move_primary_coordinator.cpp +++ b/src/mongo/db/s/move_primary_coordinator.cpp @@ -387,7 +387,8 @@ std::vector<NamespaceString> MovePrimaryCoordinator::getUnshardedCollections( std::string collName; uassertStatusOK(bsonExtractStringField(collInfo, "name", &collName)); - const NamespaceString nss(_dbName, collName); + const NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromDoc(_dbName, collName)); if (!nss.isSystem() || nss.isLegalClientSystemNS(serverGlobalParams.featureCompatibility)) { colls.push_back(nss); @@ -442,7 +443,7 @@ void MovePrimaryCoordinator::assertNoOrphanedDataOnRecipient( for (const auto& bsonColl : listResponse.docs) { std::string collName; uassertStatusOK(bsonExtractStringField(bsonColl, "name", &collName)); - colls.push_back({_dbName, collName}); + colls.push_back(NamespaceStringUtil::parseNamespaceFromResponse(_dbName, collName)); } std::sort(colls.begin(), colls.end()); diff --git a/src/mongo/db/s/resharding/resharding_collection_cloner.cpp b/src/mongo/db/s/resharding/resharding_collection_cloner.cpp index 07538097e26..c34a5d0350b 100644 --- a/src/mongo/db/s/resharding/resharding_collection_cloner.cpp +++ b/src/mongo/db/s/resharding/resharding_collection_cloner.cpp @@ -109,7 +109,7 @@ ReshardingCollectionCloner::makeRawPipeline( // Assume that the config.cache.chunks collection isn't a view either. auto tempNss = resharding::constructTemporaryReshardingNss(_sourceNss.db(), _sourceUUID); auto tempCacheChunksNss = - NamespaceString(DatabaseName::kConfig, "cache.chunks." + tempNss.ns()); + NamespaceString::makeGlobalConfigCollection("cache.chunks." + tempNss.ns()); resolvedNamespaces[tempCacheChunksNss.coll()] = {tempCacheChunksNss, std::vector<BSONObj>{}}; // Pipeline::makePipeline() ignores the collation set on the AggregationRequest (or lack diff --git a/src/mongo/db/s/shardsvr_create_global_index_command.cpp b/src/mongo/db/s/shardsvr_create_global_index_command.cpp index 0ed41877b14..a5b626fea85 100644 --- a/src/mongo/db/s/shardsvr_create_global_index_command.cpp +++ b/src/mongo/db/s/shardsvr_create_global_index_command.cpp @@ -80,7 +80,7 @@ public: } NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } void typedRun(OperationContext* opCtx) { diff --git a/src/mongo/db/s/shardsvr_drop_database_command.cpp b/src/mongo/db/s/shardsvr_drop_database_command.cpp index 3f23ffa2fa8..55c11b82e71 100644 --- a/src/mongo/db/s/shardsvr_drop_database_command.cpp +++ b/src/mongo/db/s/shardsvr_drop_database_command.cpp @@ -121,7 +121,7 @@ public: private: NamespaceString ns() const override { - return {request().getDbName(), ""}; + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/s/shardsvr_drop_database_participant_command.cpp b/src/mongo/db/s/shardsvr_drop_database_participant_command.cpp index e1c5978c9e4..dd354b2e2e2 100644 --- a/src/mongo/db/s/shardsvr_drop_database_participant_command.cpp +++ b/src/mongo/db/s/shardsvr_drop_database_participant_command.cpp @@ -88,7 +88,7 @@ public: private: NamespaceString ns() const override { - return {request().getDbName(), ""}; + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/s/shardsvr_drop_global_index_command.cpp b/src/mongo/db/s/shardsvr_drop_global_index_command.cpp index c55526cb16a..e28d4e94da2 100644 --- a/src/mongo/db/s/shardsvr_drop_global_index_command.cpp +++ b/src/mongo/db/s/shardsvr_drop_global_index_command.cpp @@ -79,7 +79,7 @@ public: } NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } void typedRun(OperationContext* opCtx) { diff --git a/src/mongo/db/s/shardsvr_get_stats_for_balancing_command.cpp b/src/mongo/db/s/shardsvr_get_stats_for_balancing_command.cpp index d50b3fbc26d..4034d70a4ea 100644 --- a/src/mongo/db/s/shardsvr_get_stats_for_balancing_command.cpp +++ b/src/mongo/db/s/shardsvr_get_stats_for_balancing_command.cpp @@ -134,7 +134,7 @@ public: } NamespaceString ns() const override { - return {request().getDbName(), ""}; + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/s/shardsvr_join_migrations_command.cpp b/src/mongo/db/s/shardsvr_join_migrations_command.cpp index eeb2cdbcd3f..d5b2e171038 100644 --- a/src/mongo/db/s/shardsvr_join_migrations_command.cpp +++ b/src/mongo/db/s/shardsvr_join_migrations_command.cpp @@ -83,7 +83,7 @@ public: static constexpr char kRegistryLockReason[] = "Running _shardsvrJoinMigrations"; NamespaceString ns() const override { - return {request().getDbName(), ""}; + return NamespaceString(request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/db/s/shardsvr_merge_chunks_command.cpp b/src/mongo/db/s/shardsvr_merge_chunks_command.cpp index 0b5c48213c1..4169f3235d5 100644 --- a/src/mongo/db/s/shardsvr_merge_chunks_command.cpp +++ b/src/mongo/db/s/shardsvr_merge_chunks_command.cpp @@ -140,7 +140,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool adminOnly() const override { diff --git a/src/mongo/db/s/shardsvr_move_primary_command.cpp b/src/mongo/db/s/shardsvr_move_primary_command.cpp index 55170519081..aeca60ed58d 100644 --- a/src/mongo/db/s/shardsvr_move_primary_command.cpp +++ b/src/mongo/db/s/shardsvr_move_primary_command.cpp @@ -83,7 +83,7 @@ public: uassert(ErrorCodes::InvalidNamespace, "'movePrimary' must be of type String", nsElt.type() == BSONType::String); - return NamespaceString(dbName.tenantId(), nsElt.str()); + return NamespaceStringUtil::parseNamespaceFromRequest(dbName.tenantId(), nsElt.str()); } bool run(OperationContext* opCtx, diff --git a/src/mongo/db/s/shardsvr_split_chunk_command.cpp b/src/mongo/db/s/shardsvr_split_chunk_command.cpp index 52536354781..33cb9dcd496 100644 --- a/src/mongo/db/s/shardsvr_split_chunk_command.cpp +++ b/src/mongo/db/s/shardsvr_split_chunk_command.cpp @@ -88,7 +88,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool errmsgRun(OperationContext* opCtx, diff --git a/src/mongo/db/s/shardsvr_write_global_index_keys_command.cpp b/src/mongo/db/s/shardsvr_write_global_index_keys_command.cpp index 77536e7773f..8eece73ffc9 100644 --- a/src/mongo/db/s/shardsvr_write_global_index_keys_command.cpp +++ b/src/mongo/db/s/shardsvr_write_global_index_keys_command.cpp @@ -67,7 +67,7 @@ public: } NamespaceString ns() const override { - return {request().getDbName(), ""}; + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/s/split_vector_command.cpp b/src/mongo/db/s/split_vector_command.cpp index 511d9ff52f0..2e2bf3cb9b3 100644 --- a/src/mongo/db/s/split_vector_command.cpp +++ b/src/mongo/db/s/split_vector_command.cpp @@ -82,7 +82,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool errmsgRun(OperationContext* opCtx, diff --git a/src/mongo/db/s/txn_two_phase_commit_cmds.cpp b/src/mongo/db/s/txn_two_phase_commit_cmds.cpp index 09c8897ae08..19c7d58e58d 100644 --- a/src/mongo/db/s/txn_two_phase_commit_cmds.cpp +++ b/src/mongo/db/s/txn_two_phase_commit_cmds.cpp @@ -184,7 +184,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } void doCheckAuthorization(OperationContext* opCtx) const override { @@ -374,7 +374,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } void doCheckAuthorization(OperationContext* opCtx) const override {} diff --git a/src/mongo/db/serverless/shard_split_commands.cpp b/src/mongo/db/serverless/shard_split_commands.cpp index b7757134c4b..b01d3867c08 100644 --- a/src/mongo/db/serverless/shard_split_commands.cpp +++ b/src/mongo/db/serverless/shard_split_commands.cpp @@ -105,7 +105,7 @@ public: } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -183,7 +183,7 @@ public: } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -260,7 +260,7 @@ public: } NamespaceString ns() const { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index 09780d00045..2c6c3bbd2f1 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -1995,9 +1995,8 @@ void curOpCommandSetup(OperationContext* opCtx, const OpMsgRequest& request) { // We construct a legacy $cmd namespace so we can fill in curOp using // the existing logic that existed for OP_QUERY commands - NamespaceString nss( - DatabaseNameUtil::deserialize(request.getValidatedTenantId(), request.getDatabase()), - "$cmd"); + NamespaceString nss(NamespaceString::makeCommandNamespace( + DatabaseNameUtil::deserialize(request.getValidatedTenantId(), request.getDatabase()))); stdx::lock_guard<Client> lk(*opCtx->getClient()); curop->setNS_inlock(nss); diff --git a/src/mongo/db/shard_role_test.cpp b/src/mongo/db/shard_role_test.cpp index 2dc888976f3..7cdd771d50b 100644 --- a/src/mongo/db/shard_role_test.cpp +++ b/src/mongo/db/shard_role_test.cpp @@ -960,7 +960,8 @@ TEST_F(ShardRoleTest, RestoreWithShardVersionIgnored) { void ShardRoleTest::testRestoreFailsIfCollectionBecomesCreated( AcquisitionPrerequisites::OperationType operationType) { - NamespaceString nss(dbNameTestDb, "NonExistentCollectionWhichWillBeCreated"); + NamespaceString nss(NamespaceString::createNamespaceString_forTest( + dbNameTestDb, "NonExistentCollectionWhichWillBeCreated")); const auto acquisition = acquireCollection( opCtx(), CollectionAcquisitionRequest::fromOpCtx(opCtx(), nss, operationType), MODE_IX); diff --git a/src/mongo/db/storage/kv/kv_engine_test_harness.cpp b/src/mongo/db/storage/kv/kv_engine_test_harness.cpp index 61971054cb3..2b1259ab8fb 100644 --- a/src/mongo/db/storage/kv/kv_engine_test_harness.cpp +++ b/src/mongo/db/storage/kv/kv_engine_test_harness.cpp @@ -1091,7 +1091,7 @@ TEST_F(DurableCatalogImplTest, Idx1) { WriteUnitOfWork uow(opCtx); BSONCollectionCatalogEntry::MetaData md; - md.nss = NamespaceString(boost::none, "a.b"); + md.nss = NamespaceString::createNamespaceString_forTest(boost::none, "a.b"); BSONCollectionCatalogEntry::IndexMetaData imd; imd.spec = BSON("name" @@ -1125,7 +1125,7 @@ TEST_F(DurableCatalogImplTest, Idx1) { WriteUnitOfWork uow(opCtx); BSONCollectionCatalogEntry::MetaData md; - md.nss = NamespaceString(boost::none, "a.b"); + md.nss = NamespaceString::createNamespaceString_forTest(boost::none, "a.b"); putMetaData(opCtx, catalog.get(), catalogId, md); // remove index BSONCollectionCatalogEntry::IndexMetaData imd; @@ -1181,7 +1181,7 @@ TEST_F(DurableCatalogImplTest, DirectoryPerDb1) { WriteUnitOfWork uow(opCtx); BSONCollectionCatalogEntry::MetaData md; - md.nss = NamespaceString(boost::none, "a.b"); + md.nss = NamespaceString::createNamespaceString_forTest(boost::none, "a.b"); BSONCollectionCatalogEntry::IndexMetaData imd; imd.spec = BSON("name" @@ -1233,7 +1233,7 @@ TEST_F(DurableCatalogImplTest, Split1) { WriteUnitOfWork uow(opCtx); BSONCollectionCatalogEntry::MetaData md; - md.nss = NamespaceString(boost::none, "a.b"); + md.nss = NamespaceString::createNamespaceString_forTest(boost::none, "a.b"); BSONCollectionCatalogEntry::IndexMetaData imd; imd.spec = BSON("name" @@ -1285,7 +1285,7 @@ TEST_F(DurableCatalogImplTest, DirectoryPerAndSplit1) { WriteUnitOfWork uow(opCtx); BSONCollectionCatalogEntry::MetaData md; - md.nss = NamespaceString(boost::none, "a.b"); + md.nss = NamespaceString::createNamespaceString_forTest(boost::none, "a.b"); BSONCollectionCatalogEntry::IndexMetaData imd; imd.spec = BSON("name" @@ -1383,7 +1383,7 @@ TEST_F(DurableCatalogImplTest, EntryIncludesTenantIdInMultitenantEnv) { // entry. RecordId catalogId; auto tenantId = TenantId(OID::gen()); - const NamespaceString nss = NamespaceString(tenantId, "a.b"); + const NamespaceString nss = NamespaceString::createNamespaceString_forTest(tenantId, "a.b"); { auto clientAndCtx = makeClientAndCtx("opCtx"); auto opCtx = clientAndCtx.opCtx(); diff --git a/src/mongo/db/views/SConscript b/src/mongo/db/views/SConscript index 2cb81766efe..53cfc7e4bec 100644 --- a/src/mongo/db/views/SConscript +++ b/src/mongo/db/views/SConscript @@ -12,6 +12,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/query/collation/collator_factory_interface', + '$BUILD_DIR/mongo/util/namespace_string_database_name_util', ], ) diff --git a/src/mongo/db/views/view.cpp b/src/mongo/db/views/view.cpp index bc86e73f26e..e9d9ec5b7ca 100644 --- a/src/mongo/db/views/view.cpp +++ b/src/mongo/db/views/view.cpp @@ -42,7 +42,9 @@ ViewDefinition::ViewDefinition(const DatabaseName& dbName, StringData viewOnName, const BSONObj& pipeline, std::unique_ptr<CollatorInterface> collator) - : _viewNss(dbName, viewName), _viewOnNss(dbName, viewOnName), _collator(std::move(collator)) { + : _viewNss(NamespaceStringUtil::parseNamespaceFromDoc(dbName, viewName)), + _viewOnNss(NamespaceStringUtil::parseNamespaceFromDoc(dbName, viewOnName)), + _collator(std::move(collator)) { for (BSONElement e : pipeline) { _pipeline.push_back(e.Obj().getOwned()); } diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp index 93847675bb1..fac9153c789 100644 --- a/src/mongo/dbtests/validate_tests.cpp +++ b/src/mongo/dbtests/validate_tests.cpp @@ -2192,8 +2192,8 @@ public: // Verify the older duplicate document appears in the lost-and-found as expected. { - const NamespaceString lostAndFoundNss = NamespaceString( - DatabaseName::kLocal, "lost_and_found." + coll()->uuid().toString()); + const NamespaceString lostAndFoundNss = NamespaceString::makeLocalCollection( + "lost_and_found." + coll()->uuid().toString()); AutoGetCollectionForRead autoColl(&_opCtx, lostAndFoundNss); Snapshotted<BSONObj> result; ASSERT(autoColl.getCollection()->findDoc(&_opCtx, RecordId(1), &result)); @@ -2451,8 +2451,8 @@ public: // Verify the older document appears in the lost-and-found as expected. { - const NamespaceString lostAndFoundNss = NamespaceString( - DatabaseName::kLocal, "lost_and_found." + coll()->uuid().toString()); + const NamespaceString lostAndFoundNss = NamespaceString::makeLocalCollection( + "lost_and_found." + coll()->uuid().toString()); AutoGetCollectionForRead autoColl(&_opCtx, lostAndFoundNss); Snapshotted<BSONObj> result; ASSERT(autoColl.getCollection()->findDoc(&_opCtx, RecordId(1), &result)); @@ -2794,8 +2794,8 @@ public: // Verify the older duplicate document appears in the lost-and-found as expected. { - const NamespaceString lostAndFoundNss = NamespaceString( - DatabaseName::kLocal, "lost_and_found." + coll()->uuid().toString()); + const NamespaceString lostAndFoundNss = NamespaceString::makeLocalCollection( + "lost_and_found." + coll()->uuid().toString()); AutoGetCollectionForRead autoColl(&_opCtx, lostAndFoundNss); Snapshotted<BSONObj> result; ASSERT(autoColl.getCollection()->findDoc(&_opCtx, RecordId(1), &result)); diff --git a/src/mongo/s/commands/cluster_coordinate_commit_txn.cpp b/src/mongo/s/commands/cluster_coordinate_commit_txn.cpp index c1c33413ee9..62abf79ce99 100644 --- a/src/mongo/s/commands/cluster_coordinate_commit_txn.cpp +++ b/src/mongo/s/commands/cluster_coordinate_commit_txn.cpp @@ -76,7 +76,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } void doCheckAuthorization(OperationContext* opCtx) const override { diff --git a/src/mongo/s/commands/cluster_filemd5_cmd.cpp b/src/mongo/s/commands/cluster_filemd5_cmd.cpp index 61cea761bf6..63b5a2a5033 100644 --- a/src/mongo/s/commands/cluster_filemd5_cmd.cpp +++ b/src/mongo/s/commands/cluster_filemd5_cmd.cpp @@ -69,7 +69,7 @@ public: if (collectionName.empty()) collectionName = "fs"; collectionName += ".chunks"; - return NamespaceString(dbName, collectionName); + return NamespaceStringUtil::parseNamespaceFromRequest(dbName, collectionName); } Status checkAuthForOperation(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp index c062456cc06..d0539898b96 100644 --- a/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp @@ -100,7 +100,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; } getClusterParameterCmd; diff --git a/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp b/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp index 8a3930b9b1e..01f79021811 100644 --- a/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp @@ -82,7 +82,8 @@ public: uassert(ErrorCodes::BadValue, str::stream() << "namespace has invalid type " << typeName(first.type()), first.canonicalType() == canonicalizeBSONType(mongo::String)); - return NamespaceString(dbName.tenantId(), first.valueStringData()); + return NamespaceStringUtil::parseNamespaceFromRequest(dbName.tenantId(), + first.valueStringData()); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_getmore_cmd.h b/src/mongo/s/commands/cluster_getmore_cmd.h index f576d877d1b..6a2e181ef1a 100644 --- a/src/mongo/s/commands/cluster_getmore_cmd.h +++ b/src/mongo/s/commands/cluster_getmore_cmd.h @@ -82,7 +82,8 @@ public: private: NamespaceString ns() const override { - return NamespaceString(_cmd.getDbName(), _cmd.getCollection()); + return NamespaceStringUtil::parseNamespaceFromRequest(_cmd.getDbName(), + _cmd.getCollection()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/s/commands/cluster_list_databases_cmd.cpp b/src/mongo/s/commands/cluster_list_databases_cmd.cpp index f86faa767f6..66448312301 100644 --- a/src/mongo/s/commands/cluster_list_databases_cmd.cpp +++ b/src/mongo/s/commands/cluster_list_databases_cmd.cpp @@ -72,7 +72,7 @@ public: void doCheckAuthorization(OperationContext*) const final {} NamespaceString ns() const final { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } ListDatabasesReply typedRun(OperationContext* opCtx) final { diff --git a/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp b/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp index af6562ecc67..52ea981c079 100644 --- a/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp +++ b/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp @@ -65,7 +65,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool adminOnly() const override { diff --git a/src/mongo/s/commands/cluster_move_primary_cmd.cpp b/src/mongo/s/commands/cluster_move_primary_cmd.cpp index 661f0821698..e401f4811ea 100644 --- a/src/mongo/s/commands/cluster_move_primary_cmd.cpp +++ b/src/mongo/s/commands/cluster_move_primary_cmd.cpp @@ -88,7 +88,7 @@ public: uassert(ErrorCodes::InvalidNamespace, "'movePrimary' must be of type String", nsElt.type() == BSONType::String); - return NamespaceString(dbName.tenantId(), nsElt.str()); + return NamespaceStringUtil::parseNamespaceFromRequest(dbName.tenantId(), nsElt.str()); } virtual bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_repair_sharded_collection_chunks_history_cmd.cpp b/src/mongo/s/commands/cluster_repair_sharded_collection_chunks_history_cmd.cpp index 7cc6f88a532..5daff9c7d5c 100644 --- a/src/mongo/s/commands/cluster_repair_sharded_collection_chunks_history_cmd.cpp +++ b/src/mongo/s/commands/cluster_repair_sharded_collection_chunks_history_cmd.cpp @@ -87,7 +87,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_rwc_defaults_commands.cpp b/src/mongo/s/commands/cluster_rwc_defaults_commands.cpp index 9a342382670..180d03b0d08 100644 --- a/src/mongo/s/commands/cluster_rwc_defaults_commands.cpp +++ b/src/mongo/s/commands/cluster_rwc_defaults_commands.cpp @@ -172,7 +172,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/s/commands/cluster_shard_collection_cmd.cpp b/src/mongo/s/commands/cluster_shard_collection_cmd.cpp index 9d7b8c22353..cab047e6ade 100644 --- a/src/mongo/s/commands/cluster_shard_collection_cmd.cpp +++ b/src/mongo/s/commands/cluster_shard_collection_cmd.cpp @@ -80,7 +80,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool run(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_split_cmd.cpp b/src/mongo/s/commands/cluster_split_cmd.cpp index 0b8deb18b26..0e4d2c44ae1 100644 --- a/src/mongo/s/commands/cluster_split_cmd.cpp +++ b/src/mongo/s/commands/cluster_split_cmd.cpp @@ -123,7 +123,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool errmsgRun(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_split_vector_cmd.cpp b/src/mongo/s/commands/cluster_split_vector_cmd.cpp index 0de63a429c0..2a4ccd15cb0 100644 --- a/src/mongo/s/commands/cluster_split_vector_cmd.cpp +++ b/src/mongo/s/commands/cluster_split_vector_cmd.cpp @@ -50,7 +50,8 @@ public: } NamespaceString parseNs(const DatabaseName& dbName, const BSONObj& cmdObj) const override { - return NamespaceString(dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); + return NamespaceStringUtil::parseNamespaceFromRequest( + dbName.tenantId(), CommandHelpers::parseNsFullyQualified(cmdObj)); } bool supportsWriteConcern(const BSONObj& cmd) const override { diff --git a/src/mongo/s/commands/cluster_user_management_commands.cpp b/src/mongo/s/commands/cluster_user_management_commands.cpp index c735219739d..42512a64b3e 100644 --- a/src/mongo/s/commands/cluster_user_management_commands.cpp +++ b/src/mongo/s/commands/cluster_user_management_commands.cpp @@ -174,9 +174,10 @@ public: NamespaceString ns() const override { const auto& cmd = request(); if constexpr (hasGetCmdParamStringData<RequestT>) { - return NamespaceString(cmd.getDbName(), cmd.getCommandParameter()); + return NamespaceStringUtil::parseNamespaceFromRequest(cmd.getDbName(), + cmd.getCommandParameter()); } else { - return NamespaceString(cmd.getDbName(), ""); + return NamespaceString(cmd.getDbName()); } } }; @@ -264,7 +265,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; @@ -299,7 +300,7 @@ public: } NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(request().getDbName()); } }; diff --git a/src/mongo/s/commands/internal_transactions_test_command.h b/src/mongo/s/commands/internal_transactions_test_command.h index 45d966a1846..d8374b7aa90 100644 --- a/src/mongo/s/commands/internal_transactions_test_command.h +++ b/src/mongo/s/commands/internal_transactions_test_command.h @@ -124,7 +124,7 @@ public: }; NamespaceString ns() const override { - return NamespaceString(Base::request().getDbName(), ""); + return NamespaceString(Base::request().getDbName()); } bool supportsWriteConcern() const override { diff --git a/src/mongo/s/commands/sharding_expressions.cpp b/src/mongo/s/commands/sharding_expressions.cpp index a4525e64656..e20683d251e 100644 --- a/src/mongo/s/commands/sharding_expressions.cpp +++ b/src/mongo/s/commands/sharding_expressions.cpp @@ -372,7 +372,8 @@ Value ExpressionInternalOwningShard::evaluate(const Document& root, Variables* v } // Retrieve the values from the incoming document. - NamespaceString ns(getExpressionContext()->ns.tenantId(), input["ns"_sd].getStringData()); + NamespaceString ns(NamespaceStringUtil::parseNamespaceFromDoc( + getExpressionContext()->ns.tenantId(), input["ns"_sd].getStringData())); const auto shardVersionObj = input["shardVersion"_sd].getDocument().toBson(); const auto shardVersion = ShardVersion::parse(BSON("" << shardVersionObj).firstElement()); const auto shardKeyVal = input["shardKeyVal"_sd].getDocument().toBson(); diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index faa516ca359..20899afae5c 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -778,7 +778,8 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, : Status(ErrorCodes::Unauthorized, "User not authorized to access cursor"); }; - NamespaceString nss(cmd.getDbName(), cmd.getCollection()); + NamespaceString nss( + NamespaceStringUtil::parseNamespaceFromRequest(cmd.getDbName(), cmd.getCollection())); int64_t cursorId = cmd.getCommandParameter(); auto pinnedCursor = cursorManager->checkOutCursor(cursorId, opCtx, authChecker); diff --git a/src/mongo/shell/bench.cpp b/src/mongo/shell/bench.cpp index 7e4ee3ae10d..b71e82a5a50 100644 --- a/src/mongo/shell/bench.cpp +++ b/src/mongo/shell/bench.cpp @@ -1049,8 +1049,8 @@ void BenchRunOp::executeOnce(DBClientBase* conn, case OpType::FINDONE: { BSONObj fixedQuery = fixQuery(this->query, *state->bsonTemplateEvaluator); BSONObj result; - auto findCommand = - std::make_unique<FindCommandRequest>(NamespaceString(this->tenantId, this->ns)); + auto findCommand = std::make_unique<FindCommandRequest>( + NamespaceString::createNamespaceString_forTest(this->tenantId, this->ns)); findCommand->setFilter(fixedQuery); findCommand->setProjection(this->projection); findCommand->setLimit(1LL); @@ -1137,8 +1137,8 @@ void BenchRunOp::executeOnce(DBClientBase* conn, uassert( 28824, "cannot use 'options' in combination with read commands", !this->options); - auto findCommand = - std::make_unique<FindCommandRequest>(NamespaceString(this->tenantId, this->ns)); + auto findCommand = std::make_unique<FindCommandRequest>( + NamespaceString::createNamespaceString_forTest(this->tenantId, this->ns)); findCommand->setFilter(fixedQuery); findCommand->setProjection(this->projection); if (this->skip) { @@ -1337,14 +1337,16 @@ void BenchRunOp::executeOnce(DBClientBase* conn, 22801, 5, "Result from benchRun thread [safe remove]", "result"_attr = result); } break; case OpType::CREATEINDEX: - conn->createIndex(NamespaceString(this->tenantId, this->ns), - this->key, - boost::none /* writeConcernObj */); + conn->createIndex( + NamespaceString::createNamespaceString_forTest(this->tenantId, this->ns), + this->key, + boost::none /* writeConcernObj */); break; case OpType::DROPINDEX: - conn->dropIndex(NamespaceString(this->tenantId, this->ns), - this->key, - boost::none /* writeConcernObj */); + conn->dropIndex( + NamespaceString::createNamespaceString_forTest(this->tenantId, this->ns), + this->key, + boost::none /* writeConcernObj */); break; case OpType::LET: { BSONObjBuilder templateBuilder; diff --git a/src/mongo/util/namespace_string_util.cpp b/src/mongo/util/namespace_string_util.cpp index 26322d4af70..5084a0c2ee4 100644 --- a/src/mongo/util/namespace_string_util.cpp +++ b/src/mongo/util/namespace_string_util.cpp @@ -92,4 +92,68 @@ NamespaceString NamespaceStringUtil::deserialize(boost::optional<TenantId> tenan return nss; } +NamespaceString NamespaceStringUtil::parseNamespaceFromRequest( + const boost::optional<TenantId>& tenantId, StringData ns) { + return deserialize(tenantId, ns); +} + +NamespaceString NamespaceStringUtil::parseNamespaceFromRequest( + const boost::optional<TenantId>& tenantId, StringData db, StringData coll) { + if (coll.empty()) + return deserialize(tenantId, db); + + uassert(ErrorCodes::InvalidNamespace, + "Collection names cannot start with '.': " + coll, + coll[0] != '.'); + + return deserialize(tenantId, str::stream() << db << "." << coll); +} + +NamespaceString NamespaceStringUtil::parseNamespaceFromRequest(const DatabaseName& dbName, + StringData coll) { + if (coll.empty()) { + return NamespaceString(dbName); + } + + uassert(ErrorCodes::InvalidNamespace, + "Collection names cannot start with '.': " + coll, + coll[0] != '.'); + + return deserialize(dbName.tenantId(), str::stream() << dbName.db() << "." << coll); +} + +NamespaceString NamespaceStringUtil::parseNamespaceFromDoc( + const boost::optional<TenantId>& tenantId, StringData ns) { + return deserialize(tenantId, ns); +} + +NamespaceString NamespaceStringUtil::parseNamespaceFromDoc( + const boost::optional<TenantId>& tenantId, StringData db, StringData coll) { + if (coll.empty()) + return deserialize(tenantId, db); + + uassert(ErrorCodes::InvalidNamespace, + "Collection names cannot start with '.': " + coll, + coll[0] != '.'); + + return deserialize(tenantId, str::stream() << db << "." << coll); +} + +NamespaceString NamespaceStringUtil::parseNamespaceFromDoc(const DatabaseName& dbName, + StringData coll) { + if (coll.empty()) + return NamespaceString(dbName); + + uassert(ErrorCodes::InvalidNamespace, + "Collection names cannot start with '.': " + coll, + coll[0] != '.'); + + return deserialize(dbName.tenantId(), str::stream() << dbName.db() << "." << coll); +} + +NamespaceString NamespaceStringUtil::parseNamespaceFromResponse(const DatabaseName& dbName, + StringData coll) { + return parseNamespaceFromDoc(dbName, coll); +} + } // namespace mongo diff --git a/src/mongo/util/namespace_string_util.h b/src/mongo/util/namespace_string_util.h index 23aebf90362..20e69c3fe17 100644 --- a/src/mongo/util/namespace_string_util.h +++ b/src/mongo/util/namespace_string_util.h @@ -77,6 +77,26 @@ public: boost::optional<TenantId> tenantId, StringData ns, const SerializationContext& context = SerializationContext()); + + static NamespaceString parseNamespaceFromRequest(const boost::optional<TenantId>& tenantId, + StringData ns); + + static NamespaceString parseNamespaceFromRequest(const boost::optional<TenantId>& tenantId, + StringData db, + StringData coll); + + static NamespaceString parseNamespaceFromRequest(const DatabaseName& dbName, StringData coll); + + static NamespaceString parseNamespaceFromDoc(const boost::optional<TenantId>& tenantId, + StringData ns); + + static NamespaceString parseNamespaceFromDoc(const boost::optional<TenantId>& tenantId, + StringData db, + StringData coll); + + static NamespaceString parseNamespaceFromDoc(const DatabaseName& dbName, StringData coll); + + static NamespaceString parseNamespaceFromResponse(const DatabaseName& dbName, StringData coll); }; } // namespace mongo |