lib/mysql_getlock.rb in mysql_getlock-0.2.1 vs lib/mysql_getlock.rb in mysql_getlock-0.2.2
- old
+ new
@@ -3,34 +3,37 @@
class MysqlGetlock
attr_reader :mysql2, :key, :logger, :timeout
TIMEOUT = -1 # inifinity
+ PSEUDO_INFINITE_TIMEOUT = 4294967295 # for < 5.5.8
class Error < ::StandardError; end
class LockError < ::StandardError; end
def initialize(mysql2:, key:, logger: nil, timeout: TIMEOUT)
self.mysql2 = mysql2
- @key = Mysql2::Client.escape(key)
- @logger = logger
- @timeout = timeout
+ set_key(key)
+ set_logger(logger)
+ set_timeout(timeout)
end
# Use this setter if you reconnect mysql2 (which means renew Mysql2::Client instance),
# but still want to use same MysqlGetlock instance
def mysql2=(mysql2)
@mysql2 = mysql2
+ @mysql_version = nil
@multiple_lockable = nil
+ @infinite_timeoutable = nil
end
def lock
if !multiple_lockable? and (current_session_key and current_session_key != key)
raise Error, "get_lock() is already issued in the same connection for '#{current_session_key}'"
end
- logger.info { "#{log_head}Wait #{timeout < 0 ? '' : "#{timeout} sec "}to acquire a mysql lock '#{key}'" } if logger
+ logger.info { "#{log_head}Wait #{timeout < -1 ? '' : "#{timeout} sec "}to acquire a mysql lock '#{key}'" } if logger
results = mysql2.query(%Q[select get_lock('#{key}', #{timeout})], as: :array)
case results.to_a.first.first
when 1
logger.info { "#{log_head}Acquired a mysql lock '#{key}'" } if logger
set_current_session_key(key)
@@ -90,20 +93,50 @@
end
end
private
+ def set_timeout(timeout)
+ if infinite_timeoutable?
+ @timeout = timeout
+ else
+ # To support MySQL < 5.5.8, put large number of seconds to express infinite timeout spuriously
+ @timeout = (timeout < 0 ? PSEUDO_INFINITE_TIMEOUT : timeout)
+ end
+ end
+
+ def set_key(key)
+ @key = Mysql2::Client.escape(key)
+ end
+
+ def set_logger(logger)
+ @logger = logger
+ end
+
def log_head
"PID-#{::Process.pid} TID-#{::Thread.current.object_id.to_s(36)}: "
end
# From MySQL 5.7.5, multiple simultaneous locks can be acquired
def multiple_lockable?
return @multiple_lockable unless @multiple_lockable.nil?
+ major, minor, patch = mysql_version
+ @multiple_lockable = (major > 5) || (major == 5 && minor > 7) || (major == 5 && minor == 7 && patch >= 5)
+ end
+
+ # Before MySQL 5.5.8, a negative timeout value means infinite timeout on Windows. As of 5.5.8, this behavior applies on all platforms.
+ def infinite_timeoutable?
+ return @infinite_timeoutable unless @infinite_timeoutable.nil?
+ major, minor, patch = mysql_version
+ @infinite_timeoutable = (major > 5) || (major == 5 && minor > 5) || (major == 5 && minor == 5 && patch >= 8)
+ end
+
+ def mysql_version
+ return @mysql_version if @mysql_version
results = mysql2.query('select version()', as: :array)
version = results.to_a.first.first
major, minor, patch = version.split('.').map(&:to_i)
- @multiple_lockable = (major > 5) || (major == 5 && minor > 7) || (major == 5 && minor == 7 && patch >= 5)
+ @mysql_version = [major, minor, patch]
end
# Before MySQL 5.7.5, only a single simultaneous lock can be acquired
@session_keys = {}