Skip to content

Instantly share code, notes, and snippets.

@jeffomatic
Created April 29, 2012 00:52
Show Gist options
  • Save jeffomatic/2522979 to your computer and use it in GitHub Desktop.
Save jeffomatic/2522979 to your computer and use it in GitHub Desktop.
Blog: Redis as a mutex service, Code: redis_spinlock
# CAVEAT EMPTOR: This is excerpted code that I pulled out of context,
# re-arranged, renamed the variables of, and otherwise dicked around with
# a lot without having put it back into a Ruby interpreter, so it's
# possible that there's some gnarly typo or bug in here. In short, don't
# cut-and-paste this code.
class AlreadyLockedException < Exception; end
def redis_spinlock(redis, lock_handle, opts = {}, &critical_section)
lock_set = opts[:lock_set] || 'named_locks'
sleep_time = opts[:sleep] || 0.1
spins = 0
begin
# Attempt to acquire the lock by adding our lock handle to the set of
# locks. If the number of elements added to the set isn't 1, then
# another process has already acquired the lock.
#
# Syntax subtlety: in somewhat obsequious fashion, the Ruby Redis
# client returns bool(true) rather than int(1) if the element was
# successfully inserted and was not passed as a single-element
# array.
added = redis.sadd lock_set, lock_handle
raise AlreadyLockedException unless added === 1 || added === true
begin
# Here, we'll perform the operation that originally required the
# lock. We'll pass the number of times we had to spin on the lock
# to the received block of code. In most cases, you'll probably
# only care whether the spin count was zero or non-zero, i.e.,
# whether you actually had to compete with another process for the
# lock.
critical_section.call(spins)
ensure
# Unlock, even if we run into errors
redis.srem lock_set, lock_handle
end
rescue AlreadyLockedException
spins += 1
sleep(sleep_time) if sleep_time > 0
retry
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment