## grendel.storage
Class UnixDotLock

    java.lang.Object
      |
      +--grendel.storage.UnixDotLock

public class UnixDotLock
extends java.lang.Object

Implements Unix-style dot-locking (locking file `"FOO"` by using an atomically-created file in the same directory named `"FOO.lock"`.)

Use it like this:

`UnixDotLock lock = new UnixDotLock(file); //` this blocks
`//` ... long-running manipulations of file
`lock.unlock();`

All the lock-retrying and lock-date-maintenance happens under the covers.

See also the description of movemail.

Implementation details:

> The protocol for getting a lock on some file `"FOO"` is as follows:

> 1. Create a file `"FOO.1234"` (random unused name.)

> 2. Hard-link `"FOO.1234"` to `"FOO.lock"`.
>    (this is the trick, because `link()` happens to be one of the few atomic, synchronized operations over NFS.)

> 3. Unlink `"FOO.1234"`
>    (regardless of whether step 2 succeeded; now either we have a `"FOO.lock"` file or we don't.)

> 4. If we obtained the lock (the `link()` call in step #2 succeeded), then we're done.

> 5. Else if the creation-time of `"FOO.lock"` is more than 60 seconds in the past, then smash the lock (unlink `"FOO.lock"`) and goto step #1.)

> 6. Else, the lock is held and current. Wait a second, then goto step #1 and try again.

> One thing implied by this is that if one wants to hold a lock for longer than 60 seconds (which we do in some cases) then one must maintain the lock file: its modification-date must be updated every less-than-60 seconds. We do this by having a ``heartbeat'' thread that wakes up periodically and updates all held locks.

Constructor Summary
`UnixDotLock(java.io.File file)` Lock the named file.

Method Summary
`protected void` | `finalize()` If this object becomes reclaimed without unlock() having been called, then call it (thus unlocking the underlying disk file.)
`static void` | `main(java.lang.String[] arg)`
`void` | `unlock()` Unlock the file.

Methods inherited from class java.lang.Object
`clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

Constructor Detail

### UnixDotLock

    public UnixDotLock(java.io.File file)
                throws java.lang.SecurityException,
                       java.io.IOException,
                       java.lang.InterruptedException

  Lock the named file. Unlock it by calling the unlock() method. If you do not call unlock() before discarding the UnixDotLock object, the file will remain locked!
  Throws:
    java.lang.SecurityException - the lock file could not be created (file permission problems?)
    java.io.IOException - a disk I/O error occurred.
    java.lang.InterruptedException - this thread was killed while waiting for the lock.

Method Detail

### unlock

    public void unlock()

  Unlock the file. This must be called before discarding the UnixDotLock object, and may be called only once. The UnixDotLock object must not be used again after calling this.
  Throws:
    java.lang.InterruptedException - this thread was killed while waiting for the lock.

### finalize

    protected void finalize()
                     throws java.lang.Throwable

  If this object becomes reclaimed without unlock() having been called, then call it (thus unlocking the underlying disk file.)
  Throws:
    java.lang.Throwable -
  Overrides:
    finalize in class java.lang.Object

### main

    public static final void main(java.lang.String[] arg)
                           throws java.lang.SecurityException,
                                  java.io.IOException,
                                  java.lang.InterruptedException