diff options
author | A. Jesse Jiryu Davis <jesse@mongodb.com> | 2021-03-08 08:16:10 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-03-08 15:09:15 +0000 |
commit | f842de553e3c71a410e5f49fdaec3eaaaebb04a9 (patch) | |
tree | b00bae9a367a00fbfc82968ee2583e3838d62ce9 /src | |
parent | 164f7ba0dee2a6d21107adb4f7af3bfb64d43177 (diff) | |
download | mongo-f842de553e3c71a410e5f49fdaec3eaaaebb04a9.tar.gz |
SERVER-53149 Finish converting getMore to IDL, try 2
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/api_parameters.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/api_parameters.h | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/getmore_cmd.cpp | 125 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_command.idl | 1 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_request.cpp | 68 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_request.h | 6 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_request_test.cpp | 176 | ||||
-rw-r--r-- | src/mongo/s/commands/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_getmore_cmd.cpp | 29 | ||||
-rw-r--r-- | src/mongo/s/commands/strategy.cpp | 13 | ||||
-rw-r--r-- | src/mongo/s/query/async_results_merger_test.cpp | 15 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 58 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.h | 6 |
14 files changed, 180 insertions, 334 deletions
diff --git a/src/mongo/db/api_parameters.cpp b/src/mongo/db/api_parameters.cpp index 51e424637db..fbe130ee4de 100644 --- a/src/mongo/db/api_parameters.cpp +++ b/src/mongo/db/api_parameters.cpp @@ -64,6 +64,17 @@ APIParameters APIParameters::fromBSON(const BSONObj& cmdObj) { APIParametersFromClient::parse("APIParametersFromClient"_sd, cmdObj)); } +void APIParameters::uassertNoApiParameters(const BSONObj& bsonObject) { + for (const auto& fieldName : + std::vector<StringData>{APIParametersFromClient::kApiVersionFieldName, + APIParametersFromClient::kApiStrictFieldName, + APIParametersFromClient::kApiDeprecationErrorsFieldName}) { + uassert(4937600, + str::stream() << "Cannot pass in API parameter field " << fieldName, + !bsonObject.hasField(fieldName)); + } +} + void APIParameters::appendInfo(BSONObjBuilder* builder) const { if (_apiVersion) { builder->append(kAPIVersionFieldName, *_apiVersion); diff --git a/src/mongo/db/api_parameters.h b/src/mongo/db/api_parameters.h index 34c129bca15..809cb49a902 100644 --- a/src/mongo/db/api_parameters.h +++ b/src/mongo/db/api_parameters.h @@ -48,6 +48,10 @@ public: static const OperationContext::Decoration<APIParameters> get; static APIParameters fromClient(const APIParametersFromClient& apiParamsFromClient); static APIParameters fromBSON(const BSONObj& cmdObj); + /* + * Throw if bsonObject includes any API parameters. + */ + static void uassertNoApiParameters(const BSONObj& bsonObject); // For use with unordered_map. struct Hash { diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index 53dbaa6d788..1e9cabe5e18 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -333,6 +333,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/api_parameters', '$BUILD_DIR/mongo/db/catalog/catalog_helpers', '$BUILD_DIR/mongo/db/catalog/collection_catalog_helper', '$BUILD_DIR/mongo/db/catalog/collection_query_info', diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index 50242d38565..fd8ad91c234 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -34,6 +34,7 @@ #include <memory> #include <string> +#include "mongo/db/api_parameters.h" #include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" @@ -48,7 +49,7 @@ #include "mongo/db/query/cursor_response.h" #include "mongo/db/query/find.h" #include "mongo/db/query/find_common.h" -#include "mongo/db/query/getmore_request.h" +#include "mongo/db/query/getmore_command_gen.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/query/plan_summary_stats.h" #include "mongo/db/read_concern.h" @@ -88,21 +89,21 @@ static const ReadConcernSupportResult kSupportsReadConcernResult{ * Validates that the lsid of 'opCtx' matches that of 'cursor'. This must be called after * authenticating, so that it is safe to report the lsid of 'cursor'. */ -void validateLSID(OperationContext* opCtx, const GetMoreRequest& request, ClientCursor* cursor) { +void validateLSID(OperationContext* opCtx, int64_t cursorId, ClientCursor* cursor) { uassert(50736, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was not created in a session, in session " << *opCtx->getLogicalSessionId(), !opCtx->getLogicalSessionId() || cursor->getSessionId()); uassert(50737, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in session " << *cursor->getSessionId() << ", without an lsid", opCtx->getLogicalSessionId() || !cursor->getSessionId()); uassert(50738, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in session " << *cursor->getSessionId() << ", in session " << *opCtx->getLogicalSessionId(), !opCtx->getLogicalSessionId() || !cursor->getSessionId() || @@ -113,23 +114,21 @@ void validateLSID(OperationContext* opCtx, const GetMoreRequest& request, Client * Validates that the txnNumber of 'opCtx' matches that of 'cursor'. This must be called after * authenticating, so that it is safe to report the txnNumber of 'cursor'. */ -void validateTxnNumber(OperationContext* opCtx, - const GetMoreRequest& request, - ClientCursor* cursor) { +void validateTxnNumber(OperationContext* opCtx, int64_t cursorId, ClientCursor* cursor) { uassert(50739, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was not created in a transaction, in transaction " << *opCtx->getTxnNumber(), !opCtx->getTxnNumber() || cursor->getTxnNumber()); uassert(50740, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in transaction " << *cursor->getTxnNumber() << ", without a txnNumber", opCtx->getTxnNumber() || !cursor->getTxnNumber()); uassert(50741, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in transaction " << *cursor->getTxnNumber() << ", in transaction " << *opCtx->getTxnNumber(), !opCtx->getTxnNumber() || !cursor->getTxnNumber() || @@ -192,7 +191,7 @@ void applyCursorReadConcern(OperationContext* opCtx, repl::ReadConcernArgs rcArg */ void setUpOperationDeadline(OperationContext* opCtx, const ClientCursor& cursor, - const GetMoreRequest& request, + const GetMoreCommand& cmd, bool disableAwaitDataFailpointActive) { // We assume that cursors created through a DBDirectClient are always used from their @@ -205,7 +204,7 @@ void setUpOperationDeadline(OperationContext* opCtx, if (cursor.isAwaitData() && !disableAwaitDataFailpointActive) { awaitDataState(opCtx).waitForInsertsDeadline = opCtx->getServiceContext()->getPreciseClockSource()->now() + - request.awaitDataTimeout.value_or(Seconds{1}); + Milliseconds{cmd.getMaxTimeMS().value_or(1000)}; } else if (cursor.getLeftoverMaxTimeMicros() < Microseconds::max()) { opCtx->setDeadlineAfterNowBy(cursor.getLeftoverMaxTimeMicros(), ErrorCodes::MaxTimeMSExpired); @@ -218,12 +217,12 @@ void setUpOperationDeadline(OperationContext* opCtx, */ void setUpOperationContextStateForGetMore(OperationContext* opCtx, const ClientCursor& cursor, - const GetMoreRequest& request, + const GetMoreCommand& cmd, bool disableAwaitDataFailpointActive) { applyCursorReadConcern(opCtx, cursor.getReadConcernArgs()); opCtx->setWriteConcern(cursor.getWriteConcernOptions()); APIParameters::get(opCtx) = cursor.getAPIParameters(); - setUpOperationDeadline(opCtx, cursor, request, disableAwaitDataFailpointActive); + setUpOperationDeadline(opCtx, cursor, cmd, disableAwaitDataFailpointActive); // If the originating command had a 'comment' field, we extract it and set it on opCtx. Note // that if the 'getMore' command itself has a 'comment' field, we give precedence to it. @@ -258,9 +257,14 @@ public: class Invocation final : public CommandInvocation { public: Invocation(Command* cmd, const OpMsgRequest& request) - : CommandInvocation(cmd), - _request(uassertStatusOK( - GetMoreRequest::parseFromBSON(request.getDatabase().toString(), request.body))) {} + : CommandInvocation(cmd), _cmd(GetMoreCommand::parse({"getMore"}, request.body)) { + NamespaceString nss(_cmd.getDbName(), _cmd.getCollection()); + uassert(ErrorCodes::InvalidNamespace, + str::stream() << "Invalid namespace for getMore: " << nss.ns(), + nss.isValid()); + + APIParameters::uassertNoApiParameters(request.body); + } private: bool supportsWriteConcern() const override { @@ -280,14 +284,14 @@ public: } NamespaceString ns() const override { - return _request.nss; + return NamespaceString(_cmd.getDbName(), _cmd.getCollection()); } void doCheckAuthorization(OperationContext* opCtx) const override { uassertStatusOK(auth::checkAuthForGetMore(AuthorizationSession::get(opCtx->getClient()), - _request.nss, - _request.cursorid, - _request.term.is_initialized())); + ns(), + _cmd.getCommandParameter(), + _cmd.getTerm().is_initialized())); } /** @@ -302,7 +306,7 @@ public: */ bool generateBatch(OperationContext* opCtx, ClientCursor* cursor, - const GetMoreRequest& request, + const GetMoreCommand& cmd, const bool isTailable, CursorResponseBuilder* nextBatch, std::uint64_t* numResults, @@ -315,7 +319,7 @@ public: BSONObj obj; PlanExecutor::ExecState state; try { - while (!FindCommon::enoughForGetMore(request.batchSize.value_or(0), *numResults) && + while (!FindCommon::enoughForGetMore(cmd.getBatchSize().value_or(0), *numResults) && PlanExecutor::ADVANCED == (state = exec->getNext(&obj, nullptr))) { // If adding this object will cause us to exceed the message size limit, then we // stash it for later. @@ -348,7 +352,7 @@ public: "getMore command executor error", "error"_attr = exception.toStatus(), "stats"_attr = redact(stats), - "cmd"_attr = request.toBSON()); + "cmd"_attr = cmd.toBSON({})); exception.addContext("Executor error during getMore"); throw; @@ -390,16 +394,18 @@ public: // the stats twice. boost::optional<AutoGetCollectionForReadMaybeLockFree> readLock; boost::optional<AutoStatsTracker> statsTracker; + NamespaceString nss(_cmd.getDbName(), _cmd.getCollection()); + int64_t cursorId = _cmd.getCommandParameter(); if (cursorPin->getExecutor()->lockPolicy() == PlanExecutor::LockPolicy::kLocksInternally) { - if (!_request.nss.isCollectionlessCursorNamespace()) { + if (!nss.isCollectionlessCursorNamespace()) { statsTracker.emplace( opCtx, - _request.nss, + nss, Top::LockType::NotLocked, AutoStatsTracker::LogMode::kUpdateTopAndCurOp, - CollectionCatalog::get(opCtx)->getDatabaseProfileLevel(_request.nss.db())); + CollectionCatalog::get(opCtx)->getDatabaseProfileLevel(nss.db())); } } else { invariant(cursorPin->getExecutor()->lockPolicy() == @@ -426,14 +432,14 @@ public: statsTracker.emplace( opCtx, - _request.nss, + nss, Top::LockType::ReadLocked, AutoStatsTracker::LogMode::kUpdateTopAndCurOp, - CollectionCatalog::get(opCtx)->getDatabaseProfileLevel(_request.nss.db())); + CollectionCatalog::get(opCtx)->getDatabaseProfileLevel(nss.db())); // Check whether we are allowed to read from this node after acquiring our locks. uassertStatusOK(repl::ReplicationCoordinator::get(opCtx)->checkCanServeReadsFor( - opCtx, _request.nss, true)); + opCtx, nss, true)); } // A user can only call getMore on their own cursor. If there were multiple users @@ -442,7 +448,7 @@ public: auto authzSession = AuthorizationSession::get(opCtx->getClient()); if (!authzSession->isCoauthorizedWith(cursorPin->getAuthenticatedUsers())) { uasserted(ErrorCodes::Unauthorized, - str::stream() << "cursor id " << _request.cursorid + str::stream() << "cursor id " << cursorId << " was not created by the authenticated user"); } @@ -450,23 +456,23 @@ public: if (!authzSession->isAuthorizedForPrivileges(cursorPin->getOriginatingPrivileges())) { uasserted(ErrorCodes::Unauthorized, str::stream() - << "not authorized for getMore with cursor id " << _request.cursorid); + << "not authorized for getMore with cursor id " << cursorId); } - if (_request.nss != cursorPin->nss()) { + if (nss != cursorPin->nss()) { uasserted(ErrorCodes::Unauthorized, - str::stream() << "Requested getMore on namespace '" << _request.nss.ns() + str::stream() << "Requested getMore on namespace '" << nss.ns() << "', but cursor belongs to a different namespace " << cursorPin->nss().ns()); } // Ensure the lsid and txnNumber of the getMore match that of the originating command. - validateLSID(opCtx, _request, cursorPin.getCursor()); - validateTxnNumber(opCtx, _request, cursorPin.getCursor()); + validateLSID(opCtx, cursorId, cursorPin.getCursor()); + validateTxnNumber(opCtx, cursorId, cursorPin.getCursor()); - if (_request.nss.isOplog() && MONGO_unlikely(rsStopGetMoreCmd.shouldFail())) { + if (nss.isOplog() && MONGO_unlikely(rsStopGetMoreCmd.shouldFail())) { uasserted(ErrorCodes::CommandFailed, - str::stream() << "getMore on " << _request.nss.ns() + str::stream() << "getMore on " << nss.ns() << " rejected due to active fail point rsStopGetMoreCmd"); } @@ -475,7 +481,7 @@ public: invariant(cursorPin->isTailable()); } - if (_request.awaitDataTimeout && !cursorPin->isAwaitData()) { + if (_cmd.getMaxTimeMS() && !cursorPin->isAwaitData()) { uasserted(ErrorCodes::BadValue, "cannot set maxTimeMS on getMore command for a non-awaitData cursor"); } @@ -488,7 +494,7 @@ public: // repeatedly release and re-acquire the collection readLock at regular intervals until // the failpoint is released. This is done in order to avoid deadlocks caused by the // pinned-cursor failpoints in this file (see SERVER-21997). - std::function<void()> dropAndReacquireReadLockIfLocked = [&readLock, opCtx, this]() { + std::function<void()> dropAndReacquireReadLockIfLocked = [&readLock, opCtx, nss]() { if (!readLock) { // This function is a no-op if 'readLock' is not held in the first place. return; @@ -497,7 +503,7 @@ public: // Make sure an interrupted operation does not prevent us from reacquiring the lock. UninterruptibleLockGuard noInterrupt(opCtx->lockState()); readLock.reset(); - readLock.emplace(opCtx, _request.nss); + readLock.emplace(opCtx, nss); }; if (MONGO_unlikely(waitAfterPinningCursorBeforeGetMoreBatch.shouldFail())) { CurOpFailpointHelpers::waitWhileFailPointEnabled( @@ -505,7 +511,7 @@ public: opCtx, "waitAfterPinningCursorBeforeGetMoreBatch", dropAndReacquireReadLockIfLocked, - _request.nss); + nss); } const bool disableAwaitDataFailpointActive = @@ -513,7 +519,7 @@ public: // Inherit properties like readConcern and maxTimeMS from our originating cursor. setUpOperationContextStateForGetMore( - opCtx, *cursorPin.getCursor(), _request, disableAwaitDataFailpointActive); + opCtx, *cursorPin.getCursor(), _cmd, disableAwaitDataFailpointActive); if (!cursorPin->isAwaitData()) { opCtx->checkForInterrupt(); // May trigger maxTimeAlwaysTimeOut fail point. @@ -579,7 +585,7 @@ public: // Mark this as an AwaitData operation if appropriate. if (cursorPin->isAwaitData() && !disableAwaitDataFailpointActive) { - auto lastKnownCommittedOpTime = _request.lastKnownCommittedOpTime; + auto lastKnownCommittedOpTime = _cmd.getLastKnownCommittedOpTime(); if (opCtx->isExhaust() && cursorPin->getLastKnownCommittedOpTime()) { // Use the commit point of the last batch for exhaust cursors. lastKnownCommittedOpTime = cursorPin->getLastKnownCommittedOpTime(); @@ -610,12 +616,12 @@ public: data["shouldNotdropLock"].booleanSafe() ? []() {} /*empty function*/ : saveAndRestoreStateWithReadLockReacquisition, - _request.nss); + nss); }); const auto shouldSaveCursor = generateBatch(opCtx, cursorPin.getCursor(), - _request, + _cmd, cursorPin->isTailable(), &nextBatch, &numResults, @@ -642,7 +648,7 @@ public: } if (shouldSaveCursor) { - respondWithId = _request.cursorid; + respondWithId = cursorId; exec->saveState(); exec->detachFromOperationContext(); @@ -658,7 +664,7 @@ public: curOp->debug().cursorExhausted = true; } - nextBatch.done(respondWithId, _request.nss.ns()); + nextBatch.done(respondWithId, nss.ns()); // Increment this metric once we have generated a response and we know it will return // documents. @@ -686,15 +692,17 @@ public: // Counted as a getMore, not as a command. globalOpCounters.gotGetMore(); auto curOp = CurOp::get(opCtx); - curOp->debug().cursorid = _request.cursorid; + NamespaceString nss(_cmd.getDbName(), _cmd.getCollection()); + int64_t cursorId = _cmd.getCommandParameter(); + curOp->debug().cursorid = cursorId; // The presence of a term in the request indicates that this is an internal replication // oplog read request. - if (_request.term && _request.nss == NamespaceString::kRsOplogNamespace) { + if (_cmd.getTerm() && nss == NamespaceString::kRsOplogNamespace) { // Validate term before acquiring locks. auto replCoord = repl::ReplicationCoordinator::get(opCtx); // Note: updateTerm returns ok if term stayed the same. - uassertStatusOK(replCoord->updateTerm(opCtx, *_request.term)); + uassertStatusOK(replCoord->updateTerm(opCtx, *_cmd.getTerm())); // If the term field is present in an oplog request, it means this is an oplog // getMore for replication oplog fetching because the term field is only allowed for @@ -709,7 +717,7 @@ public: } auto cursorManager = CursorManager::get(opCtx); - auto cursorPin = uassertStatusOK(cursorManager->pinCursor(opCtx, _request.cursorid)); + auto cursorPin = uassertStatusOK(cursorManager->pinCursor(opCtx, cursorId)); // Get the read concern level here in case the cursor is exhausted while iterating. const auto isLinearizableReadConcern = cursorPin->getReadConcernArgs().getLevel() == @@ -737,9 +745,18 @@ public: opCtx, "waitBeforeUnpinningOrDeletingCursorAfterGetMoreBatch"); } + + if (getTestCommandsEnabled()) { + validateResult(reply); + } + } + + void validateResult(rpc::ReplyBuilderInterface* reply) { + auto ret = reply->getBodyBuilder().asTempObj(); + CursorGetMoreReply::parse({"CursorGetMoreReply"}, ret.removeField("ok")); } - const GetMoreRequest _request; + const GetMoreCommand _cmd; }; bool maintenanceOk() const override { diff --git a/src/mongo/db/query/getmore_command.idl b/src/mongo/db/query/getmore_command.idl index 9e4626d546a..91fdd7e283f 100644 --- a/src/mongo/db/query/getmore_command.idl +++ b/src/mongo/db/query/getmore_command.idl @@ -50,6 +50,7 @@ commands: batchSize: type: safeInt64 optional: true + validator: {gte: 0} maxTimeMS: description: "The awaitData timeout." type: safeInt64 diff --git a/src/mongo/db/query/getmore_request.cpp b/src/mongo/db/query/getmore_request.cpp index 30d8c59337b..669c9587213 100644 --- a/src/mongo/db/query/getmore_request.cpp +++ b/src/mongo/db/query/getmore_request.cpp @@ -38,7 +38,6 @@ #include "mongo/db/api_parameters_gen.h" #include "mongo/db/commands.h" #include "mongo/db/namespace_string.h" -#include "mongo/db/query/getmore_command_gen.h" #include "mongo/db/repl/bson_extract_optime.h" #include "mongo/idl/command_generic_argument.h" #include "mongo/util/assert_util.h" @@ -46,6 +45,18 @@ namespace mongo { +namespace { + +const char kCollectionField[] = "collection"; +const char kBatchSizeField[] = "batchSize"; +const char kAwaitDataTimeoutField[] = "maxTimeMS"; +const char kTermField[] = "term"; +const char kLastKnownCommittedOpTimeField[] = "lastKnownCommittedOpTime"; + +} // namespace + +const char GetMoreRequest::kGetMoreCommandName[] = "getMore"; + GetMoreRequest::GetMoreRequest() : cursorid(0), batchSize(0) {} GetMoreRequest::GetMoreRequest(NamespaceString namespaceString, @@ -80,54 +91,29 @@ Status GetMoreRequest::isValid() const { return Status::OK(); } -// static -StatusWith<GetMoreRequest> GetMoreRequest::parseFromBSON(const std::string& dbname, - const BSONObj& cmdObj) try { - for (const auto& fieldName : - std::vector<StringData>{APIParametersFromClient::kApiVersionFieldName, - APIParametersFromClient::kApiStrictFieldName, - APIParametersFromClient::kApiDeprecationErrorsFieldName}) { - uassert(4937600, - str::stream() << "Cannot pass in API parameter field " << fieldName, - !cmdObj.hasField(fieldName)); - } +BSONObj GetMoreRequest::toBSON() const { + BSONObjBuilder builder; + + builder.append(kGetMoreCommandName, cursorid); + builder.append(kCollectionField, nss.coll()); - auto parsed = GetMoreCommand::parse({"getMore"}, cmdObj); - auto maxTimeMS = parsed.getMaxTimeMS(); - - GetMoreRequest request( - NamespaceString(dbname, parsed.getCollection()), - parsed.getCommandParameter(), - parsed.getBatchSize(), - // Treat maxTimeMS=0 the same as none. - (maxTimeMS && *maxTimeMS) ? boost::optional<Milliseconds>(*maxTimeMS) : boost::none, - parsed.getTerm() ? boost::optional<long long>(*parsed.getTerm()) : boost::none, - parsed.getLastKnownCommittedOpTime()); - - Status validStatus = request.isValid(); - if (!validStatus.isOK()) { - return validStatus; + if (batchSize) { + builder.append(kBatchSizeField, *batchSize); } - return request; -} catch (const DBException& exc) { - return exc.toStatus(); -} + if (awaitDataTimeout) { + builder.append(kAwaitDataTimeoutField, durationCount<Milliseconds>(*awaitDataTimeout)); + } -BSONObj GetMoreRequest::toBSON() const { - auto cmd = GetMoreCommand(cursorid); - cmd.setDbName(nss.db()); - cmd.setCollection(nss.coll()); - cmd.setBatchSize(batchSize); - cmd.setLastKnownCommittedOpTime(lastKnownCommittedOpTime); if (term) { - cmd.setTerm(static_cast<int64_t>(*term)); + builder.append(kTermField, *term); } - if (awaitDataTimeout) { - cmd.setMaxTimeMS(durationCount<Milliseconds>(*awaitDataTimeout)); + + if (lastKnownCommittedOpTime) { + lastKnownCommittedOpTime->append(&builder, kLastKnownCommittedOpTimeField); } - return cmd.toBSON({}); + return builder.obj(); } } // namespace mongo diff --git a/src/mongo/db/query/getmore_request.h b/src/mongo/db/query/getmore_request.h index 4c15af6c74b..61efdfcd187 100644 --- a/src/mongo/db/query/getmore_request.h +++ b/src/mongo/db/query/getmore_request.h @@ -59,12 +59,6 @@ struct GetMoreRequest { boost::optional<repl::OpTime> lastKnownCommittedOpTime); /** - * Construct a GetMoreRequest from the command specification and db name. - */ - static StatusWith<GetMoreRequest> parseFromBSON(const std::string& dbname, - const BSONObj& cmdObj); - - /** * Serializes this object into a BSON representation. Fields that are not set will not be * part of the the serialized object. */ diff --git a/src/mongo/db/query/getmore_request_test.cpp b/src/mongo/db/query/getmore_request_test.cpp index 4273838b88c..e698fa9c07f 100644 --- a/src/mongo/db/query/getmore_request_test.cpp +++ b/src/mongo/db/query/getmore_request_test.cpp @@ -41,182 +41,6 @@ namespace { using namespace mongo; -TEST(GetMoreRequestTest, parseFromBSONEmptyCommandObject) { - StatusWith<GetMoreRequest> result = GetMoreRequest::parseFromBSON("db", BSONObj()); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONCursorIdNotNumeric) { - StatusWith<GetMoreRequest> result = GetMoreRequest::parseFromBSON("db", - BSON("getMore" - << "not a number" - << "collection" - << "coll" - << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONCursorIdNotLongLong) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" - << "not a number" - << "collection" << 123 << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONMissingCollection) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONCollectionNotString) { - StatusWith<GetMoreRequest> result = GetMoreRequest::parseFromBSON( - "db", - BSON("getMore" << CursorId(123) << "collection" << 456 << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONBatchSizeNotInteger) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "batchSize" - << "not a number" - << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONInvalidCursorId) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(0) << "collection" - << "coll" - << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONNegativeCursorId) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(-123) << "collection" - << "coll" - << "$db" - << "db")); - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS("db.coll", result.getValue().nss.toString()); - ASSERT_EQUALS(CursorId(-123), result.getValue().cursorid); - ASSERT_FALSE(result.getValue().batchSize); -} - -TEST(GetMoreRequestTest, parseFromBSONUnrecognizedFieldName) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "unknown_field" << 1 << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONInvalidBatchSize) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "batchSize" << -1 << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONInvalidBatchSizeOfZero) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "batchSize" << 0 << "$db" - << "db")); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreRequestTest, parseFromBSONNoBatchSize) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "$db" - << "db")); - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS("db.coll", result.getValue().nss.toString()); - ASSERT_EQUALS(CursorId(123), result.getValue().cursorid); - ASSERT_FALSE(result.getValue().batchSize); -} - -TEST(GetMoreRequestTest, parseFromBSONBatchSizeProvided) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "batchSize" << 200 << "$db" - << "db")); - ASSERT_EQUALS("db.coll", result.getValue().nss.toString()); - ASSERT_EQUALS(CursorId(123), result.getValue().cursorid); - ASSERT(result.getValue().batchSize); - ASSERT_EQUALS(200, *result.getValue().batchSize); -} - -TEST(GetMoreRequestTest, parseFromBSONIgnoreQueryOptions) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "$queryOptions" - << "bar" - << "$db" - << "db")); - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS("db.coll", result.getValue().nss.toString()); - ASSERT_EQUALS(CursorId(123), result.getValue().cursorid); -} - -TEST(GetMoreRequestTest, parseFromBSONHasMaxTimeMS) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "maxTimeMS" << 100 << "$db" - << "db")); - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS("db.coll", result.getValue().nss.toString()); - ASSERT(result.getValue().awaitDataTimeout); - ASSERT_EQUALS(100, durationCount<Milliseconds>(*result.getValue().awaitDataTimeout)); - ASSERT_EQUALS(CursorId(123), result.getValue().cursorid); -} - -TEST(GetMoreRequestTest, parseFromBSONHasMaxTimeMSOfZero) { - StatusWith<GetMoreRequest> result = - GetMoreRequest::parseFromBSON("db", - BSON("getMore" << CursorId(123) << "collection" - << "coll" - << "maxTimeMS" << 0 << "$db" - << "db")); - ASSERT_OK(result.getStatus()); - ASSERT_EQUALS("db.coll", result.getValue().nss.toString()); - ASSERT_EQUALS(CursorId(123), result.getValue().cursorid); - - // Max time of 0 means the same thing as no max time. - ASSERT(!result.getValue().awaitDataTimeout); -} - TEST(GetMoreRequestTest, toBSONHasBatchSize) { GetMoreRequest request( NamespaceString("testdb.testcoll"), 123, 99, boost::none, boost::none, boost::none); diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 176468bf315..2b13e640112 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -103,6 +103,7 @@ env.Library( 'cluster_commands.idl', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/api_parameters', '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/auth/address_restriction', '$BUILD_DIR/mongo/db/auth/auth', diff --git a/src/mongo/s/commands/cluster_getmore_cmd.cpp b/src/mongo/s/commands/cluster_getmore_cmd.cpp index a08fd0d3e0a..25bec22c1e4 100644 --- a/src/mongo/s/commands/cluster_getmore_cmd.cpp +++ b/src/mongo/s/commands/cluster_getmore_cmd.cpp @@ -29,11 +29,12 @@ #include "mongo/platform/basic.h" +#include "mongo/db/api_parameters.h" #include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/query/cursor_response.h" -#include "mongo/db/query/getmore_request.h" +#include "mongo/db/query/getmore_command_gen.h" #include "mongo/db/stats/counters.h" #include "mongo/s/query/cluster_cursor_manager.h" #include "mongo/s/query/cluster_find.h" @@ -73,13 +74,13 @@ public: class Invocation final : public CommandInvocation { public: Invocation(Command* cmd, const OpMsgRequest& request) - : CommandInvocation(cmd), - _request(uassertStatusOK( - GetMoreRequest::parseFromBSON(request.getDatabase().toString(), request.body))) {} + : CommandInvocation(cmd), _cmd(GetMoreCommand::parse({"getMore"}, request.body)) { + APIParameters::uassertNoApiParameters(request.body); + } private: NamespaceString ns() const override { - return _request.nss; + return NamespaceString(_cmd.getDbName(), _cmd.getCollection()); } bool supportsWriteConcern() const override { @@ -92,20 +93,28 @@ public: void doCheckAuthorization(OperationContext* opCtx) const override { uassertStatusOK(auth::checkAuthForGetMore(AuthorizationSession::get(opCtx->getClient()), - _request.nss, - _request.cursorid, - _request.term.is_initialized())); + ns(), + _cmd.getCommandParameter(), + _cmd.getTerm().is_initialized())); } void run(OperationContext* opCtx, rpc::ReplyBuilderInterface* reply) override { // Counted as a getMore, not as a command. globalOpCounters.gotGetMore(); auto bob = reply->getBodyBuilder(); - auto response = uassertStatusOK(ClusterFind::runGetMore(opCtx, _request)); + auto response = uassertStatusOK(ClusterFind::runGetMore(opCtx, _cmd)); response.addToBSON(CursorResponse::ResponseType::SubsequentResponse, &bob); + + if (getTestCommandsEnabled()) { + validateResult(bob.asTempObj()); + } + } + + void validateResult(const BSONObj& replyObj) { + CursorGetMoreReply::parse({"CursorGetMoreReply"}, replyObj.removeField("ok")); } - const GetMoreRequest _request; + const GetMoreCommand _cmd; }; AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index fcbcb89cd9e..2bb1d973b16 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -57,7 +57,7 @@ #include "mongo/db/operation_time_tracker.h" #include "mongo/db/ops/write_ops.h" #include "mongo/db/query/find_common.h" -#include "mongo/db/query/getmore_request.h" +#include "mongo/db/query/getmore_command_gen.h" #include "mongo/db/query/query_request_helper.h" #include "mongo/db/read_write_concern_defaults.h" #include "mongo/db/stats/api_version_metrics.h" @@ -1331,18 +1331,17 @@ DbResponse Strategy::getMore(OperationContext* opCtx, const NamespaceString& nss } uassertStatusOK(statusGetDb); - boost::optional<std::int64_t> batchSize; + GetMoreCommand getMoreCmd(cursorId, nss.coll().toString()); + getMoreCmd.setDbName(nss.db()); if (ntoreturn) { - batchSize = ntoreturn; + getMoreCmd.setBatchSize(ntoreturn); } - GetMoreRequest getMoreRequest(nss, cursorId, batchSize, boost::none, boost::none, boost::none); - // Set the upconverted getMore as the CurOp command object. CurOp::get(opCtx)->setGenericOpRequestDetails( - opCtx, nss, nullptr, getMoreRequest.toBSON(), dbm->msg().operation()); + opCtx, nss, nullptr, getMoreCmd.toBSON({}), dbm->msg().operation()); - auto cursorResponse = ClusterFind::runGetMore(opCtx, getMoreRequest); + auto cursorResponse = ClusterFind::runGetMore(opCtx, getMoreCmd); if (cursorResponse == ErrorCodes::CursorNotFound) { return replyToQuery(ResultFlag_CursorNotFound, nullptr, 0, 0); } diff --git a/src/mongo/s/query/async_results_merger_test.cpp b/src/mongo/s/query/async_results_merger_test.cpp index ec41e728f68..a4bca4cafeb 100644 --- a/src/mongo/s/query/async_results_merger_test.cpp +++ b/src/mongo/s/query/async_results_merger_test.cpp @@ -37,7 +37,7 @@ #include "mongo/db/pipeline/change_stream_constants.h" #include "mongo/db/pipeline/resume_token.h" #include "mongo/db/query/cursor_response.h" -#include "mongo/db/query/getmore_request.h" +#include "mongo/db/query/getmore_command_gen.h" #include "mongo/db/query/query_request_helper.h" #include "mongo/executor/task_executor.h" #include "mongo/s/catalog/type_shard.h" @@ -1094,13 +1094,12 @@ TEST_F(AsyncResultsMergerTest, GetMoreBatchSizes) { readyEvent = unittest::assertGet(arm->nextEvent()); BSONObj scheduledCmd = getNthPendingRequest(0).cmdObj; - auto request = GetMoreRequest::parseFromBSON("anydbname", - scheduledCmd.addField(BSON("$db" - << "anydbname") - .firstElement())); - ASSERT_OK(request.getStatus()); - ASSERT_EQ(*request.getValue().batchSize, 1LL); - ASSERT_EQ(request.getValue().cursorid, 1LL); + auto cmd = GetMoreCommand::parse({"getMore"}, + scheduledCmd.addField(BSON("$db" + << "anydbname") + .firstElement())); + ASSERT_EQ(*cmd.getBatchSize(), 1LL); + ASSERT_EQ(cmd.getCommandParameter(), 1LL); scheduleNetworkResponses(std::move(responses)); executor()->waitForEvent(readyEvent); diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index 02c4b570ac9..8997ee6746b 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -438,7 +438,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, * and/or what's specified on the request. */ Status setUpOperationContextStateForGetMore(OperationContext* opCtx, - const GetMoreRequest& request, + const GetMoreCommand& cmd, const ClusterCursorManager::PinnedCursor& cursor) { if (auto readPref = cursor->getReadPreference()) { ReadPreferenceSetting::get(opCtx) = *readPref; @@ -461,12 +461,12 @@ Status setUpOperationContextStateForGetMore(OperationContext* opCtx, // For tailable + awaitData cursors, the request may have indicated a maximum amount of time // to wait for new data. If not, default it to 1 second. We track the deadline instead via // the 'waitForInsertsDeadline' decoration. - auto timeout = request.awaitDataTimeout.value_or(Milliseconds{1000}); + auto timeout = Milliseconds{cmd.getMaxTimeMS().value_or(1000)}; awaitDataState(opCtx).waitForInsertsDeadline = opCtx->getServiceContext()->getPreciseClockSource()->now() + timeout; invariant(cursor->setAwaitDataTimeout(timeout).isOK()); - } else if (request.awaitDataTimeout) { + } else if (cmd.getMaxTimeMS()) { return {ErrorCodes::BadValue, "maxTimeMS can only be used with getMore for tailable, awaitData cursors"}; } else if (cursor->getLeftoverMaxTimeMicros() < Microseconds::max()) { @@ -619,18 +619,18 @@ CursorId ClusterFind::runQuery(OperationContext* opCtx, * ClusterClusterCursor manager if it does not. */ void validateLSID(OperationContext* opCtx, - const GetMoreRequest& request, + int64_t cursorId, const ClusterCursorManager::PinnedCursor& cursor) { if (opCtx->getLogicalSessionId() && !cursor->getLsid()) { uasserted(50799, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was not created in a session, in session " << *opCtx->getLogicalSessionId()); } if (!opCtx->getLogicalSessionId() && cursor->getLsid()) { uasserted(50800, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in session " << *cursor->getLsid() << ", without an lsid"); } @@ -638,7 +638,7 @@ void validateLSID(OperationContext* opCtx, if (opCtx->getLogicalSessionId() && cursor->getLsid() && (*opCtx->getLogicalSessionId() != *cursor->getLsid())) { uasserted(50801, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in session " << *cursor->getLsid() << ", in session " << *opCtx->getLogicalSessionId()); } @@ -649,18 +649,18 @@ void validateLSID(OperationContext* opCtx, * the ClusterClusterCursor manager if it does not. */ void validateTxnNumber(OperationContext* opCtx, - const GetMoreRequest& request, + int64_t cursorId, const ClusterCursorManager::PinnedCursor& cursor) { if (opCtx->getTxnNumber() && !cursor->getTxnNumber()) { uasserted(50802, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was not created in a transaction, in transaction " << *opCtx->getTxnNumber()); } if (!opCtx->getTxnNumber() && cursor->getTxnNumber()) { uasserted(50803, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in transaction " << *cursor->getTxnNumber() << ", without a txnNumber"); } @@ -668,7 +668,7 @@ void validateTxnNumber(OperationContext* opCtx, if (opCtx->getTxnNumber() && cursor->getTxnNumber() && (*opCtx->getTxnNumber() != *cursor->getTxnNumber())) { uasserted(50804, - str::stream() << "Cannot run getMore on cursor " << request.cursorid + str::stream() << "Cannot run getMore on cursor " << cursorId << ", which was created in transaction " << *cursor->getTxnNumber() << ", in transaction " << *opCtx->getTxnNumber()); } @@ -679,17 +679,17 @@ void validateTxnNumber(OperationContext* opCtx, * that stored on the cursor. The cursor is returned to the ClusterCursorManager if it does not. */ void validateOperationSessionInfo(OperationContext* opCtx, - const GetMoreRequest& request, + int64_t cursorId, ClusterCursorManager::PinnedCursor* cursor) { auto returnCursorGuard = makeGuard( [cursor] { cursor->returnCursor(ClusterCursorManager::CursorState::NotExhausted); }); - validateLSID(opCtx, request, *cursor); - validateTxnNumber(opCtx, request, *cursor); + validateLSID(opCtx, cursorId, *cursor); + validateTxnNumber(opCtx, cursorId, *cursor); returnCursorGuard.dismiss(); } StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, - const GetMoreRequest& request) { + const GetMoreCommand& cmd) { auto cursorManager = Grid::get(opCtx)->getCursorManager(); auto authzSession = AuthorizationSession::get(opCtx->getClient()); @@ -699,27 +699,28 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, : Status(ErrorCodes::Unauthorized, "User not authorized to access cursor"); }; - auto pinnedCursor = - cursorManager->checkOutCursor(request.nss, request.cursorid, opCtx, authChecker); + NamespaceString nss(cmd.getDbName(), cmd.getCollection()); + int64_t cursorId = cmd.getCommandParameter(); + + auto pinnedCursor = cursorManager->checkOutCursor(nss, cursorId, opCtx, authChecker); if (!pinnedCursor.isOK()) { return pinnedCursor.getStatus(); } - invariant(request.cursorid == pinnedCursor.getValue().getCursorId()); + invariant(cursorId == pinnedCursor.getValue().getCursorId()); - validateOperationSessionInfo(opCtx, request, &pinnedCursor.getValue()); + validateOperationSessionInfo(opCtx, cursorId, &pinnedCursor.getValue()); // Ensure that the client still has the privileges to run the originating command. if (!authzSession->isAuthorizedForPrivileges( pinnedCursor.getValue()->getOriginatingPrivileges())) { uasserted(ErrorCodes::Unauthorized, - str::stream() << "not authorized for getMore with cursor id " - << request.cursorid); + str::stream() << "not authorized for getMore with cursor id " << cursorId); } // Set the originatingCommand object and the cursorID in CurOp. { CurOp::get(opCtx)->debug().nShards = pinnedCursor.getValue()->getNumRemotes(); - CurOp::get(opCtx)->debug().cursorid = request.cursorid; + CurOp::get(opCtx)->debug().cursorid = cursorId; stdx::lock_guard<Client> lk(*opCtx->getClient()); CurOp::get(opCtx)->setOriginatingCommand_inlock( pinnedCursor.getValue()->getOriginatingCommand()); @@ -734,12 +735,12 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, : ErrorCodes::InternalError); uasserted(errorCode, "Hit the 'failGetMoreAfterCursorCheckout' failpoint"); }, - [&opCtx, &request](const BSONObj& data) { + [&opCtx, nss](const BSONObj& data) { auto dataForFailCommand = data.addField(BSON("failCommands" << BSON_ARRAY("getMore")).firstElement()); auto* getMoreCommand = CommandHelpers::findCommand("getMore"); return CommandHelpers::shouldActivateFailCommandFailPoint( - dataForFailCommand, request.nss, getMoreCommand, opCtx->getClient()); + dataForFailCommand, nss, getMoreCommand, opCtx->getClient()); }); // If the 'waitAfterPinningCursorBeforeGetMoreBatch' fail point is enabled, set the 'msg' @@ -752,14 +753,14 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, } auto opCtxSetupStatus = - setUpOperationContextStateForGetMore(opCtx, request, pinnedCursor.getValue()); + setUpOperationContextStateForGetMore(opCtx, cmd, pinnedCursor.getValue()); if (!opCtxSetupStatus.isOK()) { return opCtxSetupStatus; } std::vector<BSONObj> batch; int bytesBuffered = 0; - long long batchSize = request.batchSize.value_or(0); + long long batchSize = cmd.getBatchSize().value_or(0); long long startingFrom = pinnedCursor.getValue()->getNumReturnedSoFar(); auto cursorState = ClusterCursorManager::CursorState::NotExhausted; BSONObj postBatchResumeToken; @@ -826,8 +827,7 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, // If the cursor has been exhausted, we will communicate this by returning a CursorId of zero. auto idToReturn = - (cursorState == ClusterCursorManager::CursorState::Exhausted ? CursorId(0) - : request.cursorid); + (cursorState == ClusterCursorManager::CursorState::Exhausted ? CursorId(0) : cursorId); // For empty batches, or in the case where the final result was added to the batch rather than // being stashed, we update the PBRT here to ensure that it is the most recent available. @@ -856,7 +856,7 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, auto atClusterTime = !opCtx->inMultiDocumentTransaction() ? repl::ReadConcernArgs::get(opCtx).getArgsAtClusterTime() : boost::none; - return CursorResponse(request.nss, + return CursorResponse(nss, idToReturn, std::move(batch), atClusterTime ? atClusterTime->asTimestamp() diff --git a/src/mongo/s/query/cluster_find.h b/src/mongo/s/query/cluster_find.h index 89ab0d24731..fe5907c0153 100644 --- a/src/mongo/s/query/cluster_find.h +++ b/src/mongo/s/query/cluster_find.h @@ -35,6 +35,7 @@ #include "mongo/db/cursor_id.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/query/explain_options.h" +#include "mongo/db/query/getmore_command_gen.h" namespace mongo { @@ -42,7 +43,6 @@ template <typename T> class StatusWith; class CanonicalQuery; class OperationContext; -struct GetMoreRequest; struct ReadPreferenceSetting; /** @@ -68,10 +68,10 @@ public: bool* partialResultsReturned = nullptr); /** - * Executes the getMore request 'request', and on success returns a CursorResponse. + * Executes the getMore command 'cmd', and on success returns a CursorResponse. */ static StatusWith<CursorResponse> runGetMore(OperationContext* opCtx, - const GetMoreRequest& request); + const GetMoreCommand& cmd); }; } // namespace mongo |