Skip to content

Commit

Permalink
support releaseLock
Browse files Browse the repository at this point in the history
added usage comment
  • Loading branch information
colinsurprenant committed Feb 3, 2017
1 parent 0e81924 commit 7fd2f28
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 4 deletions.
29 changes: 26 additions & 3 deletions logstash-core/src/main/java/org/logstash/FileLockFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,21 @@
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* FileLockFactory provides a way to obtain an exclusive file lock for a given dir path and lock name.
* The obtainLock() method will return a Filelock object which should be released using the releaseLock()
* method. Normally the returned FileLock object should not be manipulated directly. Only the obtainLock()
* and releaseLock() methods should be use to gain and release exclusive access.
* This is threadsafe and will work across threads on the same JVM and will also work across processes/JVM.
*
* TODO: because of the releaseLock() method, strictly speaking this class is not only a factory anymore,
* maybe we should rename it FileLockManager?
*/
public class FileLockFactory {

/**
Expand All @@ -39,7 +51,8 @@ public class FileLockFactory {

private FileLockFactory() {}

private static final Set<String> LOCK_HELD = Collections.synchronizedSet(new HashSet<String>());
private static final Set<String> LOCK_HELD = Collections.synchronizedSet(new HashSet<>());
private static final Map<FileLock, String> LOCK_MAP = Collections.synchronizedMap(new HashMap<>());

public static final FileLockFactory getDefault() {
return FileLockFactory.INSTANCE;
Expand Down Expand Up @@ -71,6 +84,7 @@ public FileLock obtainLock(String lockDir, String lockName) throws IOException {
channel = FileChannel.open(realLockPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
lock = channel.tryLock();
if (lock != null) {
LOCK_MAP.put(lock, realLockPath.toString());
return lock;
} else {
throw new LockException("Lock held by another program: " + realLockPath);
Expand All @@ -85,8 +99,8 @@ public FileLock obtainLock(String lockDir, String lockName) throws IOException {
// suppress any channel close exceptions
}

boolean remove = LOCK_HELD.remove(realLockPath.toString());
if (remove == false) {
boolean removed = LOCK_HELD.remove(realLockPath.toString());
if (removed == false) {
throw new LockException("Lock path was cleared but never marked as held: " + realLockPath);
}
}
Expand All @@ -95,4 +109,13 @@ public FileLock obtainLock(String lockDir, String lockName) throws IOException {
throw new LockException("Lock held by this virtual machine: " + realLockPath);
}
}

public void releaseLock(FileLock lock) throws IOException {
String lockPath = LOCK_MAP.remove(lock);
if (lockPath == null) { throw new LockException("Cannot release unobtained lock"); }
lock.release();
Boolean removed = LOCK_HELD.remove(lockPath);
if (removed == false) { throw new LockException("Lock path was not marked as held: " + lockPath); }
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ public class FileLockFactoryTest {
private String lockDir;
private final String LOCK_FILE = ".test";

private FileLock lock;

@Before
public void setUp() throws Exception {
lockDir = temporaryFolder.newFolder("lock").getPath();
}

@Before
public void lockFirst() throws Exception {
FileLock lock = FileLockFactory.getDefault().obtainLock(lockDir, LOCK_FILE);
lock = FileLockFactory.getDefault().obtainLock(lockDir, LOCK_FILE);
assertThat(lock.isValid(), is(equalTo(true)));
assertThat(lock.isShared(), is(equalTo(false)));
}
Expand All @@ -50,4 +52,40 @@ public void ObtainLockOnOtherLocked() throws IOException {
assertThat(lock2.isValid(), is(equalTo(true)));
assertThat(lock2.isShared(), is(equalTo(false)));
}

@Test
public void LockReleaseLock() throws IOException {
FileLockFactory.getDefault().releaseLock(lock);
}

@Test
public void LockReleaseLockObtainLock() throws IOException {
FileLockFactory.getDefault().releaseLock(lock);

FileLock lock2 = FileLockFactory.getDefault().obtainLock(lockDir, LOCK_FILE);
assertThat(lock2.isValid(), is(equalTo(true)));
assertThat(lock2.isShared(), is(equalTo(false)));
}

@Test
public void LockReleaseLockObtainLockRelease() throws IOException {
FileLockFactory.getDefault().releaseLock(lock);

FileLock lock2 = FileLockFactory.getDefault().obtainLock(lockDir, LOCK_FILE);
assertThat(lock2.isValid(), is(equalTo(true)));
assertThat(lock2.isShared(), is(equalTo(false)));

FileLockFactory.getDefault().releaseLock(lock2);
}

@Test(expected = LockException.class)
public void ReleaseNullLock() throws IOException {
FileLockFactory.getDefault().releaseLock(null);
}

@Test(expected = LockException.class)
public void ReleaseUnobtainedLock() throws IOException {
FileLockFactory.getDefault().releaseLock(lock);
FileLockFactory.getDefault().releaseLock(lock);
}
}

0 comments on commit 7fd2f28

Please sign in to comment.