131 lines
4.1 KiB
Java
131 lines
4.1 KiB
Java
|
|
package org.broadinstitute.sting.utils.file;
|
||
|
|
|
||
|
|
import org.apache.log4j.Logger;
|
||
|
|
import org.broadinstitute.sting.utils.StingException;
|
||
|
|
|
||
|
|
import java.io.File;
|
||
|
|
import java.io.IOException;
|
||
|
|
import java.io.RandomAccessFile;
|
||
|
|
import java.nio.channels.ClosedChannelException;
|
||
|
|
import java.nio.channels.FileChannel;
|
||
|
|
import java.nio.channels.FileLock;
|
||
|
|
import java.nio.channels.OverlappingFileLockException;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* a quick implementation of a file based lock, using the Java NIO classes
|
||
|
|
*/
|
||
|
|
public class FSLockWithShared {
|
||
|
|
// connect to the logger
|
||
|
|
private final static Logger logger = Logger.getLogger(FSLockWithShared.class);
|
||
|
|
|
||
|
|
// the file we're attempting to lock
|
||
|
|
private final File file;
|
||
|
|
|
||
|
|
// the file lock
|
||
|
|
private FileLock lock = null;
|
||
|
|
|
||
|
|
// the file channel we open
|
||
|
|
private FileChannel channel = null;
|
||
|
|
/**
|
||
|
|
* create a file system, given a base file to which a lock string gets appended.
|
||
|
|
* @param baseFile File descriptor of file to lock
|
||
|
|
*/
|
||
|
|
public FSLockWithShared(File baseFile) {
|
||
|
|
file = baseFile;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get a shared (read) lock on a file
|
||
|
|
* Cannot get shared lock if it does not exist
|
||
|
|
* @return boolean true if we obtained a lock
|
||
|
|
*/
|
||
|
|
public boolean sharedLock() {
|
||
|
|
|
||
|
|
// get read-only file channel
|
||
|
|
try {
|
||
|
|
channel = new RandomAccessFile(file, "r").getChannel();
|
||
|
|
}
|
||
|
|
catch (IOException e) {
|
||
|
|
logger.debug("Unable to lock file (could not open read only file channel)");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
// get shared lock (third argument is true)
|
||
|
|
try {
|
||
|
|
lock = channel.tryLock(0, Long.MAX_VALUE, true);
|
||
|
|
if (lock == null) {
|
||
|
|
logger.debug("Unable to lock file because there is already a lock active.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (ClosedChannelException e) {
|
||
|
|
logger.debug("Unable to lock file because the file channel is closed.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
catch (OverlappingFileLockException e) {
|
||
|
|
logger.debug("Unable to lock file because you already have a lock on this file.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
catch (IOException e) {
|
||
|
|
logger.debug("Unable to lock file (due to IO exception)");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get an exclusive lock on a file
|
||
|
|
* @return boolean true if we obtained a lock
|
||
|
|
*/
|
||
|
|
public boolean exclusiveLock() {
|
||
|
|
|
||
|
|
// read/write file channel is necessary for exclusive lock
|
||
|
|
try {
|
||
|
|
channel = new RandomAccessFile(file, "rw").getChannel();
|
||
|
|
}
|
||
|
|
catch (Exception e) {
|
||
|
|
logger.debug("Unable to lock file (could not open read/write file channel)");
|
||
|
|
// do we need to worry about deleting file here? Does RandomAccessFile will only create file if successful?
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get exclusive lock (third argument is false)
|
||
|
|
try {
|
||
|
|
lock = channel.tryLock(0, Long.MAX_VALUE, false);
|
||
|
|
if (lock == null) {
|
||
|
|
logger.debug("Unable to lock file because there is already a lock active.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else return true;
|
||
|
|
}
|
||
|
|
catch (ClosedChannelException e) {
|
||
|
|
logger.debug("Unable to lock file because the file channel is closed.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
catch (OverlappingFileLockException e) {
|
||
|
|
logger.debug("Unable to lock file because you already have a lock on this file.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
catch (IOException e) {
|
||
|
|
logger.debug("Unable to lock file (due to IO exception)");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* unlock the file
|
||
|
|
*
|
||
|
|
* note: this allows unlocking a file that failed to lock (no required user checks on null locks).
|
||
|
|
*/
|
||
|
|
public void unlock() {
|
||
|
|
try {
|
||
|
|
if (lock != null)
|
||
|
|
lock.release();
|
||
|
|
if (channel != null)
|
||
|
|
channel.close();
|
||
|
|
}
|
||
|
|
catch (Exception e) {
|
||
|
|
throw new StingException("An error occurred while unlocking file", e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|