From 8870b05d8626bd4e49034c8d29fc7657505bcfc5 Mon Sep 17 00:00:00 2001 From: leventov Date: Wed, 23 Sep 2015 02:02:36 +0300 Subject: [PATCH] HCOLL-387 add a way to limit hash lookup slots to 4 bytes --- .../chronicle/hash/ChronicleHashBuilder.java | 11 +++++ .../hash/ChronicleHashBuilderPrivateAPI.java | 2 + .../hash/impl/VanillaChronicleHash.java | 4 ++ .../chronicle/map/ChronicleMapBuilder.java | 41 +++++++++++++------ .../map/ChronicleMapBuilderPrivateAPI.java | 5 +++ .../chronicle/set/ChronicleSetBuilder.java | 6 +++ 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java index d89d9350f..d754778f4 100755 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java @@ -555,6 +555,17 @@ public interface ChronicleHashBuilder, */ B immutableKeys(); + /** + * Specifies whether on the current combination of platform, OS and Jvm aligned 8-byte reads + * and writes are atomic or not. By default, Chronicle tries to determine this itself, but + * if it fails it pessimistically assumes that 64-bit memory operations are not atomic. + * + * @param aligned64BitMemoryOperationsAtomic {@code true} if aligned 8-byte memory operations + * are atomic + * @return this builder back + */ + B aligned64BitMemoryOperationsAtomic(boolean aligned64BitMemoryOperationsAtomic); + /** * Configures replication of the hash containers, created by this builder. See the section about diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java index 56eef896e..3d0e0a99a 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java @@ -37,4 +37,6 @@ public interface ChronicleHashBuilderPrivateAPI { int actualSegments(boolean replicated); long maxExtraTiers(boolean replicated); + + boolean aligned64BitMemoryOperationsAtomic(); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java index e26e40c5d..9b3dda902 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java @@ -187,6 +187,10 @@ public abstract class VanillaChronicleHash 4) { + throw new IllegalStateException("aligned64BitMemoryOperationsAtomic() == false, " + + "but hash lookup slot is " + segmentHashLookupEntrySize); + } segmentHashLookupCapacity = CompactOffHeapLinearHashTable.capacityFor(entriesPerSegment); segmentHashLookupInnerSize = segmentHashLookupCapacity * segmentHashLookupEntrySize; segmentHashLookupOuterSize = CACHE_LINES.align(segmentHashLookupInnerSize, BYTES); diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index 71e103274..d3febd456 100755 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -16,9 +16,11 @@ package net.openhft.chronicle.map; +import net.openhft.chronicle.core.OS; import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.hash.ChronicleHashBuilderPrivateAPI; import net.openhft.chronicle.hash.ChronicleHashInstanceBuilder; +import net.openhft.chronicle.hash.impl.CompactOffHeapLinearHashTable; import net.openhft.chronicle.hash.impl.util.math.PoissonDistribution; import net.openhft.chronicle.hash.replication.*; import net.openhft.chronicle.hash.serialization.*; @@ -161,6 +163,7 @@ public final class ChronicleMapBuilder implements private double maxBloatFactor = 1.0; private boolean allowSegmentTiering = true; private double nonTieredSegmentsPercentile = 0.99999; + private boolean aligned64BitMemoryOperationsAtomic = OS.is64Bit() ? true : false; private boolean putReturnsNull = false; private boolean removeReturnsNull = false; @@ -758,17 +761,18 @@ public final class ChronicleMapBuilder implements entriesPerSegment = PoissonDistribution.inverseCumulativeProbability( averageEntriesPerSegment, nonTieredSegmentsPercentile); } - if (actualChunksPerSegment > 0) - return entriesPerSegment; - double averageChunksPerEntry = averageChunksPerEntry(replicated); - if (entriesPerSegment * averageChunksPerEntry > - MAX_SEGMENT_CHUNKS) - throw new IllegalStateException("Max chunks per segment is " + - MAX_SEGMENT_CHUNKS + - " configured entries() and " + - "actualSegments() so that there should be " + entriesPerSegment + - " entries per segment, while average chunks per entry is " + - averageChunksPerEntry); + boolean actualChunksDefined = actualChunksPerSegment > 0; + if (!actualChunksDefined) { + double averageChunksPerEntry = averageChunksPerEntry(replicated); + if (entriesPerSegment * averageChunksPerEntry > + MAX_SEGMENT_CHUNKS) + throw new IllegalStateException("Max chunks per segment is " + + MAX_SEGMENT_CHUNKS + + " configured entries() and " + + "actualSegments() so that there should be " + entriesPerSegment + + " entries per segment, while average chunks per entry is " + + averageChunksPerEntry); + } if (entriesPerSegment > MAX_SEGMENT_ENTRIES) throw new IllegalStateException("shouldn't be more than " + MAX_SEGMENT_ENTRIES + " entries per segment"); @@ -901,7 +905,9 @@ public final class ChronicleMapBuilder implements long segments = tryHashLookupSlotSize(4, replicated); if (segments > 0) return (int) segments; - long maxEntriesPerSegment = findMaxEntriesPerSegmentToFitHashLookupSlotSize(8, replicated); + int maxHashLookupEntrySize = aligned64BitMemoryOperationsAtomic() ? 8 : 4; + long maxEntriesPerSegment = + findMaxEntriesPerSegmentToFitHashLookupSlotSize(maxHashLookupEntrySize, replicated); long maxSegments = trySegments(maxEntriesPerSegment, MAX_SEGMENTS, replicated); if (maxSegments > 0L) return (int) maxSegments; @@ -1187,6 +1193,17 @@ public final class ChronicleMapBuilder implements return this; } + @Override + public ChronicleMapBuilder aligned64BitMemoryOperationsAtomic( + boolean aligned64BitMemoryOperationsAtomic) { + this.aligned64BitMemoryOperationsAtomic = aligned64BitMemoryOperationsAtomic; + return this; + } + + boolean aligned64BitMemoryOperationsAtomic() { + return aligned64BitMemoryOperationsAtomic; + } + /** * Configures the {@code BytesMarshaller} used to serialize/deserialize values to/from off-heap * memory in maps, created by this builder. See the diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilderPrivateAPI.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilderPrivateAPI.java index ff860f292..7eed6b1b1 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilderPrivateAPI.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilderPrivateAPI.java @@ -71,4 +71,9 @@ class ChronicleMapBuilderPrivateAPI implements ChronicleHashBuilderPrivateAPI public long maxExtraTiers(boolean replicated) { return b.maxExtraTiers(replicated); } + + @Override + public boolean aligned64BitMemoryOperationsAtomic() { + return b.aligned64BitMemoryOperationsAtomic(); + } } diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java index cb6f19f16..a355222d9 100755 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java @@ -286,6 +286,12 @@ public final class ChronicleSetBuilder return this; } + @Override + public ChronicleSetBuilder aligned64BitMemoryOperationsAtomic( + boolean aligned64BitMemoryOperationsAtomic) { + return null; + } + @Override public ChronicleSetBuilder replication(SingleChronicleHashReplication replication) { chronicleMapBuilder.replication(replication);