org.hsqldb
Class LockFile

java.lang.Object
  extended byorg.hsqldb.LockFile

public class LockFile
extends Object

The base HSQLDB cooperative file locking implementation and factory.


Here is the way this class operates:

  1. A file with a well-known path relative to each database instance is used to implement cooperative locking of database files across process boundaries (database instances running in different JVM host processes) and class loader contexts (databases whose classes have been loaded by distinct class loaders such that their open database repositories are distinct and are inaccessible across the class loader context boundaries).

  2. A background thread periodically writes a timestamp to this object's lock file at HEARTBEAT_INTERVAL millisecond intervals, acting as a heartbeat to indicate that a lock is still held.

  3. The generic lock attempt rules are:

  4. The generic release attempt rules are:

In addition to the generic lock and release rules, the protected methods lockImpl() and releaseImpl() are called during lock and release attempts, respectively. This allows transparent, JDK 1.1 compliant integration of extended strategies for locking and releasing, based on subclassing and reflective construction of such specializations in the factory method newLockFile(), determined by information gathered at run-time.

In particular, if it is available at runtime, then newLockFile() retrieves instances of NIOLockFile to capitalize, when possible, on the existence of the FileLock class. If the NIOLockFile class does not exist at run-time or the java.nio classes it uses are not supported under the run-time JVM, then newLockFile() produces vanilla LockFile instances, meaning that only purely cooperative locking takes place, as opposed to possibly O/S-enforced file locking which, at least in theory, is made available through the java.nio.channels package). However, it must be noted that even if a JVM implementation provides the full java.nio.channels package, it is not absolutely required to guarantee that the underlying platform (the current operating system) provides true process-wide file locking.

Note:

The NIOLockFile descendent exists because it has been determined though experimenatation that java.nio.channels.FileLock does not always exhibit the correct/desired behaviour under reflective method invocation. That is, it has been discovered that under some operating system/JVM combinations, after calling FileLock.release() via a reflective method invocation, the lock is not released properly, deletion of the lock file is not possible even from the owning object (this) and it is impossible for other LockFile instances or any other objects or processes to successfully obtain a lock condition on the lock file, despite the fact that the FileLock object reports that its lock is invalid (was released successfully). Frustratingly, this condition appears to persist until full exit of the JVM process in which the FileLock.tryLock() method was reflectively invoked.

To solve this, the original LockFile class was split in two and instead of reflective method invocation, reflection-based class instantiation is now performed at the level of the newLockFile() factory method. Similarly, the HSQLDB ANT build script detects the presence or abscence of JDK 1.4 features such as java.nio and only attempts to build and deploy NIOLockFile to the hsqldb.jar if such features are reported present.

Since:
HSQLDB 1.7.2
Version:
1.7.2
Author:
boucherb@users.sourceforge.net

Nested Class Summary
protected  class LockFile.HeartbeatRunner
          For internal use only.
 
Field Summary
protected  File f
          Reference to this object's lock file.
static long HEARTBEAT_INTERVAL
          The period, in milliseconds, at which heartbeat timestamps are written to this object's lock file.
protected  boolean locked
          Indicates whether this object has a lock condition on its lock file.
static byte[] MAGIC
          A magic value to place at the beginning of the lock file to differentiate it from other files.
protected  RandomAccessFile raf
          A RandomAccessFile constructed from this object's reference, f, to its lock file.
protected static HsqlTimer timer
          The the timed shceduler with which to register this object's heartbeat task.
 
Constructor Summary
LockFile()
           
 
Method Summary
 boolean equals(Object obj)
          Tests whether some other object is "equal to" this one.
protected  void finalize()
          Attempts to release any lock condition this object may have on its lock file.
 String getCanonicalPath()
          Retreives, as a String, the canonical path of this object's lock file.
 int hashCode()
          Retrieves the hash code value for this object.
 boolean isLocked()
          Retrieves whether this object has successfully obtained and is still currently holding (has not yet released) a cooperative lock condition on its lock file.
