lib/zk/locker/locker_base.rb in zk-1.4.2 vs lib/zk/locker/locker_base.rb in zk-1.5.0
- old
+ new
@@ -51,10 +51,13 @@
@path = name
@locked = false
@waiting = false
@lock_path = nil
@root_lock_path = "#{@root_lock_node}/#{@path.gsub("/", "__")}"
+ @mutex = Monitor.new
+ @cond = @mutex.new_cond
+ @node_deletion_watcher = nil
end
# block caller until lock is aquired, then yield
#
# there is no non-blocking version of this method
@@ -76,11 +79,11 @@
# # => 'lock000000007'
#
# @return [nil] if lock_path is not set
# @return [String] last path component of our lock path
def lock_basename
- lock_path and File.basename(lock_path)
+ synchronize { lock_path and File.basename(lock_path) }
end
# returns our current idea of whether or not we hold the lock, which does
# not actually check the state on the server.
#
@@ -89,12 +92,12 @@
# want to make double-triple certain of the state of the lock, use {#assert!}
#
# @return [true] if we hold the lock
# @return [false] if we don't hold the lock
#
- def locked?(check_if_any=false)
- false|@locked
+ def locked?
+ synchronize { !!@locked }
end
# * If this instance holds the lock {#locked? is true} we return true (as
# we have already succeeded in acquiring the lock)
# * If this instance doesn't hold the lock, we'll do a check on the server
@@ -117,16 +120,19 @@
# unlocked it successfully
#
# @return [false] we did not own the lock
#
def unlock
- if @locked
- cleanup_lock_path!
- @locked = false
- true
- else
- false # i know, i know, but be explicit
+ synchronize do
+ if @locked
+ cleanup_lock_path!
+ @locked = false
+ @node_deletion_watcher = nil
+ true
+ else
+ false # i know, i know, but be explicit
+ end
end
end
# (see #unlock)
# @deprecated the use of unlock! is deprecated and may be removed or have
@@ -159,16 +165,29 @@
def lock!(blocking=false)
lock(blocking)
end
# returns true if this locker is waiting to acquire lock
+ # this should be used in tests only.
#
# @private
def waiting?
- false|@waiting
+ synchronize do
+ !!(@node_deletion_watcher and @node_deletion_watcher.blocked?)
+ end
end
+ # blocks the caller until this lock is blocked
+ # @private
+ def wait_until_blocked(timeout=nil)
+ synchronize do
+ @cond.wait_until { @node_deletion_watcher }
+ end
+
+ @node_deletion_watcher.wait_until_blocked(timeout)
+ end
+
# This is for users who wish to check that the assumption is correct
# that they actually still hold the lock. (check for session interruption,
# perhaps a lock is obtained in one method and handed to another)
#
# This, unlike {#locked?} will actually go and check the conditions
@@ -194,23 +213,22 @@
# puts "hah! he thinks we're workin!"
# sleep(60)
# end
#
def assert!
- raise LockAssertionFailedError, "have not obtained the lock yet" unless locked?
- raise LockAssertionFailedError, "not connected" unless zk.connected?
- raise LockAssertionFailedError, "lock_path was #{lock_path.inspect}" unless lock_path
- raise LockAssertionFailedError, "the lock path #{lock_path} did not exist!" unless zk.exists?(lock_path)
- raise LockAssertionFailedError, "we do not actually hold the lock" unless got_lock?
+ synchronize do
+ raise LockAssertionFailedError, "have not obtained the lock yet" unless locked?
+ raise LockAssertionFailedError, "not connected" unless zk.connected?
+ raise LockAssertionFailedError, "lock_path was #{lock_path.inspect}" unless lock_path
+ raise LockAssertionFailedError, "the lock path #{lock_path} did not exist!" unless zk.exists?(lock_path)
+ raise LockAssertionFailedError, "we do not actually hold the lock" unless got_lock?
+ end
end
protected
- def in_waiting_status
- w, @waiting = @waiting, true
- yield
- ensure
- @waiting = w
+ def synchronize
+ @mutex.synchronize { yield }
end
def digit_from(path)
self.class.digit_from_lock_path(path)
end
@@ -243,11 +261,14 @@
# prefix is the string that will appear in front of the sequence num,
# defaults to 'lock'
#
def create_lock_path!(prefix='lock')
- @lock_path = @zk.create("#{root_lock_path}/#{prefix}", "", :mode => :ephemeral_sequential)
+ synchronize do
+ @lock_path = @zk.create("#{root_lock_path}/#{prefix}", "", :mode => :ephemeral_sequential)
+ end
+
logger.debug { "got lock path #{@lock_path}" }
@lock_path
rescue NoNode
create_root_path!
retry
@@ -255,14 +276,10 @@
def cleanup_lock_path!
logger.debug { "removing lock path #{@lock_path}" }
zk.delete(@lock_path)
- begin
- zk.delete(root_lock_path)
- rescue NotEmpty
- end
-
+ zk.delete(root_lock_path, :ignore => :not_empty)
@lock_path = nil
end
end # LockerBase
end # Locker
end # ZK