diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2018-06-29 12:35:35 -0400 |
---|---|---|
committer | Jack Mulrow <jack.mulrow@mongodb.com> | 2018-07-11 11:19:29 -0400 |
commit | 12d6b2807700431d9e2027580a0389bbcfe68a0d (patch) | |
tree | 865fa79e382ec7334811afc1d602ce028bd96f65 | |
parent | ad0d0e46190ee408662f3874ba85ea0b0b3731c7 (diff) | |
download | mongo-12d6b2807700431d9e2027580a0389bbcfe68a0d.tar.gz |
SERVER-35595 Add a passthrough coordinateCommitTransaction command
-rw-r--r-- | jstests/core/txns/statement_ids_accepted.js | 34 | ||||
-rw-r--r-- | jstests/core/views/views_all_commands.js | 1 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/s/coordinate_commit_transaction_command.cpp | 98 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_common.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/session.cpp | 8 |
6 files changed, 143 insertions, 2 deletions
diff --git a/jstests/core/txns/statement_ids_accepted.js b/jstests/core/txns/statement_ids_accepted.js index 790e690a82d..0c21d675905 100644 --- a/jstests/core/txns/statement_ids_accepted.js +++ b/jstests/core/txns/statement_ids_accepted.js @@ -242,6 +242,40 @@ stmtId: NumberInt(2), autocommit: false })); + assert.commandFailedWithCode(sessionDb.runCommand({ + prepareTransaction: 1, + txnNumber: NumberLong(txnNumber++), + stmtId: NumberInt(0), + autocommit: false + }), + ErrorCodes.Unauthorized); + + jsTestLog("Check that coordinateCommitTransaction accepts a statement ID"); + assert.commandWorked(sessionDb.runCommand({ + insert: collName, + documents: [{_id: "doc3"}], + readConcern: {level: "snapshot"}, + txnNumber: NumberLong(txnNumber), + stmtId: NumberInt(0), + startTransaction: true, + autocommit: false + })); + // coordinateCommitTransaction can only be run on the admin database. + assert.commandWorked(sessionDb.adminCommand({ + coordinateCommitTransaction: 1, + participants: [], + txnNumber: NumberLong(txnNumber++), + stmtId: NumberInt(1), + autocommit: false + })); + assert.commandFailedWithCode(sessionDb.runCommand({ + coordinateCommitTransaction: 1, + participants: [], + txnNumber: NumberLong(txnNumber++), + stmtId: NumberInt(0), + autocommit: false + }), + ErrorCodes.Unauthorized); // refreshLogicalSessionCacheNow is intentionally omitted. diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 0f3d90ac06b..42f362d4afd 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -145,6 +145,7 @@ connPoolSync: {skip: isUnrelated}, connectionStatus: {skip: isUnrelated}, convertToCapped: {command: {convertToCapped: "view", size: 12345}, expectFailure: true}, + coordinateCommitTransaction: {skip: isUnrelated}, copydb: {skip: "Tested in replsets/copydb.js"}, copydbsaslstart: {skip: isUnrelated}, count: {command: {count: "view"}}, diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index ab49a992561..4571f53be06 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -122,6 +122,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/s/common_s', ], ) @@ -271,6 +272,7 @@ env.Library( 'config/configsvr_shard_collection_command.cpp', 'config/configsvr_split_chunk_command.cpp', 'config/configsvr_update_zone_key_range_command.cpp', + 'coordinate_commit_transaction_command.cpp', 'flush_database_cache_updates_command.cpp', 'flush_routing_table_cache_updates_command.cpp', 'get_database_version_command.cpp', @@ -298,6 +300,7 @@ env.Library( '$BUILD_DIR/mongo/db/repl/replica_set_messages', '$BUILD_DIR/mongo/s/commands/shared_cluster_commands', 'balancer', + 'sharded_transaction_types', 'sharding_runtime_d', ], ) diff --git a/src/mongo/db/s/coordinate_commit_transaction_command.cpp b/src/mongo/db/s/coordinate_commit_transaction_command.cpp new file mode 100644 index 00000000000..c399c37a7cd --- /dev/null +++ b/src/mongo/db/s/coordinate_commit_transaction_command.cpp @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2018 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include "mongo/db/commands.h" +#include "mongo/db/repl/repl_client_info.h" +#include "mongo/db/s/coordinate_commit_transaction_gen.h" +#include "mongo/db/session_catalog.h" +#include "mongo/util/log.h" + +namespace mongo { +namespace { + +class CoordinateCommitTransactionCmd : public TypedCommand<CoordinateCommitTransactionCmd> { +public: + using Request = CoordinateCommitTransaction; + class Invocation final : public InvocationBase { + public: + using InvocationBase::InvocationBase; + + void typedRun(OperationContext* opCtx) { + auto session = OperationContextSession::get(opCtx); + uassert(ErrorCodes::CommandFailed, + "commitTransaction must be run within a session", + session); + + // commitTransaction is retryable. + if (session->transactionIsCommitted()) { + // We set the client last op to the last optime observed by the system to ensure + // that we wait for the specified write concern on an optime greater than or equal + // to the commit oplog entry. + auto& replClient = repl::ReplClientInfo::forClient(opCtx->getClient()); + replClient.setLastOpToSystemLastOpTime(opCtx); + return; + } + + uassert(ErrorCodes::NoSuchTransaction, + "Transaction isn't in progress", + session->inMultiDocumentTransaction()); + + session->commitTransaction(opCtx); + } + + private: + bool supportsWriteConcern() const override { + return true; + } + + NamespaceString ns() const override { + return NamespaceString(request().getDbName(), ""); + } + + void doCheckAuthorization(OperationContext* opCtx) const override {} + }; + + bool adminOnly() const override { + return true; + } + + std::string help() const override { + return "Coordinates the commit for a transaction. Only called by mongos."; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kNever; + } +} coordinateCommitTransactionCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index 3ec67f8a8fb..00539b7d061 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -111,6 +111,7 @@ const StringMap<int> sessionCheckoutWhitelist = {{"abortTransaction", 1}, {"aggregate", 1}, {"applyOps", 1}, {"commitTransaction", 1}, + {"coordinateCommitTransaction", 1}, {"count", 1}, {"dbHash", 1}, {"delete", 1}, diff --git a/src/mongo/db/session.cpp b/src/mongo/db/session.cpp index 9871262b989..ac81a40ea12 100644 --- a/src/mongo/db/session.cpp +++ b/src/mongo/db/session.cpp @@ -87,6 +87,7 @@ namespace { const StringMap<int> txnCmdWhitelist = {{"abortTransaction", 1}, {"aggregate", 1}, {"commitTransaction", 1}, + {"coordinateCommitTransaction", 1}, {"delete", 1}, {"distinct", 1}, {"doTxn", 1}, @@ -105,8 +106,11 @@ const StringMap<int> txnCmdWhitelist = {{"abortTransaction", 1}, 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}, {"doTxn", 1}, {"prepareTransaction", 1}}; +const StringMap<int> txnAdminCommands = {{"abortTransaction", 1}, + {"commitTransaction", 1}, + {"coordinateCommitTransaction", 1}, + {"doTxn", 1}, + {"prepareTransaction", 1}}; void fassertOnRepeatedExecution(const LogicalSessionId& lsid, TxnNumber txnNumber, |