static boolean isLocked(String path)
          Retrieves whether there is potentially already a cooperative lock, operating system lock or some other situation preventing a cooperative lock condition from being aquired, relative to the specified path.
 boolean isValid()
          Retrieves whether this object holds a valid lock on its lock file.
protected  boolean lockImpl()
          Provides any specialized locking actions for the tryLock() method.
static LockFile newLockFile(String path)
          Retrieves a LockFile instance, initialized with a File object whose path is the one specified by the path argument.
protected  boolean releaseImpl()
          Provides any specialized release actions for the tryRelease() method.
 String toString()
          Retrieves a String representation of this object.
protected  String toStringImpl()
          Retreives an implementation-specific tail value for the toString() method.
protected  void trace(Object o)
          Prints tracing information and the value of the specified object
 boolean tryLock()
          Attempts, if not already held, to obtain a cooperative lock condition on this object's lock file.
 boolean tryRelease()
          Attempts to release any cooperative lock condition this object may have on its lock file.
 
Methods inherited from class java.lang.Object
clone, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

f

protected File f
Reference to this object's lock file.


raf

protected RandomAccessFile raf
A RandomAccessFile constructed from this object's reference, f, to its lock file.

This RandomAccessFile is used to periodically write out the heartbeat timestamp to this object's lock file.


HEARTBEAT_INTERVAL

public static final long HEARTBEAT_INTERVAL
The period, in milliseconds, at which heartbeat timestamps are written to this object's lock file.

See Also:
Constant Field Values

MAGIC

public static final byte[] MAGIC
A magic value to place at the beginning of the lock file to differentiate it from other files. The value is "HSQLLOCK".getBytes().


locked

protected boolean locked
Indicates whether this object has a lock condition on its lock file.


timer

protected static final HsqlTimer timer
The the timed shceduler with which to register this object's heartbeat task.

Constructor Detail

LockFile

public LockFile()
Method Detail

lockImpl

protected boolean lockImpl()
                    throws Exception
Provides any specialized locking actions for the tryLock() method.

Descendents are free to provide additional functionality here, using the following rules:

 PRE:

 This method is only called if tryLock() thinks it needs to get a lock
 condition, so it can be assumed the locked == false upon entry, raf is
 a non-null instance that can be used to get a FileChannel if desired,
 and the lock file is, at the very least, readable.  Further, this
 object's heatbeat task is definitely cancelled and/or has not yet been
 scheduled, so whatever timestamp is recorded in the lock file, if it
 exists, is what was written by a previous locker, if any.  A timestamp
 value in a preexisting file is only considered valid if the file is
 of the correct length and its first eight bytes are
 the value MAGIC.

 POST:

 This method must return false if any additional locking work fails,
 else true.
 
The default implementation of this method reflectively (for JDK1.1 compliance) invokes f.deleteOnExit() in a silent manner and always returns true.

Returns:
true if no extended locking actions are taken or the actions succeed, else false.
Throws:
Exception - if a situation is encountered that absolutely prevents the status of the lock condtion to be determined. (e.g. an IO exception occurs here)

releaseImpl

protected boolean releaseImpl()
                       throws Exception
Provides any specialized release actions for the tryRelease() method.

Returns:
true if there are no specialized release actions performed or they succeed, else false
Throws:
Exception - if a situation is encountered that absolutely prevents the status of the lock condtion to be determined. (e.g. an IO exception occurs here).

newLockFile

public static LockFile newLockFile(String path)
                            throws Exception
Retrieves a LockFile instance, initialized with a File object whose path is the one specified by the path argument.

Parameters:
path - the path of the File object with which the retrieved LockFile object is to be initialized
Returns:
a LockFile instance initialized with a File object whose path is the one specified by the path argument.
Throws:
Exception

equals

