diff --git a/rxlib/src/main/java/org/rx/io/CompositeLock.java b/rxlib/src/main/java/org/rx/io/CompositeLock.java index d087eebb..844558ab 100644 --- a/rxlib/src/main/java/org/rx/io/CompositeLock.java +++ b/rxlib/src/main/java/org/rx/io/CompositeLock.java @@ -34,26 +34,29 @@ enum Flags implements NEnum { private final FileStream owner; private final FlagsEnum flags; - final Map rwLocks = Collections.synchronizedMap(new ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD, AbstractReferenceMap.ReferenceStrength.WEAK)); + final Map rwLocks = new ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD, AbstractReferenceMap.ReferenceStrength.WEAK); @SneakyThrows private T lock(FileStream.Block block, boolean shared, @NonNull Func fn) { Lock lock = null; - if (flags.has(Flags.READ_WRITE_LOCK)) { - ReadWriteLock rwLock = rwLocks.computeIfAbsent(block, k -> { - ReadWriteLock t = overlaps(k.position, k.size); - if (t == null) { - t = new ReentrantReadWriteLock(); + FileLock fLock = null; + try { + if (flags.has(Flags.READ_WRITE_LOCK)) { + ReadWriteLock rwLock; + synchronized (rwLocks) { + rwLock = rwLocks.computeIfAbsent(block, k -> { + ReadWriteLock t = overlaps(k.position, k.size); + if (t == null) { + t = new ReentrantReadWriteLock(); + } + return t; + }); } - return t; - }); // log.info("Lock {} - {}", rwLock, block); - lock = shared ? rwLock.readLock() : rwLock.writeLock(); - lock.lock(); - } + lock = shared ? rwLock.readLock() : rwLock.writeLock(); + lock.lock(); + } - FileLock fLock = null; - try { if (flags.has(Flags.FILE_LOCK)) { fLock = owner.getRandomAccessFile().getChannel().lock(block.position, block.size, shared); } diff --git a/rxlib/src/test/java/org/rx/io/TestIO.java b/rxlib/src/test/java/org/rx/io/TestIO.java index 6789d34f..d942da99 100644 --- a/rxlib/src/test/java/org/rx/io/TestIO.java +++ b/rxlib/src/test/java/org/rx/io/TestIO.java @@ -5,6 +5,8 @@ import lombok.Data; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.map.AbstractReferenceMap; +import org.apache.commons.collections4.map.ReferenceMap; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.reflect.TypeUtils; import org.junit.jupiter.api.Test; @@ -34,6 +36,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import static org.rx.core.Extends.sleep; import static org.rx.core.Sys.toJsonString; @@ -461,6 +465,33 @@ public void kvsIdx() { }, 100); log.info("{}", indexer); } + + final Map rwLocks = Collections.synchronizedMap(new ReferenceMap<>(AbstractReferenceMap.ReferenceStrength.HARD, AbstractReferenceMap.ReferenceStrength.WEAK)); + + @Test + public void overlapsLock() { + ReentrantReadWriteLock r = new ReentrantReadWriteLock(); + rwLocks.put(new FileStream.Block(4, 2), r); + assert overlaps(0, 4) == null; + assert overlaps(6, 10) == null; + assert overlaps(3, 1) == null; + assert overlaps(3, 2) == r; + assert overlaps(3, 4) == r; + assert overlaps(5, 1) == r; + assert overlaps(5, 3) == r; + } + + private ReadWriteLock overlaps(long position, long size) { + for (Map.Entry entry : rwLocks.entrySet()) { + FileStream.Block block = entry.getKey(); + if (position + size <= block.position) + continue; // That is below this + if (block.position + block.size <= position) + continue; // This is below that + return entry.getValue(); + } + return null; + } //endregion @Test