com.bigdata.zookeeper
Class ZLockImpl

java.lang.Object
  extended by com.bigdata.zookeeper.ZLockImpl
All Implemented Interfaces:
ZLock

public class ZLockImpl
extends Object
implements ZLock

ZLock implementation class. The lock request is realized as an EPHEMERAL SEQUENTIAL child of the lock node. If the lock request znode is in the first position of the lexically sorted children of the lock node then it holds the ZLock. Some points to note:

Assuming it has the correct ACL, any thread in any process MAY release the ZLock, NOT just the one that acquired it. This is done by deleting the EPHERMERAL znode corresponding to the lock request. The ZLock will also be lost if the ZooKeeper client is timed out by the zookeeper server ensemble. You can use isLockHeld() to determine if the ZLock has been broken asynchronously.

This class handles the KeeperException.SessionExpiredException by noting that the ZooKeeper client's lock (if it held one) has been lost since their ephemeral znode will have been destroyed by the zookeeper ensemble. The application MUST acquire a new ZLockImpl instance if they wish to contend for the lock again. A KeeperException.SessionExpiredException will be thrown from lock() or lock(long, TimeUnit) if the session expired while contending for the lock.

Since the zlock MAY be lost asynchronously (due to an expired session or even someone stomping on the lock), the application SHOULD test the lock using periodically using isLockHeld(). isLockHeld() will throw a KeeperException.SessionExpiredException if the session associated with the ZooKeeper instance is expired. Otherwise it reports true if the lock is still held and false if the lock was lost to some other cause, e.g. unlock() or someone stomping on the lock. The application SHOULD handle an expired session using its own semantics for the operation for which it obtained the lock and MAY choose to obtain a new ZLockImpl using a new ZooKeeper client and its associated session and contend for the zlock again.

Version:
$Id$
Author:
Bryan Thompson
See Also:
getLock(ZooKeeper, String, List)

Nested Class Summary
protected  class ZLockImpl.ZLockWatcher
          Inner class provides watcher for the lock.
 
Field Summary
protected  List<org.apache.zookeeper.data.ACL> acl
           
protected static boolean DEBUG
           
protected static boolean INFO
           
static String INVALID
          The suffix for a marker that is a sibling of the lock node.
protected static org.apache.log4j.Logger log
           
protected  String zpath
          The zpath of the lock node (the parent node whose ephemeral sequential children represent the queue of processes contending for the lock).
 
Constructor Summary
protected ZLockImpl(org.apache.zookeeper.ZooKeeper zookeeper, String zpath, List<org.apache.zookeeper.data.ACL> acl)
          The ctor merely validates the arguments.
 
Method Summary
 void destroyLock()
          Creates a marker node (a sibling of the lock node) to prevent new children from being added to the queue and then deletes all children in the queue in reverse lexical order so as to not trigger cascades of watchers and finally deletes the lock node itself and then the marker node.
static ZLockImpl getLock(org.apache.zookeeper.ZooKeeper zookeeper, String zpath, List<org.apache.zookeeper.data.ACL> acl)
          Factory for a ZLock which may be used to contend for the a global synchronous lock.
 String getLockRequestZNode()
          The EPHEMERAL znode (not zpath) representing the lock request and null iff the ZLockImpl is not contending for the lock.
 String[] getQueue()
          Returns the ordered queue.
 org.apache.zookeeper.ZooKeeper getZooKeeper()
          The ZooKeeper instance specified to the ctor.
 String getZPath()
          The zpath of the lock node.
 boolean isLockHeld()
          Synchronously verifies that the lock is still held by testing the children of the lock node.
 void lock()
          Creates a new lock request (an EPHEMERAL SEQUENTIAL znode that is a child of the lock node) and waits for the ZLock to be granted.
 void lock(long timeout, TimeUnit unit)
          Creates a new lock request (an EPHEMERAL SEQUENTIAL znode that is a child of the lock node) and awaits up to the timeout for the ZLock to be granted.
 String toString()
          Non-blocking representation of lock state (does not tell you if the lock is held).
 void unlock()
          Releases the ZLock.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

log

protected static final org.apache.log4j.Logger log

INFO

protected static final boolean INFO

DEBUG

protected static final boolean DEBUG

INVALID

public static final transient String INVALID
The suffix for a marker that is a sibling of the lock node. The presence of this marker indicates that the queue is being destroyed. The #isConditionSatisified() logic will not allow a lock to be granted if this marker is found. Likewise, new children are not permitted into the queue when this marker is present. Note: If you are monitoring a znode whose children a lock nodes, then a child ending with this string IS NOT a lock node!

See Also:
Constant Field Values

zpath

protected final String zpath
The zpath of the lock node (the parent node whose ephemeral sequential children represent the queue of processes contending for the lock).


acl

protected final List<org.apache.zookeeper.data.ACL> acl
Constructor Detail

ZLockImpl

protected ZLockImpl(org.apache.zookeeper.ZooKeeper zookeeper,
                    String zpath,
                    List<org.apache.zookeeper.data.ACL> acl)
The ctor merely validates the arguments. No action is taken until the lock is requested.

