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