Protect about failure to reopen map immediately after it is closed

Remove RandomAccessFiles closed by interrupt
Merge file locks into canonical files store to avoid desync

Fixes ChronicleEnterprise/Chronicle-Map-Enterprise#68
This commit is contained in:
Ilya Kaznacheev
2021-08-25 20:13:45 +03:00
committed by Ilya Kaznacheev
parent 73ae264124
commit 62e9c6f159
4 changed files with 304 additions and 309 deletions
@@ -18,38 +18,71 @@ package net.openhft.chronicle.hash.impl.util;
import net.openhft.chronicle.core.CleaningRandomAccessFile;
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;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
public final class CanonicalRandomAccessFiles {
/**
* Java file locks are maintained on a per JVM basis. So we need to manage them.
*/
private static final String DISABLE_LOCKING = "chronicle.map.disable.locking";
private static final boolean USE_EXCLUSIVE_LOCKING = !Jvm.getBoolean(DISABLE_LOCKING);
private static final boolean USE_SHARED_LOCKING = !OS.isWindows() && !Jvm.getBoolean(DISABLE_LOCKING) &&
!"shared".equalsIgnoreCase(System.getProperty(DISABLE_LOCKING));
private static final AtomicBoolean LOCK_WARNING_PRINTED = new AtomicBoolean();
private static final ConcurrentHashMap<File, RafReference> CANONICAL_RAFS = new ConcurrentHashMap<>();
private CanonicalRandomAccessFiles() {
}
public static RandomAccessFile acquire(@NotNull final File file) throws FileNotFoundException {
return CANONICAL_RAFS.compute(file, (f, ref) -> {
if (ref == null) {
try {
return new RafReference(new CleaningRandomAccessFile(f, "rw"));
} catch (FileNotFoundException e) {
throw Jvm.rethrow(e);
}
} else {
ref.refCount++;
return ref;
}
}).raf;
return acquire0(file, (ref) -> {}).raf;
}
public static void release(@NotNull final File file) throws IOException {
CANONICAL_RAFS.computeIfPresent(file, (f, ref) -> {
private static RafReference acquire0(@NotNull final File file, Consumer<RafReference> action) {
return CANONICAL_RAFS.compute(file, (f, ref) -> {
while (ref != null) {
try {
ref.raf.length();
} catch (IOException e) {
// File is closed by interrupt;
break;
}
ref.refCount++;
action.accept(ref);
return ref;
}
try {
return new RafReference(new CleaningRandomAccessFile(f, "rw"));
} catch (FileNotFoundException e) {
throw Jvm.rethrow(e);
}
});
}
public static void release(@NotNull final File file) {
release0(file, (ref) -> {});
}
private static RafReference release0(@NotNull final File file, Consumer<RafReference> action) {
return CANONICAL_RAFS.computeIfPresent(file, (f, ref) -> {
action.accept(ref);
if (--ref.refCount == 0) {
try {
ref.raf.close();
@@ -63,15 +96,234 @@ public final class CanonicalRandomAccessFiles {
});
}
public static void acquireSharedFileLock(@NotNull final File canonicalFile, @NotNull final FileChannel channel) {
if (USE_SHARED_LOCKING)
acquire0(canonicalFile, (rafReference) -> {
try {
if (rafReference.lockRef == null)
rafReference.lockRef = new FileLockReference(channel.lock(0, Long.MAX_VALUE, true));
else {
if (!rafReference.lockRef.fileLock.isShared()) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, null);
}
rafReference.lockRef.reserve();
}
} catch (IOException | IllegalStateException e) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, e);
}
});
else
printWarningTheFirstTime();
}
public static void acquireExclusiveFileLock(@NotNull final File canonicalFile, @NotNull final FileChannel channel) {
if (USE_EXCLUSIVE_LOCKING)
acquire0(canonicalFile, (rafReference) -> {
if (rafReference.lockRef == null) {
try {
final FileLock fileLock = channel.lock(0, Long.MAX_VALUE, false);
rafReference.lockRef = new FileLockReference(fileLock);
} catch (IOException e) {
throw newUnableToAcquireExclusiveFileLockException(canonicalFile, e);
}
} else {
throw newUnableToAcquireExclusiveFileLockException(canonicalFile, null);
}
});
else
printWarningTheFirstTime();
}
public static void releaseSharedFileLock(@NotNull final File canonicalFile) {
if (USE_SHARED_LOCKING)
releaseFileLock0(canonicalFile);
else
printWarningTheFirstTime();
}
public static void releaseExclusiveFileLock(@NotNull final File canonicalFile) {
if (USE_EXCLUSIVE_LOCKING)
releaseFileLock0(canonicalFile);
else
printWarningTheFirstTime();
}
private static void releaseFileLock0(@NotNull File canonicalFile) {
release0(canonicalFile, (rafReference) -> {
if (rafReference.lockRef == null)
throw new ChronicleFileLockException("Trying to release lock on file " + canonicalFile + " that did not exist");
else {
final int cnt = rafReference.lockRef.release();
if (cnt == 0)
rafReference.lockRef = null;
}
});
}
/**
* Tries to execute a closure under exclusive file lock.
* If USE_LOCKING is false, provides synchronization only within local JVM.
*
* @param fileIOAction Closure to run, can throw {@link IOException}s.
* @return <code>true</code> if the lock was successfully acquired and IO action was executed, <code>false</code> otherwise.
*/
public static boolean tryRunExclusively(@NotNull final File canonicalFile,
@NotNull final FileChannel fileChannel,
@NotNull final FileIOAction fileIOAction) {
AtomicBoolean locked = new AtomicBoolean(false);
acquire0(canonicalFile, (rafReference) -> {
if (rafReference.lockRef != null)
return;
try {
if (USE_EXCLUSIVE_LOCKING) {
try (FileLock ignored = fileChannel.tryLock()) {
if (ignored == null) {
rafReference.lockRef = null;
return;
}
fileIOAction.fileIOAction();
locked.set(true);
}
catch (OverlappingFileLockException ignored) {
// File lock is being held by this JVM, unsuccessful attempt.
}
} else {
fileIOAction.fileIOAction();
locked.set(true);
}
rafReference.lockRef = null;
} catch (Exception e) {
throw Jvm.rethrow(e);
}
}
);
release(canonicalFile);
return locked.get();
}
/**
* Executes a closure under exclusive file lock.
* If USE_LOCKING is false, provides synchronization only within local JVM.
*
* @param fileIOAction Closure to run, can throw {@link IOException}s.
*/
public static void runExclusively(@NotNull final File canonicalFile,
@NotNull final FileChannel fileChannel,
@NotNull final FileIOAction fileIOAction) {
acquire0(canonicalFile, (rafReference) -> {
if (rafReference.lockRef != null)
throw new ChronicleFileLockException("A file lock instance already exists for the file " + canonicalFile);
try {
if (USE_EXCLUSIVE_LOCKING) {
try (FileLock ignored = fileChannel.lock()) {
fileIOAction.fileIOAction();
}
} else {
fileIOAction.fileIOAction();
}
} catch (Exception e) {
throw Jvm.rethrow(e);
}
});
}
static void dump() {
System.out.println(CANONICAL_RAFS);
}
private static ChronicleFileLockException newUnableToAcquireSharedFileLockException(@NotNull final File canonicalFile, @Nullable final Exception e) {
return new ChronicleFileLockException("Unable to acquire a shared file lock for " + canonicalFile + ". " +
"Make sure another process is not recovering the map.", e);
}
private static ChronicleFileLockException newUnableToAcquireExclusiveFileLockException(@NotNull final File canonicalFile, @Nullable final Exception e) {
return new ChronicleFileLockException("Unable to acquire an exclusive file lock for " + canonicalFile + ". " +
"Make sure no other process is using the map.", e);
}
private static void printWarningTheFirstTime() {
if (LOCK_WARNING_PRINTED.compareAndSet(false, true)) {
Jvm.warn().on(CanonicalRandomAccessFiles.class, "File locking is disabled or 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!");
}
}
// This class is not thread-safe but instances
// are protected by means of the FILE_LOCKS map
public static final class FileLockReference {
private final FileLock fileLock;
private int refCount;
FileLockReference(@NotNull final FileLock fileLock) {
this.fileLock = fileLock;
refCount = 1;
}
int reserve() {
if (refCount == 0)
throw new IllegalStateException("Ref counter previously released");
return ++refCount;
}
int release() {
final int cnt = --refCount;
if (cnt == 0) {
try {
fileLock.release();
} catch (IOException e) {
throw new ChronicleFileLockException(e);
}
}
if (cnt < 0)
throw new IllegalStateException("Ref counter was " + cnt);
return cnt;
}
@Override
public String toString() {
return "FileLockReference{" +
"fileLock=" + fileLock +
", refCount=" + refCount +
'}';
}
}
@FunctionalInterface
public interface FileIOAction {
void fileIOAction() throws IOException;
}
// This class is not thread-safe but instances
// are protected by means of the CANONICAL_RAFS map
private static final class RafReference {
private final RandomAccessFile raf;
private FileLockReference lockRef;
private int refCount;
RafReference(@NotNull final RandomAccessFile raf) {
this.raf = raf;
this.lockRef = null;
refCount = 1;
}
@Override
public String toString() {
return "RafReference{" +
"raf=" + raf +
", lockRef=" + lockRef +
", refCount=" + refCount +
'}';
}
}
}
@@ -1713,7 +1713,7 @@ public final class ChronicleMapBuilder<K, V> implements
TimingPauser pauser = Pauser.balanced();
while (raf.length() == 0) {
final boolean locked = FileLockUtil.tryRunExclusively(canonicalFile, fileChannel, () -> {
final boolean locked = CanonicalRandomAccessFiles.tryRunExclusively(canonicalFile, fileChannel, () -> {
// Double-checked locking
if (raf.length() == 0) {
map.set(newMap());
@@ -1840,8 +1840,8 @@ public final class ChronicleMapBuilder<K, V> implements
map.initBeforeMapping(canonicalFile, raf, headerBuffer.limit(), false);
map.createMappedStoreAndSegments(resources);
FileLockUtil.acquireSharedFileLock(canonicalFile, raf.getChannel());
map.addCloseable(() -> FileLockUtil.releaseSharedFileLock(canonicalFile));
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, raf.getChannel());
map.addCloseable(() -> CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile));
commitChronicleMapReady(map, raf, headerBuffer, headerSize);
return map;
}
@@ -1907,22 +1907,22 @@ public final class ChronicleMapBuilder<K, V> implements
map.initTransientsFromBuilder(this);
if (!recover) {
map.createMappedStoreAndSegments(resources);
FileLockUtil.acquireSharedFileLock(file, raf.getChannel());
CanonicalRandomAccessFiles.acquireSharedFileLock(file, raf.getChannel());
} else {
if (!headerWritten)
writeNotComplete(fileChannel, headerBuffer, headerSize);
try {
FileLockUtil.acquireExclusiveFileLock(file, raf.getChannel());
CanonicalRandomAccessFiles.acquireExclusiveFileLock(file, raf.getChannel());
map.recover(resources, corruptionListener, corruption);
} finally {
FileLockUtil.releaseExclusiveFileLock(file);
CanonicalRandomAccessFiles.releaseExclusiveFileLock(file);
}
// We are ready with exclusive access.
// Demote the lock from exclusive to shared
FileLockUtil.acquireSharedFileLock(file, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(file, fileChannel);
commitChronicleMapReady(map, raf, headerBuffer, headerSize);
}
map.addCloseable(() -> FileLockUtil.releaseSharedFileLock(file));
map.addCloseable(() -> CanonicalRandomAccessFiles.releaseSharedFileLock(file));
if (MAP_CREATION_DEBUG) {
Jvm.warn().on(getClass(), "<map creation debug> Created map [name=" + map.name() +
", size=" + map.longSize() + "] from file [canonizedMapDataFile=" +
@@ -1,257 +0,0 @@
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;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
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 String DISABLE_LOCKING = "chronicle.map.disable.locking";
private static final ConcurrentHashMap<File, FileLockReference> FILE_LOCKS = new ConcurrentHashMap<>();
private static final boolean USE_EXCLUSIVE_LOCKING = !Jvm.getBoolean(DISABLE_LOCKING);
private static final boolean USE_SHARED_LOCKING = !OS.isWindows() && !Jvm.getBoolean(DISABLE_LOCKING) &&
!"shared".equalsIgnoreCase(System.getProperty(DISABLE_LOCKING));
private static final AtomicBoolean LOCK_WARNING_PRINTED = new AtomicBoolean();
private FileLockUtil() {
}
public static void acquireSharedFileLock(@NotNull final File canonicalFile, @NotNull final FileChannel channel) {
if (USE_SHARED_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
}
} catch (IOException | IllegalStateException e) {
throw newUnableToAcquireSharedFileLockException(canonicalFile, e);
}
}
);
else
printWarningTheFirstTime();
}
public static void acquireExclusiveFileLock(@NotNull final File canonicalFile, @NotNull final FileChannel channel) {
if (USE_EXCLUSIVE_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
printWarningTheFirstTime();
}
public static void releaseSharedFileLock(@NotNull final File canonicalFile) {
if (USE_SHARED_LOCKING)
releaseFileLock0(canonicalFile);
else
printWarningTheFirstTime();
}
public static void releaseExclusiveFileLock(@NotNull final File canonicalFile) {
if (USE_EXCLUSIVE_LOCKING)
releaseFileLock0(canonicalFile);
else
printWarningTheFirstTime();
}
/**
* @deprecated Use {@link #releaseExclusiveFileLock(File)} or {@link #releaseSharedFileLock(File)} instead.
*/
@Deprecated
public static void releaseFileLock(@NotNull final File canonicalFile) {
releaseExclusiveFileLock(canonicalFile);
}
private static void releaseFileLock0(@NotNull 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;
}
}
);
}
/**
* Tries to execute a closure under exclusive file lock.
* If USE_LOCKING is false, provides synchronization only within local JVM.
*
* @param fileIOAction Closure to run, can throw {@link IOException}s.
* @return <code>true</code> if the lock was successfully acquired and IO action was executed, <code>false</code> otherwise.
*/
public static boolean tryRunExclusively(@NotNull final File canonicalFile,
@NotNull final FileChannel fileChannel,
@NotNull final FileIOAction fileIOAction) {
AtomicBoolean locked = new AtomicBoolean(false);
FILE_LOCKS.compute(canonicalFile, (f, flr) -> {
if (flr != null)
return flr;
try {
if (USE_EXCLUSIVE_LOCKING) {
try (FileLock ignored = fileChannel.tryLock()) {
if (ignored == null)
return null;
fileIOAction.fileIOAction();
locked.set(true);
}
catch (OverlappingFileLockException ignored) {
// File lock is being held by this JVM, unsuccessful attempt.
}
} else {
fileIOAction.fileIOAction();
locked.set(true);
}
return null;
} catch (Exception e) {
throw Jvm.rethrow(e);
}
}
);
return locked.get();
}
/**
* Executes a closure under exclusive file lock.
* If USE_LOCKING is false, provides synchronization only within local JVM.
*
* @param fileIOAction Closure to run, can throw {@link IOException}s.
*/
public static void runExclusively(@NotNull final File canonicalFile,
@NotNull final FileChannel fileChannel,
@NotNull final FileIOAction fileIOAction) {
FILE_LOCKS.compute(canonicalFile, (f, flr) -> {
if (flr != null)
throw new ChronicleFileLockException("A file lock instance already exists for the file " + canonicalFile);
try {
if (USE_EXCLUSIVE_LOCKING) {
try (FileLock ignored = fileChannel.lock()) {
fileIOAction.fileIOAction();
}
} else {
fileIOAction.fileIOAction();
}
return null;
} catch (Exception e) {
throw Jvm.rethrow(e);
}
}
);
}
static void dump() {
System.out.println(FILE_LOCKS);
}
private static ChronicleFileLockException newUnableToAcquireSharedFileLockException(@NotNull final File canonicalFile, @Nullable final Exception e) {
return new ChronicleFileLockException("Unable to acquire a shared file lock for " + canonicalFile + ". " +
"Make sure another process is not recovering the map.", e);
}
private static ChronicleFileLockException newUnableToAcquireExclusiveFileLockException(@NotNull final File canonicalFile, @Nullable final Exception e) {
return new ChronicleFileLockException("Unable to acquire an exclusive file lock for " + canonicalFile + ". " +
"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 disabled or 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!");
}
}
// This class is not thread-safe but instances
// are protected by means of the FILE_LOCKS map
private static final class FileLockReference {
private final FileLock fileLock;
private int refCount;
FileLockReference(@NotNull final FileLock fileLock) {
this.fileLock = fileLock;
refCount = 1;
}
int reserve() {
if (refCount == 0)
throw new IllegalStateException("Ref counter previously released");
return ++refCount;
}
int release() {
final int cnt = --refCount;
if (cnt == 0) {
try {
fileLock.release();
} catch (IOException e) {
throw new ChronicleFileLockException(e);
}
}
if (cnt < 0)
throw new IllegalStateException("Ref counter was " + cnt);
return cnt;
}
@Override
public String toString() {
return "FileLockReference{" +
"fileLock=" + fileLock +
", refCount=" + refCount +
'}';
}
}
@FunctionalInterface
interface FileIOAction {
void fileIOAction() throws IOException;
}
}
@@ -39,78 +39,78 @@ public class FileLockUtilTest {
@Test
public void testShared() {
if (!OS.isWindows()) {
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
FileLockUtil.releaseSharedFileLock(canonicalFile);
FileLockUtil.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
}
}
@Test
public void testExclusiveNormalCase() {
FileLockUtil.acquireExclusiveFileLock(canonicalFile, fileChannel);
FileLockUtil.releaseExclusiveFileLock(canonicalFile);
FileLockUtil.acquireExclusiveFileLock(canonicalFile, fileChannel);
FileLockUtil.releaseExclusiveFileLock(canonicalFile);
CanonicalRandomAccessFiles.acquireExclusiveFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.releaseExclusiveFileLock(canonicalFile);
CanonicalRandomAccessFiles.acquireExclusiveFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.releaseExclusiveFileLock(canonicalFile);
}
@Test
public void testTryExclusiveButWasShared() {
if (!OS.isWindows()) {
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
try {
FileLockUtil.acquireExclusiveFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireExclusiveFileLock(canonicalFile, fileChannel);
fail();
} catch (ChronicleFileLockException ignore) {
}
FileLockUtil.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
}
}
@Test
public void testTrySharedButWasExclusive() {
if (!OS.isWindows()) {
FileLockUtil.acquireExclusiveFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireExclusiveFileLock(canonicalFile, fileChannel);
try {
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
fail();
} catch (ChronicleFileLockException ignore) {
}
FileLockUtil.releaseExclusiveFileLock(canonicalFile);
CanonicalRandomAccessFiles.releaseExclusiveFileLock(canonicalFile);
}
}
@Test
public void testComplicated() {
if (!OS.isWindows()) {
FileLockUtil.acquireExclusiveFileLock(canonicalFile, fileChannel);
FileLockUtil.releaseExclusiveFileLock(canonicalFile);
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
FileLockUtil.releaseSharedFileLock(canonicalFile);
FileLockUtil.releaseSharedFileLock(canonicalFile);
FileLockUtil.acquireExclusiveFileLock(canonicalFile, fileChannel);
FileLockUtil.releaseExclusiveFileLock(canonicalFile);
CanonicalRandomAccessFiles.acquireExclusiveFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.releaseExclusiveFileLock(canonicalFile);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.acquireExclusiveFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.releaseExclusiveFileLock(canonicalFile);
}
}
@Test
public void testRunExclusively() {
final AtomicInteger cnt = new AtomicInteger();
FileLockUtil.runExclusively(canonicalFile, fileChannel, cnt::incrementAndGet);
CanonicalRandomAccessFiles.runExclusively(canonicalFile, fileChannel, cnt::incrementAndGet);
assertEquals(1, cnt.get());
}
@Test
public void testRunExclusivelyButUsed() {
if (!OS.isWindows()) {
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
try {
FileLockUtil.runExclusively(canonicalFile, fileChannel, () -> {
CanonicalRandomAccessFiles.runExclusively(canonicalFile, fileChannel, () -> {
});
fail();
} catch (ChronicleFileLockException e) {
FileLockUtil.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
}
}
}
@@ -118,16 +118,16 @@ public class FileLockUtilTest {
@Test
public void testTryRunExclusively() {
if (!OS.isWindows()) {
FileLockUtil.acquireSharedFileLock(canonicalFile, fileChannel);
CanonicalRandomAccessFiles.acquireSharedFileLock(canonicalFile, fileChannel);
boolean lockedAndRun = FileLockUtil.tryRunExclusively(canonicalFile, fileChannel, () -> {
boolean lockedAndRun = CanonicalRandomAccessFiles.tryRunExclusively(canonicalFile, fileChannel, () -> {
});
assertFalse(lockedAndRun);
FileLockUtil.releaseSharedFileLock(canonicalFile);
CanonicalRandomAccessFiles.releaseSharedFileLock(canonicalFile);
lockedAndRun = FileLockUtil.tryRunExclusively(canonicalFile, fileChannel, () -> {
lockedAndRun = CanonicalRandomAccessFiles.tryRunExclusively(canonicalFile, fileChannel, () -> {
});
assertTrue(lockedAndRun);