diff --git a/pom.xml b/pom.xml
index a838bb414..68acc6ecd 100755
--- a/pom.xml
+++ b/pom.xml
@@ -52,7 +52,7 @@
net.openhft
lang
- 6.4.7-SNAPSHOT
+ 6.4.8-SNAPSHOT
diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java
index eddc5782a..be93dadf3 100644
--- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java
+++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java
@@ -16,35 +16,33 @@
package net.openhft.chronicle.map;
+import net.openhft.chronicle.map.serialization.MetaBytesInterop;
+import net.openhft.chronicle.map.serialization.MetaBytesWriter;
import net.openhft.lang.Maths;
import net.openhft.lang.io.*;
import net.openhft.lang.io.serialization.*;
import net.openhft.lang.io.serialization.impl.*;
-import net.openhft.lang.model.Byteable;
-import net.openhft.lang.model.DataValueClasses;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import static net.openhft.chronicle.map.Objects.builderEquals;
-import static net.openhft.chronicle.map.Objects.hash;
public class ChronicleMapBuilder implements Cloneable {
public static final short UDP_REPLICATION_MODIFICATION_ITERATOR_ID = 128;
private static final Logger LOG = LoggerFactory.getLogger(ChronicleMapBuilder.class.getName());
- final Class keyClass;
- final Class valueClass;
+ SerializationBuilder keyBuilder;
+ SerializationBuilder valueBuilder;
boolean transactional = false;
Replicator firstReplicator;
- Map, Replicator> replicators =
- new HashMap, Replicator>();
+ Map, Replicator> replicators = new HashMap, Replicator>();
boolean forceReplicatedImpl = false;
// used when configuring the number of segments.
private int minSegments = -1;
@@ -66,60 +64,18 @@ public class ChronicleMapBuilder implements Cloneable {
private TimeProvider timeProvider = TimeProvider.SYSTEM;
private BytesMarshallerFactory bytesMarshallerFactory;
private ObjectSerializer objectSerializer;
- @NotNull
- private BytesMarshaller keyMarshaller;
- @NotNull
- private BytesMarshaller valueMarshaller;
- @NotNull
- private ObjectFactory valueFactory;
private MapEventListener> eventListener =
MapEventListeners.nop();
ChronicleMapBuilder(Class keyClass, Class valueClass) {
- this.keyClass = keyClass;
- this.valueClass = valueClass;
- keyMarshaller = chooseDefaultMarshaller(keyClass);
- valueMarshaller = chooseDefaultMarshaller(valueClass);
- valueFactory = marshallerUseFactory(valueClass) ?
- new AllocateInstanceObjectFactory(valueClass.isInterface() ?
- DataValueClasses.directClassFor(valueClass) :
- valueClass) :
- NullObjectFactory.INSTANCE;
+ keyBuilder = new SerializationBuilder(keyClass, SerializationBuilder.Role.KEY);
+ valueBuilder = new SerializationBuilder(valueClass, SerializationBuilder.Role.VALUE);
}
public static ChronicleMapBuilder of(Class keyClass, Class valueClass) {
return new ChronicleMapBuilder(keyClass, valueClass);
}
- private static boolean marshallerUseFactory(Class c) {
- return Byteable.class.isAssignableFrom(c) ||
- BytesMarshallable.class.isAssignableFrom(c) ||
- Externalizable.class.isAssignableFrom(c);
- }
-
- @SuppressWarnings("unchecked")
- private static BytesMarshaller chooseDefaultMarshaller(@NotNull Class tClass) {
- Class classForMarshaller = marshallerUseFactory(tClass) && tClass.isInterface() ?
- DataValueClasses.directClassFor(tClass) : tClass;
- if (Byteable.class.isAssignableFrom(tClass))
- return new ByteableMarshaller(classForMarshaller);
- if (BytesMarshallable.class.isAssignableFrom(tClass))
- return new BytesMarshallableMarshaller(classForMarshaller);
- if (Externalizable.class.isAssignableFrom(tClass))
- return new ExternalizableMarshaller(classForMarshaller);
- if (tClass == CharSequence.class)
- return (BytesMarshaller) CharSequenceMarshaller.INSTANCE;
- if (tClass == String.class)
- return (BytesMarshaller) StringMarshaller.INSTANCE;
- if (tClass == Integer.class)
- return (BytesMarshaller) IntegerMarshaller.INSTANCE;
- if (tClass == Long.class)
- return (BytesMarshaller) LongMarshaller.INSTANCE;
- if (tClass == Double.class)
- return (BytesMarshaller) DoubleMarshaller.INSTANCE;
- return SerializableMarshaller.INSTANCE;
- }
-
private static long roundUpMapHeaderSize(long headerSize) {
long roundUp = (headerSize + 127L) & ~127L;
if (roundUp - headerSize < 64)
@@ -129,12 +85,12 @@ public class ChronicleMapBuilder implements Cloneable {
@Override
public ChronicleMapBuilder clone() {
-
try {
@SuppressWarnings("unchecked")
- final ChronicleMapBuilder result = (ChronicleMapBuilder) super.clone();
+ final ChronicleMapBuilder result = (ChronicleMapBuilder) super.clone();
+ result.keyBuilder = keyBuilder.clone();
+ result.valueBuilder = valueBuilder.clone();
return result;
-
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
@@ -393,12 +349,8 @@ public class ChronicleMapBuilder implements Cloneable {
", largeSegments=" + largeSegments() +
", timeProvider=" + timeProvider() +
", bytesMarshallerfactory=" + bytesMarshallerFactory() +
-
- ", keyClass=" + keyClass +
- ", valueClass=" + valueClass +
- ", keyMarshaller=" + keyMarshaller +
- ", valueMarshaller=" + valueMarshaller +
- ", valueFactory=" + valueFactory +
+ ", keyBuilder=" + keyBuilder +
+ ", valueBuilder=" + valueBuilder +
", eventListener=" + eventListener +
'}';
}
@@ -481,76 +433,19 @@ public class ChronicleMapBuilder implements Cloneable {
return this;
}
- @NotNull
- public BytesMarshaller keyMarshaller() {
- return keyMarshaller;
- }
-
- public ChronicleMapBuilder keyMarshaller(
- @NotNull BytesMarshaller keyMarshaller) {
- this.keyMarshaller = keyMarshaller;
+ public ChronicleMapBuilder keyMarshaller(@NotNull BytesMarshaller keyMarshaller) {
+ keyBuilder.marshaller(keyMarshaller, null);
return this;
}
- @NotNull
- public BytesMarshaller valueMarshaller() {
- return valueMarshaller;
- }
-
public ChronicleMapBuilder valueMarshallerAndFactory(
@NotNull BytesMarshaller valueMarshaller, @NotNull ObjectFactory valueFactory) {
- this.valueMarshaller = valueMarshaller;
- this.valueFactory = valueFactory;
+ valueBuilder.marshaller(valueMarshaller, valueFactory);
return this;
}
- @NotNull
- public ObjectFactory valueFactory() {
- return valueFactory;
- }
-
- @SuppressWarnings("unchecked")
- public ChronicleMapBuilder valueFactory(
- @NotNull ObjectFactory valueFactory) {
- if (!marshallerUseFactory(valueClass)) {
- throw new IllegalStateException("Default marshaller for " + valueClass +
- " value don't use object factory");
- } else if (valueMarshaller instanceof ByteableMarshaller) {
- if (valueFactory instanceof AllocateInstanceObjectFactory) {
- valueMarshaller = new ByteableMarshaller(
- ((AllocateInstanceObjectFactory) valueFactory).allocatedClass());
- } else {
- valueMarshaller = new ByteableMarshallerWithCustomFactory(
- ((ByteableMarshaller) valueMarshaller).tClass, valueFactory);
- }
- } else if (valueMarshaller instanceof BytesMarshallableMarshaller) {
- if (valueFactory instanceof AllocateInstanceObjectFactory) {
- valueMarshaller = new BytesMarshallableMarshaller(
- ((AllocateInstanceObjectFactory) valueFactory).allocatedClass());
- } else {
- valueMarshaller = new BytesMarshallableMarshallerWithCustomFactory(
- ((BytesMarshallableMarshaller) valueMarshaller).marshaledClass(),
- valueFactory
- );
- }
- } else if (valueMarshaller instanceof ExternalizableMarshaller) {
- if (valueFactory instanceof AllocateInstanceObjectFactory) {
- valueMarshaller = new ExternalizableMarshaller(
- ((AllocateInstanceObjectFactory) valueFactory).allocatedClass());
- } else {
- valueMarshaller = new ExternalizableMarshallerWithCustomFactory(
- ((ExternalizableMarshaller) valueMarshaller).marshaledClass(),
- valueFactory
- );
- }
- } else {
- // valueMarshaller is custom, it is user's responsibility to use the same factory inside
- // marshaller and standalone
- throw new IllegalStateException(
- "Change the value factory simultaneously with marshaller " +
- "using valueMarshallerAndFactory() method");
- }
- this.valueFactory = valueFactory;
+ public ChronicleMapBuilder valueFactory(@NotNull ObjectFactory valueFactory) {
+ valueBuilder.factory(valueFactory);
return this;
}
@@ -570,7 +465,8 @@ public class ChronicleMapBuilder implements Cloneable {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
try {
- VanillaChronicleMap map = (VanillaChronicleMap) ois.readObject();
+ VanillaChronicleMap map =
+ (VanillaChronicleMap) ois.readObject();
map.headerSize = roundUpMapHeaderSize(fis.getChannel().position());
map.createMappedStoreAndSegments(file);
return establishReplication(map);
@@ -593,7 +489,7 @@ public class ChronicleMapBuilder implements Cloneable {
if (!file.exists())
throw new FileNotFoundException("Unable to create " + file);
- VanillaChronicleMap map = newMap();
+ VanillaChronicleMap map = newMap();
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
@@ -610,20 +506,29 @@ public class ChronicleMapBuilder implements Cloneable {
}
public ChronicleMap create() throws IOException {
- VanillaChronicleMap map = newMap();
+ VanillaChronicleMap map = newMap();
BytesStore bytesStore = new DirectStore(objectSerializer(), map.sizeInBytes(), true);
map.createMappedStoreAndSegments(bytesStore);
return establishReplication(map);
}
- private VanillaChronicleMap newMap() throws IOException {
+ private VanillaChronicleMap newMap() throws IOException {
+ preMapConstruction();
if (firstReplicator == null && !forceReplicatedImpl) {
- return new VanillaChronicleMap(this);
+ return new VanillaChronicleMap,
+ V, Object, MetaBytesWriter>(this);
} else {
- return new ReplicatedChronicleMap(this);
+ return new ReplicatedChronicleMap,
+ V, Object, MetaBytesWriter>(this);
}
}
+ private void preMapConstruction() {
+ int maxSize = entrySize() * figureBufferAllocationFactor();
+ keyBuilder.maxSize(maxSize);
+ valueBuilder.maxSize(maxSize);
+ }
+
private ChronicleMap establishReplication(ChronicleMap map)
throws IOException {
if (map instanceof ReplicatedChronicleMap) {
@@ -646,312 +551,11 @@ public class ChronicleMapBuilder implements Cloneable {
return map;
}
- private static enum CharSequenceMarshaller implements BytesMarshaller {
- INSTANCE;
-
- @Override
- public void write(Bytes bytes, CharSequence s) {
- bytes.writeUTFΔ(s);
- }
-
- @Nullable
- @Override
- public CharSequence read(Bytes bytes) {
- return bytes.readUTFΔ();
- }
-
- @Nullable
- @Override
- public CharSequence read(Bytes bytes, @Nullable CharSequence s) {
- if (s instanceof StringBuilder) {
- if (bytes.readUTFΔ((StringBuilder) s))
- return s;
- return null;
- }
- return bytes.readUTFΔ();
- }
- }
-
- private static enum StringMarshaller implements BytesMarshaller {
- INSTANCE;
-
- @Override
- public void write(Bytes bytes, String s) {
- bytes.writeUTFΔ(s);
- }
-
- @Nullable
- @Override
- public String read(Bytes bytes) {
- return bytes.readUTFΔ();
- }
-
- @Nullable
- @Override
- public String read(Bytes bytes, @Nullable String s) {
- return bytes.readUTFΔ();
- }
- }
-
- private static enum IntegerMarshaller implements BytesMarshaller {
- INSTANCE;
-
- @Override
- public void write(Bytes bytes, Integer v) {
- bytes.writeInt(v);
- }
-
- @Nullable
- @Override
- public Integer read(Bytes bytes) {
- return bytes.readInt();
- }
-
- @Nullable
- @Override
- public Integer read(Bytes bytes, @Nullable Integer v) {
- return bytes.readInt();
- }
- }
-
- private static enum LongMarshaller implements BytesMarshaller {
- INSTANCE;
-
- @Override
- public void write(Bytes bytes, Long v) {
- bytes.writeLong(v);
- }
-
- @Nullable
- @Override
- public Long read(Bytes bytes) {
- return bytes.readLong();
- }
-
- @Nullable
- @Override
- public Long read(Bytes bytes, @Nullable Long v) {
- return bytes.readLong();
- }
- }
-
- private static enum DoubleMarshaller implements BytesMarshaller {
- INSTANCE;
-
- @Override
- public void write(Bytes bytes, Double v) {
- bytes.writeDouble(v);
- }
-
- @Nullable
- @Override
- public Double read(Bytes bytes) {
- return bytes.readDouble();
- }
-
- @Nullable
- @Override
- public Double read(Bytes bytes, @Nullable Double v) {
- return bytes.readDouble();
- }
- }
-
-
- private static enum SerializableMarshaller implements BytesMarshaller {
- INSTANCE;
-
- @Override
- public void write(Bytes bytes, Object obj) {
- bytes.writeObject(obj);
- }
-
- @Nullable
- @Override
- public Object read(Bytes bytes) {
- return bytes.readObject();
- }
-
- @Nullable
- @Override
- public Object read(Bytes bytes, @Nullable Object obj) {
- return bytes.readInstance(null, obj);
- }
- }
-
- private static class ByteableMarshaller implements BytesMarshaller {
- private static final long serialVersionUID = 0L;
-
- @NotNull
- final Class tClass;
-
- ByteableMarshaller(@NotNull Class tClass) {
- this.tClass = tClass;
- }
-
- @Override
- public void write(Bytes bytes, T t) {
- bytes.write(t.bytes(), t.offset(), t.maxSize());
- }
-
- @Nullable
- @Override
- public T read(Bytes bytes) {
- return read(bytes, null);
- }
-
- @Nullable
- @Override
- public T read(Bytes bytes, @Nullable T t) {
- try {
- if (t == null)
- t = getInstance();
- t.bytes(bytes, bytes.position());
- bytes.skip(t.maxSize());
- return t;
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- @NotNull
- T getInstance() throws Exception {
- return (T) NativeBytes.UNSAFE.allocateInstance(tClass);
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj != null && obj.getClass() == getClass() &&
- ((ByteableMarshaller) obj).tClass == tClass;
- }
-
- @Override
- public int hashCode() {
- return tClass.hashCode();
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{tClass=" + tClass + "}";
- }
- }
-
- private static class ByteableMarshallerWithCustomFactory
- extends ByteableMarshaller {
- private static final long serialVersionUID = 0L;
-
- @NotNull
- private final ObjectFactory factory;
-
- ByteableMarshallerWithCustomFactory(@NotNull Class tClass,
- @NotNull ObjectFactory factory) {
- super(tClass);
- this.factory = factory;
- }
-
- @NotNull
- @Override
- T getInstance() throws Exception {
- return factory.create();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || obj.getClass() != getClass())
- return false;
- ByteableMarshallerWithCustomFactory that = (ByteableMarshallerWithCustomFactory) obj;
- return that.tClass == tClass && that.factory.equals(this.factory);
- }
-
- @Override
- public int hashCode() {
- return hash(tClass, factory);
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{tClass=" + tClass + ",factory=" + factory + "}";
- }
- }
-
- private static class BytesMarshallableMarshallerWithCustomFactory
- extends BytesMarshallableMarshaller {
- private static final long serialVersionUID = 0L;
-
- @NotNull
- private final ObjectFactory factory;
-
- BytesMarshallableMarshallerWithCustomFactory(@NotNull Class tClass,
- @NotNull ObjectFactory factory) {
- super(tClass);
- this.factory = factory;
- }
-
- @NotNull
- @Override
- protected T getInstance() throws Exception {
- return factory.create();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || obj.getClass() != getClass())
- return false;
- BytesMarshallableMarshallerWithCustomFactory that =
- (BytesMarshallableMarshallerWithCustomFactory) obj;
- return that.marshaledClass() == marshaledClass() && that.factory.equals(this.factory);
- }
-
- @Override
- public int hashCode() {
- return hash(marshaledClass(), factory);
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{marshaledClass=" + marshaledClass() +
- ",factory=" + factory + "}";
- }
- }
-
- private static class ExternalizableMarshallerWithCustomFactory
- extends ExternalizableMarshaller {
- private static final long serialVersionUID = 0L;
-
- @NotNull
- private final ObjectFactory factory;
-
- ExternalizableMarshallerWithCustomFactory(@NotNull Class tClass,
- @NotNull ObjectFactory factory) {
- super(tClass);
- this.factory = factory;
- }
-
- @NotNull
- @Override
- protected T getInstance() throws Exception {
- return factory.create();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || obj.getClass() != getClass())
- return false;
- ExternalizableMarshallerWithCustomFactory that =
- (ExternalizableMarshallerWithCustomFactory) obj;
- return that.marshaledClass() == marshaledClass() && that.factory.equals(this.factory);
- }
-
- @Override
- public int hashCode() {
- return hash(marshaledClass(), factory);
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{marshaledClass=" + marshaledClass() +
- ",factory=" + factory + "}";
- }
+ private int figureBufferAllocationFactor() {
+ // if expected map size is about 1000, seems rather wasteful to allocate
+ // key and value serialization buffers each x64 of expected entry size..
+ return (int) Math.min(Math.max(2L, entries() >> 10),
+ VanillaChronicleMap.MAX_ENTRY_OVERSIZE_FACTOR);
}
}
diff --git a/src/main/java/net/openhft/chronicle/map/MapEventListener.java b/src/main/java/net/openhft/chronicle/map/MapEventListener.java
index 4822551e6..68b4e88a2 100644
--- a/src/main/java/net/openhft/chronicle/map/MapEventListener.java
+++ b/src/main/java/net/openhft/chronicle/map/MapEventListener.java
@@ -40,7 +40,7 @@ public abstract class MapEventListener>
* @param usingValue value provided to reuse, could be null.
* @return null if null should be returned, or a value to put in the map and return.
*/
- public V onGetMissing(M map, Bytes keyBytes, K key, V usingValue) {
+ public V onGetMissing(M map, K key, V usingValue) {
return null;
}
diff --git a/src/main/java/net/openhft/chronicle/map/MapEventListeners.java b/src/main/java/net/openhft/chronicle/map/MapEventListeners.java
index 51df6b807..e07915ba6 100644
--- a/src/main/java/net/openhft/chronicle/map/MapEventListeners.java
+++ b/src/main/java/net/openhft/chronicle/map/MapEventListeners.java
@@ -36,14 +36,9 @@ public final class MapEventListeners {
public final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Override
- public Object onGetMissing(ChronicleMap map, Bytes keyBytes,
+ public Object onGetMissing(ChronicleMap map,
Object key, Object usingValue) {
- StringBuilder sb = new StringBuilder();
- sb.append(map.file()).append(" missed ");
-
- keyBytes.toString(sb, 0, 0, keyBytes.limit());
-
- LOGGER.info(sb.toString());
+ LOGGER.info("{} missed {}", map.file(), key);
return null;
}
@@ -62,13 +57,14 @@ public final class MapEventListeners {
sb.append(" | ");
}
Bytes slice = entry.slice(metaDataBytes, entry.limit() - metaDataBytes);
- long keyLength = slice.readStopBit();
- slice.toString(sb, slice.position(), 0L, slice.position() + keyLength);
- slice.position(slice.position() + keyLength);
- long valueLength = slice.readStopBit();
- slice.alignPositionAddr(4);
+ VanillaChronicleMap vanillaMap = (VanillaChronicleMap) map;
+ long keySize = vanillaMap.keySizeMarshaller.readSize(slice);
+ slice.toString(sb, slice.position(), 0L, slice.position() + keySize);
+ slice.position(slice.position() + keySize);
+ long valueSize = vanillaMap.valueSizeMarshaller.readSize(slice);
+ vanillaMap.alignment.alignPositionAddr(slice);
sb.append(" = ");
- slice.toString(sb, slice.position(), 0L, slice.position() + valueLength);
+ slice.toString(sb, slice.position(), 0L, slice.position() + valueSize);
LOGGER.info(sb.toString());
}
@@ -89,7 +85,7 @@ public final class MapEventListeners {
public final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Override
- public Object onGetMissing(ChronicleMap map, Bytes keyBytes,
+ public Object onGetMissing(ChronicleMap map,
Object key, Object usingValue) {
LOGGER.info("{} missed {}", map.file(), key);
return null;
diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java
index d4d000ae4..5c7df7df2 100644
--- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java
+++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java
@@ -20,10 +20,13 @@ package net.openhft.chronicle.map;
import net.openhft.lang.Maths;
import net.openhft.lang.collection.ATSDirectBitSet;
import net.openhft.lang.io.Bytes;
-import net.openhft.lang.io.DirectBytes;
import net.openhft.lang.io.MultiStoreBytes;
import net.openhft.lang.io.NativeBytes;
+import net.openhft.chronicle.map.serialization.BytesReader;
+import net.openhft.chronicle.map.serialization.MetaBytesInterop;
+import net.openhft.chronicle.map.serialization.MetaBytesWriter;
import net.openhft.lang.model.Byteable;
+import net.openhft.chronicle.map.threadlocal.ThreadLocalCopies;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,7 +37,7 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicReferenceArray;
-import static net.openhft.chronicle.map.VanillaChronicleMap.Hasher.hash;
+import static net.openhft.chronicle.map.serialization.Hasher.hash;
import static net.openhft.lang.collection.DirectBitSet.NOT_FOUND;
/**
@@ -72,7 +75,9 @@ import static net.openhft.lang.collection.DirectBitSet.NOT_FOUND;
* @param the entries key type
* @param the entries value type
*/
-class ReplicatedChronicleMap extends VanillaChronicleMap
+class ReplicatedChronicleMap,
+ V, VW, MVW extends MetaBytesWriter>
+ extends VanillaChronicleMap
implements ChronicleMap,
Replica, Replica.EntryExternalizable, Replica.EntryResolver, Closeable {
// for file, jdbc and UDP replication
@@ -193,7 +198,6 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
* @return the previous value
* @see #put(Object, Object)
*/
-
V put(K key, V value, byte identifier, long timeStamp) {
assert identifier > 0;
return put0(key, value, true, identifier, timeStamp);
@@ -216,12 +220,16 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
final byte identifier, long timeStamp) {
checkKey(key);
checkValue(value);
- Bytes keyBytes = getKeyAsBytes(key);
- long hash = Hasher.hash(keyBytes);
- int segmentNum = hasher.getSegment(hash);
- int segmentHash = hasher.segmentHash(hash);
- return segment(segmentNum).put(keyBytes, key, value, segmentHash, replaceIfPresent,
- identifier, timeStamp);
+ ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
+ KI keyWriter = keyInteropProvider.get(copies, originalKeyInterop);
+ copies = metaKeyInteropProvider.getCopies(copies);
+ MKI metaKeyWriter =
+ metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyWriter, key);
+ long hash = metaKeyWriter.hash(keyWriter, key);
+ int segmentNum = getSegment(hash);
+ int segmentHash = segmentHash(hash);
+ return segment(segmentNum).put(copies, metaKeyWriter, keyWriter, key, value, segmentHash,
+ replaceIfPresent, identifier, timeStamp);
}
/**
@@ -235,12 +243,16 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
@Override
V lookupUsing(K key, V value, boolean create) {
checkKey(key);
- Bytes keyBytes = getKeyAsBytes(key);
- long hash = Hasher.hash(keyBytes);
- int segmentNum = hasher.getSegment(hash);
- int segmentHash = hasher.segmentHash(hash);
- return segment(segmentNum).acquire(keyBytes, key, value, segmentHash, create,
- timeProvider.currentTimeMillis());
+ ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
+ KI keyWriter = keyInteropProvider.get(copies, originalKeyInterop);
+ copies = metaKeyInteropProvider.getCopies(copies);
+ MKI metaKeyWriter =
+ metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyWriter, key);
+ long hash = metaKeyWriter.hash(keyWriter, key);
+ int segmentNum = getSegment(hash);
+ int segmentHash = segmentHash(hash);
+ return segment(segmentNum).acquire(copies, metaKeyWriter, keyWriter, key, value,
+ segmentHash, create, timeProvider.currentTimeMillis());
}
@Override
@@ -310,27 +322,36 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
localIdentifier, timeProvider.currentTimeMillis()) != null;
}
- private V removeIfValueIs(final Object key, final V expectedValue,
+ private V removeIfValueIs(final Object k, final V expectedValue,
final byte identifier, final long timestamp) {
- checkKey(key);
- Bytes keyBytes = getKeyAsBytes((K) key);
- long hash = Hasher.hash(keyBytes);
- int segmentNum = hasher.getSegment(hash);
- int segmentHash = hasher.segmentHash(hash);
- return segment(segmentNum).remove(keyBytes, (K) key, expectedValue, segmentHash,
- timestamp, identifier);
+ checkKey(k);
+ K key = (K) k;
+ ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
+ KI keyWriter = keyInteropProvider.get(copies, originalKeyInterop);
+ copies = metaKeyInteropProvider.getCopies(copies);
+ MKI metaKeyWriter =
+ metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyWriter, key);
+ long hash = metaKeyWriter.hash(keyWriter, key);
+ int segmentNum = getSegment(hash);
+ int segmentHash = segmentHash(hash);
+ return segment(segmentNum).remove(copies, metaKeyWriter, keyWriter, key, expectedValue,
+ segmentHash, timestamp, identifier);
}
@Override
V replaceIfValueIs(@net.openhft.lang.model.constraints.NotNull final K key, final V existingValue, final V newValue) {
checkKey(key);
checkValue(newValue);
- Bytes keyBytes = getKeyAsBytes(key);
- long hash = Hasher.hash(keyBytes);
- int segmentNum = hasher.getSegment(hash);
- int segmentHash = hasher.segmentHash(hash);
- return segment(segmentNum).replace(keyBytes, key, existingValue, newValue, segmentHash,
- timeProvider.currentTimeMillis());
+ ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
+ KI keyWriter = keyInteropProvider.get(copies, originalKeyInterop);
+ copies = metaKeyInteropProvider.getCopies(copies);
+ MKI metaKeyWriter =
+ metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyWriter, key);
+ long hash = metaKeyWriter.hash(keyWriter, key);
+ int segmentNum = getSegment(hash);
+ int segmentHash = segmentHash(hash);
+ return segment(segmentNum).replace(copies, metaKeyWriter, keyWriter, key, existingValue,
+ newValue, segmentHash, timeProvider.currentTimeMillis());
}
/**
@@ -343,9 +364,9 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
final long initialLimit = entry.limit();
- final long keyLen = entry.readStopBit();
+ final long keySize = keySizeMarshaller.readSize(entry);
final long keyPosition = entry.position();
- entry.skip(keyLen);
+ entry.skip(keySize);
final long keyLimit = entry.position();
final long timeStamp = entry.readLong();
@@ -356,18 +377,18 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
final boolean isDeleted = entry.readBoolean();
- long valueLen;
+ long valueSize;
if (!isDeleted) {
- valueLen = entry.readStopBit();
- assert valueLen > 0;
+ valueSize = valueSizeMarshaller.readSize(entry);
+ assert valueSize > 0;
} else {
- valueLen = 0;
+ valueSize = 0;
}
final long valuePosition = entry.position();
- destination.writeStopBit(keyLen);
- destination.writeStopBit(valueLen);
+ keySizeMarshaller.writeSize(destination, keySize);
+ valueSizeMarshaller.writeSize(destination, valueSize);
destination.writeStopBit(timeStamp);
// we store the isDeleted flag in the identifier
@@ -401,7 +422,7 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
alignment.alignPositionAddr(entry);
// writes the value
- entry.limit(entry.position() + valueLen);
+ entry.limit(entry.position() + valueSize);
destination.write(entry);
if (debugEnabled) {
@@ -416,8 +437,8 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
@Override
public void readExternalEntry(@NotNull Bytes source) {
- final long keyLen = source.readStopBit();
- final long valueLen = source.readStopBit();
+ final long keySize = keySizeMarshaller.readSize(source);
+ final long valueSize = valueSizeMarshaller.readSize(source);
final long timeStamp = source.readStopBit();
final byte id = source.readByte();
final byte remoteIdentifier;
@@ -439,13 +460,13 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
final long keyPosition = source.position();
- final long keyLimit = keyPosition + keyLen;
+ final long keyLimit = keyPosition + keySize;
source.limit(keyLimit);
- long hash = Hasher.hash(source);
+ long hash = hash(source);
- int segmentNum = hasher.getSegment(hash);
- int segmentHash = hasher.segmentHash(hash);
+ int segmentNum = getSegment(hash);
+ int segmentHash = segmentHash(hash);
boolean debugEnabled = LOG.isDebugEnabled();
@@ -471,7 +492,7 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
final long valuePosition = keyLimit;
- final long valueLimit = valuePosition + valueLen;
+ final long valueLimit = valuePosition + valueSize;
segment(segmentNum).remotePut(source, segmentHash, remoteIdentifier, timeStamp,
valuePosition, valueLimit);
setLastModificationTime(remoteIdentifier, timeStamp);
@@ -493,9 +514,9 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
public K key(@NotNull Bytes entry, K usingKey) {
final long start = entry.position();
try {
- // keyLen
- entry.readStopBit();
- return keyMarshaller.read(entry, usingKey);
+ long keySize = keySizeMarshaller.readSize(entry);
+ ThreadLocalCopies copies = keyReaderProvider.getCopies(null);
+ return keyReaderProvider.get(copies, originalKeyReader).read(entry, keySize);
} finally {
entry.position(start);
}
@@ -506,9 +527,7 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
public V value(@NotNull Bytes entry, V usingValue) {
final long start = entry.position();
try {
-
- // keyLen
- entry.skip(entry.readStopBit());
+ entry.skip(keySizeMarshaller.readSize(entry));
//timeStamp
entry.readLong();
@@ -519,15 +538,17 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
final boolean isDeleted = entry.readBoolean();
- long valueLen;
+ long valueSize;
if (!isDeleted) {
- valueLen = entry.readStopBit();
- assert valueLen > 0;
+ valueSize = valueSizeMarshaller.readSize(entry);
+ assert valueSize > 0;
} else {
return null;
}
alignment.alignPositionAddr(entry);
- return valueMarshaller.read(entry, usingValue);
+ ThreadLocalCopies copies = valueReaderProvider.getCopies(null);
+ BytesReader valueReader = valueReaderProvider.get(copies, originalValueReader);
+ return valueReader.read(entry, valueSize, usingValue);
} finally {
entry.position(start);
}
@@ -537,13 +558,13 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
public boolean wasRemoved(@NotNull Bytes entry) {
final long start = entry.position();
try {
- return entry.readBoolean(entry.readStopBit() + 10);
+ return entry.readBoolean(keySizeMarshaller.readSize(entry) + 10);
} finally {
entry.position(start);
}
}
- class Segment extends VanillaChronicleMap.Segment {
+ class Segment extends VanillaChronicleMap.Segment {
private volatile IntIntMultiMap hashLookupLiveAndDeleted;
private volatile IntIntMultiMap hashLookupLiveOnly;
@@ -563,10 +584,10 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
return hashLookupLiveOnly;
}
- private long entrySize(long keyLen, long valueLen) {
+ private long entrySize(long keySize, long valueSize) {
long result = alignment.alignAddr(metaDataBytes +
- expectedStopBits(keyLen) + keyLen + 10 +
- expectedStopBits(valueLen)) + valueLen;
+ keySizeMarshaller.sizeEncodingSize(keySize) + keySize + 10 +
+ valueSizeMarshaller.sizeEncodingSize(valueSize)) + valueSize;
// replication enforces that the entry size will never be larger than an unsigned short
if (result > MAX_UNSIGNED_SHORT)
throw new IllegalStateException("ENTRY WRITE_BUFFER_SIZE TOO LARGE : Replicated " +
@@ -581,24 +602,28 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
/**
* @see VanillaChronicleMap.Segment#acquire
*/
- V acquire(Bytes keyBytes, K key, V usingValue, int hash2, boolean create, long timestamp) {
+ V acquire(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter,
+ K key, V usingValue, int hash2, boolean create, long timestamp) {
lock();
try {
+ long keySize = metaKeyWriter.size(keyWriter, key);
MultiStoreBytes entry = tmpBytes;
- long offset = searchKey(keyBytes, hash2, entry, hashLookupLiveOnly);
+ long offset = searchKey(keyWriter, metaKeyWriter, key, keySize, hash2, entry,
+ hashLookupLiveOnly);
if (offset >= 0) {
// skip the timestamp, identifier and is deleted flag
entry.skip(10);
- return onKeyPresentOnAcquire(key, usingValue, offset, entry);
+ return onKeyPresentOnAcquire(copies, key, usingValue, offset, entry);
} else {
boolean usingValuePassed = usingValue != null;
- usingValue = tryObtainUsingValueOnAcquire(keyBytes, key, usingValue, create);
+ usingValue = tryObtainUsingValueOnAcquire(key, usingValue, create);
if (usingValue != null) {
// see VanillaChronicleMap.Segment.acquire() for explanation
// why `usingValue` is `create`.
- offset = putEntryOnAcquire(keyBytes, hash2, usingValue, create, timestamp);
+ offset = putEntryOnAcquire(copies, metaKeyWriter, keyWriter, key, keySize,
+ hash2, usingValue, create, timestamp);
incrementSize();
if (usingValuePassed || !create)
notifyPut(offset, true, key, usingValue, posFromOffset(offset));
@@ -612,10 +637,12 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
}
- private long putEntryOnAcquire(Bytes keyBytes, int hash2, V value, boolean usingValue,
+ private long putEntryOnAcquire(ThreadLocalCopies copies,
+ MKI metaKeyWriter, KI keyWriter, K key,
+ long keySize, int hash2, V value, boolean usingValue,
long timestamp) {
- return putEntry(keyBytes, hash2, value, usingValue, localIdentifier,
- timestamp, hashLookupLiveOnly);
+ return putEntry(copies, metaKeyWriter, keyWriter, key, keySize, hash2, value,
+ usingValue, localIdentifier, timestamp, hashLookupLiveOnly);
}
@@ -626,16 +653,16 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
final long timestamp, final byte identifier) {
lock();
try {
- long keyLen = keyBytes.remaining();
+ long keySize = keyBytes.remaining();
hashLookupLiveAndDeleted.startSearch(hash2);
for (int pos; (pos = hashLookupLiveAndDeleted.nextPos()) >= 0; ) {
long offset = offsetFromPos(pos);
NativeBytes entry = entry(offset);
- if (!keyEquals(keyBytes, keyLen, entry))
+ if (!remoteKeyEquals(keyBytes, keySize, entry))
continue;
// key is found
- entry.skip(keyLen);
+ entry.skip(keySize);
long timeStampPos = entry.position();
@@ -677,17 +704,17 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
lock();
try {
// inBytes position and limit correspond to the key
- final long keyLen = inBytes.remaining();
+ final long keySize = inBytes.remaining();
hashLookupLiveAndDeleted.startSearch(hash2);
for (int pos; (pos = hashLookupLiveAndDeleted.nextPos()) >= 0; ) {
long offset = offsetFromPos(pos);
NativeBytes entry = entry(offset);
- if (!keyEquals(inBytes, keyLen, entry))
+ if (!remoteKeyEquals(inBytes, keySize, entry))
continue;
// key is found
- entry.skip(keyLen);
+ entry.skip(keySize);
final long timeStampPos = entry.positionAddr();
@@ -704,15 +731,15 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
// deleted flag
entry.writeBoolean(false);
- long valueLenPos = entry.position();
- long valueLen = readValueLen(entry);
- long entryEndAddr = entry.positionAddr() + valueLen;
+ long valueSizePos = entry.position();
+ long valueSize = readValueSize(entry);
+ long entryEndAddr = entry.positionAddr() + valueSize;
// write the value
inBytes.limit(valueLimit);
inBytes.position(valuePos);
- putValue(pos, offset, entry, valueLenPos, entryEndAddr, inBytes, null, true,
+ putValue(pos, offset, entry, valueSizePos, entryEndAddr, null, null, inBytes,
hashLookupLiveAndDeleted);
if (wasDeleted) {
@@ -724,13 +751,13 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
// key is not found
- long valueLen = valueLimit - valuePos;
- int pos = alloc(inBlocks(entrySize(keyLen, valueLen)));
+ long valueSize = valueLimit - valuePos;
+ int pos = alloc(inBlocks(entrySize(keySize, valueSize)));
long offset = offsetFromPos(pos);
clearMetaData(offset);
NativeBytes entry = entry(offset);
- entry.writeStopBit(keyLen);
+ keySizeMarshaller.writeSize(entry, keySize);
// write the key
entry.write(inBytes);
@@ -739,7 +766,7 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
entry.writeByte(identifier);
entry.writeBoolean(false);
- entry.writeStopBit(valueLen);
+ valueSizeMarshaller.writeSize(entry, valueSize);
alignment.alignPositionAddr(entry);
// write the value
@@ -758,21 +785,26 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
}
- V put(Bytes keyBytes, K key, V value, int hash2, boolean replaceIfPresent,
+ private boolean remoteKeyEquals(Bytes keyBytes, long keySize, Bytes entry) {
+ return keySize == keySizeMarshaller.readSize(entry) && entry.startsWith(keyBytes);
+ }
+
+ V put(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter,
+ K key, V value, int hash2, boolean replaceIfPresent,
final byte identifier, final long timestamp) {
lock();
try {
IntIntMultiMap hashLookup = hashLookupLiveAndDeleted;
- long keyLen = keyBytes.remaining();
+ long keySize = metaKeyWriter.size(keyWriter, key);
hashLookup.startSearch(hash2);
int pos;
while ((pos = hashLookup.nextPos()) >= 0) {
long offset = offsetFromPos(pos);
NativeBytes entry = entry(offset);
- if (!keyEquals(keyBytes, keyLen, entry))
+ if (!keyEquals(keyWriter, metaKeyWriter, key, keySize, entry))
continue;
// key is found
- entry.skip(keyLen);
+ entry.skip(keySize);
final long timeStampPos = entry.positionAddr();
@@ -791,8 +823,8 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
// deleted flag
entry.writeBoolean(false);
- final V prevValue = replaceValueOnPut(key, value, entry, pos, offset,
- !wasDeleted && !putReturnsNull, hashLookup);
+ final V prevValue = replaceValueOnPut(copies, key, value, entry, pos,
+ offset, !wasDeleted && !putReturnsNull, hashLookup);
if (wasDeleted) {
// remove() would have got rid of this so we have to add it back in
@@ -804,12 +836,13 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
} else {
// we wont replaceIfPresent and the entry is not deleted
- return putReturnsNull ? null : readValue(entry, null);
+ return putReturnsNull ? null : readValue(copies, entry, null);
}
}
// key is not found
- long offset = putEntry(keyBytes, hash2, value, false, identifier, timestamp, hashLookup);
+ long offset = putEntry(copies, metaKeyWriter, keyWriter, key, keySize, hash2, value,
+ false, identifier, timestamp, hashLookup);
incrementSize();
notifyPut(offset, true, key, value, posFromOffset(offset));
return null;
@@ -848,55 +881,61 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
/**
- * Puts entry. If {@code value} implements {@link net.openhft.lang.model.Byteable} interface and
+ * Puts entry. If {@code value} implements {@link Byteable} interface and
* {@code usingValue} is {@code true}, the value is backed with the bytes of this entry.
*
- * @param keyBytes serialized key
* @param hash2 a hash of the {@code keyBytes}. Caller was searching for the key in the
* {@code searchedHashLookup} using this hash.
* @param value the value to put
* @param usingValue {@code true} if the value should be backed with the bytes of the entry,
- * if it implements {@link net.openhft.lang.model.Byteable} interface,
+ * if it implements {@link Byteable} interface,
* {@code false} if it should put itself
* @param identifier the identifier of the outer CHM node
* @param timestamp the timestamp when the entry was put (this could be later if it was a
* remote put) this method is called only from usual put or acquire
* @param searchedHashLookup the hash lookup that used to find the entry based on the key
* @return offset of the written entry in the Segment bytes
- * @see VanillaChronicleMap.Segment#putEntry(Bytes, Object, boolean)
+ * @see VanillaChronicleMap.Segment#putEntry
*/
- private long putEntry(Bytes keyBytes, int hash2, V value, boolean usingValue,
- final int identifier, final long timestamp,
+ private long putEntry(ThreadLocalCopies copies, MKI metaKeyWriter,
+ KI keyWriter, K key, long keySize, int hash2, V value,
+ boolean usingValue, final int identifier, final long timestamp,
IntIntMultiMap searchedHashLookup) {
- long keyLen = keyBytes.remaining();
// "if-else polymorphism" is not very beautiful, but allows to
// reuse the rest code of this method and doesn't hurt performance.
boolean byteableValue = usingValue && value instanceof Byteable;
- long valueLen;
- Bytes valueBytes = null;
+ long valueSize;
+ MetaBytesWriter metaValueWriter = null;
+ VW valueWriter = null;
Byteable valueAsByteable = null;
if (!byteableValue) {
- valueBytes = getValueAsBytes(value);
- valueLen = valueBytes.remaining();
+ copies = valueWriterProvider.getCopies(copies);
+ valueWriter = valueWriterProvider.get(copies, originalValueWriter);
+ copies = metaValueWriterProvider.getCopies(copies);
+ metaValueWriter = metaValueWriterProvider.get(
+ copies, originalMetaValueWriter, valueWriter, value);
+ valueSize = metaValueWriter.size(valueWriter, value);
} else {
valueAsByteable = (Byteable) value;
- valueLen = valueAsByteable.maxSize();
+ valueSize = valueAsByteable.maxSize();
}
- long entrySize = entrySize(keyLen, valueLen);
+ long entrySize = entrySize(keySize, valueSize);
int pos = alloc(inBlocks(entrySize));
long offset = offsetFromPos(pos);
clearMetaData(offset);
NativeBytes entry = entry(offset);
- entry.writeStopBit(keyLen);
- entry.write(keyBytes);
+ keySizeMarshaller.writeSize(entry, keySize);
+ metaKeyWriter.write(keyWriter, entry, key);
+
entry.writeLong(timestamp);
entry.writeByte(identifier);
entry.writeBoolean(false);
- writeValueOnPutEntry(valueLen, valueBytes, valueAsByteable, entry);
+ writeValueOnPutEntry(valueSize, metaValueWriter, valueWriter, value, valueAsByteable,
+ entry);
// we have to add it both to the live
if (searchedHashLookup == hashLookupLiveAndDeleted) {
@@ -911,25 +950,24 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
/**
- * @see VanillaChronicleMap.Segment#remove(net.openhft.lang.io.Bytes, Object, Object, int)
+ * @see VanillaChronicleMap.Segment#remove
*/
- public V remove(Bytes keyBytes, K key, V expectedValue, int hash2,
- final long timestamp, final byte identifier) {
+ V remove(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter,
+ K key, V expectedValue, int hash2,
+ final long timestamp, final byte identifier) {
assert identifier > 0;
lock();
try {
- long keyLen = keyBytes.remaining();
-
+ long keySize = metaKeyWriter.size(keyWriter, key);
final IntIntMultiMap multiMap = hashLookupLiveAndDeleted;
-
multiMap.startSearch(hash2);
for (int pos; (pos = multiMap.nextPos()) >= 0; ) {
long offset = offsetFromPos(pos);
NativeBytes entry = entry(offset);
- if (!keyEquals(keyBytes, keyLen, entry))
+ if (!keyEquals(keyWriter, metaKeyWriter, key, keySize, entry))
continue;
// key is found
- entry.skip(keyLen);
+ entry.skip(keySize);
long timeStampPos = entry.position();
if (shouldIgnore(entry, timestamp, identifier)) {
@@ -951,9 +989,9 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
return null;
}
- long valueLen = readValueLen(entry);
+ long valueSize = readValueSize(entry);
V valueRemoved = expectedValue != null || !removeReturnsNull
- ? readValue(entry, null, valueLen) : null;
+ ? readValue(copies, entry, null, valueSize) : null;
if (expectedValue != null && !expectedValue.equals(valueRemoved))
return null;
@@ -982,29 +1020,29 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
/**
- * @see VanillaChronicleMap.Segment#remove(net.openhft.lang.io.Bytes, Object, Object, int)
+ * @see VanillaChronicleMap.Segment#replace
*/
- public V replace(Bytes keyBytes, K key, V expectedValue, V newValue, int hash2,
- long timestamp) {
+ V replace(ThreadLocalCopies copies, MKI metaKeyWriter, KI keyWriter,
+ K key, V expectedValue, V newValue, int hash2, long timestamp) {
lock();
try {
- long keyLen = keyBytes.remaining();
+ long keySize = metaKeyWriter.size(keyWriter, key);
hashLookupLiveOnly.startSearch(hash2);
for (int pos; (pos = hashLookupLiveOnly.nextPos()) >= 0; ) {
long offset = offsetFromPos(pos);
NativeBytes entry = entry(offset);
- if (!keyEquals(keyBytes, keyLen, entry))
+ if (!keyEquals(keyWriter, metaKeyWriter, key, keySize, entry))
continue;
// key is found
- entry.skip(keyLen);
+ entry.skip(keySize);
if (shouldIgnore(entry, timestamp, localIdentifier))
return null;
// skip the is deleted flag
entry.skip(1);
- return onKeyPresentOnReplace(key, expectedValue, newValue, pos, offset, entry,
- hashLookupLiveOnly);
+ return onKeyPresentOnReplace(copies, key, expectedValue, newValue, pos, offset,
+ entry, hashLookupLiveOnly);
}
// key is not found
return null;
@@ -1033,8 +1071,8 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
@Override
public void accept(int hash, int pos) {
final NativeBytes entry = entry(offsetFromPos(pos));
- long keyLen = entry.readStopBit();
- entry.skip(keyLen);
+ long keySize = keySizeMarshaller.readSize(entry);
+ entry.skip(keySize);
final long entryTimestamp = entry.readLong();
@@ -1052,13 +1090,19 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
@Override
public Entry getEntry(long pos) {
bytes.position(offsetFromPos(pos) + metaDataBytes);
- bytes.readStopBit();
- K key = keyMarshaller.read(bytes);
+
+ long keySize = keySizeMarshaller.readSize(bytes);
+ ThreadLocalCopies copies = keyReaderProvider.getCopies(null);
+ K key = keyReaderProvider.get(copies, originalKeyReader).read(bytes, keySize);
+
long timestamp = bytes.readLong();
bytes.skip(2L); // identifier and isDeleted flag
- bytes.readStopBit();
+
+ long valueSize = valueSizeMarshaller.readSize(bytes);
alignment.alignPositionAddr(bytes);
- V value = valueMarshaller.read(bytes);
+ copies = valueReaderProvider.getCopies(copies);
+ V value = valueReaderProvider.get(copies, originalValueReader).read(bytes, valueSize);
+
return new TimestampTrackingEntry(key, value, timestamp);
}
@@ -1090,7 +1134,7 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
}
- class EntryIterator extends VanillaChronicleMap.EntryIterator {
+ class EntryIterator extends VanillaChronicleMap.EntryIterator {
@Override
void removePresent(VanillaChronicleMap.Segment seg, int pos) {
@SuppressWarnings("unchecked")
@@ -1100,17 +1144,23 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
final NativeBytes entry = segment.entry(offset);
final long limit = entry.limit();
- final long keyLen = entry.readStopBit();
+ final long keySize = keySizeMarshaller.readSize(entry);
long keyPosition = entry.position();
- entry.skip(keyLen);
+ entry.skip(keySize);
long timestamp = entry.readLong();
entry.position(keyPosition);
if (timestamp > ((TimestampTrackingEntry) returnedEntry).timestamp) {
// The entry was updated after being returned from iterator.next()
// Check that it is still the entry with the same key
K key = returnedEntry.getKey();
- DirectBytes returnedKeyBytes = getKeyAsBytes(key);
- if (returnedKeyBytes.remaining() != keyLen || !entry.startsWith(returnedKeyBytes)) {
+ ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
+ KI keyWriter = keyInteropProvider.get(copies, originalKeyInterop);
+ copies = metaKeyInteropProvider.getCopies(copies);
+ MKI metaKeyWriter =
+ metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyWriter, key);
+ long returnedKeySize = metaKeyWriter.size(keyWriter, key);
+ if (returnedKeySize != keySize ||
+ !metaKeyWriter.startsWith(keyWriter, entry, key)) {
// The case:
// 1. iterator.next() - thread 1
// 2. map.put() which cause relocation of the key, returned above - thread 2
@@ -1121,14 +1171,12 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
return;
}
}
- entry.limit(entry.position() + keyLen);
- final int segmentHash = hasher.segmentHash(hash(entry));
- entry.limit(limit);
+ final int segmentHash = segmentHash(hash(entry, keyPosition, keyPosition + keySize));
segment.hashLookupLiveOnly.remove(segmentHash, pos);
segment.decrementSize();
- entry.skip(keyLen);
+ entry.skip(keySize);
entry.writeLong(timeProvider.currentTimeMillis());
entry.writeByte(localIdentifier);
entry.writeBoolean(true);
@@ -1137,7 +1185,7 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
}
- class EntrySet extends VanillaChronicleMap.EntrySet {
+ class EntrySet extends VanillaChronicleMap.EntrySet {
@NotNull
@Override
public Iterator> iterator() {
@@ -1252,9 +1300,9 @@ class ReplicatedChronicleMap extends VanillaChronicleMap
}
@Override
- public V onGetMissing(ChronicleMap map, Bytes keyBytes, K key,
+ public V onGetMissing(ChronicleMap map, K key,
V usingValue) {
- return nextListener.onGetMissing(map, keyBytes, key, usingValue);
+ return nextListener.onGetMissing(map, key, usingValue);
}
@Override
diff --git a/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java b/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java
new file mode 100644
index 000000000..ca6743b2f
--- /dev/null
+++ b/src/main/java/net/openhft/chronicle/map/SerializationBuilder.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.chronicle.map;
+
+import net.openhft.chronicle.map.serialization.*;
+import net.openhft.chronicle.map.serialization.impl.*;
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.*;
+import net.openhft.lang.io.serialization.impl.*;
+import net.openhft.lang.model.Byteable;
+import net.openhft.lang.model.DataValueClasses;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.Externalizable;
+import java.io.Serializable;
+
+import static net.openhft.chronicle.map.Objects.hash;
+import static net.openhft.chronicle.map.serialization.SizeMarshallers.stopBit;
+
+final class SerializationBuilder implements Cloneable {
+
+ private static boolean marshallerUseFactory(Class c) {
+ return Byteable.class.isAssignableFrom(c) ||
+ BytesMarshallable.class.isAssignableFrom(c) ||
+ Externalizable.class.isAssignableFrom(c);
+ }
+
+ enum Role {KEY, VALUE}
+ private enum CopyingInterop {FROM_MARSHALLER, FROM_WRITER}
+
+ private final Serializable bufferIdentity;
+ final Class eClass;
+ private SizeMarshaller sizeMarshaller = stopBit();
+ private BytesReader reader;
+ private Object interop;
+ private CopyingInterop copyingInterop = null;
+ private MetaBytesInterop metaInterop;
+ private MetaProvider metaInteropProvider;
+ private ObjectFactory factory;
+
+ @SuppressWarnings("unchecked")
+ SerializationBuilder(Class eClass, Role role) {
+ this.bufferIdentity = role;
+ this.eClass = eClass;
+ Class classForMarshaller = marshallerUseFactory(eClass) && eClass.isInterface() ?
+ DataValueClasses.directClassFor(eClass) : eClass;
+
+ ObjectFactory factory = null;
+ if (role == Role.VALUE) {
+ factory = marshallerUseFactory(eClass) ?
+ new AllocateInstanceObjectFactory(
+ eClass.isInterface() ? classForMarshaller : eClass) :
+ NullObjectFactory.INSTANCE;
+ }
+
+ if (Byteable.class.isAssignableFrom(eClass)) {
+ agileMarshaller(ByteableMarshaller.of((Class) classForMarshaller), factory);
+ } else if (eClass == CharSequence.class || eClass == String.class) {
+ reader((BytesReader) CharSequenceReader.of(), factory);
+ writer((BytesWriter) CharSequenceWriter.instance());
+ } else if (eClass == Long.class) {
+ agileMarshaller((AgileBytesMarshaller) LongMarshaller.INSTANCE, factory);
+ } else if (eClass == byte[].class) {
+ reader((BytesReader) ByteArrayMarshaller.INSTANCE, factory);
+ interop((BytesInterop) ByteArrayMarshaller.INSTANCE);
+ } else {
+ marshaller(chooseMarshaller(eClass, classForMarshaller), factory);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private BytesMarshaller chooseMarshaller(Class eClass, Class classForMarshaller) {
+ if (BytesMarshallable.class.isAssignableFrom(eClass))
+ return new BytesMarshallableMarshaller(classForMarshaller);
+ if (Externalizable.class.isAssignableFrom(eClass))
+ return new ExternalizableMarshaller(classForMarshaller);
+ if (eClass == Integer.class)
+ return (BytesMarshaller) IntegerMarshaller.INSTANCE;
+ if (eClass == Double.class)
+ return (BytesMarshaller) DoubleMarshaller.INSTANCE;
+ return SerializableMarshaller.INSTANCE;
+ }
+
+ private SerializationBuilder copyingInterop(CopyingInterop copyingInterop) {
+ this.copyingInterop = copyingInterop;
+ return this;
+ }
+
+ public SerializationBuilder agileMarshaller(AgileBytesMarshaller agileBytesMarshaller,
+ ObjectFactory factory) {
+ if (factory == null) factory = this.factory;
+ return sizeMarshaller(agileBytesMarshaller)
+ .reader(agileBytesMarshaller, factory)
+ .interop(agileBytesMarshaller);
+ }
+
+ public SerializationBuilder interop(BytesInterop interop) {
+ return copyingInterop(null)
+ .setInterop(interop)
+ .metaInterop(DelegatingMetaBytesInterop.>instance())
+ .metaInteropProvider(DelegatingMetaBytesInteropProvider
+ .>instance());
+ }
+
+ public SerializationBuilder writer(BytesWriter writer) {
+ return copyingInterop(CopyingInterop.FROM_WRITER)
+ .sizeMarshaller(stopBit())
+ .setInterop(writer)
+ .metaInterop(CopyingMetaBytesInterop
+ .>forBytesWriter(bufferIdentity));
+ }
+
+ public SerializationBuilder marshaller(BytesMarshaller marshaller,
+ ObjectFactory factory) {
+ if (factory == null) factory = this.factory;
+ return copyingInterop(CopyingInterop.FROM_MARSHALLER)
+ .sizeMarshaller(stopBit())
+ .reader(BytesReaders.fromBytesMarshaller(marshaller), factory)
+ .setInterop(marshaller)
+ .metaInterop(CopyingMetaBytesInterop
+ .>forBytesMarshaller(bufferIdentity));
+ }
+
+ public SerializationBuilder maxSize(long maxSize) {
+ boolean mutable = eClass != String.class; // for example
+ if (copyingInterop == CopyingInterop.FROM_MARSHALLER) {
+ metaInteropProvider(CopyingMetaBytesInterop
+ .>providerForBytesMarshaller(mutable, maxSize));
+ } else if (copyingInterop == CopyingInterop.FROM_WRITER) {
+ metaInteropProvider(CopyingMetaBytesInterop
+ .>providerForBytesWriter(mutable, maxSize));
+ }
+ return this;
+ }
+
+ public SizeMarshaller sizeMarshaller() {
+ return sizeMarshaller;
+ }
+
+ public SerializationBuilder sizeMarshaller(SizeMarshaller sizeMarshaller) {
+ this.sizeMarshaller = sizeMarshaller;
+ return this;
+ }
+
+ public BytesReader reader() {
+ return reader;
+ }
+
+ public SerializationBuilder reader(BytesReader reader, ObjectFactory factory) {
+ this.reader = reader;
+ if (factory != null)
+ this.factory = factory;
+ return this;
+
+ }
+
+ public Object interop() {
+ return interop;
+ }
+
+ private SerializationBuilder setInterop(Object interop) {
+ this.interop = interop;
+ return this;
+ }
+
+ public MetaBytesInterop metaInterop() {
+ return metaInterop;
+ }
+
+ private SerializationBuilder metaInterop(MetaBytesInterop metaInterop) {
+ this.metaInterop = metaInterop;
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public MetaProvider> metaInteropProvider() {
+ return (MetaProvider>) metaInteropProvider;
+ }
+
+ private SerializationBuilder metaInteropProvider(
+ MetaProvider metaInteropProvider) {
+ this.metaInteropProvider = metaInteropProvider;
+ return this;
+ }
+
+ public ObjectFactory factory() {
+ return factory;
+ }
+
+ @SuppressWarnings("unchecked")
+ public SerializationBuilder factory(ObjectFactory factory) {
+ if (!marshallerUseFactory(eClass)) {
+ throw new IllegalStateException("Default marshaller for " + eClass +
+ " value don't use object factory");
+ } else if (interop instanceof ByteableMarshaller) {
+ if (factory instanceof AllocateInstanceObjectFactory) {
+ agileMarshaller(ByteableMarshaller.of((Class) eClass), factory);
+ } else {
+ agileMarshaller(ByteableMarshaller.of((Class) eClass, (ObjectFactory) factory),
+ factory);
+ }
+ } else if (interop instanceof BytesMarshallableMarshaller) {
+ if (factory instanceof AllocateInstanceObjectFactory) {
+ interop = new BytesMarshallableMarshaller(
+ ((AllocateInstanceObjectFactory) factory).allocatedClass());
+ } else {
+ interop = new BytesMarshallableMarshallerWithCustomFactory(
+ ((BytesMarshallableMarshaller) interop).marshaledClass(),
+ factory
+ );
+ }
+ } else if (interop instanceof ExternalizableMarshaller) {
+ if (factory instanceof AllocateInstanceObjectFactory) {
+ interop = new ExternalizableMarshaller(
+ ((AllocateInstanceObjectFactory) factory).allocatedClass());
+ } else {
+ interop = new ExternalizableMarshallerWithCustomFactory(
+ ((ExternalizableMarshaller) interop).marshaledClass(),
+ factory
+ );
+ }
+ } else {
+ // interop is custom, it is user's responsibility to use the same factory inside
+ // marshaller and standalone
+ throw new IllegalStateException(
+ "Change the value factory simultaneously with marshaller " +
+ "using *AndFactory() method");
+ }
+ this.factory = factory;
+ return this;
+ }
+
+ @Override
+ public SerializationBuilder clone() {
+ try {
+ return (SerializationBuilder) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private enum IntegerMarshaller implements BytesMarshaller {
+ INSTANCE;
+
+ @Override
+ public void write(Bytes bytes, Integer v) {
+ bytes.writeInt(v);
+ }
+
+ @Nullable
+ @Override
+ public Integer read(Bytes bytes) {
+ return bytes.readInt();
+ }
+
+ @Nullable
+ @Override
+ public Integer read(Bytes bytes, @Nullable Integer v) {
+ return bytes.readInt();
+ }
+ }
+
+ private enum DoubleMarshaller implements BytesMarshaller {
+ INSTANCE;
+
+ @Override
+ public void write(Bytes bytes, Double v) {
+ bytes.writeDouble(v);
+ }
+
+ @Nullable
+ @Override
+ public Double read(Bytes bytes) {
+ return bytes.readDouble();
+ }
+
+ @Nullable
+ @Override
+ public Double read(Bytes bytes, @Nullable Double v) {
+ return bytes.readDouble();
+ }
+ }
+
+
+ private enum SerializableMarshaller implements BytesMarshaller {
+ INSTANCE;
+
+ @Override
+ public void write(Bytes bytes, Object obj) {
+ bytes.writeObject(obj);
+ }
+
+ @Nullable
+ @Override
+ public Object read(Bytes bytes) {
+ return bytes.readObject();
+ }
+
+ @Nullable
+ @Override
+ public Object read(Bytes bytes, @Nullable Object obj) {
+ return bytes.readInstance(null, obj);
+ }
+ }
+
+ private static class BytesMarshallableMarshallerWithCustomFactory
+ extends BytesMarshallableMarshaller {
+ private static final long serialVersionUID = 0L;
+
+ @NotNull
+ private final ObjectFactory factory;
+
+ BytesMarshallableMarshallerWithCustomFactory(@NotNull Class