From 4d7dd56c43127b5076feab2afd5e6bbaa533fe54 Mon Sep 17 00:00:00 2001 From: Peter Lawrey Date: Wed, 29 Oct 2014 13:46:40 +0000 Subject: [PATCH 1/2] Use consistent hashing and thread local caches of StringBuilders. --- .../hash/ChronicleHashErrorListeners.java | 8 ++-- .../chronicle/hash/serialization/Hasher.java | 5 +-- .../openhft/chronicle/map/TcpReplicator.java | 10 +---- .../chronicle/map/VanillaChronicleMap.java | 1 - .../net/openhft/chronicle/map/CHMTest5.java | 4 ++ .../chronicle/map/EntryCountMapTest.java | 4 +- .../chronicle/map/StatelessClientTest.java | 31 +++++++------- .../map/fromdocs/BondVOInterface.java | 2 + .../openhft/lang/values/IntValue$$Native.java | 42 ++++++++++++++----- 9 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashErrorListeners.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashErrorListeners.java index dd0f75ae7..5d9654e93 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashErrorListeners.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashErrorListeners.java @@ -19,7 +19,6 @@ package net.openhft.chronicle.hash; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class ChronicleHashErrorListeners { @@ -39,21 +38,20 @@ public final class ChronicleHashErrorListeners { private static enum LoggingErrorListener implements ChronicleHashErrorListener { INSTANCE; - final Logger LOG = LoggerFactory.getLogger(getClass()); @Override public void onLockTimeout(long threadId) throws IllegalStateException { if (threadId > 1L << 32) { - LOG.warn("Grabbing lock held by processId: {}, threadId: {}", + LoggerFactory.getLogger(getClass()).warn("Grabbing lock held by processId: {}, threadId: {}", (threadId >>> 33), (threadId & 0xFFFFFFL)); } else { - LOG.warn("Grabbing lock held by threadId: {}", threadId); + LoggerFactory.getLogger(getClass()).warn("Grabbing lock held by threadId: {}", threadId); } } @Override public void errorOnUnlock(IllegalMonitorStateException e) { - LOG.warn("Failed to unlock as expected", e); + LoggerFactory.getLogger(getClass()).warn("Failed to unlock as expected", e); } } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java b/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java index 185ef64a5..b2325416c 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java @@ -18,6 +18,7 @@ package net.openhft.chronicle.hash.serialization; +import net.openhft.lang.Maths; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.NativeBytes; import sun.misc.Unsafe; @@ -75,8 +76,6 @@ public enum Hasher { } public static long hash(long value) { - value ^= (value >>> 41) - (value >>> 21); - value ^= (value >>> 15) + (value >>> 7); - return value; + return Maths.hash(value); } } diff --git a/src/main/java/net/openhft/chronicle/map/TcpReplicator.java b/src/main/java/net/openhft/chronicle/map/TcpReplicator.java index 80ad3962e..3937a5d2f 100644 --- a/src/main/java/net/openhft/chronicle/map/TcpReplicator.java +++ b/src/main/java/net/openhft/chronicle/map/TcpReplicator.java @@ -1879,15 +1879,7 @@ class KeyValueSerializer { } private boolean nullCheck(Bytes in) { - try { - return in.readBoolean(); - } catch (BufferUnderflowException e) { - - - e.printStackTrace(); - throw e; - } - + return in.readBoolean(); } K readKey(Bytes reader) { diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index 15c5b6632..0a7e62c66 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -51,7 +51,6 @@ class VanillaChronicleMap, V, VW, MVW extends MetaBytesWriter> extends AbstractMap implements ChronicleMap, Serializable { private static final long serialVersionUID = 2L; - private static final Logger LOG = LoggerFactory.getLogger(VanillaChronicleMap.class); /** * Because DirectBitSet implementations couldn't find more than 64 continuous clear or set diff --git a/src/test/java/net/openhft/chronicle/map/CHMTest5.java b/src/test/java/net/openhft/chronicle/map/CHMTest5.java index 948d1a796..e631c45be 100644 --- a/src/test/java/net/openhft/chronicle/map/CHMTest5.java +++ b/src/test/java/net/openhft/chronicle/map/CHMTest5.java @@ -245,12 +245,16 @@ public class CHMTest5 { boolean compareAndSwapMaxNumberOfProcessesAllowed(int expected, int value); + @Deprecated() void busyLockEntry() throws InterruptedException, IllegalStateException; + @Deprecated() boolean tryLockNanosEntry(long nanos); + @Deprecated() boolean tryLockEntry(); + @Deprecated() void unlockEntry() throws IllegalMonitorStateException; } } \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java b/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java index 1440e0305..194bd61cd 100644 --- a/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java @@ -55,7 +55,7 @@ public class EntryCountMapTest { @Test public void testSmall() throws Exception { - for (int i = 0; i < 60; i++) { + for (int i = 0; i < 6; i++) { // regression test. for (int s : new int[]{1, 2, 4, 8}) { if (s <= 4) @@ -77,7 +77,7 @@ public class EntryCountMapTest { @Test public void testMedium() throws Exception { - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 1; i++) { // regression test. int s = 16; testEntriesMaxSize(s, 512, 1000, i); diff --git a/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java b/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java index 33ff9b497..ec906ec8b 100644 --- a/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java +++ b/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java @@ -28,6 +28,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import static net.openhft.chronicle.hash.StatelessBuilder.remoteAddress; @@ -39,6 +40,8 @@ public class StatelessClientTest { public static final int SIZE = 100000; + private static final AtomicInteger PORT_COUNTER = new AtomicInteger(58076); + public final int port = PORT_COUNTER.getAndIncrement(); @Test @@ -52,13 +55,13 @@ public class StatelessClientTest { { statelessMap = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); } // server { serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); } @@ -95,13 +98,13 @@ public class StatelessClientTest { { statelessMap = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); } // server { serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); } @@ -136,13 +139,13 @@ public class StatelessClientTest { { statelessMap = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); } // server { serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); } @@ -175,7 +178,7 @@ public class StatelessClientTest { // server { serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); serverMap.put(10, "EXAMPLE-10"); } @@ -185,7 +188,7 @@ public class StatelessClientTest { { statelessMap = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); Assert.assertEquals("EXAMPLE-10", statelessMap.get(10)); Assert.assertEquals(1, statelessMap.size()); @@ -208,13 +211,13 @@ public class StatelessClientTest { { statelessMap = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); } // server { serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); serverMap.put(10, "EXAMPLE-10"); } @@ -240,13 +243,13 @@ public class StatelessClientTest { { statelessMap = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); } // server { serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); } @@ -282,7 +285,7 @@ public class StatelessClientTest { { statelessMap1 = ChronicleMapBuilder.of(Integer .class, CharSequence.class) - .stateless(remoteAddress(new InetSocketAddress("localhost", 8076))).create(); + .stateless(remoteAddress(new InetSocketAddress("localhost", port))).create(); statelessMap2 = ChronicleMapBuilder.of(Integer .class, CharSequence.class) .stateless(remoteAddress(new InetSocketAddress("localhost", 8077))).create(); @@ -291,7 +294,7 @@ public class StatelessClientTest { // server { serverMap1 = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .replicators((byte) 2, TcpReplicationConfig.of(8076)).create(); + .replicators((byte) 2, TcpReplicationConfig.of(port)).create(); serverMap2 = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .replicators((byte) 2, TcpReplicationConfig.of(8077)).create(); diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java b/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java index d1b5e4814..ec567ce9c 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java @@ -22,8 +22,10 @@ import net.openhft.lang.model.constraints.MaxSize; public interface BondVOInterface { /* add support for entry based locking */ + @Deprecated() void busyLockEntry() throws InterruptedException; + @Deprecated() void unlockEntry(); long getIssueDate(); diff --git a/src/test/java/net/openhft/lang/values/IntValue$$Native.java b/src/test/java/net/openhft/lang/values/IntValue$$Native.java index 686a4ec49..19a6415a0 100644 --- a/src/test/java/net/openhft/lang/values/IntValue$$Native.java +++ b/src/test/java/net/openhft/lang/values/IntValue$$Native.java @@ -34,7 +34,6 @@ public class IntValue$$Native implements IntValue, BytesMarshallable, Byteable, private long _offset; - public void setValue(int $) { _bytes.writeInt(_offset + VALUE, $); } @@ -44,7 +43,6 @@ public class IntValue$$Native implements IntValue, BytesMarshallable, Byteable, } - public void setOrderedValue(int $) { _bytes.writeOrderedInt(_offset + VALUE, $); } @@ -55,20 +53,36 @@ public class IntValue$$Native implements IntValue, BytesMarshallable, Byteable, public int addValue(int $) { return _bytes.addInt(_offset + VALUE, $); - } public int addAtomicValue(int $) { + } + + public int addAtomicValue(int $) { return _bytes.addAtomicInt(_offset + VALUE, $); - } public boolean compareAndSwapValue(int _1, int _2) { + } + + public boolean compareAndSwapValue(int _1, int _2) { return _bytes.compareAndSwapInt(_offset + VALUE, _1, _2); - } public boolean tryLockNanosValue(long nanos) { + } + + public boolean tryLockNanosValue(long nanos) { return _bytes.tryLockNanosInt(_offset + VALUE, nanos); - } public boolean tryLockValue() { + } + + public boolean tryLockValue() { return _bytes.tryLockInt(_offset + VALUE); - } public void unlockValue() { + } + + @Deprecated() + public void unlockValue() { _bytes.unlockInt(_offset + VALUE); - } public void busyLockValue() throws InterruptedException { + } + + @Deprecated() + public void busyLockValue() throws InterruptedException { _bytes.busyLockInt(_offset + VALUE); - } @Override - public void copyFrom(net.openhft.lang.values.IntValue from) { + } + + @Override + public void copyFrom(net.openhft.lang.values.IntValue from) { setValue(from.getValue()); } @@ -76,27 +90,33 @@ public class IntValue$$Native implements IntValue, BytesMarshallable, Byteable, public void writeMarshallable(Bytes out) { out.writeInt(getValue()); } + @Override public void readMarshallable(Bytes in) { setValue(in.readInt()); } + @Override public void bytes(Bytes bytes, long offset) { this._bytes = bytes; this._offset = offset; } + @Override public Bytes bytes() { return _bytes; } + @Override public long offset() { return _offset; } + @Override public int maxSize() { return 4; } + public int hashCode() { long lhc = longHashCode(); return (int) ((lhc >>> 32) ^ lhc); @@ -111,7 +131,7 @@ public class IntValue$$Native implements IntValue, BytesMarshallable, Byteable, if (!(o instanceof IntValue)) return false; IntValue that = (IntValue) o; - if(!isEqual(getValue(), that.getValue())) return false; + if (!isEqual(getValue(), that.getValue())) return false; return true; } From bfd866e45d53aa5a7a025ee89a064a93ba886f53 Mon Sep 17 00:00:00 2001 From: Peter Lawrey Date: Wed, 29 Oct 2014 13:53:08 +0000 Subject: [PATCH 2/2] Tweet the constants used for hashing based on the city hash. --- .../chronicle/hash/serialization/Hasher.java | 6 +++--- .../chronicle/map/EntryCountMapTest.java | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java b/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java index b2325416c..8d1cca2bf 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/Hasher.java @@ -29,9 +29,9 @@ import static java.nio.ByteOrder.nativeOrder; public enum Hasher { ; - private static final long LONG_LEVEL_PRIME_MULTIPLE = 1011001110001111L; - private static final short SHORT_LEVEL_PRIME_MULTIPLE = 10191; - private static final byte BYTE_LEVEL_PRIME_MULTIPLE = 109; + private static final long LONG_LEVEL_PRIME_MULTIPLE = 0x9ddfea08eb382d69L; + private static final short SHORT_LEVEL_PRIME_MULTIPLE = 0x404f; + private static final byte BYTE_LEVEL_PRIME_MULTIPLE = 0x57; private static final int INT_HASH_LOW_SHORT_MULTIPLE = nativeOrder() == LITTLE_ENDIAN ? SHORT_LEVEL_PRIME_MULTIPLE : 1; diff --git a/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java b/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java index 194bd61cd..5a93f56dd 100644 --- a/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java @@ -55,7 +55,7 @@ public class EntryCountMapTest { @Test public void testSmall() throws Exception { - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 10; i++) { // regression test. for (int s : new int[]{1, 2, 4, 8}) { if (s <= 4) @@ -77,7 +77,7 @@ public class EntryCountMapTest { @Test public void testMedium() throws Exception { - for (int i = 0; i < 1; i++) { + for (int i = 0; i < 2; i++) { // regression test. int s = 16; testEntriesMaxSize(s, 512, 1000, i); @@ -85,7 +85,7 @@ public class EntryCountMapTest { testEntriesMaxSize(s, 2000, 3100, i); testEntriesMaxSize(s, 4000, 5100, i); testEntriesMaxSize(s, 5000, 7100, i); - testEntriesMaxSize(s, 8000, 10100, i); + testEntriesMaxSize(s, 8000, 10200, i); testEntriesMaxSize(s, 12000, 16000, i); testEntriesMaxSize(s, 16000, 21000, i); s = 32; @@ -94,8 +94,8 @@ public class EntryCountMapTest { testEntriesMaxSize(s, 5000, 7900, i); testEntriesMaxSize(s, 8000, 12000, i); testEntriesMaxSize(s, 12000, 15900, i); - testEntriesMaxSize(s, 16000, 21000, i); - testEntriesMaxSize(s, 32000, 42000, i); + testEntriesMaxSize(s, 16000, 21200, i); + testEntriesMaxSize(s, 32000, 42200, i); s = 64; testEntriesMaxSize(s, 5000, 7550, i); testEntriesMaxSize(s, 8000, 11400, i); @@ -105,13 +105,13 @@ public class EntryCountMapTest { testEntriesMaxSize(s, 40000, 54000, i); s = 128; testEntriesMaxSize(s, 16000, 23000, i); - testEntriesMaxSize(s, 32000, 43000, i); - testEntriesMaxSize(s, 40000, 55200, i); - testEntriesMaxSize(s, 64000, 90000, i); + testEntriesMaxSize(s, 32000, 44200, i); + testEntriesMaxSize(s, 40000, 56000, i); + testEntriesMaxSize(s, 64000, 92000, i); testEntriesMaxSize(s, 129000, 190000, i); s = 256; - testEntriesMaxSize(s, 64000, 90000, i); - testEntriesMaxSize(s, 129000, 190000, i); + testEntriesMaxSize(s, 64000, 92000, i); + testEntriesMaxSize(s, 129000, 192000, i); } // hyperbolic average gives more weight to small numbers. System.out.printf("Score: %.2f%n", scoreCount / score);