From 0f53ed3c5bc13fe113083c47da30ffc6fc10e855 Mon Sep 17 00:00:00 2001 From: leventov Date: Wed, 17 Sep 2014 21:15:27 +0400 Subject: [PATCH] HCOLL-140 Prevent MultiMaps from occasionally being too dense --- .../chronicle/map/VanillaIntIntMultiMap.java | 19 ++++++++++++++----- .../map/VanillaShortShortMultiMap.java | 8 +++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/map/VanillaIntIntMultiMap.java b/src/main/java/net/openhft/chronicle/map/VanillaIntIntMultiMap.java index 7322bdb9b..aff236ba7 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaIntIntMultiMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaIntIntMultiMap.java @@ -27,6 +27,17 @@ import net.openhft.lang.io.DirectStore; */ class VanillaIntIntMultiMap implements IntIntMultiMap { + static int multiMapCapacity(int minCapacity) { + if (minCapacity < 0) + throw new IllegalArgumentException(); + int capacity = Maths.nextPower2(minCapacity, 16); + if (((double) minCapacity) / capacity > 2./3.) { + // multi map shouldn't be too dense + capacity <<= 1; + } + return capacity; + } + private static final int ENTRY_SIZE = 8; private static final int ENTRY_SIZE_SHIFT = 3; private static final int UNSET_KEY = 0; @@ -50,9 +61,7 @@ class VanillaIntIntMultiMap implements IntIntMultiMap { private long searchPos = -1L; public VanillaIntIntMultiMap(int minCapacity) { - if (minCapacity < 0) - throw new IllegalArgumentException(); - capacity = Maths.nextPower2(minCapacity, 16); + capacity = multiMapCapacity(minCapacity); capacityMask = capacity - 1; capacityMask2 = indexToPos(capacity - 1); bytes = DirectStore.allocateLazy(indexToPos(capacity)).bytes(); @@ -75,7 +84,7 @@ class VanillaIntIntMultiMap implements IntIntMultiMap { * constructor as the first argument */ public static long sizeInBytes(int minCapacity) { - return indexToPos(Maths.nextPower2(minCapacity, 16)); + return indexToPos(multiMapCapacity(minCapacity)); } /** @@ -84,7 +93,7 @@ class VanillaIntIntMultiMap implements IntIntMultiMap { * constructor as the second argument */ public static long sizeOfBitSetInBytes(int minCapacity) { - return Maths.nextPower2(minCapacity, 64L) / 8L; + return Math.max(multiMapCapacity(minCapacity), 64L) / 8L; } public static ATSDirectBitSet newPositions(int capacity) { diff --git a/src/main/java/net/openhft/chronicle/map/VanillaShortShortMultiMap.java b/src/main/java/net/openhft/chronicle/map/VanillaShortShortMultiMap.java index 36de37266..09a8f7171 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaShortShortMultiMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaShortShortMultiMap.java @@ -23,6 +23,8 @@ import net.openhft.lang.collection.DirectBitSet; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.DirectStore; +import static net.openhft.chronicle.map.VanillaIntIntMultiMap.multiMapCapacity; + /** * Supports a simple interface for int -> int[] off heap. */ @@ -43,9 +45,9 @@ class VanillaShortShortMultiMap implements IntIntMultiMap { private int searchPos = -1; public VanillaShortShortMultiMap(int minCapacity) { - if (minCapacity < 0 || minCapacity > (1 << 16)) + capacity = multiMapCapacity(minCapacity); + if (capacity > (1 << 16)) throw new IllegalArgumentException(); - capacity = Maths.nextPower2(minCapacity, 16); capacityMask = capacity - 1; capacityMask2 = (capacity - 1) * ENTRY_SIZE; bytes = DirectStore.allocateLazy(capacity * ENTRY_SIZE).bytes(); @@ -68,7 +70,7 @@ class VanillaShortShortMultiMap implements IntIntMultiMap { * constructor as the first argument */ public static long sizeInBytes(int minCapacity) { - return Maths.nextPower2(minCapacity, 16L) * ENTRY_SIZE; + return ((long) multiMapCapacity(minCapacity)) * ENTRY_SIZE; } /**