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.net.Socket;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.OutputStream;
024:
025: /**
026: * A {@link LockFactory} that wraps another {@link
027: * LockFactory} and verifies that each lock obtain/release
028: * is "correct" (never results in two processes holding the
029: * lock at the same time). It does this by contacting an
030: * external server ({@link LockVerifyServer}) to assert that
031: * at most one process holds the lock at a time. To use
032: * this, you should also run {@link LockVerifyServer} on the
033: * host & port matching what you pass to the constructor.
034: *
035: * @see LockVerifyServer
036: * @see LockStressTest
037: */
038:
039: public class VerifyingLockFactory extends LockFactory {
040:
041: LockFactory lf;
042: byte id;
043: String host;
044: int port;
045:
046: private class CheckedLock extends Lock {
047: private Lock lock;
048:
049: public CheckedLock(Lock lock) {
050: this .lock = lock;
051: }
052:
053: private void verify(byte message) {
054: try {
055: Socket s = new Socket(host, port);
056: OutputStream out = s.getOutputStream();
057: out.write(id);
058: out.write(message);
059: InputStream in = s.getInputStream();
060: int result = in.read();
061: in.close();
062: out.close();
063: s.close();
064: if (result != 0)
065: throw new RuntimeException(
066: "lock was double acquired");
067: } catch (Exception e) {
068: throw new RuntimeException(e);
069: }
070: }
071:
072: public synchronized boolean obtain(long lockWaitTimeout)
073: throws LockObtainFailedException, IOException {
074: boolean obtained = lock.obtain(lockWaitTimeout);
075: if (obtained)
076: verify((byte) 1);
077: return obtained;
078: }
079:
080: public synchronized boolean obtain()
081: throws LockObtainFailedException, IOException {
082: return lock.obtain();
083: }
084:
085: public synchronized boolean isLocked() {
086: return lock.isLocked();
087: }
088:
089: public synchronized void release() throws IOException {
090: if (isLocked()) {
091: verify((byte) 0);
092: lock.release();
093: }
094: }
095: }
096:
097: /**
098: * @param id should be a unique id across all clients
099: * @param lf the LockFactory that we are testing
100: * @param host host or IP where {@link LockVerifyServer}
101: is running
102: * @param port the port {@link LockVerifyServer} is
103: listening on
104: */
105: public VerifyingLockFactory(byte id, LockFactory lf, String host,
106: int port) throws IOException {
107: this .id = id;
108: this .lf = lf;
109: this .host = host;
110: this .port = port;
111: }
112:
113: public synchronized Lock makeLock(String lockName) {
114: return new CheckedLock(lf.makeLock(lockName));
115: }
116:
117: public synchronized void clearLock(String lockName)
118: throws IOException {
119: lf.clearLock(lockName);
120: }
121: }
|