public boolean equals(Object obj)
Tests whether some other object is "equal to" this one. An object is considered equal to a LockFile object iff it is not null, it is an instance of LockFile and either it's the identical instance or it has the same lock file. More formally, is is considered equal iff it is not null, it is an instance of LockFile, and the expression:

 this == other ||
 this.f == null ? other.f == null : this.f.equals(other.f);
 
yeilds true.

Parameters:
obj - the reference object with which to compare.
Returns:
true if this object is equal to the obj argument; false otherwise.
See Also:
hashCode()

getCanonicalPath

public String getCanonicalPath()
Retreives, as a String, the canonical path of this object's lock file.

Returns:
the absolute path of this object's lock file.

hashCode

public int hashCode()
Retrieves the hash code value for this object. The value is zero if the File object attribute f is null, else it is the hashCode of f. That is, two LockFile objects have the same hashCode value if they have the same lock file.

Returns:
a hash code value for this object.
See Also:
equals(java.lang.Object)

isLocked

public boolean isLocked()
Retrieves whether this object has successfully obtained and is still currently holding (has not yet released) a cooperative lock condition on its lock file.

Note: Due to the retrictions placed on the JVM by platform-independence, it is very possible to successfully obtain and hold a cooperative lock on a lock file and yet for the lock to become invalid while held.

For instance, under JVMs with no java.nio package or operating systems that cannot live up to the contracts set forth for FileLock, it is quite possible for another process or even an uncooperative bit of code running in the same JVM to delete or overwrite the lock file while this object holds a lock on it.

Because of this, the isValid() method is provided in the public interface in order to allow clients to detect such situations.

Returns:
true iff this object has successfully obtained and is currently holding (has not yet released) a lock on its lock file
See Also:
isValid()

isLocked

public static boolean isLocked(String path)
Retrieves whether there is potentially already a cooperative lock, operating system lock or some other situation preventing a cooperative lock condition from being aquired, relative to the specified path.

Parameters:
path - the path to test

isValid

public boolean isValid()
Retrieves whether this object holds a valid lock on its lock file.

More formally, this method retrieves true iff:

 isLocked() &&
 f != null &&
 f.exists() &&
 raf != null
 

Returns:
true iff this object holds a valid lock on its lock file.

toString

public String toString()
Retrieves a String representation of this object.

The String is of the form:

 super.toString() +
 "[file=" + getAbsolutePath() +
 ", exists=" + f.exists() +
 ", locked=" + isLocked() +
 ", valid=" + isValid() +
 ", " + toStringImpl() +
 "]";
 

Returns:
a String representation of this object.
See Also:
toStringImpl()

toStringImpl

protected String toStringImpl()
Retreives an implementation-specific tail value for the toString() method.

The default implementation returns the empty string.

Returns:
an implementation-specific tail value for the toString() method
See Also:
toString()

tryLock

public boolean tryLock()
                throws Exception
Attempts, if not already held, to obtain a cooperative lock condition on this object's lock file.

Returns:
true if this object already holds a lock or the lock was obtained successfully, else false
Throws:
Exception - if an error occurs that absolutely prevents the lock status of the lock condition from being determined (e.g. an unhandled file I/O error).

tryRelease

public boolean tryRelease()
                   throws Exception
Attempts to release any cooperative lock condition this object may have on its lock file.

Returns:
true if this object does not hold a lock or the lock is released successfully, else false.
Throws:
Exception - if an error occurs that absolutely prevents the status of the lock condition from being determined (e.g. an unhandled file I/O exception).

trace

protected void trace(Object o)
Prints tracing information and the value of the specified object

Parameters:
o - the value to print

finalize

protected void finalize()
                 throws Throwable
Attempts to release any lock condition this object may have on its lock file.

Throws:
Throwable - if this object encounters an unhandled exception trying to release the lock condition, if any, that it has on its lock file.


Copyright © 2001 - 2004 HSQL Development Group. All Rights Reserved.