From da5c96f5297c66b1d3920c5f0ab9e91da3b345f7 Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Mon, 12 Feb 2024 01:39:08 +0100 Subject: [PATCH 1/2] chore: Refactor and optimize MySQL advisory lock handling This commit removes unused MySQL lock variables, --- Makefile | 14 ++++++++++++++ docker-compose.yml | 20 ++++++++++++++++++++ lib/with_advisory_lock/mysql.rb | 14 ++++++++------ test/with_advisory_lock/shared_test.rb | 4 ++-- test/with_advisory_lock/thread_test.rb | 4 ++-- 5 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 Makefile create mode 100644 docker-compose.yml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..eb1d44e --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +.PHONY: test-pg test-mysql + +test-pg: + docker compose up -d pg + sleep 10 # give some time for the service to start + DATABASE_URL=postgres://with_advisory:with_advisory_pass@localhost/with_advisory_lock_test appraisal rake test + +test-mysql: + docker compose up -d mysql + sleep 10 # give some time for the service to start + DATABASE_URL=mysql2://with_advisory:with_advisory_pass@0.0.0.0:3306/with_advisory_lock_test appraisal rake test + + +test: test-pg test-mysql diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2440305 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: "3.9" +services: + pg: + image: postgres:16 + environment: + POSTGRES_USER: with_advisory + POSTGRES_PASSWORD: with_advisory_pass + POSTGRES_DB: with_advisory_lock_test + ports: + - "5432:5432" + mysql: + image: mysql:8 + environment: + MYSQL_USER: with_advisory + MYSQL_PASSWORD: with_advisory_pass + MYSQL_DATABASE: with_advisory_lock_test + MYSQL_RANDOM_ROOT_PASSWORD: "yes" + MYSQL_ROOT_HOST: '%' + ports: + - "3306:3306" diff --git a/lib/with_advisory_lock/mysql.rb b/lib/with_advisory_lock/mysql.rb index bdb35e7..3ca8ef9 100644 --- a/lib/with_advisory_lock/mysql.rb +++ b/lib/with_advisory_lock/mysql.rb @@ -2,10 +2,8 @@ module WithAdvisoryLock class MySQL < Base - # Caches nested lock support by MySQL reported version - @@mysql_nl_cache = {} - @@mysql_nl_cache_mutex = Mutex.new - # See https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock + # See https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html + # See https://dev.mysql.com/doc/refman/8.0/en/locking-functions.html def try_lock raise ArgumentError, 'shared locks are not supported on MySQL' if shared raise ArgumentError, 'transaction level locks are not supported on MySQL' if transaction @@ -18,8 +16,12 @@ def release_lock end def execute_successful?(mysql_function) - sql = "SELECT #{mysql_function} AS #{unique_column_name}" - connection.select_value(sql).to_i.positive? + execute_query(mysql_function) == 1 + end + + def execute_query(mysql_function) + sql = "SELECT #{mysql_function}" + connection.query_value(sql) end # MySQL wants a string as the lock key. diff --git a/test/with_advisory_lock/shared_test.rb b/test/with_advisory_lock/shared_test.rb index 7cd23a4..f2b0ba1 100644 --- a/test/with_advisory_lock/shared_test.rb +++ b/test/with_advisory_lock/shared_test.rb @@ -24,7 +24,7 @@ def cleanup! private def work - ApplicationRecord.connection_pool.with_connection do + Tag.connection_pool.with_connection do Tag.with_advisory_lock('test', timeout_seconds: 0, shared: @shared) do @locked = true sleep 0.01 until @cleanup @@ -117,7 +117,7 @@ class PostgreSQLTest < SupportedEnvironmentTest end def pg_lock_modes - ApplicationRecord.connection.select_values("SELECT mode FROM pg_locks WHERE locktype = 'advisory';") + Tag.connection.select_values("SELECT mode FROM pg_locks WHERE locktype = 'advisory';") end test 'allows shared lock to be upgraded to an exclusive lock' do diff --git a/test/with_advisory_lock/thread_test.rb b/test/with_advisory_lock/thread_test.rb index 2c86be0..4e00f27 100644 --- a/test/with_advisory_lock/thread_test.rb +++ b/test/with_advisory_lock/thread_test.rb @@ -10,7 +10,7 @@ class SeparateThreadTest < GemTestCase @t1_return_value = nil @t1 = Thread.new do - ApplicationRecord.connection_pool.with_connection do + Label.connection_pool.with_connection do @t1_return_value = Label.with_advisory_lock(@lock_name) do @mutex.synchronize { @t1_acquired_lock = true } sleep @@ -21,7 +21,7 @@ class SeparateThreadTest < GemTestCase # Wait for the thread to acquire the lock: sleep(0.1) until @mutex.synchronize { @t1_acquired_lock } - ApplicationRecord.connection.reconnect! + Label.connection.reconnect! end teardown do From 21fb861b3f29ff9b217ce2fa5e72dadc5e48833e Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Mon, 12 Feb 2024 01:51:02 +0100 Subject: [PATCH 2/2] chore: truncate table in tests --- test/test_helper.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 14b0d01..189bd4a 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -49,9 +49,11 @@ def is_postgresql_adapter?; adapter_support.postgresql?; end setup do ENV['FLOCK_DIR'] = Dir.mktmpdir if is_sqlite3_adapter? - Tag.delete_all - TagAudit.delete_all - Label.delete_all + ApplicationRecord.connection.truncate_tables( + Tag.table_name, + TagAudit.table_name, + Label.table_name + ) end teardown do @@ -60,3 +62,4 @@ def is_postgresql_adapter?; adapter_support.postgresql?; end end puts "Testing with #{env_db} database, ActiveRecord #{ActiveRecord.gem_version} and #{RUBY_ENGINE} #{RUBY_ENGINE_VERSION} as #{RUBY_VERSION}" +puts "Connection Pool size: #{ActiveRecord::Base.connection_pool.size}" \ No newline at end of file