diff options
author | Arun Banala <arun.banala@mongodb.com> | 2021-09-20 17:03:29 +0100 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-09-30 17:15:26 +0000 |
commit | 5e0dffb6d2723470e1f1bd93de6565c7a4e0353a (patch) | |
tree | 3ee6ca0e236a67c1a8a687774b0c53dda9a268b2 /src/mongo/db | |
parent | 9f8e95a95b592c3686dcb1aa82ebcd9b7515974b (diff) | |
download | mongo-5e0dffb6d2723470e1f1bd93de6565c7a4e0353a.tar.gz |
SERVER-60144 Handle stale routing info on mongos for sharded time-series collections
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/catalog/coll_mod.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/coll_mod.idl | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/create_indexes.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/commands/dbcommands.cpp | 13 | ||||
-rw-r--r-- | src/mongo/db/commands/drop_indexes.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/commands/list_indexes.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/create_indexes.idl | 6 | ||||
-rw-r--r-- | src/mongo/db/drop_indexes.idl | 6 | ||||
-rw-r--r-- | src/mongo/db/list_indexes.idl | 6 | ||||
-rw-r--r-- | src/mongo/db/s/create_collection_coordinator.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 13 | ||||
-rw-r--r-- | src/mongo/db/timeseries/catalog_helper.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/timeseries/catalog_helper.h | 3 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_commands_conversion_helper.h | 3 |
16 files changed, 97 insertions, 21 deletions
diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index a683d603d7c..a052e22d81f 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -491,8 +491,15 @@ Status _collModInternal(OperationContext* opCtx, .throwIfReshardingInProgress(nss); } + // If db/collection/view does not exist, short circuit and return. if (!db || (!coll && !view)) { + if (nss.isTimeseriesBucketsCollection()) { + // If a sharded time-series collection is dropped, it's possible that a stale mongos + // sends the request on the buckets namespace instead of the view namespace. Ensure that + // the shardVersion is upto date before throwing an error. + CollectionShardingState::get(opCtx, nss)->checkShardVersionOrThrow(opCtx); + } return Status(ErrorCodes::NamespaceNotFound, "ns does not exist"); } diff --git a/src/mongo/db/coll_mod.idl b/src/mongo/db/coll_mod.idl index 0a71b5522d1..e1f193294d3 100644 --- a/src/mongo/db/coll_mod.idl +++ b/src/mongo/db/coll_mod.idl @@ -150,4 +150,10 @@ commands: description: "Adjusts parameters for timeseries collections" optional: true type: CollModTimeseries + isTimeseriesNamespace: + description: "This flag is set to true when the command was originally sent to + mongos on the time-series view, but got rewritten to target + time-series buckets namespace before being sent to shards." + optional: true + type: bool reply_type: CollModReply diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 00a74a47efb..50addeb0673 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -652,7 +652,10 @@ public: // If the request namespace refers to a time-series collection, transforms the user // time-series index request to one on the underlying bucket. boost::optional<CreateIndexesCommand> timeseriesCmdOwnership; - if (auto options = timeseries::getTimeseriesOptions(opCtx, origCmd.getNamespace())) { + auto isCommandOnTimeseriesBucketNamespace = + origCmd.getIsTimeseriesNamespace() && *origCmd.getIsTimeseriesNamespace(); + if (auto options = timeseries::getTimeseriesOptions( + opCtx, origCmd.getNamespace(), !isCommandOnTimeseriesBucketNamespace)) { timeseriesCmdOwnership = timeseries::makeTimeseriesCreateIndexesCommand(opCtx, origCmd, *options); cmd = ×eriesCmdOwnership.get(); diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index fbf3dbaad96..bb14f4e07c2 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -121,7 +121,10 @@ std::unique_ptr<CollMod> makeTimeseriesBucketsCollModCommand(OperationContext* o const CollMod& origCmd) { const auto& origNs = origCmd.getNamespace(); - auto timeseriesOptions = timeseries::getTimeseriesOptions(opCtx, origNs); + auto isCommandOnTimeseriesBucketNamespace = + origCmd.getIsTimeseriesNamespace() && *origCmd.getIsTimeseriesNamespace(); + auto timeseriesOptions = + timeseries::getTimeseriesOptions(opCtx, origNs, !isCommandOnTimeseriesBucketNamespace); // Return early with null if we are not working with a time-series collection. if (!timeseriesOptions) { @@ -141,7 +144,8 @@ std::unique_ptr<CollMod> makeTimeseriesBucketsCollModCommand(OperationContext* o index->setKeyPattern(std::move(bucketsIndexSpecWithStatus.getValue())); } - auto ns = origNs.makeTimeseriesBucketsNamespace(); + auto ns = + isCommandOnTimeseriesBucketNamespace ? origNs : origNs.makeTimeseriesBucketsNamespace(); auto cmd = std::make_unique<CollMod>(ns); cmd->setIndex(index); cmd->setValidator(origCmd.getValidator()); @@ -166,7 +170,10 @@ std::unique_ptr<CollMod> makeTimeseriesViewCollModCommand(OperationContext* opCt const CollMod& origCmd) { const auto& ns = origCmd.getNamespace(); - auto timeseriesOptions = timeseries::getTimeseriesOptions(opCtx, ns); + auto isCommandOnTimeseriesBucketNamespace = + origCmd.getIsTimeseriesNamespace() && *origCmd.getIsTimeseriesNamespace(); + auto timeseriesOptions = + timeseries::getTimeseriesOptions(opCtx, ns, !isCommandOnTimeseriesBucketNamespace); // Return early with null if we are not working with a time-series collection. if (!timeseriesOptions) { diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index e06cdaec2f4..ce3bbfbb0fa 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -96,7 +96,10 @@ public: Reply typedRun(OperationContext* opCtx) final { // If the request namespace refers to a time-series collection, transform the user // time-series index request to one on the underlying bucket. - if (auto options = timeseries::getTimeseriesOptions(opCtx, request().getNamespace())) { + auto isCommandOnTimeseriesBucketNamespace = + request().getIsTimeseriesNamespace() && *request().getIsTimeseriesNamespace(); + if (auto options = timeseries::getTimeseriesOptions( + opCtx, request().getNamespace(), !isCommandOnTimeseriesBucketNamespace)) { auto timeseriesCmd = timeseries::makeTimeseriesDropIndexesCommand(opCtx, request(), *options); return dropIndexes(opCtx, timeseriesCmd.getNamespace(), timeseriesCmd.getIndex()); diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index 54725eb7fb5..c9a42882944 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -74,8 +74,13 @@ IndexSpecsWithNamespaceString getIndexSpecsWithNamespaceString(OperationContext* // Since time-series collections don't have UUIDs, we skip the time-series lookup // if the target collection is specified as a UUID. if (const auto& origNss = origNssOrUUID.nss()) { - if (auto timeseriesOptions = timeseries::getTimeseriesOptions(opCtx, *origNss)) { - auto bucketsNss = origNss->makeTimeseriesBucketsNamespace(); + auto isCommandOnTimeseriesBucketNamespace = + cmd.getIsTimeseriesNamespace() && *cmd.getIsTimeseriesNamespace(); + if (auto timeseriesOptions = timeseries::getTimeseriesOptions( + opCtx, *origNss, !isCommandOnTimeseriesBucketNamespace)) { + auto bucketsNss = isCommandOnTimeseriesBucketNamespace + ? *origNss + : origNss->makeTimeseriesBucketsNamespace(); AutoGetCollectionForReadCommandMaybeLockFree autoColl(opCtx, bucketsNss); const CollectionPtr& coll = autoColl.getCollection(); diff --git a/src/mongo/db/commands/write_commands.cpp b/src/mongo/db/commands/write_commands.cpp index 64c8b9d3f7b..d794025b2c0 100644 --- a/src/mongo/db/commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands.cpp @@ -121,6 +121,9 @@ bool isTimeseries(OperationContext* opCtx, const Request& request) { "system.buckets namespace", !request.getIsTimeseriesNamespace() || request.getNamespace().isTimeseriesBucketsCollection()); + const auto bucketNss = request.getIsTimeseriesNamespace() + ? request.getNamespace() + : request.getNamespace().makeTimeseriesBucketsNamespace(); // If the buckets collection exists now, the time-series insert path will check for the // existence of the buckets collection later on with a lock. @@ -128,11 +131,9 @@ bool isTimeseries(OperationContext* opCtx, const Request& request) { // collection does not yet exist, this check may return false unnecessarily. As a result, an // insert attempt into the time-series namespace will either succeed or fail, depending on who // wins the race. - return request.getIsTimeseriesNamespace() || - CollectionCatalog::get(opCtx) - ->lookupCollectionByNamespaceForRead( - opCtx, request.getNamespace().makeTimeseriesBucketsNamespace()) - .get(); + return CollectionCatalog::get(opCtx) + ->lookupCollectionByNamespaceForRead(opCtx, bucketNss) + .get(); } NamespaceString makeTimeseriesBucketsNamespace(const NamespaceString& nss) { diff --git a/src/mongo/db/create_indexes.idl b/src/mongo/db/create_indexes.idl index 12f629ed7e2..e7b60e73790 100644 --- a/src/mongo/db/create_indexes.idl +++ b/src/mongo/db/create_indexes.idl @@ -183,3 +183,9 @@ commands: description: 'Commit Quorum options' type: CommitQuorum optional: true + isTimeseriesNamespace: + description: "This flag is set to true when the command was originally sent to + mongos on the time-series view, but got rewritten to target + time-series buckets namespace before being sent to shards." + type: bool + optional: true diff --git a/src/mongo/db/drop_indexes.idl b/src/mongo/db/drop_indexes.idl index 76d17a53e9e..cb4ea9eddb2 100644 --- a/src/mongo/db/drop_indexes.idl +++ b/src/mongo/db/drop_indexes.idl @@ -71,4 +71,10 @@ commands: - string - array<string> - object + isTimeseriesNamespace: + description: "This flag is set to true when the command was originally sent to + mongos on the time-series view, but got rewritten to target + time-series buckets namespace before being sent to shards." + type: bool + optional: true reply_type: DropIndexesReply diff --git a/src/mongo/db/list_indexes.idl b/src/mongo/db/list_indexes.idl index 48900398be6..d4f2caf9d96 100644 --- a/src/mongo/db/list_indexes.idl +++ b/src/mongo/db/list_indexes.idl @@ -179,4 +179,10 @@ commands: type: safeBool optional: true unstable: true + isTimeseriesNamespace: + description: "This flag is set to true when the command was originally sent to + mongos on the time-series view, but got rewritten to target + time-series buckets namespace before being sent to shards." + type: bool + optional: true reply_type: ListIndexesReply diff --git a/src/mongo/db/s/create_collection_coordinator.cpp b/src/mongo/db/s/create_collection_coordinator.cpp index 2b40e7df204..9cc00c593f2 100644 --- a/src/mongo/db/s/create_collection_coordinator.cpp +++ b/src/mongo/db/s/create_collection_coordinator.cpp @@ -623,7 +623,7 @@ void CreateCollectionCoordinator::_checkCommandArguments(OperationContext* opCtx str::stream() << "can't shard time-series collection " << nss(), feature_flags::gFeatureFlagShardedTimeSeries.isEnabled( serverGlobalParams.featureCompatibility) || - !timeseries::getTimeseriesOptions(opCtx, nss().getTimeseriesViewNamespace())); + !timeseries::getTimeseriesOptions(opCtx, nss(), false)); } // Ensure the namespace is valid. diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index b0b2a905864..df094434a39 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -1506,7 +1506,18 @@ void ExecCommandDatabase::_initiateCommand() { if (!opCtx->getClient()->isInDirectClient() && readConcernArgs.getLevel() != repl::ReadConcernLevel::kAvailableReadConcern && (iAmPrimary || (readConcernArgs.hasLevel() || readConcernArgs.getArgsAfterClusterTime()))) { - oss.initializeClientRoutingVersionsFromCommand(_invocation->ns(), request.body); + // If a timeseries collection is sharded, only the buckets collection would be sharded. We + // expect all versioned commands to be sent over 'system.buckets' namespace. But it is + // possible that a stale mongos may send the request over a view namespace. In this case, we + // initialize the 'OperationShardingState' with buckets namespace. + auto bucketNss = _invocation->ns().makeTimeseriesBucketsNamespace(); + auto namespaceForSharding = CollectionCatalog::get(opCtx) + ->lookupCollectionByNamespaceForRead(opCtx, bucketNss) + .get() + ? bucketNss + : _invocation->ns(); + + oss.initializeClientRoutingVersionsFromCommand(namespaceForSharding, request.body); auto const shardingState = ShardingState::get(opCtx); if (OperationShardingState::isOperationVersioned(opCtx) || oss.hasDbVersion()) { diff --git a/src/mongo/db/timeseries/catalog_helper.cpp b/src/mongo/db/timeseries/catalog_helper.cpp index 5ac55527f1a..4b577d55d30 100644 --- a/src/mongo/db/timeseries/catalog_helper.cpp +++ b/src/mongo/db/timeseries/catalog_helper.cpp @@ -38,8 +38,9 @@ namespace mongo { namespace timeseries { boost::optional<TimeseriesOptions> getTimeseriesOptions(OperationContext* opCtx, - const NamespaceString& nss) { - auto bucketsNs = nss.makeTimeseriesBucketsNamespace(); + const NamespaceString& nss, + bool convertToBucketsNamespace) { + auto bucketsNs = convertToBucketsNamespace ? nss.makeTimeseriesBucketsNamespace() : nss; auto bucketsColl = CollectionCatalog::get(opCtx)->lookupCollectionByNamespaceForRead(opCtx, bucketsNs); if (!bucketsColl) { diff --git a/src/mongo/db/timeseries/catalog_helper.h b/src/mongo/db/timeseries/catalog_helper.h index 969410d1c45..14cc681b4c3 100644 --- a/src/mongo/db/timeseries/catalog_helper.h +++ b/src/mongo/db/timeseries/catalog_helper.h @@ -46,7 +46,8 @@ namespace timeseries { * collection. Otherwise returns boost::none. */ boost::optional<TimeseriesOptions> getTimeseriesOptions(OperationContext* opCtx, - const NamespaceString& nss); + const NamespaceString& nss, + bool convertToBucketsNamespace); } // namespace timeseries } // namespace mongo diff --git a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp index 233add4ada4..79d8483ab6f 100644 --- a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp +++ b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.cpp @@ -41,9 +41,17 @@ namespace mongo::timeseries { +namespace { +NamespaceString makeTimeseriesBucketsNamespace(const NamespaceString& nss) { + return nss.isTimeseriesBucketsCollection() ? nss : nss.makeTimeseriesBucketsNamespace(); +} +} // namespace + + BSONObj makeTimeseriesCommand(const BSONObj& origCmd, const NamespaceString& ns, - const StringData nsFieldName) { + const StringData nsFieldName, + boost::optional<StringData> appendTimeSeriesFlag) { // Translate time-series collection view namespace to bucket namespace. const auto bucketNs = ns.makeTimeseriesBucketsNamespace(); BSONObjBuilder builder; @@ -54,6 +62,10 @@ BSONObj makeTimeseriesCommand(const BSONObj& origCmd, builder.append(entry); } } + + if (appendTimeSeriesFlag) { + builder.append(*appendTimeSeriesFlag, true); + } return builder.obj(); } @@ -137,7 +149,7 @@ CreateIndexesCommand makeTimeseriesCreateIndexesCommand(OperationContext* opCtx, indexes.push_back(builder.obj()); } - auto ns = origNs.makeTimeseriesBucketsNamespace(); + auto ns = makeTimeseriesBucketsNamespace(origNs); auto cmd = CreateIndexesCommand(ns, std::move(indexes)); cmd.setV(origCmd.getV()); cmd.setIgnoreUnknownIndexOptions(origCmd.getIgnoreUnknownIndexOptions()); @@ -150,7 +162,7 @@ DropIndexes makeTimeseriesDropIndexesCommand(OperationContext* opCtx, const DropIndexes& origCmd, const TimeseriesOptions& options) { const auto& origNs = origCmd.getNamespace(); - auto ns = origNs.makeTimeseriesBucketsNamespace(); + auto ns = makeTimeseriesBucketsNamespace(origNs); const auto& origIndex = origCmd.getIndex(); if (auto keyPtr = stdx::get_if<BSONObj>(&origIndex)) { diff --git a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.h b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.h index eef1de61621..d2641a17d65 100644 --- a/src/mongo/db/timeseries/timeseries_commands_conversion_helper.h +++ b/src/mongo/db/timeseries/timeseries_commands_conversion_helper.h @@ -43,7 +43,8 @@ namespace mongo::timeseries { */ BSONObj makeTimeseriesCommand(const BSONObj& origCmd, const NamespaceString& ns, - StringData nsFieldName); + StringData nsFieldName, + boost::optional<StringData> appendTimeSeriesFlag); /* * Returns a CreateIndexesCommand for creating indexes on the bucket collection. |