From c79b078c36c257481852bb8259bb6dc38c07b05d Mon Sep 17 00:00:00 2001 From: leventov Date: Thu, 10 Dec 2015 17:36:46 +0300 Subject: [PATCH] Apply timed tryLock() heuristic from commit 6c56813b5e428967f28f77d27e87e3270e78ca63 to tryWriteLock() and tryUpgradeUpdateToWriteLock(), was used only in tryReadLock() and tryUpdateLock() --- .../chronicle/hash/impl/BigSegmentHeader.java | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java b/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java index 8a3d3ee74..5b8d4ff4b 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java @@ -23,6 +23,8 @@ import net.openhft.chronicle.core.OS; import java.util.concurrent.TimeUnit; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + public final class BigSegmentHeader implements SegmentHeader { public static final BigSegmentHeader INSTANCE = new BigSegmentHeader(); @@ -42,6 +44,13 @@ public final class BigSegmentHeader implements SegmentHeader { static final long LOWEST_POSSIBLY_FREE_CHUNK_OFFSET = ENTRIES_OFFSET + 4L; static final long DELETED_OFFSET = LOWEST_POSSIBLY_FREE_CHUNK_OFFSET + 4L; + + private static final int TRY_LOCK_NANOS_THRESHOLD = 2_000_000; + + private static long roundUpNanosToMillis(long nanos) { + return NANOSECONDS.toMillis(nanos + 900_000); + } + private BigSegmentHeader() { } @@ -108,10 +117,10 @@ public final class BigSegmentHeader implements SegmentHeader { private boolean tryReadLock0(long address, long time, TimeUnit unit) { long timeInNanos = unit.toNanos(time); - if (timeInNanos < 2000000) { + if (timeInNanos < TRY_LOCK_NANOS_THRESHOLD) { return tryReadLockNanos(address, timeInNanos); } else { - return tryReadLockMillis(address, (timeInNanos + 900000) / 1000000); + return tryReadLockMillis(address, roundUpNanosToMillis(timeInNanos)); } } @@ -175,10 +184,10 @@ public final class BigSegmentHeader implements SegmentHeader { private boolean tryUpdateLock0(long address, long time, TimeUnit unit) { long timeInNanos = unit.toNanos(time); - if (timeInNanos < 2000000) { + if (timeInNanos < TRY_LOCK_NANOS_THRESHOLD) { return tryUpdateLockNanos(address, timeInNanos); } else { - return tryUpdateLockMillis(address, (timeInNanos + 900000) / 1000000); + return tryUpdateLockMillis(address, roundUpNanosToMillis(timeInNanos)); } } @@ -231,7 +240,16 @@ public final class BigSegmentHeader implements SegmentHeader { } private boolean tryWriteLock0(long address, long time, TimeUnit unit) { - long end = System.nanoTime() + unit.toNanos(time); + long timeInNanos = unit.toNanos(time); + if (timeInNanos < TRY_LOCK_NANOS_THRESHOLD) { + return tryWriteLockNanos(address, timeInNanos); + } else { + return tryWriteLockMillis(address, roundUpNanosToMillis(timeInNanos)); + } + } + + private boolean tryWriteLockNanos(long address, long timeInNanos) { + long end = System.nanoTime() + timeInNanos; registerWait(address); do { if (LOCK.tryWriteLockAndDeregisterWait(A, null, address + LOCK_OFFSET)) @@ -241,6 +259,25 @@ public final class BigSegmentHeader implements SegmentHeader { return false; } + /** + * Use a timer which is more insensitive to jumps in time like GCs and context switches. + */ + private boolean tryWriteLockMillis(long address, long timeInMillis) { + long lastTime = System.currentTimeMillis(); + registerWait(address); + do { + if (LOCK.tryWriteLockAndDeregisterWait(A, null, address + LOCK_OFFSET)) + return true; + long now = System.currentTimeMillis(); + if (now != lastTime) { + lastTime = now; + timeInMillis--; + } + } while (timeInMillis >= 0); + deregisterWait(address); + return false; + } + private static void registerWait(long address) { LOCK.registerWait(A, null, address + LOCK_OFFSET); } @@ -273,7 +310,16 @@ public final class BigSegmentHeader implements SegmentHeader { } private boolean tryUpgradeUpdateToWriteLock0(long address, long time, TimeUnit unit) { - long end = System.nanoTime() + unit.toNanos(time); + long timeInNanos = unit.toNanos(time); + if (timeInNanos < TRY_LOCK_NANOS_THRESHOLD) { + return tryUpgradeUpdateToWriteLockNanos(address, timeInNanos); + } else { + return tryUpgradeUpdateToWriteLockMillis(address, roundUpNanosToMillis(timeInNanos)); + } + } + + private boolean tryUpgradeUpdateToWriteLockNanos(long address, long timeInNanos) { + long end = System.nanoTime() + timeInNanos; registerWait(address); do { if (LOCK.tryUpgradeUpdateToWriteLockAndDeregisterWait(A, null, address + LOCK_OFFSET)) @@ -283,6 +329,25 @@ public final class BigSegmentHeader implements SegmentHeader { return false; } + /** + * Use a timer which is more insensitive to jumps in time like GCs and context switches. + */ + private boolean tryUpgradeUpdateToWriteLockMillis(long address, long timeInMillis) { + long lastTime = System.currentTimeMillis(); + registerWait(address); + do { + if (LOCK.tryUpgradeUpdateToWriteLockAndDeregisterWait(A, null, address + LOCK_OFFSET)) + return true; + long now = System.currentTimeMillis(); + if (now != lastTime) { + lastTime = now; + timeInMillis--; + } + } while (timeInMillis >= 0); + deregisterWait(address); + return false; + } + @Override public void readUnlock(long address) { LOCK.readUnlock(A, null, address + LOCK_OFFSET);