📄 lockfile.java
字号:
* 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 {@link #MAGIC MAGIC}. * * POST: * * This method must return false if any additional locking work fails, * else true. * </pre> * * The default implementation of this method reflectively (for JDK1.1 * compliance) invokes f.deleteOnExit() in a silent manner and always * returns true. <p> * * @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) * @return <code>true</code> if no extended locking * actions are taken or the actions succeed, * else <code>false</code>. */ protected boolean lockImpl() throws Exception { String mn; mn = "lockImpl(): "; trace(mn + "entered."); FileUtil.deleteOnExit(f); return true; } /** * Opens this object's {@link #raf RandomAccessFile}. <p> * * @throws Exception if an IOException occurs */ private void openRAF() throws Exception { trace("openRAF(): entered."); raf = new RandomAccessFile(f, "rw"); trace("openRAF(): got new 'rw' mode " + raf); } /** * Retrieves the last written hearbeat timestamp from * this object's lock file. If this object's lock file * does not exist, <code>Long.MIN_VALUE</code> (the earliest * time representable as a long in Java) is retrieved. <p> * * @throws Exception if an error occurs while reading the hearbeat * timestamp from this object's lock file. * @return the hearbeat timestamp from this object's lock file, * as a <code>long</code> value or, if this object's lock * file does not exist, Long.MIN_VALUE, the earliest time * representable as a long in Java, */ private long readHeartbeat() throws Exception { DataInputStream dis; long heartbeat; heartbeat = Long.MIN_VALUE; String mn = "readHeartbeat(): "; String path = "lock file [" + cpath + "]"; trace(mn + "entered."); if (!f.exists()) { trace(mn + path + " does not exist. Return '" + heartbeat + "'"); return heartbeat; } dis = new DataInputStream(new FileInputStream(f)); trace(mn + " got new " + dis); for (int i = 0; i < MAGIC.length; i++) { if (MAGIC[i] != dis.readByte()) { trace(mn + path + " is not lock file. Return '" + heartbeat + "'"); return heartbeat; } } heartbeat = dis.readLong(); trace(mn + " read: [" + HsqlDateTime.getTimestampString(heartbeat) + "]"); dis.close(); trace(mn + " closed " + dis); return heartbeat; } /** * Provides any specialized release actions for the tryRelease() * method. <p> * * @return 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). */ protected boolean releaseImpl() throws Exception { trace("releaseImpl(): no action: returning true"); return true; } /** Schedules the lock heartbeat task. */ private void startHeartbeat() { Runnable r; trace("startHeartbeat(): entered."); if (timerTask == null || HsqlTimer.isCancelled(timerTask)) { r = new HeartbeatRunner(); // now, periodic at HEARTBEAT_INTERVAL, running this, fixed rate timerTask = timer.schedulePeriodicallyAfter(0, HEARTBEAT_INTERVAL, r, true); trace("startHeartbeat(): heartbeat task scheduled."); } trace("startHeartbeat(): exited."); } /** Cancels the lock heartbeat task. */ private void stopHeartbeat() { String mn = "stopHeartbeat(): "; trace(mn + "entered"); if (timerTask != null &&!HsqlTimer.isCancelled(timerTask)) { HsqlTimer.cancel(timerTask); timerTask = null; } trace(mn + "exited"); } /** * Writes a magic value to this object's lock file that distiguishes * it as an HSQLDB lock file. * * @throws Exception if the magic value cannot be written to * the lock file */ private void writeMagic() throws Exception { String mn = "writeMagic(): "; String path = "lock file [" + cpath + "]"; trace(mn + "entered."); trace(mn + "raf.seek(0)"); raf.seek(0); trace(mn + "raf.write(byte[])"); raf.write(MAGIC); trace(mn + "wrote [\"HSQLLOCK\".getBytes()] to " + path); } /** * Writes the current hearbeat timestamp value to this * object's lock file. <p> * * @throws Exception if the current heartbeat timestamp value * cannot be written */ private void writeHeartbeat() throws Exception { long time; String mn = "writeHeartbeat(): "; String path = "lock file [" + cpath + "]"; trace(mn + "entered."); time = System.currentTimeMillis(); trace(mn + "raf.seek(" + MAGIC.length + ")"); raf.seek(MAGIC.length); trace(mn + "raf.writeLong(" + time + ")"); raf.writeLong(time); trace(mn + "wrote [" + time + "] to " + path); } /** * Retrieves a <code>LockFile</code> instance, initialized with a * <code>File</code> object whose path is the one specified by * the <code>path</code> argument. <p> * * @return a <code>LockFile</code> instance initialized with a * <code>File</code> object whose path is the one specified * by the <code>path</code> argument. * @param path the path of the <code>File</code> object with * which the retrieved <code>LockFile</code> * object is to be initialized */ public static LockFile newLockFile(String path) throws Exception { File f; LockFile lf; Class c; c = null; try { Class.forName("java.nio.channels.FileLock"); c = Class.forName("org.hsqldb.persist.NIOLockFile"); lf = (LockFile) c.newInstance(); } catch (Exception e) { lf = new LockFile(); } f = new File(path); FileUtil.makeParentDirectories(f); lf.setFile(f); return lf; } public static LockFile newLockFileLock(String path) throws HsqlException { LockFile lf = null; try { lf = LockFile.newLockFile(path + ".lck"); } catch (Exception e) { throw Trace.error(Trace.FILE_IO_ERROR, e.toString()); } boolean locked = false; String msg = ""; try { locked = lf.tryLock(); } catch (Exception e) { // e.printStackTrace(); msg = e.toString(); } if (!locked) { throw Trace.error(Trace.DATABASE_ALREADY_IN_USE, lf + ": " + msg); } return lf; } /** * Tests whether some other object is "equal to" this one. * * An object is considered equal to a <code>LockFile</code> object iff it * is not null, it is an instance of <code>LockFile</code> 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 * <code>LockFile</code>, and the expression: <p> * * <pre> * this == other || * this.f == null ? other.f == null : this.f.equals(other.f); * </pre> * * yeilds true. <p> * * @param obj the reference object with which to compare. * @return <code>true</code> if this object is equal to * the <code>obj</code> argument; * <code>false</code> otherwise. * @see #hashCode */ public boolean equals(Object obj) { // do faster tests first if (this == obj) { return true; } else if (obj instanceof LockFile) { LockFile that = (LockFile) obj; return (f == null) ? that.f == null : f.equals(that.f); } else { return false; } } /** * Retrieves, as a String, the canonical path of this object's lock file. * * @return the canonical path of this object's lock file. */ public String getCanonicalPath() { return cpath; } /** * Retrieves the hash code value for this object. * * The value is zero if the <code>File</code> object attribute * <code>f</code> is <code>null</code>, else it is the <code>hashCode</code>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -