class MysqlGetlock
Constants
- PSEUDO_INFINITE_TIMEOUT
- TIMEOUT
- VERSION
Attributes
key[R]
logger[R]
mysql2[R]
timeout[R]
Public Class Methods
new(mysql2:, key:, logger: nil, timeout: TIMEOUT)
click to toggle source
# File lib/mysql_getlock.rb, line 13 def initialize(mysql2:, key:, logger: nil, timeout: TIMEOUT) self.mysql2 = mysql2 set_key(key) set_logger(logger) set_timeout(timeout) end
Private Class Methods
session_keys()
click to toggle source
# File lib/mysql_getlock.rb, line 161 def self.session_keys @session_keys end
Public Instance Methods
lock()
click to toggle source
# File lib/mysql_getlock.rb, line 29 def lock _lock(@timeout) end
locked?()
click to toggle source
# File lib/mysql_getlock.rb, line 57 def locked? results = mysql2.query(%Q[select is_used_lock('#{key}')], as: :array) !!results.to_a.first.first end
mysql2=(mysql2)
click to toggle source
Use this setter if you reconnect mysql2 (which means renew Mysql2::Client instance), but still want to use same MysqlGetlock
instance
# File lib/mysql_getlock.rb, line 22 def mysql2=(mysql2) @mysql2 = mysql2 @mysql_version = nil @multiple_lockable = nil @infinite_timeoutable = nil end
self_locked?()
click to toggle source
return true if locked by myself
# File lib/mysql_getlock.rb, line 63 def self_locked? results = mysql2.query(%Q[select is_used_lock('#{key}')], as: :array) lock_id = results.to_a.first.first return nil if lock_id.nil? results = mysql2.query(%Q[select connection_id()], as: :array) self_id = results.to_a.first.first self_id == lock_id end
synchronize() { || ... }
click to toggle source
# File lib/mysql_getlock.rb, line 72 def synchronize(&block) raise LockError unless lock begin yield ensure unlock end end
try_lock()
click to toggle source
# File lib/mysql_getlock.rb, line 33 def try_lock _lock(0) end
unlock()
click to toggle source
# File lib/mysql_getlock.rb, line 37 def unlock if !multiple_lockable? and (current_session_key and current_session_key != key) raise Error, "get_lock() was issued for another key '#{current_session_key}', please unlock it beforehand" end results = mysql2.query(%Q[select release_lock('#{key}')], as: :array) release_current_session_key case results.to_a.first.first when 1 logger.info { "#{log_head}Released a mysql lock '#{key}'" } if logger true when 0 logger.info { "#{log_head}Failed to release a mysql lock since somebody else locked '#{key}'" } if logger false else # nil logger.info { "#{log_head}Mysql lock did not exist '#{key}'" } if logger true end end
Private Instance Methods
_lock(timeout)
click to toggle source
# File lib/mysql_getlock.rb, line 83 def _lock(timeout) 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 if timeout == 0 # try_lock # no wait else logger.info { "#{log_head}Wait #{timeout < -1 ? '' : "#{timeout} sec "}to acquire a mysql lock '#{key}'" } if logger end 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) true when 0 if timeout == 0 # try_lock logger.info { "#{log_head}A mysql lock is already acquired by the other session '#{key}'" } if logger else logger.info { "#{log_head}Timeout to acquire a mysql lock '#{key}'" } if logger end release_current_session_key false else # nil logger.info { "#{log_head}Unknown Error to acquire a mysql lock '#{key}'" } if logger release_current_session_key false end end
current_session_key()
click to toggle source
# File lib/mysql_getlock.rb, line 165 def current_session_key MysqlGetlock.session_keys[mysql2.object_id] end
infinite_timeoutable?()
click to toggle source
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.
# File lib/mysql_getlock.rb, line 144 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
log_head()
click to toggle source
# File lib/mysql_getlock.rb, line 132 def log_head "PID-#{::Process.pid} TID-#{::Thread.current.object_id.to_s(36)}: " end
multiple_lockable?()
click to toggle source
From MySQL 5.7.5, multiple simultaneous locks can be acquired
# File lib/mysql_getlock.rb, line 137 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
mysql_version()
click to toggle source
# File lib/mysql_getlock.rb, line 150 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) @mysql_version = [major, minor, patch] end
release_current_session_key()
click to toggle source
# File lib/mysql_getlock.rb, line 173 def release_current_session_key MysqlGetlock.session_keys.delete(mysql2.object_id) end
set_current_session_key(key)
click to toggle source
# File lib/mysql_getlock.rb, line 169 def set_current_session_key(key) MysqlGetlock.session_keys[mysql2.object_id] = key end
set_key(key)
click to toggle source
# File lib/mysql_getlock.rb, line 124 def set_key(key) @key = Mysql2::Client.escape(key) end
set_logger(logger)
click to toggle source
# File lib/mysql_getlock.rb, line 128 def set_logger(logger) @logger = logger end
set_timeout(timeout)
click to toggle source
# File lib/mysql_getlock.rb, line 115 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