001: package org.apache.lucene.store;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.IOException;
021:
022: /** An interprocess mutex lock.
023: * <p>Typical use might look like:<pre>
024: * new Lock.With(directory.makeLock("my.lock")) {
025: * public Object doBody() {
026: * <i>... code to execute while locked ...</i>
027: * }
028: * }.run();
029: * </pre>
030: *
031: *
032: * @version $Id: Lock.java 595448 2007-11-15 20:42:54Z mikemccand $
033: * @see Directory#makeLock(String)
034: */
035: public abstract class Lock {
036:
037: /** How long {@link #obtain(long)} waits, in milliseconds,
038: * in between attempts to acquire the lock. */
039: public static long LOCK_POLL_INTERVAL = 1000;
040:
041: /** Pass this value to {@link #obtain(long)} to try
042: * forever to obtain the lock. */
043: public static final long LOCK_OBTAIN_WAIT_FOREVER = -1;
044:
045: /** Attempts to obtain exclusive access and immediately return
046: * upon success or failure.
047: * @return true iff exclusive access is obtained
048: */
049: public abstract boolean obtain() throws IOException;
050:
051: /**
052: * If a lock obtain called, this failureReason may be set
053: * with the "root cause" Exception as to why the lock was
054: * not obtained.
055: */
056: protected Throwable failureReason;
057:
058: /** Attempts to obtain an exclusive lock within amount of
059: * time given. Polls once per {@link #LOCK_POLL_INTERVAL}
060: * (currently 1000) milliseconds until lockWaitTimeout is
061: * passed.
062: * @param lockWaitTimeout length of time to wait in
063: * milliseconds or {@link
064: * #LOCK_OBTAIN_WAIT_FOREVER} to retry forever
065: * @return true if lock was obtained
066: * @throws LockObtainFailedException if lock wait times out
067: * @throws IllegalArgumentException if lockWaitTimeout is
068: * out of bounds
069: * @throws IOException if obtain() throws IOException
070: */
071: public boolean obtain(long lockWaitTimeout)
072: throws LockObtainFailedException, IOException {
073: failureReason = null;
074: boolean locked = obtain();
075: if (lockWaitTimeout < 0
076: && lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER)
077: throw new IllegalArgumentException(
078: "lockWaitTimeout should be LOCK_OBTAIN_WAIT_FOREVER or a non-negative number (got "
079: + lockWaitTimeout + ")");
080:
081: long maxSleepCount = lockWaitTimeout / LOCK_POLL_INTERVAL;
082: long sleepCount = 0;
083: while (!locked) {
084: if (lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER
085: && sleepCount++ >= maxSleepCount) {
086: String reason = "Lock obtain timed out: "
087: + this .toString();
088: if (failureReason != null) {
089: reason += ": " + failureReason;
090: }
091: LockObtainFailedException e = new LockObtainFailedException(
092: reason);
093: if (failureReason != null) {
094: e.initCause(failureReason);
095: }
096: throw e;
097: }
098: try {
099: Thread.sleep(LOCK_POLL_INTERVAL);
100: } catch (InterruptedException e) {
101: throw new IOException(e.toString());
102: }
103: locked = obtain();
104: }
105: return locked;
106: }
107:
108: /** Releases exclusive access. */
109: public abstract void release() throws IOException;
110:
111: /** Returns true if the resource is currently locked. Note that one must
112: * still call {@link #obtain()} before using the resource. */
113: public abstract boolean isLocked();
114:
115: /** Utility class for executing code with exclusive access. */
116: public abstract static class With {
117: private Lock lock;
118: private long lockWaitTimeout;
119:
120: /** Constructs an executor that will grab the named lock. */
121: public With(Lock lock, long lockWaitTimeout) {
122: this .lock = lock;
123: this .lockWaitTimeout = lockWaitTimeout;
124: }
125:
126: /** Code to execute with exclusive access. */
127: protected abstract Object doBody() throws IOException;
128:
129: /** Calls {@link #doBody} while <i>lock</i> is obtained. Blocks if lock
130: * cannot be obtained immediately. Retries to obtain lock once per second
131: * until it is obtained, or until it has tried ten times. Lock is released when
132: * {@link #doBody} exits.
133: * @throws LockObtainFailedException if lock could not
134: * be obtained
135: * @throws IOException if {@link Lock#obtain} throws IOException
136: */
137: public Object run() throws LockObtainFailedException,
138: IOException {
139: boolean locked = false;
140: try {
141: locked = lock.obtain(lockWaitTimeout);
142: return doBody();
143: } finally {
144: if (locked)
145: lock.release();
146: }
147: }
148: }
149:
150: }
|