summaryrefslogtreecommitdiff
path: root/src/mongo/db/service_entry_point_common.cpp
diff options
context:
space:
mode:
authorSiyuan Zhou <siyuan.zhou@mongodb.com>2018-10-10 21:10:05 -0400
committerSiyuan Zhou <siyuan.zhou@mongodb.com>2018-10-24 20:19:20 -0400
commit248601a6473fc7364e5d790a357acbace2a42f7a (patch)
treeca3b954d14757df9c41802038ff9086c6ab66037 /src/mongo/db/service_entry_point_common.cpp
parent887cc3f6db2a15d94e8ae2195d8183f16337d926 (diff)
downloadmongo-248601a6473fc7364e5d790a357acbace2a42f7a.tar.gz
SERVER-37179 Pass the reference of OperationSessionInfoFromClient around.
Diffstat (limited to 'src/mongo/db/service_entry_point_common.cpp')
-rw-r--r--src/mongo/db/service_entry_point_common.cpp106
1 files changed, 44 insertions, 62 deletions
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index 1eda9934455..7b1c0849936 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -105,32 +105,31 @@ using logger::LogComponent;
// session for commands that can take a lock and then run another whitelisted command in
// DBDirectClient. Otherwise, the nested command would try to check out a session under a lock,
// which is not allowed.
-const StringMap<int> sessionCommandAutomaticCheckOutWhiteList = {
- {"abortTransaction", 1},
- {"aggregate", 1},
- {"applyOps", 1},
- {"commitTransaction", 1},
- {"count", 1},
- {"dbHash", 1},
- {"delete", 1},
- {"distinct", 1},
- {"doTxn", 1},
- {"explain", 1},
- {"filemd5", 1},
- {"find", 1},
- {"findandmodify", 1},
- {"findAndModify", 1},
- {"geoNear", 1},
- {"geoSearch", 1},
- {"getMore", 1},
- {"group", 1},
- {"insert", 1},
- {"killCursors", 1},
- {"prepareTransaction", 1},
- {"refreshLogicalSessionCacheNow", 1},
- {"update", 1}};
-
-const StringMap<int> sessionCommandNoCheckOutWhiteList = {
+const StringMap<int> sessionCheckOutList = {{"abortTransaction", 1},
+ {"aggregate", 1},
+ {"applyOps", 1},
+ {"commitTransaction", 1},
+ {"count", 1},
+ {"dbHash", 1},
+ {"delete", 1},
+ {"distinct", 1},
+ {"doTxn", 1},
+ {"explain", 1},
+ {"filemd5", 1},
+ {"find", 1},
+ {"findandmodify", 1},
+ {"findAndModify", 1},
+ {"geoNear", 1},
+ {"geoSearch", 1},
+ {"getMore", 1},
+ {"group", 1},
+ {"insert", 1},
+ {"killCursors", 1},
+ {"prepareTransaction", 1},
+ {"refreshLogicalSessionCacheNow", 1},
+ {"update", 1}};
+
+const StringMap<int> skipSessionCheckOutList = {
{"coordinateCommitTransaction", 1}, {"voteAbortTransaction", 1}, {"voteCommitTransaction", 1}};
bool shouldActivateFailCommandFailPoint(const BSONObj& data, StringData cmdName) {
@@ -391,7 +390,7 @@ void appendClusterAndOperationTime(OperationContext* opCtx,
void invokeInTransaction(OperationContext* opCtx,
CommandInvocation* invocation,
TransactionParticipant* txnParticipant,
- const boost::optional<OperationSessionInfoFromClient>& sessionOptions,
+ const OperationSessionInfoFromClient& sessionOptions,
rpc::ReplyBuilderInterface* replyBuilder) {
txnParticipant->unstashTransactionResources(opCtx, invocation->definition()->getName());
ScopeGuard guard = MakeGuard([&txnParticipant, opCtx]() {
@@ -404,8 +403,8 @@ void invokeInTransaction(OperationContext* opCtx,
// Exceptions are used to resolve views in a sharded cluster, so they should be handled
// specially to avoid unnecessary aborts.
- auto startTransaction = sessionOptions->getStartTransaction();
- if (startTransaction && *startTransaction) {
+ // If "startTransaction" is present, it must be true.
+ if (sessionOptions.getStartTransaction()) {
// If the first command a shard receives in a transactions fails with this code, the
// shard may not be included in the final participant list if the router's retry after
// resolving the view does not re-target it, which is possible if the underlying
@@ -442,7 +441,7 @@ bool runCommandImpl(OperationContext* opCtx,
LogicalTime startOperationTime,
const ServiceEntryPointCommon::Hooks& behaviors,
BSONObjBuilder* extraFieldsBuilder,
- const boost::optional<OperationSessionInfoFromClient>& sessionOptions) {
+ const OperationSessionInfoFromClient& sessionOptions) {
const Command* command = invocation->definition();
auto bytesToReserve = command->reserveBytesForReply();
// SERVER-22100: In Windows DEBUG builds, the CRT heap debugging overhead, in conjunction with the
@@ -577,7 +576,7 @@ void execCommandDatabase(OperationContext* opCtx,
BSONObjBuilder extraFieldsBuilder;
auto startOperationTime = getClientOperationTime(opCtx);
auto invocation = command->parse(opCtx, request);
- boost::optional<OperationSessionInfoFromClient> sessionOptions = boost::none;
+ OperationSessionInfoFromClient sessionOptions;
try {
{
@@ -611,54 +610,37 @@ void execCommandDatabase(OperationContext* opCtx,
// using to service an earlier operation in the command's chain. To avoid this, only check
// out sessions for commands that require them.
const bool shouldCheckoutSession = static_cast<bool>(opCtx->getTxnNumber()) &&
- sessionCommandAutomaticCheckOutWhiteList.find(command->getName()) !=
- sessionCommandAutomaticCheckOutWhiteList.cend();
-
- // Parse the arguments specific to multi-statement transactions.
- boost::optional<bool> startMultiDocTxn = boost::none;
- boost::optional<bool> autocommitVal = boost::none;
- boost::optional<bool> coordinatorVal = boost::none;
- if (sessionOptions) {
- startMultiDocTxn = sessionOptions->getStartTransaction();
- autocommitVal = sessionOptions->getAutocommit();
- coordinatorVal = sessionOptions->getCoordinator();
- if (command->getName() == "doTxn") {
- // Autocommit and 'startMultiDocTxn' are overridden for 'doTxn' to get the oplog
- // entry generation behavior used for multi-document transactions. The 'doTxn'
- // command still logically behaves as a commit.
- autocommitVal = false;
- startMultiDocTxn = true;
- }
- }
+ sessionCheckOutList.find(command->getName()) != sessionCheckOutList.cend();
// Reject commands with 'txnNumber' that do not check out the Session, since no retryable
// writes or transaction machinery will be used to execute commands that do not check out
// the Session. Do not check this if we are in DBDirectClient because the outer command is
// responsible for checking out the Session.
- if (!opCtx->getClient()->isInDirectClient()) {
+ const auto skipSessionCheckout =
+ skipSessionCheckOutList.find(command->getName()) != skipSessionCheckOutList.cend();
+ const auto shouldNotCheckOutSession = !shouldCheckoutSession //
+ && !opCtx->getClient()->isInDirectClient() // Skip DBDirectClient.
+ && !skipSessionCheckout; // If we know they cannot check out, don't bother.
+
+ if (shouldNotCheckOutSession) {
uassert(ErrorCodes::OperationNotSupportedInTransaction,
str::stream() << "It is illegal to run command " << command->getName()
<< " in a multi-document transaction.",
- shouldCheckoutSession || !autocommitVal || command->getName() == "doTxn" ||
- sessionCommandNoCheckOutWhiteList.find(command->getName()) !=
- sessionCommandNoCheckOutWhiteList.cend());
+ !sessionOptions.getAutocommit());
uassert(50768,
str::stream() << "It is illegal to provide a txnNumber for command "
<< command->getName(),
- shouldCheckoutSession || !opCtx->getTxnNumber() ||
- sessionCommandNoCheckOutWhiteList.find(command->getName()) !=
- sessionCommandNoCheckOutWhiteList.cend());
+ !opCtx->getTxnNumber());
}
- if (autocommitVal) {
+ if (sessionOptions.getAutocommit()) {
uassertStatusOK(CommandHelpers::canUseTransactions(dbname, command->getName()));
}
// This constructor will check out the session and start a transaction, if necessary. It
// handles the appropriate state management for both multi-statement transactions and
// retryable writes.
- OperationContextSessionMongod sessionTxnState(
- opCtx, shouldCheckoutSession, autocommitVal, startMultiDocTxn, coordinatorVal);
+ OperationContextSessionMongod sessionTxnState(opCtx, shouldCheckoutSession, sessionOptions);
std::unique_ptr<MaintenanceModeSetter> mmSetter;
@@ -771,8 +753,8 @@ void execCommandDatabase(OperationContext* opCtx,
if (!opCtx->getClient()->isInDirectClient() || !txnParticipant ||
!txnParticipant->inMultiDocumentTransaction()) {
const bool upconvertToSnapshot = txnParticipant &&
- txnParticipant->inMultiDocumentTransaction() && sessionOptions &&
- (sessionOptions->getStartTransaction() == boost::optional<bool>(true));
+ txnParticipant->inMultiDocumentTransaction() &&
+ sessionOptions.getStartTransaction();
readConcernArgs = uassertStatusOK(
_extractReadConcern(invocation.get(), request.body, upconvertToSnapshot));
}