| java.lang.Object org.hsqldb.persist.LockFile
All known Subclasses: org.hsqldb.persist.NIOLockFile,
LockFile | public class LockFile (Code) | | The base HSQLDB cooperative file locking implementation and factory.
Here is the way this class operates:
- 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).
- A background thread periodically writes a timestamp to this object's
lock file at
LockFile.HEARTBEAT_INTERVAL millisecond intervals,
acting as a heartbeat to indicate that a lock is still held.
- The generic lock attempt rules are:
- If a lock condition is already held by this object, do nothing and
signify that the lock attempt was successful, else...
- If no lock file exists, go ahead and create one, silently issue the
java.io.File.deleteOnExit File.deleteOnExit() directive via
refelective method invocation (in order to stay JDK 1.1 compliant),
schedule a periodic heartbeat task and signify that the lock attempt
was successful, else...
- The lock file must already exist, so try to read its heartbeat
timestamp. If the read fails, assume that a lock condition is held by
another process or a database in an inaccessible class loader context
and signify that the attempt failed, else if the read value
is less than
HEARTBEAT_INTERVAL milliseconds into the
past or futuer, assume that a lock condition is held by another
process or a database in an inaccessible class loader context and
signify that the lock attempt failed, else assume that the file is
not in use, schedule a periodic heartbeat task and signify that the
lock attempt was successful.
- The generic release attempt rules are:
- If a lock condition is not currently held, do nothing and signify
that the release attempt was successful, else...
- A lock condition is currently held, so try to release it. By
default, releasing the lock condition consists of closing and
nullifying any objects that have a file descriptor open on the
lock file. If the release is successful, cancel the periodic
heartbeat task and signify that the release succeeded, else signify
that the release attempt failed.
In addition to the generic lock and release rules, the protected methods
LockFile.lockImpl() lockImpl() and
LockFile.releaseImpl() 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
LockFile.newLockFile newLockFile() , determined by information gathered
at run-time.
In particular, if it is available at runtime, then newLockFile() retrieves
instances of
org.hsqldb.NIOLockFile NIOLockFile to capitalize,
when possible, on the existence of the
java.nio.channels.FileLockFileLock 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.
author: boucherb@users version: 1.7.2 since: 1.7.2 |
Inner Class :protected class HeartbeatRunner implements Runnable | |
Field Summary | |
final public static long | HEARTBEAT_INTERVAL The period, in milliseconds, at which heartbeat timestamps are written
to this object's lock file. | final public static byte[] | MAGIC A magic value to place at the beginning of the lock file to
differentiate it from other files. | protected File | f Canonical reference to this object's lock file. | protected boolean | locked Indicates whether this object has a lock condition on its lock file. | protected RandomAccessFile | raf A RandomAccessFile constructed from this object's reference, f, to its
lock file. | final protected static HsqlTimer | timer The timed scheduler with which to register this object's
heartbeat task. |
Method Summary | |
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. | protected void | finalize() Attempts to release any lock condition this object may have on its
lock file. | public String | getCanonicalPath() Retrieves, as a String, the canonical path of this object's lock file. | 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 . | 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. | 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. | public boolean | isValid() Retrieves whether this object holds a valid lock on its lock file. | protected boolean | lockImpl() Provides any specialized locking actions for the
LockFile.tryLock() tryLock() method. | public static LockFile | newLockFile(String path) Retrieves a LockFile instance, initialized with a
File object whose path is the one specified by
the path argument. | public static LockFile | newLockFileLock(String path) | protected boolean | releaseImpl() Provides any specialized release actions for the tryRelease()
method. | public String | toString() Retrieves a String representation of this object. | protected String | toStringImpl() Retrieves an implementation-specific tail value for the
toString() method. | protected void | trace(Object o) | public boolean | tryLock() Attempts, if not already held, to obtain a cooperative lock condition
on this object's lock file. | public boolean | tryRelease() Attempts to release any cooperative lock condition this object
may have on its lock file. |
HEARTBEAT_INTERVAL | final public static long HEARTBEAT_INTERVAL(Code) | | The period, in milliseconds, at which heartbeat timestamps are written
to this object's lock file.
|
MAGIC | final public static byte[] MAGIC(Code) | | A magic value to place at the beginning of the lock file to
differentiate it from other files. The value is "HSQLLOCK".getBytes().
|
f | protected File f(Code) | | Canonical reference to this object's lock file.
|
locked | protected boolean locked(Code) | | Indicates whether this object has a lock condition on its lock file.
|
raf | protected RandomAccessFile raf(Code) | | 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.
|
timer | final protected static HsqlTimer timer(Code) | | The timed scheduler with which to register this object's
heartbeat task.
|
equals | public boolean equals(Object obj)(Code) | | 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. true if this object is equal tothe obj argument;false otherwise. See Also: LockFile.hashCode |
finalize | protected void finalize() throws Throwable(Code) | | Attempts to release any lock condition this object may have on its
lock file.
throws: Throwable - if this object encounters an unhandled exceptiontrying to release the lock condition,if any, that it has on its lock file. |
getCanonicalPath | public String getCanonicalPath()(Code) | | Retrieves, as a String, the canonical path of this object's lock file.
the canonical path of this object's lock file. |
hashCode | public int hashCode()(Code) | | 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.
a hash code value for this object. See Also: LockFile.equals(java.lang.Object) |
isLocked | public boolean isLocked()(Code) | | 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
java.nio.channels.FileLock 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.
true iff this object has successfully obtainedand is currently holding (has not yet released)a lock on its lock file See Also: LockFile.isValid |
isLocked | public static boolean isLocked(String path)(Code) | | 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()(Code) | | 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
true iff this object holds a valid lock on itslock file. |
lockImpl | protected boolean lockImpl() throws Exception(Code) | | Provides any specialized locking actions for the
LockFile.tryLock() 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
LockFile.MAGIC 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.
throws: Exception - if a situation is encountered that absolutelyprevents the status of the lock condtionto be determined. (e.g. an IO exceptionoccurs here) true if no extended lockingactions are taken or the actions succeed,else false . |
newLockFile | public static LockFile newLockFile(String path) throws Exception(Code) | | Retrieves a LockFile instance, initialized with a
File object whose path is the one specified by
the path argument.
a LockFile instance initialized with aFile object whose path is the one specifiedby the path argument. Parameters: path - the path of the File object withwhich the retrieved LockFile object is to be initialized |
releaseImpl | protected boolean releaseImpl() throws Exception(Code) | | Provides any specialized release actions for the tryRelease()
method.
true if there are no specialized releaseactions performed or they succeed,else false throws: Exception - if a situation is encountered that absolutelyprevents the status of the lock condtionto be determined. (e.g. an IO exceptionoccurs here). |
toString | public String toString()(Code) | | 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() +
"]";
a String representation of this object. See Also: LockFile.toStringImpl |
toStringImpl | protected String toStringImpl()(Code) | | Retrieves an implementation-specific tail value for the
toString() method.
The default implementation returns the empty string.
an implementation-specific tail value for the toString() method See Also: LockFile.toString |
trace | protected void trace(Object o)(Code) | | Prints tracing information and the value of the specified object
Parameters: o - the value to print |
tryLock | public boolean tryLock() throws Exception(Code) | | Attempts, if not already held, to obtain a cooperative lock condition
on this object's lock file.
throws: Exception - if an error occurs that absolutely prevents the lockstatus of the lock condition from being determined(e.g. an unhandled file I/O error). true if this object already holds a lock orthe lock was obtained successfully, elsefalse |
tryRelease | public boolean tryRelease() throws Exception(Code) | | Attempts to release any cooperative lock condition this object
may have on its lock file.
throws: Exception - if an error occurs that absolutely preventsthe status of the lock condition frombeing determined (e.g. an unhandled fileI/O exception). true if this object does not hold alock or the lock is released successfully,else false . |
|
|