summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorXueruiFa <xuerui.fa@mongodb.com>2020-07-16 18:03:11 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-29 15:23:07 +0000
commit7b910aba3c500839692d142b4c64560b1fc2f29b (patch)
treef56189478f203aac17cbe9d10bf91b1969653155 /src
parent4b880132b11c16a4a0cba4e5c3ce77892dd01f7c (diff)
downloadmongo-7b910aba3c500839692d142b4c64560b1fc2f29b.tar.gz
SERVER-49376: Ensure cursors inherit API settings of the initiating command
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/clientcursor.cpp1
-rw-r--r--src/mongo/db/clientcursor.h13
-rw-r--r--src/mongo/db/commands.h8
-rw-r--r--src/mongo/db/commands/find_cmd.cpp1
-rw-r--r--src/mongo/db/commands/getmore_cmd.cpp1
-rw-r--r--src/mongo/db/commands/list_collections.cpp1
-rw-r--r--src/mongo/db/commands/list_indexes.cpp1
-rw-r--r--src/mongo/db/commands/run_aggregate.cpp1
-rw-r--r--src/mongo/db/exec/sbe_cmd.cpp1
-rw-r--r--src/mongo/db/query/find.cpp1
-rw-r--r--src/mongo/db/query/getmore_request.cpp10
-rw-r--r--src/mongo/dbtests/cursor_manager_test.cpp39
-rw-r--r--src/mongo/s/query/SConscript3
-rw-r--r--src/mongo/s/query/cluster_aggregation_planner.cpp6
-rw-r--r--src/mongo/s/query/cluster_client_cursor.h6
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl.cpp4
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl.h2
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl_test.cpp27
-rw-r--r--src/mongo/s/query/cluster_client_cursor_mock.cpp8
-rw-r--r--src/mongo/s/query/cluster_client_cursor_mock.h6
-rw-r--r--src/mongo/s/query/cluster_client_cursor_params.h7
-rw-r--r--src/mongo/s/query/cluster_cursor_manager_test.cpp26
-rw-r--r--src/mongo/s/query/cluster_find.cpp5
-rw-r--r--src/mongo/s/query/store_possible_cursor.cpp6
25 files changed, 171 insertions, 14 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index 2f5aad83e4c..decffa6e11c 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -1192,6 +1192,7 @@ env.Library(
'query/query_planner',
'repl/repl_coordinator_interface',
's/sharding_api_d',
+ 'shared_request_handling',
'stats/serveronly_stats',
'storage/oplog_hack',
'storage/snapshot_helper',
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 845c31e48b9..33d41061774 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -83,6 +83,7 @@ ClientCursor::ClientCursor(ClientCursorParams params,
_authenticatedUsers(std::move(params.authenticatedUsers)),
_lsid(operationUsingCursor->getLogicalSessionId()),
_txnNumber(operationUsingCursor->getTxnNumber()),
+ _apiParameters(std::move(params.apiParameters)),
_writeConcernOptions(std::move(params.writeConcernOptions)),
_readConcernArgs(std::move(params.readConcernArgs)),
_originatingCommand(params.originatingCommandObj),
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index 1536921d8e1..ee2040764b6 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -35,6 +35,7 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/db/cursor_id.h"
+#include "mongo/db/initialize_api_parameters.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/logical_session_id.h"
#include "mongo/db/query/plan_executor.h"
@@ -58,12 +59,14 @@ struct ClientCursorParams {
ClientCursorParams(std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> planExecutor,
NamespaceString nss,
UserNameIterator authenticatedUsersIter,
+ APIParameters apiParameters,
WriteConcernOptions writeConcernOptions,
repl::ReadConcernArgs readConcernArgs,
BSONObj originatingCommandObj,
PrivilegeVector originatingPrivileges)
: exec(std::move(planExecutor)),
nss(std::move(nss)),
+ apiParameters(std::move(apiParameters)),
writeConcernOptions(std::move(writeConcernOptions)),
readConcernArgs(std::move(readConcernArgs)),
queryOptions(exec->getCanonicalQuery()
@@ -93,6 +96,7 @@ struct ClientCursorParams {
std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> exec;
const NamespaceString nss;
std::vector<UserName> authenticatedUsers;
+ const APIParameters apiParameters;
const WriteConcernOptions writeConcernOptions;
const repl::ReadConcernArgs readConcernArgs;
int queryOptions = 0;
@@ -141,14 +145,18 @@ public:
return _txnNumber;
}
- repl::ReadConcernArgs getReadConcernArgs() const {
- return _readConcernArgs;
+ APIParameters getAPIParameters() const {
+ return _apiParameters;
}
WriteConcernOptions getWriteConcernOptions() const {
return _writeConcernOptions;
}
+ repl::ReadConcernArgs getReadConcernArgs() const {
+ return _readConcernArgs;
+ }
+
/**
* Returns a pointer to the underlying query plan executor. All cursors manage a PlanExecutor,
* so this method never returns a null pointer.
@@ -358,6 +366,7 @@ private:
// A transaction number for this cursor, if it was provided in the originating command.
const boost::optional<TxnNumber> _txnNumber;
+ const APIParameters _apiParameters;
const WriteConcernOptions _writeConcernOptions;
const repl::ReadConcernArgs _readConcernArgs;
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 6a07d0404be..590be041081 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -355,12 +355,16 @@ public:
return false;
}
- // List of API versions that include this command.
+ /*
+ * Returns the list of API versions that include this command.
+ */
virtual const std::set<std::string>& apiVersions() const {
return kNoApiVersions;
}
- // API versions in which this command is deprecated.
+ /*
+ * Returns the list of API versions in which this command is deprecated.
+ */
virtual const std::set<std::string>& deprecatedApiVersions() const {
return kNoApiVersions;
}
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 517fb24bd54..55233df9dc2 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -490,6 +490,7 @@ public:
{std::move(exec),
nss,
AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
_request.body,
diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp
index ba9947b3e7e..1b3f43bf16c 100644
--- a/src/mongo/db/commands/getmore_cmd.cpp
+++ b/src/mongo/db/commands/getmore_cmd.cpp
@@ -220,6 +220,7 @@ void setUpOperationContextStateForGetMore(OperationContext* opCtx,
bool disableAwaitDataFailpointActive) {
applyCursorReadConcern(opCtx, cursor.getReadConcernArgs());
opCtx->setWriteConcern(cursor.getWriteConcernOptions());
+ APIParameters::get(opCtx) = cursor.getAPIParameters();
setUpOperationDeadline(opCtx, cursor, request, disableAwaitDataFailpointActive);
// If the originating command had a 'comment' field, we extract it and set it on opCtx. Note
diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp
index e90b0eeed4d..f8d10652830 100644
--- a/src/mongo/db/commands/list_collections.cpp
+++ b/src/mongo/db/commands/list_collections.cpp
@@ -405,6 +405,7 @@ public:
{std::move(exec),
cursorNss,
AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
jsobj,
diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp
index 15e8bb52420..6b3a51ad12e 100644
--- a/src/mongo/db/commands/list_indexes.cpp
+++ b/src/mongo/db/commands/list_indexes.cpp
@@ -218,6 +218,7 @@ public:
{std::move(exec),
nss,
AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
cmdObj,
diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp
index acc5fa1cd4e..855556d154d 100644
--- a/src/mongo/db/commands/run_aggregate.cpp
+++ b/src/mongo/db/commands/run_aggregate.cpp
@@ -704,6 +704,7 @@ Status runAggregate(OperationContext* opCtx,
std::move(exec),
origNss,
AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
cmdObj,
diff --git a/src/mongo/db/exec/sbe_cmd.cpp b/src/mongo/db/exec/sbe_cmd.cpp
index d88039b3d22..d544e79599f 100644
--- a/src/mongo/db/exec/sbe_cmd.cpp
+++ b/src/mongo/db/exec/sbe_cmd.cpp
@@ -114,6 +114,7 @@ public:
{std::move(exec),
nss,
AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
cmdObj,
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index 440c3c580d0..cc317eadf3a 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -744,6 +744,7 @@ bool runQuery(OperationContext* opCtx,
{std::move(exec),
nss,
AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ APIParameters::get(opCtx),
opCtx->getWriteConcern(),
readConcernArgs,
upconvertedQuery,
diff --git a/src/mongo/db/query/getmore_request.cpp b/src/mongo/db/query/getmore_request.cpp
index f39ca762f07..808f33d0e0b 100644
--- a/src/mongo/db/query/getmore_request.cpp
+++ b/src/mongo/db/query/getmore_request.cpp
@@ -51,6 +51,9 @@ const char kBatchSizeField[] = "batchSize";
const char kAwaitDataTimeoutField[] = "maxTimeMS";
const char kTermField[] = "term";
const char kLastKnownCommittedOpTimeField[] = "lastKnownCommittedOpTime";
+const char kApiVersion[] = "apiVersion";
+const char kApiStrict[] = "apiStrict";
+const char kApiDeprecationErrors[] = "apiDeprecationErrors";
} // namespace
@@ -105,6 +108,13 @@ StatusWith<GetMoreRequest> GetMoreRequest::parseFromBSON(const std::string& dbna
for (BSONElement el : cmdObj) {
const auto fieldName = el.fieldNameStringData();
+
+ auto containsAPIParamField = fieldName == kApiVersion || fieldName == kApiStrict ||
+ fieldName == kApiDeprecationErrors;
+ uassert(4937600,
+ str::stream() << "Cannot pass in API parameter field " << fieldName,
+ !containsAPIParamField);
+
if (fieldName == kGetMoreCommandName) {
if (el.type() != BSONType::NumberLong) {
return {ErrorCodes::TypeMismatch,
diff --git a/src/mongo/dbtests/cursor_manager_test.cpp b/src/mongo/dbtests/cursor_manager_test.cpp
index b8a841b56a3..31ad5c0c8a9 100644
--- a/src/mongo/dbtests/cursor_manager_test.cpp
+++ b/src/mongo/dbtests/cursor_manager_test.cpp
@@ -89,6 +89,7 @@ public:
makeFakePlanExecutor(opCtx),
kTestNss,
{},
+ APIParameters(),
opCtx->getWriteConcern(),
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -140,6 +141,7 @@ TEST_F(CursorManagerTest, ShouldBeAbleToKillPinnedCursor) {
{makeFakePlanExecutor(),
kTestNss,
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -166,6 +168,7 @@ TEST_F(CursorManagerTest, ShouldBeAbleToKillPinnedCursorMultiClient) {
{makeFakePlanExecutor(),
kTestNss,
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -202,6 +205,7 @@ TEST_F(CursorManagerTest, InactiveCursorShouldTimeout) {
{makeFakePlanExecutor(),
NamespaceString{"test.collection"},
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -217,6 +221,7 @@ TEST_F(CursorManagerTest, InactiveCursorShouldTimeout) {
{makeFakePlanExecutor(),
NamespaceString{"test.collection"},
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -237,6 +242,7 @@ TEST_F(CursorManagerTest, InactivePinnedCursorShouldNotTimeout) {
{makeFakePlanExecutor(),
NamespaceString{"test.collection"},
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -261,6 +267,7 @@ TEST_F(CursorManagerTest, MarkedAsKilledCursorsShouldBeDeletedOnCursorPin) {
{makeFakePlanExecutor(),
NamespaceString{"test.collection"},
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -294,6 +301,7 @@ TEST_F(CursorManagerTest, InactiveKilledCursorsShouldTimeout) {
{makeFakePlanExecutor(),
NamespaceString{"test.collection"},
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -326,6 +334,7 @@ TEST_F(CursorManagerTest, UsingACursorShouldUpdateTimeOfLastUse) {
{makeFakePlanExecutor(),
kTestNss,
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -339,6 +348,7 @@ TEST_F(CursorManagerTest, UsingACursorShouldUpdateTimeOfLastUse) {
{makeFakePlanExecutor(),
kTestNss,
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -376,6 +386,7 @@ TEST_F(CursorManagerTest, CursorShouldNotTimeOutUntilIdleForLongEnoughAfterBeing
{makeFakePlanExecutor(),
kTestNss,
{},
+ APIParameters(),
{},
repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
BSONObj(),
@@ -403,6 +414,34 @@ TEST_F(CursorManagerTest, CursorShouldNotTimeOutUntilIdleForLongEnoughAfterBeing
}
/**
+ * Test that a cursor correctly stores API parameters.
+ */
+TEST_F(CursorManagerTest, CursorStoresAPIParameters) {
+ APIParameters apiParams = APIParameters();
+ apiParams.setAPIVersion("2");
+ apiParams.setAPIStrict(true);
+ apiParams.setAPIDeprecationErrors(true);
+
+ CursorManager* cursorManager = useCursorManager();
+ auto cursorPin = cursorManager->registerCursor(
+ _opCtx.get(),
+ {makeFakePlanExecutor(),
+ kTestNss,
+ {},
+ apiParams,
+ {},
+ repl::ReadConcernArgs(repl::ReadConcernLevel::kLocalReadConcern),
+ BSONObj(),
+ PrivilegeVector()});
+
+ auto storedAPIParams = cursorPin->getAPIParameters();
+
+ ASSERT_EQ(apiParams.getAPIVersion(), storedAPIParams.getAPIVersion());
+ ASSERT_EQ(apiParams.getAPIStrict(), storedAPIParams.getAPIStrict());
+ ASSERT_EQ(apiParams.getAPIDeprecationErrors(), storedAPIParams.getAPIDeprecationErrors());
+}
+
+/**
* Test that cursors inherit the logical session id from their operation context
*/
TEST_F(CursorManagerTestCustomOpCtx, LogicalSessionIdOnOperationCtxTest) {
diff --git a/src/mongo/s/query/SConscript b/src/mongo/s/query/SConscript
index 0b924534119..05daa81d443 100644
--- a/src/mongo/s/query/SConscript
+++ b/src/mongo/s/query/SConscript
@@ -47,6 +47,7 @@ env.Library(
"cluster_client_cursor_impl.cpp",
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/shared_request_handling',
"router_exec_stage",
],
)
@@ -93,6 +94,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/shared_request_handling',
],
)
@@ -123,6 +125,7 @@ env.Library(
'$BUILD_DIR/mongo/db/kill_sessions',
'$BUILD_DIR/mongo/db/logical_session_cache',
'$BUILD_DIR/mongo/db/logical_session_id',
+ '$BUILD_DIR/mongo/db/shared_request_handling',
],
)
diff --git a/src/mongo/s/query/cluster_aggregation_planner.cpp b/src/mongo/s/query/cluster_aggregation_planner.cpp
index 8271c404702..6632dee755a 100644
--- a/src/mongo/s/query/cluster_aggregation_planner.cpp
+++ b/src/mongo/s/query/cluster_aggregation_planner.cpp
@@ -250,8 +250,10 @@ BSONObj establishMergingMongosCursor(OperationContext* opCtx,
std::unique_ptr<Pipeline, PipelineDeleter> pipelineForMerging,
const PrivilegeVector& privileges) {
- ClusterClientCursorParams params(
- requestedNss, ReadPreferenceSetting::get(opCtx), ReadConcernArgs::get(opCtx));
+ ClusterClientCursorParams params(requestedNss,
+ APIParameters::get(opCtx),
+ ReadPreferenceSetting::get(opCtx),
+ ReadConcernArgs::get(opCtx));
params.originatingCommandObj = CurOp::get(opCtx)->opDescription().getOwned();
params.tailableMode = pipelineForMerging->getContext()->tailableMode;
diff --git a/src/mongo/s/query/cluster_client_cursor.h b/src/mongo/s/query/cluster_client_cursor.h
index 6dc1ae8419e..44aae05e34d 100644
--- a/src/mongo/s/query/cluster_client_cursor.h
+++ b/src/mongo/s/query/cluster_client_cursor.h
@@ -33,6 +33,7 @@
#include "mongo/client/read_preference.h"
#include "mongo/db/auth/user_name.h"
+#include "mongo/db/initialize_api_parameters.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/logical_session_id.h"
#include "mongo/s/query/cluster_client_cursor_params.h"
@@ -176,6 +177,11 @@ public:
virtual boost::optional<TxnNumber> getTxnNumber() const = 0;
/**
+ * Returns the APIParameters for this cursor.
+ */
+ virtual APIParameters getAPIParameters() const = 0;
+
+ /**
* Returns the readPreference for this cursor.
*/
virtual boost::optional<ReadPreferenceSetting> getReadPreference() const = 0;
diff --git a/src/mongo/s/query/cluster_client_cursor_impl.cpp b/src/mongo/s/query/cluster_client_cursor_impl.cpp
index fefd913f8a7..d0cc5fd88b2 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_impl.cpp
@@ -205,6 +205,10 @@ void ClusterClientCursorImpl::incNBatches() {
++_nBatchesReturned;
}
+APIParameters ClusterClientCursorImpl::getAPIParameters() const {
+ return _params.apiParameters;
+}
+
boost::optional<ReadPreferenceSetting> ClusterClientCursorImpl::getReadPreference() const {
return _params.readPreference;
}
diff --git a/src/mongo/s/query/cluster_client_cursor_impl.h b/src/mongo/s/query/cluster_client_cursor_impl.h
index 23f1c351fda..e3a853db464 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl.h
+++ b/src/mongo/s/query/cluster_client_cursor_impl.h
@@ -102,6 +102,8 @@ public:
boost::optional<TxnNumber> getTxnNumber() const final;
+ APIParameters getAPIParameters() const final;
+
boost::optional<ReadPreferenceSetting> getReadPreference() const final;
boost::optional<ReadConcernArgs> getReadConcern() const final;
diff --git a/src/mongo/s/query/cluster_client_cursor_impl_test.cpp b/src/mongo/s/query/cluster_client_cursor_impl_test.cpp
index 0119abcbd68..630182bda5f 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl_test.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_impl_test.cpp
@@ -56,10 +56,11 @@ TEST_F(ClusterClientCursorImplTest, NumReturnedSoFar) {
mockStage->queueResult(BSON("a" << i));
}
- ClusterClientCursorImpl cursor(_opCtx.get(),
- std::move(mockStage),
- ClusterClientCursorParams(NamespaceString("unused"), {}),
- boost::none);
+ ClusterClientCursorImpl cursor(
+ _opCtx.get(),
+ std::move(mockStage),
+ ClusterClientCursorParams(NamespaceString("unused"), APIParameters(), {}),
+ boost::none);
ASSERT_EQ(cursor.getNumReturnedSoFar(), 0);
@@ -251,6 +252,24 @@ TEST_F(ClusterClientCursorImplTest, ShouldStoreLSIDIfSetOnOpCtx) {
}
}
+TEST_F(ClusterClientCursorImplTest, ShouldStoreAPIParameters) {
+ auto mockStage = std::make_unique<RouterStageMock>(_opCtx.get());
+
+ APIParameters apiParams = APIParameters();
+ apiParams.setAPIVersion("2");
+ apiParams.setAPIStrict(true);
+ apiParams.setAPIDeprecationErrors(true);
+
+ ClusterClientCursorParams params(NamespaceString("test"), apiParams, {});
+ ClusterClientCursorImpl cursor(
+ _opCtx.get(), std::move(mockStage), std::move(params), boost::none);
+ auto storedAPIParams = cursor.getAPIParameters();
+
+ ASSERT_EQ(apiParams.getAPIVersion(), storedAPIParams.getAPIVersion());
+ ASSERT_EQ(apiParams.getAPIStrict(), storedAPIParams.getAPIStrict());
+ ASSERT_EQ(apiParams.getAPIDeprecationErrors(), storedAPIParams.getAPIDeprecationErrors());
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/s/query/cluster_client_cursor_mock.cpp b/src/mongo/s/query/cluster_client_cursor_mock.cpp
index e6f86dccade..9391f57f4fc 100644
--- a/src/mongo/s/query/cluster_client_cursor_mock.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_mock.cpp
@@ -149,6 +149,14 @@ boost::optional<TxnNumber> ClusterClientCursorMock::getTxnNumber() const {
return _txnNumber;
}
+void ClusterClientCursorMock::setAPIParameters(APIParameters& apiParameters) {
+ _apiParameters = apiParameters;
+}
+
+APIParameters ClusterClientCursorMock::getAPIParameters() const {
+ return _apiParameters;
+}
+
boost::optional<ReadPreferenceSetting> ClusterClientCursorMock::getReadPreference() const {
return boost::none;
}
diff --git a/src/mongo/s/query/cluster_client_cursor_mock.h b/src/mongo/s/query/cluster_client_cursor_mock.h
index f72551a24da..a34ce2376eb 100644
--- a/src/mongo/s/query/cluster_client_cursor_mock.h
+++ b/src/mongo/s/query/cluster_client_cursor_mock.h
@@ -90,6 +90,10 @@ public:
boost::optional<TxnNumber> getTxnNumber() const final;
+ void setAPIParameters(APIParameters& apiParameters);
+
+ APIParameters getAPIParameters() const final;
+
boost::optional<ReadPreferenceSetting> getReadPreference() const final;
boost::optional<ReadConcernArgs> getReadConcern() const final;
@@ -141,6 +145,8 @@ private:
Date_t _lastUseDate;
std::uint64_t _nBatchesReturned = 0;
+
+ APIParameters _apiParameters = APIParameters();
};
} // namespace mongo
diff --git a/src/mongo/s/query/cluster_client_cursor_params.h b/src/mongo/s/query/cluster_client_cursor_params.h
index cd6563f842c..d8bb0ae8da0 100644
--- a/src/mongo/s/query/cluster_client_cursor_params.h
+++ b/src/mongo/s/query/cluster_client_cursor_params.h
@@ -39,6 +39,7 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/db/cursor_id.h"
+#include "mongo/db/initialize_api_parameters.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/pipeline/pipeline.h"
#include "mongo/db/query/cursor_response.h"
@@ -68,9 +69,10 @@ using repl::ReadConcernArgs;
*/
struct ClusterClientCursorParams {
ClusterClientCursorParams(NamespaceString nss,
+ APIParameters apiParameters,
boost::optional<ReadPreferenceSetting> readPref = boost::none,
boost::optional<ReadConcernArgs> readConcernArgs = boost::none)
- : nsString(std::move(nss)) {
+ : nsString(std::move(nss)), apiParameters(std::move(apiParameters)) {
if (readPref) {
readPreference = std::move(readPref.get());
}
@@ -147,6 +149,9 @@ struct ClusterClientCursorParams {
// set.
TailableModeEnum tailableMode = TailableModeEnum::kNormal;
+ // The API parameters associated with the cursor.
+ APIParameters apiParameters;
+
// Set if a readPreference must be respected throughout the lifetime of the cursor.
boost::optional<ReadPreferenceSetting> readPreference;
diff --git a/src/mongo/s/query/cluster_cursor_manager_test.cpp b/src/mongo/s/query/cluster_cursor_manager_test.cpp
index aa8974161cc..1c68a2b3d2a 100644
--- a/src/mongo/s/query/cluster_cursor_manager_test.cpp
+++ b/src/mongo/s/query/cluster_cursor_manager_test.cpp
@@ -964,6 +964,32 @@ TEST_F(ClusterCursorManagerTest, DoNotDestroyKilledPinnedCursors) {
ASSERT(isMockCursorKilled(0));
}
+// Test that a cursor correctly stores API parameters.
+TEST_F(ClusterCursorManagerTest, CursorStoresAPIParameters) {
+ APIParameters apiParams = APIParameters();
+ apiParams.setAPIVersion("2");
+ apiParams.setAPIStrict(true);
+ apiParams.setAPIDeprecationErrors(true);
+
+ auto cursor = allocateMockCursor();
+ cursor->setAPIParameters(apiParams);
+
+ auto cursorId =
+ assertGet(getManager()->registerCursor(_opCtx.get(),
+ std::move(cursor),
+ nss,
+ ClusterCursorManager::CursorType::SingleTarget,
+ ClusterCursorManager::CursorLifetime::Mortal,
+ UserNameIterator()));
+ auto pinnedCursor =
+ assertGet(getManager()->checkOutCursor(nss, cursorId, _opCtx.get(), successAuthChecker));
+ auto storedAPIParams = pinnedCursor->getAPIParameters();
+
+ ASSERT_EQ(apiParams.getAPIVersion(), storedAPIParams.getAPIVersion());
+ ASSERT_EQ(apiParams.getAPIStrict(), storedAPIParams.getAPIStrict());
+ ASSERT_EQ(apiParams.getAPIDeprecationErrors(), storedAPIParams.getAPIDeprecationErrors());
+}
+
TEST_F(ClusterCursorManagerTest, CannotRegisterCursorDuringShutdown) {
ASSERT_OK(getManager()->registerCursor(_opCtx.get(),
allocateMockCursor(),
diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp
index 6f374202b8f..8ceba8426ed 100644
--- a/src/mongo/s/query/cluster_find.cpp
+++ b/src/mongo/s/query/cluster_find.cpp
@@ -248,7 +248,8 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
// Construct the query and parameters. Defer setting skip and limit here until
// we determine if the query is targeting multi-shards or a single shard below.
- ClusterClientCursorParams params(query.nss(), readPref, ReadConcernArgs::get(opCtx));
+ ClusterClientCursorParams params(
+ query.nss(), APIParameters::get(opCtx), readPref, ReadConcernArgs::get(opCtx));
params.originatingCommandObj = CurOp::get(opCtx)->opDescription().getOwned();
params.batchSize = query.getQueryRequest().getEffectiveBatchSize();
params.tailableMode = query.getQueryRequest().getTailableMode();
@@ -440,6 +441,8 @@ Status setUpOperationContextStateForGetMore(OperationContext* opCtx,
ReadConcernArgs::get(opCtx) = *readConcern;
}
+ APIParameters::get(opCtx) = cursor->getAPIParameters();
+
// 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.
auto comment = cursor->getOriginatingCommand()["comment"];
diff --git a/src/mongo/s/query/store_possible_cursor.cpp b/src/mongo/s/query/store_possible_cursor.cpp
index b76a47cddbe..6b6391dbb27 100644
--- a/src/mongo/s/query/store_possible_cursor.cpp
+++ b/src/mongo/s/query/store_possible_cursor.cpp
@@ -99,8 +99,10 @@ StatusWith<BSONObj> storePossibleCursor(OperationContext* opCtx,
return cmdResult;
}
- ClusterClientCursorParams params(
- incomingCursorResponse.getValue().getNSS(), boost::none, ReadConcernArgs::get(opCtx));
+ ClusterClientCursorParams params(incomingCursorResponse.getValue().getNSS(),
+ APIParameters::get(opCtx),
+ boost::none,
+ ReadConcernArgs::get(opCtx));
params.remotes.emplace_back();
auto& remoteCursor = params.remotes.back();
remoteCursor.setShardId(shardId.toString());