diff options
author | Sanika Phanse <sanika.phanse@mongodb.com> | 2022-04-12 18:36:32 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-04-12 23:44:20 +0000 |
commit | 84467ea62f22f10137fa919a4c019afbac6ac63b (patch) | |
tree | 1b047144210be72d7758aea85902d4c58da779f6 /src/mongo | |
parent | 673e9e2290ac6a792fa95d34167c6d2bbec4b6c4 (diff) | |
download | mongo-84467ea62f22f10137fa919a4c019afbac6ac63b.tar.gz |
SERVER-63081 Create a test command for internal transactions
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/SConscript | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/internal_transactions_test_command.idl (renamed from src/mongo/s/commands/internal_transactions_test_commands.idl) | 63 | ||||
-rw-r--r-- | src/mongo/db/commands/internal_transactions_test_command_d.cpp | 66 | ||||
-rw-r--r-- | src/mongo/s/commands/SConscript | 6 | ||||
-rw-r--r-- | src/mongo/s/commands/internal_transactions_test_command.h (renamed from src/mongo/s/commands/internal_transactions_test_commands.cpp) | 79 | ||||
-rw-r--r-- | src/mongo/s/commands/internal_transactions_test_command_s.cpp | 50 |
6 files changed, 204 insertions, 64 deletions
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index 6a08a6b7e9e..c6d2d8232e0 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -142,6 +142,7 @@ env.Library( 'rotate_certificates_command.cpp', 'generic_servers.cpp', 'generic_servers.idl', + 'internal_transactions_test_command.idl', 'isself.cpp', 'logical_session_server_status_section.cpp', 'mr_common.cpp', @@ -512,6 +513,7 @@ env.Library( "driverHelpers.cpp", 'get_cluster_parameter_command.cpp', "internal_rename_if_options_and_indexes_match_cmd.cpp", + "internal_transactions_test_command_d.cpp", "fle2_compact_cmd.cpp", "map_reduce_command.cpp", "oplog_application_checks.cpp", @@ -554,6 +556,7 @@ env.Library( '$BUILD_DIR/mongo/db/catalog/database_holder', '$BUILD_DIR/mongo/db/catalog/index_key_validate', '$BUILD_DIR/mongo/db/change_stream_options_manager', + '$BUILD_DIR/mongo/db/cluster_transaction_api', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/curop_failpoint_helpers', '$BUILD_DIR/mongo/db/dbhelpers', @@ -581,6 +584,7 @@ env.Library( '$BUILD_DIR/mongo/db/server_feature_flags', '$BUILD_DIR/mongo/db/server_options_core', '$BUILD_DIR/mongo/db/timeseries/timeseries_conversion_util', + '$BUILD_DIR/mongo/db/transaction_api', '$BUILD_DIR/mongo/idl/idl_parser', '$BUILD_DIR/mongo/util/net/ssl_manager', 'core', diff --git a/src/mongo/s/commands/internal_transactions_test_commands.idl b/src/mongo/db/commands/internal_transactions_test_command.idl index 1e68776ba94..292355cf255 100644 --- a/src/mongo/s/commands/internal_transactions_test_commands.idl +++ b/src/mongo/db/commands/internal_transactions_test_command.idl @@ -33,27 +33,29 @@ imports: - "mongo/idl/basic_types.idl" structs: - TestInternalTransactionsReply: - description: "Response for testInternalTransactions command" - strict: false - fields: - responses: - type: array<object> + TestInternalTransactionsCommandReply: + description: "Response for internal transaction command." + strict: false + fields: + responses: + description: "List of responses to commands in the transaction." + type: array<object> - TestInternalTransactionsCommandInfo: - description: "A command, its database name, and other test options" - strict: false - fields: - dbName: - type: string - command: - type: object - assertSucceeds: - type: bool - default: true - exhaustCursor: - type: bool - optional: true + TestInternalTransactionsCommandInfo: + description: "A command, its database name, and other test options." + strict: false + fields: + dbName: + type: string + command: + type: object + # TODO SERVER-64986: Remove assertSucceeds parameter. + assertSucceeds: + type: bool + default: true + exhaustCursor: + type: bool + optional: true commands: testInternalTransactions: @@ -62,13 +64,14 @@ commands: namespace: ignored api_version: "" fields: - useClusterClient: - description: "Whether the transaction API client used should opt into running the - 'cluster' versions of commands that enables a non-router node to run - the router versions of commands. Only meaningful on mongod because a - mongos will always run 'cluster' commands." - type: bool - default: false - commandInfos: - type: array<TestInternalTransactionsCommandInfo> - reply_type: TestInternalTransactionsReply + useClusterClient: + description: "Whether the transaction API client used should opt into running the + 'cluster' versions of commands that enables a non-router node to run + the router versions of commands. Only meaningful on mongod because a + mongos will always run 'cluster' commands." + type: bool + default: false + commandInfos: + description: "List of TestInternalTransactionsCommandInfos to run in a single transaction." + type: array<TestInternalTransactionsCommandInfo> + reply_type: TestInternalTransactionsCommandReply diff --git a/src/mongo/db/commands/internal_transactions_test_command_d.cpp b/src/mongo/db/commands/internal_transactions_test_command_d.cpp new file mode 100644 index 00000000000..6892bbb8e62 --- /dev/null +++ b/src/mongo/db/commands/internal_transactions_test_command_d.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * 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 Server Side 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_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand + +#include "mongo/db/cluster_transaction_api.h" +#include "mongo/db/transaction_participant_resource_yielder.h" +#include "mongo/s/commands/internal_transactions_test_command.h" + +namespace mongo { +namespace { + +class InternalTransactionsTestCommandD + : public InternalTransactionsTestCommandBase<InternalTransactionsTestCommandD> { +public: + static txn_api::TransactionWithRetries getTxn(OperationContext* opCtx, + ExecutorPtr executor, + StringData commandName, + bool useClusterClient) { + // If a sharded mongod is acting as a mongos, it will need special routing behaviors. + if (useClusterClient) { + return txn_api::TransactionWithRetries( + opCtx, + executor, + std::make_unique<txn_api::details::SEPTransactionClient>( + opCtx, + executor, + std::make_unique<txn_api::details::ClusterSEPTransactionClientBehaviors>( + opCtx->getServiceContext())), + TransactionParticipantResourceYielder::make(commandName)); + } + + return txn_api::TransactionWithRetries( + opCtx, executor, TransactionParticipantResourceYielder::make(commandName)); + } +}; + +MONGO_REGISTER_TEST_COMMAND(InternalTransactionsTestCommandD); +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 91a07c18245..be0eb7d5203 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -12,15 +12,10 @@ env.Library( source=[ 'flush_router_config_cmd.cpp', 'get_shard_map_cmd.cpp', - 'internal_transactions_test_commands.cpp', - 'internal_transactions_test_commands.idl', ], LIBDEPS_PRIVATE=[ - '$BUILD_DIR/mongo/db/cluster_transaction_api', '$BUILD_DIR/mongo/db/commands', - '$BUILD_DIR/mongo/db/transaction_api', '$BUILD_DIR/mongo/s/grid', - '$BUILD_DIR/mongo/s/sharding_router_api', '$BUILD_DIR/mongo/s/startup_initialization', ] ) @@ -98,6 +93,7 @@ env.Library( 'cluster_validate_db_metadata_cmd.cpp', 'cluster_whats_my_uri_cmd.cpp', 'cluster_write_cmd_s.cpp', + 'internal_transactions_test_command_s.cpp', 'kill_sessions_remote.cpp', 'refine_collection_shard_key.idl', 's_read_write_concern_defaults_server_status.cpp', diff --git a/src/mongo/s/commands/internal_transactions_test_commands.cpp b/src/mongo/s/commands/internal_transactions_test_command.h index 1843dd9c28e..dc4b7fc00c8 100644 --- a/src/mongo/s/commands/internal_transactions_test_commands.cpp +++ b/src/mongo/s/commands/internal_transactions_test_command.h @@ -30,40 +30,28 @@ #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/cluster_transaction_api.h" #include "mongo/db/commands.h" +#include "mongo/db/commands/internal_transactions_test_command_gen.h" #include "mongo/db/query/find_command_gen.h" #include "mongo/db/transaction_api.h" #include "mongo/logv2/log.h" -#include "mongo/s/commands/internal_transactions_test_commands_gen.h" #include "mongo/s/grid.h" -#include "mongo/s/transaction_router_resource_yielder.h" +#include "mongo/stdx/future.h" namespace mongo { namespace { -class InternalTransactionsTestCommand final : public TypedCommand<InternalTransactionsTestCommand> { +template <typename Impl> +class InternalTransactionsTestCommandBase : public TypedCommand<Impl> { public: using Request = TestInternalTransactions; - class Invocation final : public InvocationBase { + class Invocation final : public TypedCommand<Impl>::InvocationBase { public: - using InvocationBase::InvocationBase; - - TestInternalTransactionsReply typedRun(OperationContext* opCtx) { - Grid::get(opCtx)->assertShardingIsInitialized(); - - auto fixedExec = Grid::get(opCtx)->getExecutorPool()->getFixedExecutor(); - auto txn = txn_api::TransactionWithRetries( - opCtx, - fixedExec, - std::make_unique<txn_api::details::SEPTransactionClient>( - opCtx, - fixedExec, - std::make_unique<txn_api::details::ClusterSEPTransactionClientBehaviors>( - opCtx->getServiceContext())), - TransactionRouterResourceYielder::makeForLocalHandoff()); + using Base = typename TypedCommand<Impl>::InvocationBase; + using Base::Base; + TestInternalTransactionsCommandReply typedRun(OperationContext* opCtx) { struct SharedBlock { SharedBlock(std::vector<TestInternalTransactionsCommandInfo> commandInfos_) : commandInfos(commandInfos_) {} @@ -71,13 +59,29 @@ public: std::vector<TestInternalTransactionsCommandInfo> commandInfos; std::vector<BSONObj> responses; }; - auto sharedBlock = std::make_shared<SharedBlock>(request().getCommandInfos()); + + auto sharedBlock = std::make_shared<SharedBlock>(Base::request().getCommandInfos()); + + const auto executor = Grid::get(opCtx)->isShardingInitialized() + ? static_cast<ExecutorPtr>(Grid::get(opCtx)->getExecutorPool()->getFixedExecutor()) + : static_cast<ExecutorPtr>(getTransactionExecutor()); + + // If internalTransactionsTestCommand is received by a mongod, it should be instantiated + // with the TransactionParticipant's resource yielder. If on a mongos, txn should be + // instantiated with the TransactionRouter's resource yielder. + auto txn = Impl::getTxn(opCtx, + std::move(executor), + Base::request().kCommandName, + Base::request().getUseClusterClient()); // Swallow errors and let clients inspect the responses array to determine success / // failure. (void)txn.runSyncNoThrow( opCtx, [sharedBlock](const txn_api::TransactionClient& txnClient, ExecutorPtr txnExec) { + // Iterate through commands and record responses for each. Return immediately if + // we encounter a response with a retriedStmtId. This field indicates that the + // command and everything following it have already been executed. for (const auto& commandInfo : sharedBlock->commandInfos) { const auto& dbName = commandInfo.getDbName(); const auto& command = commandInfo.getCommand(); @@ -101,26 +105,27 @@ public: continue; } - auto res = txnClient.runCommand(dbName, command).get(); + const auto res = txnClient.runCommand(dbName, command).get(); sharedBlock->responses.emplace_back( CommandHelpers::filterCommandReplyForPassthrough( res.removeField("recoveryToken"))); + // TODO SERVER-64986: Remove assert check. if (assertSucceeds) { // Note this only inspects the top level ok field for non-write // commands. uassertStatusOK(getStatusFromWriteCommandReply(res)); } + // TODO SERVER-65048: Check if result has retriedStmtId & retriedStmtIds + // field, exit. } - return SemiFuture<void>::makeReady(); }); - - return TestInternalTransactionsReply(std::move(sharedBlock->responses)); + return TestInternalTransactionsCommandReply(std::move(sharedBlock->responses)); }; NamespaceString ns() const override { - return NamespaceString(request().getDbName(), ""); + return NamespaceString(Base::request().getDbName(), ""); } bool supportsWriteConcern() const override { @@ -134,6 +139,23 @@ public: ->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), ActionType::internal)); } + + const std::shared_ptr<ThreadPool>& getTransactionExecutor() { + static Mutex mutex = + MONGO_MAKE_LATCH("InternalTransactionsTestCommandExecutor::_mutex"); + static std::shared_ptr<ThreadPool> executor; + + stdx::lock_guard<Latch> lg(mutex); + if (!executor) { + ThreadPool::Options options; + options.poolName = "InternalTransaction"; + options.minThreads = 0; + options.maxThreads = 4; + executor = std::make_shared<ThreadPool>(std::move(options)); + executor->startup(); + } + return executor; + } }; std::string help() const override { @@ -146,11 +168,10 @@ public: return true; } - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kNever; + BasicCommand::AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return BasicCommand::AllowedOnSecondary::kNever; } }; -MONGO_REGISTER_TEST_COMMAND(InternalTransactionsTestCommand); } // namespace } // namespace mongo diff --git a/src/mongo/s/commands/internal_transactions_test_command_s.cpp b/src/mongo/s/commands/internal_transactions_test_command_s.cpp new file mode 100644 index 00000000000..16f141fb5e3 --- /dev/null +++ b/src/mongo/s/commands/internal_transactions_test_command_s.cpp @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * 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 Server Side 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. + */ + +#include "mongo/s/commands/internal_transactions_test_command.h" +#include "mongo/s/transaction_router_resource_yielder.h" + +namespace mongo { +namespace { + +class InternalTransactionsTestCommandS + : public InternalTransactionsTestCommandBase<InternalTransactionsTestCommandS> { +public: + static txn_api::TransactionWithRetries getTxn(OperationContext* opCtx, + ExecutorPtr executor, + StringData commandName, + bool useClusterClient) { + return txn_api::TransactionWithRetries( + opCtx, executor, TransactionRouterResourceYielder::makeForLocalHandoff()); + } +}; + +MONGO_REGISTER_TEST_COMMAND(InternalTransactionsTestCommandS); +} // namespace +} // namespace mongo |