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 127546a2c..10e20f132 100644
--- a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java
+++ b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java
@@ -16,8 +16,11 @@
package net.openhft.chronicle.hash.impl;
-import net.openhft.chronicle.hash.*;
-import net.openhft.chronicle.hash.impl.hashlookup.HashLookup;
+import net.openhft.chronicle.hash.ChronicleHash;
+import net.openhft.chronicle.hash.ExternalHashQueryContext;
+import net.openhft.chronicle.hash.HashEntry;
+import net.openhft.chronicle.hash.HashSegmentContext;
+import net.openhft.chronicle.hash.impl.stage.entry.HashLookup;
import net.openhft.chronicle.hash.impl.util.BuildVersion;
import net.openhft.chronicle.hash.serialization.BytesReader;
import net.openhft.chronicle.hash.serialization.SizeMarshaller;
diff --git a/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/EntryConsumer.java b/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/EntryConsumer.java
deleted file mode 100644
index e9c8e2c3c..000000000
--- a/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/EntryConsumer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2015 higherfrequencytrading.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package net.openhft.chronicle.hash.impl.hashlookup;
-
-public interface EntryConsumer {
- void accept(long key, long value);
-}
diff --git a/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/HashLookup.java b/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/HashLookup.java
deleted file mode 100644
index 46de62019..000000000
--- a/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/HashLookup.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2015 higherfrequencytrading.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package net.openhft.chronicle.hash.impl.hashlookup;
-
-import net.openhft.lang.Maths;
-
-import static net.openhft.lang.MemoryUnit.BITS;
-import static net.openhft.lang.MemoryUnit.BYTES;
-import static net.openhft.lang.io.NativeBytes.UNSAFE;
-
-public class HashLookup {
-
- // to fit 64 bits per slot.
- public static final int MAX_SEGMENT_CHUNKS = 1 << 30;
- public static final int MAX_SEGMENT_ENTRIES = 1 << 29;
-
- public static int valueBits(long actualChunksPerSegment) {
- return 64 - Long.numberOfLeadingZeros(actualChunksPerSegment - 1L);
- }
-
- public static int keyBits(long entriesPerSegment, int valueBits) {
- // key hash cardinality is between 1.0 and 2.0 of key cardinality
- int minKeyBits = 64 - Long.numberOfLeadingZeros(entriesPerSegment - 1L);
- // This minimizes probability of hash collision => on search, additional cache line touch
- // and key comparison, that is quite high cost.
- // between 8.0 and 16.0
- minKeyBits += 3;
- int actualEntryBits = (int) BYTES.align((long) (minKeyBits + valueBits), BITS);
- // devote the rest bits for key
- return actualEntryBits - valueBits;
- }
-
- public static int entrySize(int keyBits, int valueBits) {
- return (int) BYTES.alignAndConvert((long) (keyBits + valueBits), BITS);
- }
-
- public static long capacityFor(long entriesPerSegment) {
- if (entriesPerSegment < 0L)
- throw new IllegalArgumentException("entriesPerSegment should be positive");
- long capacity = Maths.nextPower2(entriesPerSegment, 64L);
- if (((double) entriesPerSegment) / (double) capacity > 2./3.) {
- // hash lookup shouldn't be too dense
- capacity <<= 1L;
- }
- return capacity;
- }
-
- private static final long UNSET_KEY = 0L;
- private static final long UNSET_ENTRY = 0L;
-
- private static long mask(int bits) {
- return (1L << bits) - 1L;
- }
-
- private long address;
-
- private long capacityMask;
-
- private int entrySize;
- private long capacityMask2;
-
- private int keyBits;
- private long keyMask;
- private long valueMask;
- private long entryMask;
-
- // search state
- private long searchKey = UNSET_KEY;
- private long searchStartPos = -1L;
- private long searchPos = -1L;
-
- public void reuse(long address, long capacity, int entrySize, int keyBits, int valueBits) {
- this.address = address;
-
- this.capacityMask = capacity - 1L;
-
- this.entrySize = entrySize;
- this.capacityMask2 = capacityMask * entrySize;
-
- this.keyBits = keyBits;
- this.keyMask = mask(keyBits);
- this.valueMask = mask(valueBits);
- this.entryMask = mask(keyBits + valueBits);
- }
-
- private long indexToPos(long index) {
- return index * entrySize;
- }
-
- private long maskUnsetKey(long key) {
- return (key &= keyMask) != UNSET_KEY ? key : keyMask;
- }
-
- private void checkValueForPut(long value) {
- assert (value & ~valueMask) == 0L : "Value out of range, was " + value;
- }
-
- private boolean empty(long entry) {
- return (entry & entryMask) == UNSET_ENTRY;
- }
-
- private long key(long entry) {
- return entry & keyMask;
- }
-
- private long value(long entry) {
- return (entry >>> keyBits) & valueMask;
- }
-
- private long entry(long key, long value) {
- return key | (value << keyBits);
- }
-
- private long pos(long key) {
- return indexToPos(key & capacityMask);
- }
-
- private long step(long pos) {
- return (pos += entrySize) <= capacityMask2 ? pos : 0L;
- }
-
- private long stepBack(long pos) {
- return (pos -= entrySize) >= 0 ? pos : capacityMask2;
- }
-
- private long readEntry(long pos) {
- return UNSAFE.getLong(address + pos);
- }
-
- private void writeEntry(long pos, long prevEntry, long key, long value) {
- long entry = (prevEntry & ~entryMask) | entry(key, value);
- UNSAFE.putLong(address + pos, entry);
- }
-
- private void writeEntryVolatile(long pos, long prevEntry, long key, long value) {
- long entry = (prevEntry & ~entryMask) | entry(key, value);
- UNSAFE.putLongVolatile(null, address + pos, entry);
- }
-
- private void writeEntry(long pos, long prevEntry, long anotherEntry) {
- long entry = (prevEntry & ~entryMask) | (anotherEntry & entryMask);
- UNSAFE.putLong(address + pos, entry);
- }
-
- private void clearEntry(long pos, long prevEntry) {
- long entry = (prevEntry & ~entryMask);
- UNSAFE.putLong(address + pos, entry);
- }
-
- public void init0(long key) {
- key = maskUnsetKey(key);
- searchKey = key;
- searchStartPos = pos(key);
- }
-
- public boolean isInit() {
- return searchKey != UNSET_KEY;
- }
-
- public void close0() {
- searchKey = UNSET_KEY;
- }
-
- public void initSearch0() {
- searchPos = searchStartPos;
- }
-
- public boolean isSearchInit() {
- return searchPos >= 0L;
- }
-
- public void closeSearch0() {
- searchPos = -1L;
- }
-
- public long nextPos() {
- long pos = searchPos;
- while (true) {
- long entry = readEntry(pos);
- if (empty(entry)) {
- searchPos = pos;
- return -1L;
- }
- pos = step(pos);
- if (pos == searchStartPos)
- break;
- if (key(entry) == searchKey) {
- searchPos = pos;
- return value(entry);
- }
- }
- throw new IllegalStateException("MultiMap is full, that most likely means you " +
- "misconfigured entrySize/chunkSize, and entries tend to take less chunks than " +
- "expected");
- }
-
- public void found() {
- searchPos = stepBack(searchPos);
- }
-
- public void remove() {
- // for support of patterns like context.remove().put()
- searchPos = remove0();
- }
-
- private long remove0() {
- return remove00(searchPos);
- }
-
- private long remove00(long posToRemove) {
- long entryToRemove = readEntry(posToRemove);
- long posToShift = posToRemove;
- while (true) {
- posToShift = step(posToShift);
- long entryToShift = readEntry(posToShift);
- if (empty(entryToShift))
- break;
- long insertPos = pos(key(entryToShift));
- // the following condition essentially means circular permutations
- // of three (r = posToRemove, s = posToShift, i = insertPos)
- // positions are accepted:
- // [...i..r...s.] or
- // [...r..s...i.] or
- // [...s..i...r.]
- boolean cond1 = insertPos <= posToRemove;
- boolean cond2 = posToRemove <= posToShift;
- if ((cond1 && cond2) ||
- // chain wrapped around capacity
- (posToShift < insertPos && (cond1 || cond2))) {
- writeEntry(posToRemove, entryToRemove, entryToShift);
- posToRemove = posToShift;
- entryToRemove = entryToShift;
- }
- }
- clearEntry(posToRemove, entryToRemove);
- return posToRemove;
- }
-
- public void put(long value) {
- checkValueForPut(value);
- writeEntry(searchPos, readEntry(searchPos), searchKey, value);
- }
-
- public void putVolatile(long value) {
- checkValueForPut(value);
- writeEntryVolatile(searchPos, readEntry(searchPos), searchKey, value);
- }
-
- public void clear() {
- UNSAFE.setMemory(address, capacityMask2 + entrySize, (byte) 0);
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder("{");
- forEach((key, value) -> sb.append(key).append('=').append(value).append(','));
- sb.append('}');
- return sb.toString();
- }
-
- public void forEach(EntryConsumer action) {
- for (long pos = 0L; pos <= capacityMask2; pos += entrySize) {
- long entry = readEntry(pos);
- if (!empty(entry))
- action.accept(key(entry), value(entry));
- }
- }
-
- public void forEachRemoving(HashLookupIteration iteration) {
- long pos = 0L;
- while (!empty(readEntry(pos))) {
- pos = step(pos);
- }
- long startPos = pos;
- do {
- pos = step(pos);
- long entry = readEntry(pos);
- if (!empty(entry)) {
- iteration.accept(key(entry), value(entry));
- if (iteration.remove()) {
- remove00(pos);
- pos = stepBack(pos);
- }
- }
- } while (pos != startPos && iteration.continueIteration());
- }
-}
diff --git a/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/HashLookupIteration.java b/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/HashLookupIteration.java
deleted file mode 100644
index 6579fa49e..000000000
--- a/src/main/java/net/openhft/chronicle/hash/impl/hashlookup/HashLookupIteration.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2015 higherfrequencytrading.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package net.openhft.chronicle.hash.impl.hashlookup;
-
-public interface HashLookupIteration {
- void accept(long hash, long pos);
-
- boolean remove();
-
- boolean continueIteration();
-}
diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookup.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookup.java
index 4d0357fa9..1445af585 100644
--- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookup.java
+++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookup.java
@@ -17,7 +17,6 @@
package net.openhft.chronicle.hash.impl.stage.entry;
import net.openhft.chronicle.hash.impl.VanillaChronicleHashHolder;
-import net.openhft.chronicle.hash.impl.hashlookup.EntryConsumer;
import net.openhft.lang.Maths;
import net.openhft.sg.Stage;
import net.openhft.sg.StageRef;
@@ -219,6 +218,10 @@ public class HashLookup {
return posToRemove;
}
+ interface EntryConsumer {
+ void accept(long key, long value);
+ }
+
String hashLookupToString() {
final StringBuilder sb = new StringBuilder("{");
forEach((key, value) -> sb.append(key).append('=').append(value).append(','));
diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java
index c58eed9c5..bc53c9d7f 100755
--- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java
+++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java
@@ -19,12 +19,12 @@ package net.openhft.chronicle.map;
import net.openhft.chronicle.hash.ChronicleHashBuilder;
import net.openhft.chronicle.hash.ChronicleHashInstanceBuilder;
import net.openhft.chronicle.hash.impl.ChronicleHashBuilderImpl;
-import net.openhft.chronicle.hash.impl.hashlookup.HashLookup;
-import net.openhft.chronicle.hash.serialization.internal.SerializationBuilder;
+import net.openhft.chronicle.hash.impl.stage.entry.HashLookup;
import net.openhft.chronicle.hash.replication.*;
import net.openhft.chronicle.hash.serialization.*;
import net.openhft.chronicle.hash.serialization.internal.MetaBytesWriter;
import net.openhft.chronicle.hash.serialization.internal.MetaProvider;
+import net.openhft.chronicle.hash.serialization.internal.SerializationBuilder;
import net.openhft.chronicle.map.replication.MapRemoteOperations;
import net.openhft.chronicle.set.ChronicleSetBuilder;
import net.openhft.lang.Maths;
@@ -56,8 +56,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static java.lang.Math.round;
import static net.openhft.chronicle.hash.impl.util.Objects.builderEquals;
-import static net.openhft.chronicle.map.DefaultSpi.*;
import static net.openhft.chronicle.map.DefaultSpi.mapEntryOperations;
+import static net.openhft.chronicle.map.DefaultSpi.mapRemoteOperations;
import static net.openhft.lang.model.DataValueGenerator.firstPrimitiveFieldType;
/**
diff --git a/src/test/java/net/openhft/chronicle/map/HashLookupTest.java b/src/test/java/net/openhft/chronicle/map/HashLookupTest.java
deleted file mode 100755
index 79c28abb4..000000000
--- a/src/test/java/net/openhft/chronicle/map/HashLookupTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2015 higherfrequencytrading.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-package net.openhft.chronicle.map;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import net.openhft.chronicle.hash.impl.hashlookup.EntryConsumer;
-import net.openhft.chronicle.hash.impl.hashlookup.HashLookup;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.*;
-
-import static net.openhft.lang.io.NativeBytes.UNSAFE;
-
-/**
- * User: peter.lawrey Date: 09/12/13
- */
-@RunWith(value = Parameterized.class)
-public class HashLookupTest {
-
- static final long CAPACITY = 64;
- static long address;
- HashLookup map = new HashLookup();
- Multimap referenceMap = HashMultimap.create();
-
- public HashLookupTest(Integer entrySize, Integer keyBits, Integer valueBits)
- throws Exception {
- map.reuse(address, CAPACITY, entrySize, keyBits, valueBits);
- clean();
- }
-
- void clean() {
- UNSAFE.setMemory(address, CAPACITY * 8L, (byte) 0);
- }
-
- @BeforeClass
- public static void setUp() {
- address = UNSAFE.allocateMemory(CAPACITY * 8L);
- }
-
- @AfterClass
- public static void tearDown() {
- UNSAFE.freeMemory(address);
- }
-
- @Parameterized.Parameters
- public static Collection