Skip to content

Commit 5b1ed5a

Browse files
authored
chore: refractor postgresql class (#99)
1 parent a078c31 commit 5b1ed5a

File tree

3 files changed

+41
-19
lines changed

3 files changed

+41
-19
lines changed

lib/with_advisory_lock.rb

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
loader.setup
1111

1212
module WithAdvisoryLock
13+
LOCK_PREFIX_ENV = 'WITH_ADVISORY_LOCK_PREFIX'.freeze
1314
end
1415

1516
ActiveSupport.on_load :active_record do

lib/with_advisory_lock/base.rb

+2-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def initialize(connection, lock_name, options)
3636
end
3737

3838
def lock_str
39-
@lock_str ||= "#{ENV['WITH_ADVISORY_LOCK_PREFIX']}#{lock_name}"
39+
@lock_str ||= "#{ENV[LOCK_PREFIX_ENV]}#{lock_name}"
4040
end
4141

4242
def lock_stack_item
@@ -56,9 +56,7 @@ def already_locked?
5656
def with_advisory_lock_if_needed(&block)
5757
if disable_query_cache
5858
return lock_and_yield do
59-
connection.uncached do
60-
yield
61-
end
59+
connection.uncached(&block)
6260
end
6361
end
6462

lib/with_advisory_lock/postgresql.rb

+38-15
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,65 @@
22

33
module WithAdvisoryLock
44
class PostgreSQL < Base
5-
# See http://www.postgresql.org/docs/9.1/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
5+
# See https://www.postgresql.org/docs/16/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
6+
7+
# MRI returns 't', jruby returns true. YAY!
8+
LOCK_RESULT_VALUES = ['t', true].freeze
9+
PG_ADVISORY_UNLOCK = 'pg_advisory_unlock'
10+
PG_TRY_ADVISORY = 'pg_try_advisory'
11+
ERROR_MESSAGE_REGEX = / ERROR: +current transaction is aborted,/
12+
613
def try_lock
7-
pg_function = "pg_try_advisory#{transaction ? '_xact' : ''}_lock#{shared ? '_shared' : ''}"
8-
execute_successful?(pg_function)
14+
execute_successful?(advisory_try_lock_function(transaction))
915
end
1016

1117
def release_lock
1218
return if transaction
1319

14-
pg_function = "pg_advisory_unlock#{shared ? '_shared' : ''}"
15-
execute_successful?(pg_function)
20+
execute_successful?(advisory_unlock_function)
1621
rescue ActiveRecord::StatementInvalid => e
17-
raise unless e.message =~ / ERROR: +current transaction is aborted,/
22+
raise unless e.message =~ ERROR_MESSAGE_REGEX
1823

1924
begin
2025
connection.rollback_db_transaction
21-
execute_successful?(pg_function)
26+
execute_successful?(advisory_unlock_function)
2227
ensure
2328
connection.begin_db_transaction
2429
end
2530
end
2631

32+
def advisory_try_lock_function(transaction_scope)
33+
[
34+
'pg_try_advisory',
35+
transaction_scope ? '_xact' : nil,
36+
'_lock',
37+
shared ? '_shared' : nil
38+
].compact.join
39+
end
40+
41+
def advisory_unlock_function
42+
[
43+
'pg_advisory_unlock',
44+
shared ? '_shared' : nil
45+
].compact.join
46+
end
47+
2748
def execute_successful?(pg_function)
49+
result = connection.select_value(prepare_sql(pg_function))
50+
LOCK_RESULT_VALUES.include?(result)
51+
end
52+
53+
def prepare_sql(pg_function)
2854
comment = lock_name.to_s.gsub(%r{(/\*)|(\*/)}, '--')
29-
sql = "SELECT #{pg_function}(#{lock_keys.join(',')}) AS #{unique_column_name} /* #{comment} */"
30-
result = connection.select_value(sql)
31-
# MRI returns 't', jruby returns true. YAY!
32-
['t', true].include?(result)
55+
"SELECT #{pg_function}(#{lock_keys.join(',')}) AS #{unique_column_name} /* #{comment} */"
3356
end
3457

3558
# PostgreSQL wants 2 32bit integers as the lock key.
3659
def lock_keys
37-
@lock_keys ||= [stable_hashcode(lock_name), ENV['WITH_ADVISORY_LOCK_PREFIX']].map do |ea|
38-
# pg advisory args must be 31 bit ints
39-
ea.to_i & 0x7fffffff
40-
end
60+
@lock_keys ||= [
61+
stable_hashcode(lock_name),
62+
ENV[LOCK_PREFIX_ENV]
63+
].map { |ea| ea.to_i & 0x7fffffff }
4164
end
4265
end
4366
end

0 commit comments

Comments
 (0)