summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRandolph Tan <randolph@10gen.com>2018-09-25 16:52:27 -0400
committerRandolph Tan <randolph@10gen.com>2018-09-27 10:31:35 -0400
commit5674fa1f3087f65ea326b33f5b81647d4dcfb8d6 (patch)
treebe74b03f086a8a338c5354eaf9b2e5f2d86d8996 /src
parentf58a039003b982d40de3ce1be56563270f6b78de (diff)
downloadmongo-5674fa1f3087f65ea326b33f5b81647d4dcfb8d6.tar.gz
SERVER-37239 Router should validate if commands are allowed to run within transactions
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/commands.cpp59
-rw-r--r--src/mongo/db/commands.h5
-rw-r--r--src/mongo/db/service_entry_point_common.cpp2
-rw-r--r--src/mongo/db/transaction_participant.cpp57
-rw-r--r--src/mongo/db/transaction_participant.h2
-rw-r--r--src/mongo/s/commands/strategy.cpp2
6 files changed, 67 insertions, 60 deletions
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 921b9d7a397..82cca3d77e9 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -104,6 +104,40 @@ bool checkAuthorizationImplPreParse(OperationContext* opCtx,
return false;
}
+// The command names that are allowed in a multi-document transaction.
+const StringMap<int> txnCmdWhitelist = {{"abortTransaction", 1},
+ {"aggregate", 1},
+ {"commitTransaction", 1},
+ {"coordinateCommitTransaction", 1},
+ {"delete", 1},
+ {"distinct", 1},
+ {"doTxn", 1},
+ {"find", 1},
+ {"findandmodify", 1},
+ {"findAndModify", 1},
+ {"geoSearch", 1},
+ {"getMore", 1},
+ {"insert", 1},
+ {"killCursors", 1},
+ {"prepareTransaction", 1},
+ {"update", 1},
+ {"voteAbortTransaction", 1},
+ {"voteCommitTransaction", 1}};
+
+// The command names that are allowed in a multi-document transaction only when test commands are
+// enabled.
+const StringMap<int> txnCmdForTestingWhitelist = {{"dbHash", 1}};
+
+
+// The commands that can be run on the 'admin' database in multi-document transactions.
+const StringMap<int> txnAdminCommands = {{"abortTransaction", 1},
+ {"commitTransaction", 1},
+ {"coordinateCommitTransaction", 1},
+ {"doTxn", 1},
+ {"prepareTransaction", 1},
+ {"voteAbortTransaction", 1},
+ {"voteCommitTransaction", 1}};
+
} // namespace
@@ -398,6 +432,31 @@ bool CommandHelpers::uassertShouldAttemptParse(OperationContext* opCtx,
}
}
+
+Status CommandHelpers::canUseTransactions(StringData dbName, StringData cmdName) {
+ if (cmdName == "count"_sd) {
+ return {ErrorCodes::OperationNotSupportedInTransaction,
+ "Cannot run 'count' in a multi-document transaction. Please see "
+ "http://dochub.mongodb.org/core/transaction-count for a recommended alternative."};
+ }
+
+ if (txnCmdWhitelist.find(cmdName) == txnCmdWhitelist.cend() &&
+ !(getTestCommandsEnabled() &&
+ txnCmdForTestingWhitelist.find(cmdName) != txnCmdForTestingWhitelist.cend())) {
+ return {ErrorCodes::OperationNotSupportedInTransaction,
+ str::stream() << "Cannot run '" << cmdName << "' in a multi-document transaction."};
+ }
+
+ if (dbName == "config"_sd || dbName == "local"_sd ||
+ (dbName == "admin"_sd && txnAdminCommands.find(cmdName) == txnAdminCommands.cend())) {
+ return {ErrorCodes::OperationNotSupportedInTransaction,
+ str::stream() << "Cannot run command against the '" << dbName
+ << "' database in a transaction"};
+ }
+
+ return Status::OK();
+}
+
constexpr StringData CommandHelpers::kHelpFieldName;
//////////////////////////////////////////////////////////////
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index f49c9e3792e..d0a29a025ec 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -237,6 +237,11 @@ struct CommandHelpers {
const Command* command,
const OpMsgRequest& request);
+ /**
+ * Returns OK if command is allowed to run under a transaction in the given database.
+ */
+ static Status canUseTransactions(StringData dbName, StringData cmdName);
+
static constexpr StringData kHelpFieldName = "help"_sd;
};
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index 439bd7e7602..55dedecb657 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -680,7 +680,7 @@ void execCommandDatabase(OperationContext* opCtx,
}
if (autocommitVal) {
- uassertStatusOK(TransactionParticipant::isValid(dbname, command->getName()));
+ uassertStatusOK(CommandHelpers::canUseTransactions(dbname, command->getName()));
}
// This constructor will check out the session and start a transaction, if necessary. It
diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp
index d848960eb42..a2c967afbe4 100644
--- a/src/mongo/db/transaction_participant.cpp
+++ b/src/mongo/db/transaction_participant.cpp
@@ -81,39 +81,6 @@ MONGO_FAIL_POINT_DEFINE(hangAfterReservingPrepareTimestamp);
const auto getTransactionParticipant = Session::declareDecoration<TransactionParticipant>();
-// The command names that are allowed in a multi-document transaction.
-const StringMap<int> txnCmdWhitelist = {{"abortTransaction", 1},
- {"aggregate", 1},
- {"commitTransaction", 1},
- {"coordinateCommitTransaction", 1},
- {"delete", 1},
- {"distinct", 1},
- {"doTxn", 1},
- {"find", 1},
- {"findandmodify", 1},
- {"findAndModify", 1},
- {"geoSearch", 1},
- {"getMore", 1},
- {"insert", 1},
- {"killCursors", 1},
- {"prepareTransaction", 1},
- {"update", 1},
- {"voteAbortTransaction", 1},
- {"voteCommitTransaction", 1}};
-
-// The command names that are allowed in a multi-document transaction only when test commands are
-// enabled.
-const StringMap<int> txnCmdForTestingWhitelist = {{"dbHash", 1}};
-
-// The commands that can be run on the 'admin' database in multi-document transactions.
-const StringMap<int> txnAdminCommands = {{"abortTransaction", 1},
- {"commitTransaction", 1},
- {"coordinateCommitTransaction", 1},
- {"doTxn", 1},
- {"prepareTransaction", 1},
- {"voteAbortTransaction", 1},
- {"voteCommitTransaction", 1}};
-
// The command names that are allowed in a prepared transaction.
const StringMap<int> preparedTxnCmdWhitelist = {
{"abortTransaction", 1}, {"commitTransaction", 1}, {"prepareTransaction", 1}};
@@ -1066,30 +1033,6 @@ void TransactionParticipant::_checkIsCommandValidWithTxnState(WithLock wl,
preparedTxnCmdWhitelist.find(cmdName) != preparedTxnCmdWhitelist.cend());
}
-Status TransactionParticipant::isValid(StringData dbName, StringData cmdName) {
- if (cmdName == "count"_sd) {
- return {ErrorCodes::OperationNotSupportedInTransaction,
- "Cannot run 'count' in a multi-document transaction. Please see "
- "http://dochub.mongodb.org/core/transaction-count for a recommended alternative."};
- }
-
- if (txnCmdWhitelist.find(cmdName) == txnCmdWhitelist.cend() &&
- !(getTestCommandsEnabled() &&
- txnCmdForTestingWhitelist.find(cmdName) != txnCmdForTestingWhitelist.cend())) {
- return {ErrorCodes::OperationNotSupportedInTransaction,
- str::stream() << "Cannot run '" << cmdName << "' in a multi-document transaction."};
- }
-
- if (dbName == "config"_sd || dbName == "local"_sd ||
- (dbName == "admin"_sd && txnAdminCommands.find(cmdName) == txnAdminCommands.cend())) {
- return {ErrorCodes::OperationNotSupportedInTransaction,
- str::stream() << "Cannot run command against the '" << dbName
- << "' database in a transaction"};
- }
-
- return Status::OK();
-}
-
BSONObj TransactionParticipant::reportStashedState() const {
BSONObjBuilder builder;
reportStashedState(&builder);
diff --git a/src/mongo/db/transaction_participant.h b/src/mongo/db/transaction_participant.h
index 70042946744..22b3d1485f1 100644
--- a/src/mongo/db/transaction_participant.h
+++ b/src/mongo/db/transaction_participant.h
@@ -354,8 +354,6 @@ public:
void beginOrContinueTransactionUnconditionally(TxnNumber txnNumber);
- static Status isValid(StringData dbName, StringData cmdName);
-
void transitionToPreparedforTest() {
stdx::lock_guard<stdx::mutex> lk(_mutex);
_txnState.transitionTo(lk, TransactionState::kPrepared);
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index 8d07a963fd1..861435ae606 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -365,6 +365,8 @@ void runCommand(OperationContext* opCtx,
auto startTxnSetting = osi->getStartTransaction();
bool startTransaction = startTxnSetting ? *startTxnSetting : false;
+ uassertStatusOK(CommandHelpers::canUseTransactions(nss.db(), command->getName()));
+
txnRouter->beginOrContinueTxn(opCtx, *txnNumber, startTransaction);
}