diff --git a/.rubocop.yml b/.rubocop.yml index 488493f..5955f09 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ --- -require: +plugins: - rubocop-performance - rubocop-rake - rubocop-minitest diff --git a/test/prof_stack2.rb b/test/prof_stack2.rb index f0ced04..f893a01 100644 --- a/test/prof_stack2.rb +++ b/test/prof_stack2.rb @@ -16,13 +16,13 @@ def run case mode = ENV.fetch('PROFILE_MODE', :single).to_sym when :single - execute(client, mode) do |client| - ATTEMPTS.times { |i| client.call('get', "key#{i}") } + execute(client, mode) do |cli| + ATTEMPTS.times { |i| cli.call('get', "key#{i}") } end when :transaction - execute(client, mode) do |client| + execute(client, mode) do |cli| ATTEMPTS.times do |i| - client.multi do |tx| + cli.multi do |tx| SIZE.times do |j| n = SIZE * i + j tx.call('set', "{group:#{i}}:key:#{n}", n) @@ -31,9 +31,9 @@ def run end end when :pipeline - execute(client, mode) do |client| + execute(client, mode) do |cli| ATTEMPTS.times do |i| - client.pipelined do |pi| + cli.pipelined do |pi| SIZE.times do |j| n = SIZE * i + j pi.call('get', "key#{n}") diff --git a/test/test_concurrency.rb b/test/test_concurrency.rb index 0f816cf..2e044bd 100644 --- a/test/test_concurrency.rb +++ b/test/test_concurrency.rb @@ -132,6 +132,84 @@ def test_threading_with_transaction assert_equal(WANT, @client.call('GET', '{key}1')) end + def test_ractor + skip('Ractor is not available') unless Object.const_defined?(:Ractor, false) + skip("#{RedisClient.default_driver} is not safe for Ractor") if RedisClient.default_driver != RedisClient::RubyConnection + skip('OpenSSL gem has non-shareable objects') if TEST_REDIS_SSL + skip('test case may get stuck') if RUBY_ENGINE == 'ruby' && RUBY_ENGINE_VERSION.split('.').take(2).join('.').to_f < 3.1 + + ractors = Array.new(MAX_THREADS) do |i| + Ractor.new(i) do |i| + c = ::RedisClient.cluster( + nodes: TEST_NODE_URIS, + fixed_hostname: TEST_FIXED_HOSTNAME, + **TEST_GENERIC_OPTIONS + ).new_client + c.call('get', "key#{i}") + rescue StandardError => e + e + ensure + c&.close + end + end + + ractors.each { |r| assert_equal(WANT, r.take) } + end + + def test_ractor_with_pipelining + skip('Ractor is not available') unless Object.const_defined?(:Ractor, false) + skip("#{RedisClient.default_driver} is not safe for Ractor") if RedisClient.default_driver != RedisClient::RubyConnection + skip('OpenSSL gem has non-shareable objects') if TEST_REDIS_SSL + skip('test case may get stuck') if RUBY_ENGINE == 'ruby' && RUBY_ENGINE_VERSION.split('.').take(2).join('.').to_f < 3.1 + + ractors = Array.new(MAX_THREADS) do |i| + Ractor.new(i) do |i| + c = ::RedisClient.cluster( + nodes: TEST_NODE_URIS, + fixed_hostname: TEST_FIXED_HOSTNAME, + **TEST_GENERIC_OPTIONS + ).new_client + c.pipelined do |pi| + pi.call('get', "key#{i}") + pi.call('echo', 'hi') + end + rescue StandardError => e + e + ensure + c&.close + end + end + + ractors.each { |r| assert_equal([WANT, 'hi'], r.take) } + end + + def test_ractor_with_transaction + skip('Ractor is not available') unless Object.const_defined?(:Ractor, false) + skip("#{RedisClient.default_driver} is not safe for Ractor") if RedisClient.default_driver != RedisClient::RubyConnection + skip('OpenSSL gem has non-shareable objects') if TEST_REDIS_SSL + skip('test case may get stuck') if RUBY_ENGINE == 'ruby' && RUBY_ENGINE_VERSION.split('.').take(2).join('.').to_f < 3.1 + + ractors = Array.new(MAX_THREADS) do |i| + Ractor.new(i) do |i| + c = ::RedisClient.cluster( + nodes: TEST_NODE_URIS, + fixed_hostname: TEST_FIXED_HOSTNAME, + **TEST_GENERIC_OPTIONS + ).new_client + c.multi(watch: ["key#{i}"]) do |tx| + tx.call('incr', "key#{i}") + tx.call('incr', "key#{i}") + end + rescue StandardError => e + e + ensure + c&.close + end + end + + ractors.each { |r| assert_equal([2, 3], r.take) } + end + private def new_test_client diff --git a/test/testing_constants.rb b/test/testing_constants.rb index 6dcf724..2252128 100644 --- a/test/testing_constants.rb +++ b/test/testing_constants.rb @@ -86,4 +86,9 @@ BENCH_ENVOY_OPTIONS = { port: 7000, protocol: 2 }.freeze BENCH_REDIS_CLUSTER_PROXY_OPTIONS = { port: 7001, protocol: 2 }.freeze +if Object.const_defined?(:Ractor, false) && Ractor.respond_to?(:make_shareable) + Ractor.make_shareable(TEST_NODE_URIS) + Ractor.make_shareable(TEST_GENERIC_OPTIONS) +end + # rubocop:enable Lint/UnderscorePrefixedVariableName