HCOLL-387 add a way to limit hash lookup slots to 4 bytes

This commit is contained in:
leventov
2015-09-23 02:02:36 +03:00
parent b113118707
commit 8870b05d86
6 changed files with 57 additions and 12 deletions
@@ -555,6 +555,17 @@ public interface ChronicleHashBuilder<K, H extends ChronicleHash<K, ?, ?, ?>,
*/
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 <i>not</i> 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 <a
* href="https://github.com/OpenHFT/Chronicle-Map#tcp--udp-replication"> the section about
@@ -37,4 +37,6 @@ public interface ChronicleHashBuilderPrivateAPI<K> {
int actualSegments(boolean replicated);
long maxExtraTiers(boolean replicated);
boolean aligned64BitMemoryOperationsAtomic();
}
@@ -187,6 +187,10 @@ public abstract class VanillaChronicleHash<K, KI, MKI extends MetaBytesInterop<K
segmentHashLookupKeyBits = keyBits(entriesPerSegment, segmentHashLookupValueBits);
segmentHashLookupEntrySize =
entrySize(segmentHashLookupKeyBits, segmentHashLookupValueBits);
if (!privateAPI.aligned64BitMemoryOperationsAtomic() && segmentHashLookupEntrySize > 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);
@@ -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<K, V> 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<K, V> 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<K, V> 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<K, V> implements
return this;
}
@Override
public ChronicleMapBuilder<K, V> 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 <a href="https://github.com/OpenHFT/Chronicle-Map#serialization">the
@@ -71,4 +71,9 @@ class ChronicleMapBuilderPrivateAPI<K> implements ChronicleHashBuilderPrivateAPI
public long maxExtraTiers(boolean replicated) {
return b.maxExtraTiers(replicated);
}
@Override
public boolean aligned64BitMemoryOperationsAtomic() {
return b.aligned64BitMemoryOperationsAtomic();
}
}
@@ -286,6 +286,12 @@ public final class ChronicleSetBuilder<K>
return this;
}
@Override
public ChronicleSetBuilder<K> aligned64BitMemoryOperationsAtomic(
boolean aligned64BitMemoryOperationsAtomic) {
return null;
}
@Override
public ChronicleSetBuilder<K> replication(SingleChronicleHashReplication replication) {
chronicleMapBuilder.replication(replication);