From 9a9b33b6cfb477fca76d3a93f9e3390d574e1ce3 Mon Sep 17 00:00:00 2001 From: Ivan Rakov Date: Wed, 16 Jun 2021 19:25:46 +0300 Subject: [PATCH] tidy. --- .../chronicle/map/ChronicleMapBuilder.java | 43 +++++++++++-------- .../openhft/chronicle/map/FileLockUtil.java | 7 ++- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index 614a9b639..42131f1bf 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -39,6 +39,8 @@ import net.openhft.chronicle.hash.serialization.impl.TypedMarshallableReaderWrit import net.openhft.chronicle.map.internal.AnalyticsHolder; import net.openhft.chronicle.map.replication.MapRemoteOperations; import net.openhft.chronicle.set.ChronicleSetBuilder; +import net.openhft.chronicle.threads.Pauser; +import net.openhft.chronicle.threads.TimingPauser; import net.openhft.chronicle.values.ValueModel; import net.openhft.chronicle.values.Values; import net.openhft.chronicle.wire.Marshallable; @@ -58,6 +60,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -1703,25 +1706,31 @@ public final class ChronicleMapBuilder implements final AtomicBoolean newFile = new AtomicBoolean(); final FileChannel fileChannel = raf.getChannel(); - while (true) { - if (raf.length() == 0) { - final boolean locked = FileLockUtil.tryRunExclusively(canonicalFile, fileChannel, () -> { - if (raf.length() == 0) { - map.set(newMap()); - headerBuffer.set(writeHeader(fileChannel, map.get())); - newFile.set(true); - } else { - newFile.set(false); - } - }); + TimingPauser pauser = Pauser.balanced(); - if (locked) - break; - else - Jvm.pause(10); - } - else + while (raf.length() == 0) { + final boolean locked = FileLockUtil.tryRunExclusively(canonicalFile, fileChannel, () -> { + if (raf.length() == 0) { + map.set(newMap()); + headerBuffer.set(writeHeader(fileChannel, map.get())); + newFile.set(true); + } else { + newFile.set(false); + } + }); + + if (locked) break; + else { + try { + pauser.pause(10, TimeUnit.SECONDS); + } + catch (TimeoutException e) { + LOG.warn("Failed to write header: can't acquire exclusive file lock on empty file for 10 seconds", e); + + Jvm.rethrow(e); + } + } } if (newFile.get()) { diff --git a/src/main/java/net/openhft/chronicle/map/FileLockUtil.java b/src/main/java/net/openhft/chronicle/map/FileLockUtil.java index d22637005..4c3ba6c98 100644 --- a/src/main/java/net/openhft/chronicle/map/FileLockUtil.java +++ b/src/main/java/net/openhft/chronicle/map/FileLockUtil.java @@ -10,6 +10,7 @@ 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; @@ -91,10 +92,11 @@ public final class FileLockUtil { } /** - * Executes a closure under exclusive file lock. + * 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 true if the lock was successfully acquired and IO action was executed, false otherwise. */ public static boolean tryRunExclusively(@NotNull final File canonicalFile, @NotNull final FileChannel fileChannel, @@ -115,6 +117,9 @@ public final class FileLockUtil { locked.set(true); } + catch (OverlappingFileLockException ignored) { + // File lock is being held by this JVM, unsuccessful attempt. + } } else { fileIOAction.fileIOAction();