Parameters:
zookeeper - The ZooKeeper client instance that will be used to request the lock.
zpath - The zpath of the lock node.
acl -
Throws:
IllegalArgumentException - if any argument is null.
Method Detail

getLock

public static ZLockImpl getLock(org.apache.zookeeper.ZooKeeper zookeeper,
                                String zpath,
                                List<org.apache.zookeeper.data.ACL> acl)
Factory for a ZLock which may be used to contend for the a global synchronous lock.

Parameters:
zookeeper - The Zookeeper client instance that will be used to request the lock.
zpath - The path identifying the lock node.
acl - The ACL to be used.
Returns:
A ZLockImpl which may be used to request a global synchronous lock.
Throws:
IllegalArgumentException - if any argument is null.

getZooKeeper

public org.apache.zookeeper.ZooKeeper getZooKeeper()
The ZooKeeper instance specified to the ctor.


toString

public String toString()
Non-blocking representation of lock state (does not tell you if the lock is held).

Overrides:
toString in class Object

getZPath

public final String getZPath()
The zpath of the lock node.


getLockRequestZNode

public String getLockRequestZNode()
                           throws InterruptedException
The EPHEMERAL znode (not zpath) representing the lock request and null iff the ZLockImpl is not contending for the lock.

Throws:
InterruptedException

isLockHeld

public boolean isLockHeld()
                   throws InterruptedException,
                          org.apache.zookeeper.KeeperException
Synchronously verifies that the lock is still held by testing the children of the lock node. This is necessary in order to avoid snafus such as
 lock.unlock();
 lock.isLockHeld()==true
 
where the process still things it holds the lock.

There are distributed variants of this snafu as well. For example, someone deletes the znode corresponding to the lock request. If we do not synchronously verify that the lock request znode still exists then we will fail to notice that someone else now holds the lock!

As an optimization, we do not test zookeeper if we have already been informed that the ZLock has been lost.

Specified by:
isLockHeld in interface ZLock
Returns:
true iff the lock is held.
Throws:
org.apache.zookeeper.KeeperException
org.apache.zookeeper.KeeperException.SessionExpiredException - IFF the lock was lost because the zookeeper session expired.
InterruptedException

lock

public void lock()
          throws org.apache.zookeeper.KeeperException,
                 InterruptedException
Creates a new lock request (an EPHEMERAL SEQUENTIAL znode that is a child of the lock node) and waits for the ZLock to be granted.

Specified by:
lock in interface ZLock
Throws:
org.apache.zookeeper.KeeperException - if the lock node or the ephemeral child could not be created.
org.apache.zookeeper.KeeperException.SessionExpiredException - If the ZooKeeper client's session was expired. note that this exception is non-recoverable for a given ZooKeeper instance. However, if the application handles the exception according to its own semantics then it MAY obtain a new ZooKeeper instance associated with a new session.
InterruptedException - if the thread was interrupted while awaiting the lock.

lock

public void lock(long timeout,
                 TimeUnit unit)
          throws org.apache.zookeeper.KeeperException,
                 InterruptedException,
                 TimeoutException
Description copied from interface: ZLock
Creates a new lock request (an EPHEMERAL SEQUENTIAL znode that is a child of the lock node) and awaits up to the timeout for the ZLock to be granted.

Specified by:
lock in interface ZLock
Parameters:
timeout - The timeout.
unit - The unit in which that timeout is expressed.
Throws:
org.apache.zookeeper.KeeperException
org.apache.zookeeper.KeeperException.SessionExpiredException - If the ZooKeeper client's session was expired. note that this exception is non-recoverable for a given ZooKeeper instance. However, if the application handles the exception according to its own semantics then it MAY obtain a new ZooKeeper instance associated with a new session.
InterruptedException - if the thread was interrupted while awaiting the lock.
TimeoutException - if the timeout noticeably expired before the lock was granted.

unlock

public void unlock()
            throws org.apache.zookeeper.KeeperException,
                   InterruptedException
Releases the ZLock. A warning is logged if the ZLock was asynchronously broken. Use isLockHeld() to verify that you still hold the ZLock.

Specified by:
unlock in interface ZLock
Throws:
IllegalStateException - if the caller had never acquired the ZLock.
org.apache.zookeeper.KeeperException
InterruptedException

destroyLock

public void destroyLock()
                 throws org.apache.zookeeper.KeeperException,
                        InterruptedException
Creates a marker node (a sibling of the lock node) to prevent new children from being added to the queue and then deletes all children in the queue in reverse lexical order so as to not trigger cascades of watchers and finally deletes the lock node itself and then the marker node. If we get a KeeperException.SessionExpiredException then we abort.

Specified by:
destroyLock in interface ZLock
Throws:
org.apache.zookeeper.KeeperException
InterruptedException

getQueue

public String[] getQueue()
                  throws org.apache.zookeeper.KeeperException,
                         InterruptedException
Returns the ordered queue.

Returns:
Throws:
org.apache.zookeeper.KeeperException
InterruptedException


Copyright © 2006-2009 SYSTAP, LLC. All Rights Reserved.