class UncomplicatedMutex

Constants

LUA_ACQUIRE
LUA_RELEASE
MutexTimeout

Attributes

lock_name[R]

Public Class Methods

new(obj, opts = {}) click to toggle source
# File lib/uncomplicated_mutex.rb, line 12
def initialize(obj, opts = {})
  @verbose          = opts[:verbose]
  @timeout          = opts[:timeout] || 300
  @redis            = opts[:redis] || Redis.new
  @lock_name        = opts[:lock_name] || "lock:#{obj.class.name}:#{obj.id}".squeeze(":")
  @token            = Digest::MD5.new.hexdigest("#{@lock_name}_#{Time.now.to_f}")
  set_expiration_time
end

Public Instance Methods

acquire_mutex() click to toggle source
# File lib/uncomplicated_mutex.rb, line 21
def acquire_mutex
  puts("Running transaction to acquire the lock #{@lock_name}") if @verbose
  @redis.eval(LUA_ACQUIRE, [ @lock_name ], [ @timeout, @token ]) == 1
end
current_token_value() click to toggle source
# File lib/uncomplicated_mutex.rb, line 26
def current_token_value
  @redis.get(@lock_name)
end
destroy_mutex() click to toggle source
# File lib/uncomplicated_mutex.rb, line 30
def destroy_mutex
  puts("Destroying the lock #{@lock_name}") if @verbose
  @redis.del(@lock_name)
end
lock() { |block| ... } click to toggle source
# File lib/uncomplicated_mutex.rb, line 35
def lock(&block)
  begin
    wait_for_mutex
    yield block
  ensure
    release_mutex
  end
end
recurse_until_ready(depth = 1) click to toggle source
# File lib/uncomplicated_mutex.rb, line 44
def recurse_until_ready(depth = 1)
  return false if time_has_expired
  @initial_token = current_token_value if depth == 1
  wait_a_tick if depth > 1
  acquire_mutex || recurse_until_ready(depth + 1)
end
release_mutex() click to toggle source
# File lib/uncomplicated_mutex.rb, line 51
def release_mutex
  puts("Releasing the lock #{@lock_name} if it still holds the value '#{@token}'") if @verbose
  @redis.eval(LUA_RELEASE, [ @lock_name ], [ @token ])
end
same_token_as_before() click to toggle source
# File lib/uncomplicated_mutex.rb, line 56
def same_token_as_before
  new_token = current_token_value
  if new_token == @initial_token
    true
  else
    @initial_token = new_token
    false
  end
end
set_expiration_time() click to toggle source
# File lib/uncomplicated_mutex.rb, line 66
def set_expiration_time
  @expiration_time = Time.now.to_i + @timeout
end
time_has_expired() click to toggle source
# File lib/uncomplicated_mutex.rb, line 70
def time_has_expired
  if Time.now.to_i > @expiration_time
    if same_token_as_before
      true
    else
      set_expiration_time
      false
    end
  else
    false
  end
end
wait_a_tick() click to toggle source
# File lib/uncomplicated_mutex.rb, line 83
def wait_a_tick
  sleep_time = rand(100).to_f / 100.0
  puts("Sleeping #{sleep_time} for the lock #{@lock_name} to become available") if @verbose
  sleep(sleep_time)
end
wait_for_mutex() click to toggle source
# File lib/uncomplicated_mutex.rb, line 89
def wait_for_mutex
  if recurse_until_ready
    puts("Acquired lock #{@lock_name}") if @verbose
  else
    puts("Failed to acquire the lock") if @verbose
    raise MutexTimeout.new("Failed to acquire the lock")
  end
end