From d90484129655677ad245a8078bcbac238fedefb6 Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov Date: Thu, 11 Jan 2024 11:54:27 +0100 Subject: [PATCH 1/4] RUBY-1791 Raise if transactions not supported --- lib/mongo/error.rb | 1 + lib/mongo/error/transactions_not_supported.rb | 36 +++++++++++++++++++ lib/mongo/server/description/features.rb | 1 + lib/mongo/session.rb | 15 ++++++++ spec/mongo/session_transaction_spec.rb | 13 +++++++ 5 files changed, 66 insertions(+) create mode 100644 lib/mongo/error/transactions_not_supported.rb diff --git a/lib/mongo/error.rb b/lib/mongo/error.rb index 36296735d7..92d6d5f4b3 100644 --- a/lib/mongo/error.rb +++ b/lib/mongo/error.rb @@ -217,6 +217,7 @@ def write_concern_error_labels require 'mongo/error/server_api_conflict' require 'mongo/error/server_api_not_supported' require 'mongo/error/server_not_usable' +require 'mongo/error/transactions_not_supported' require 'mongo/error/unknown_payload_type' require 'mongo/error/unmet_dependency' require 'mongo/error/unsupported_option' diff --git a/lib/mongo/error/transactions_not_supported.rb b/lib/mongo/error/transactions_not_supported.rb new file mode 100644 index 0000000000..90e7b8d2da --- /dev/null +++ b/lib/mongo/error/transactions_not_supported.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +# rubocop:todo all + +# Copyright (C) 2019-2020 MongoDB Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Mongo + class Error + + # Transactions are not supported by the cluster. There might be the + # following reasons: + # - topology is standalone + # - topology is replica set and server version is < 4.0 + # - topology is sharded and server version is < 4.2 + # + # @param [ String ] reason The reason why transactions are no supported. + # + # @since 2.7.0 + class TransactionsNotSupported < Error + def initialize(reason) + super("Transactions are not supported for the cluster: #{reason}") + end + end + end +end diff --git a/lib/mongo/server/description/features.rb b/lib/mongo/server/description/features.rb index 849374546c..97a222713b 100644 --- a/lib/mongo/server/description/features.rb +++ b/lib/mongo/server/description/features.rb @@ -48,6 +48,7 @@ class Features # provided by the client during findAndModify operations, requiring the # driver to raise client-side errors when those options are provided. find_and_modify_option_validation: 8, + sharded_transactions: 8, transactions: 7, scram_sha_256: 7, array_filters: 6, diff --git a/lib/mongo/session.rb b/lib/mongo/session.rb index bc12896af0..6498067316 100644 --- a/lib/mongo/session.rb +++ b/lib/mongo/session.rb @@ -538,6 +538,8 @@ def with_transaction(options=nil) # # @since 2.6.0 def start_transaction(options = nil) + check_transactions_supported! + if options Lint.validate_read_concern_option(options[:read_concern]) @@ -1185,5 +1187,18 @@ def check_matching_cluster!(client) raise Mongo::Error::InvalidSession.new(MISMATCHED_CLUSTER_ERROR_MSG) end end + + def check_transactions_supported! + raise Mongo::Error::TransactionsNotSupported, "standalone topology" if cluster.single? + + cluster.next_primary.with_connection do |conn| + if cluster.replica_set? && !conn.features.transactions_enabled? + raise Mongo::Error::TransactionsNotSupported, "server version is < 4.0" + end + if cluster.sharded? && !conn.features.sharded_transactions_enabled? + raise Mongo::Error::TransactionsNotSupported, "sharded transactions require server version >= 4.2" + end + end + end end end diff --git a/spec/mongo/session_transaction_spec.rb b/spec/mongo/session_transaction_spec.rb index 851b08433f..fc4c21da6a 100644 --- a/spec/mongo/session_transaction_spec.rb +++ b/spec/mongo/session_transaction_spec.rb @@ -26,6 +26,17 @@ class SessionTransactionSpecError < StandardError; end collection.delete_many end + describe 'start_transaction' do + context 'when topology is sharded and server is < 4.2' do + max_server_fcv '4.2' + require_topology :sharded + + it 'raises an error' do + expect { session.start_transaction }.to raise_error(Mongo::Error::TransactionsNotSupported, /sharded transactions require server version/) + end + end + end + describe '#abort_transaction' do require_topology :replica_set @@ -75,6 +86,8 @@ class SessionTransactionSpecError < StandardError; end end describe '#with_transaction' do + require_topology :replica_set + context 'callback successful' do it 'commits' do session.with_transaction do From 4ab601626b67aab857006f5936e19974166e6365 Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov Date: Thu, 11 Jan 2024 14:54:28 +0100 Subject: [PATCH 2/4] Fix spec --- spec/mongo/session_transaction_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/mongo/session_transaction_spec.rb b/spec/mongo/session_transaction_spec.rb index fc4c21da6a..5c9f159308 100644 --- a/spec/mongo/session_transaction_spec.rb +++ b/spec/mongo/session_transaction_spec.rb @@ -28,7 +28,7 @@ class SessionTransactionSpecError < StandardError; end describe 'start_transaction' do context 'when topology is sharded and server is < 4.2' do - max_server_fcv '4.2' + max_server_fcv '4.1' require_topology :sharded it 'raises an error' do From b14aebb73d3e3f9edc1b70966c6597a00383ea64 Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov Date: Thu, 11 Jan 2024 17:10:41 +0100 Subject: [PATCH 3/4] 1791 --- spec/mongo/session_transaction_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/mongo/session_transaction_spec.rb b/spec/mongo/session_transaction_spec.rb index 5c9f159308..37fcc92f08 100644 --- a/spec/mongo/session_transaction_spec.rb +++ b/spec/mongo/session_transaction_spec.rb @@ -136,6 +136,7 @@ class SessionTransactionSpecError < StandardError; end expect(Mongo::Utils).to receive(:monotonic_time).ordered.and_return(start + 1) expect(Mongo::Utils).to receive(:monotonic_time).ordered.and_return(start + 2) expect(Mongo::Utils).to receive(:monotonic_time).ordered.and_return(start + 200) + allow(session).to receive('check_transactions_supported!').and_return true expect do session.with_transaction do @@ -169,6 +170,7 @@ class SessionTransactionSpecError < StandardError; end expect(Mongo::Utils).to receive(:monotonic_time).ordered.and_return(start + i) end expect(Mongo::Utils).to receive(:monotonic_time).ordered.and_return(start + 200) + allow(session).to receive('check_transactions_supported!').and_return true exc = Mongo::Error::OperationFailure.new('timeout test') exc.add_label(label) From 2ce09dfaeb25666cbed8a96e97b19edd32ca2c0e Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov Date: Mon, 15 Jan 2024 13:21:11 +0100 Subject: [PATCH 4/4] Fix code review remarks --- lib/mongo/error/transactions_not_supported.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mongo/error/transactions_not_supported.rb b/lib/mongo/error/transactions_not_supported.rb index 90e7b8d2da..bbaa6c7c58 100644 --- a/lib/mongo/error/transactions_not_supported.rb +++ b/lib/mongo/error/transactions_not_supported.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -# rubocop:todo all # Copyright (C) 2019-2020 MongoDB Inc. # @@ -17,7 +16,6 @@ module Mongo class Error - # Transactions are not supported by the cluster. There might be the # following reasons: # - topology is standalone