Disable file locking on Windows, work on #229

This commit is contained in:
Per Minborg
2020-09-02 19:24:19 +02:00
parent 36f03b4e4a
commit 07a9ba94ca
2 changed files with 72 additions and 39 deletions
@@ -1,5 +1,7 @@
package net.openhft.chronicle.map;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.OS;
import net.openhft.chronicle.hash.ChronicleFileLockException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -9,72 +11,91 @@ import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public final class FileLockUtil {
/**
* Java file locks are maintained on a per JVM basis. So we need to manage them.
*/
private static final ConcurrentHashMap<File, FileLockReference> FILE_LOCKS = new ConcurrentHashMap<>();
private static final boolean USE_LOCKING = !OS.isWindows();
private static final AtomicBoolean LOCK_WARNING_PRINTED = new AtomicBoolean();
private FileLockUtil() { }
public static void acquireSharedFileLock(@NotNull final File canonicalFile, @NotNull final FileChannel channel) {
FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
try {
if (flr == null)
return new FileLockReference(channel.lock(0, Long.MAX_VALUE, true));
else {
if (!flr.fileLock.isShared()) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, null);
if (USE_LOCKING)
FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
try {
if (flr == null)
return new FileLockReference(channel.lock(0, Long.MAX_VALUE, true));
else {
if (!flr.fileLock.isShared()) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, null);
}
flr.reserve();
return flr; // keep the old one
}
flr.reserve();
return flr; // keep the old one
} catch (IOException e) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, e);
}
} catch (IOException e) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, e);
}
}
);
);
else
printWarningTheFirstTime();
}
public static void acquireExclusiveFileLock(@NotNull final File canonicalFile, @NotNull final FileChannel channel) {
FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
if (flr == null) {
try {
final FileLock fileLock = channel.lock(0, Long.MAX_VALUE, false);
return new FileLockReference(fileLock);
} catch (IOException e) {
throw newUnableToAcquireExclusiveFileLockException(canonicalFile, e);
if (USE_LOCKING)
FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
if (flr == null) {
try {
final FileLock fileLock = channel.lock(0, Long.MAX_VALUE, false);
return new FileLockReference(fileLock);
} catch (IOException e) {
throw newUnableToAcquireExclusiveFileLockException(canonicalFile, e);
}
} else {
throw newUnableToAcquireExclusiveFileLockException(canonicalFile, null);
}
} else {
throw newUnableToAcquireExclusiveFileLockException(canonicalFile, null);
}
}
);
}
);
else
printWarningTheFirstTime();
}
public static void releaseFileLock(@NotNull final File canonicalFile) {
FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
if (flr == null)
throw new ChronicleFileLockException("Trying to release lock on file " + canonicalFile + " that did not exist");
else {
final int cnt = flr.release();
if (cnt == 0)
return null; // Remove the old one
else
return flr;
if (USE_LOCKING)
FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
if (flr == null)
throw new ChronicleFileLockException("Trying to release lock on file " + canonicalFile + " that did not exist");
else {
final int cnt = flr.release();
if (cnt == 0)
return null; // Remove the old one
else
return flr;
}
}
}
);
);
else
printWarningTheFirstTime();
}
public static void runExclusively(@NotNull final File canonicalFile,
@NotNull final FileChannel fileChannel,
@NotNull final Runnable fileIOAction) {
// This method runs regardless of the USE_LOCKING flag since it is only used
// for initial map creation. This works on all platforms
// Atomically acquire a FileLockReference
final FileLockReference fileLockRef = FILE_LOCKS.compute(canonicalFile, (f, flr) ->
{
@@ -155,4 +176,11 @@ public final class FileLockUtil {
"Make sure no other process is using the map.", e);
}
private static void printWarningTheFirstTime() {
if (LOCK_WARNING_PRINTED.compareAndSet(false, true)) {
Jvm.warn().on(FileLockUtil.class, "File locking is not supported on this platform (" + System.getProperty("os.name") + "). " +
"Make sure you are not running ChronicleMapBuilder::*recover* methods when other processes or threads have the mapped file open!");
}
}
}