diff --git a/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java index b464fb929..a09c46587 100644 --- a/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/AbstractChronicleMapBuilder.java @@ -138,7 +138,7 @@ public abstract class AbstractChronicleMapBuilder defaultValueProvider = NullValueProvider.INSTANCE; - private PrepareValueBytes prepareValueBytes = null; + private PrepareValueBytes prepareValueBytes = null; private byte identifier = -1; private StatelessBuilder statelessBuilder; @@ -735,7 +735,7 @@ public abstract class AbstractChronicleMapBuilder prepareValueBytes) { + B prepareValueBytesOnAcquire(@NotNull PrepareValueBytes prepareValueBytes) { this.prepareValueBytes = prepareValueBytes; this.defaultValue = null; this.defaultValueProvider = null; diff --git a/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java index 3d60a400c..4a8aba2df 100644 --- a/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/OffHeapUpdatableChronicleMapBuilder.java @@ -38,7 +38,7 @@ public final class OffHeapUpdatableChronicleMapBuilder OffHeapUpdatableChronicleMapBuilder(Class keyClass, Class valueClass) { super(keyClass, valueClass); - prepareValueBytesOnAcquire(new ZeroOutValueBytes(valueSize())); + prepareValueBytesOnAcquire(new ZeroOutValueBytes(valueSize())); } @Override @@ -118,19 +118,21 @@ public final class OffHeapUpdatableChronicleMapBuilder /** * Configures the procedure which is called on the bytes, which later the returned value is * pointing to, if the key is absent, on {@link ChronicleMap#acquireUsing(Object, Object) - * acquireUsing()} call on maps, created by this builder. + * acquireUsing()} call on maps, created by this builder. See {@link PrepareValueBytes} for + * more information. * *

The default preparation callback zeroes out the value bytes. * * @param prepareValueBytes what to do with the value bytes before assigning them into the * {@link Byteable} value to return from {@code acquireUsing()} call * @return this builder back + * @see PrepareValueBytes * @see #defaultValue(Object) * @see #defaultValueProvider(DefaultValueProvider) */ @Override public OffHeapUpdatableChronicleMapBuilder prepareValueBytesOnAcquire( - @NotNull PrepareValueBytes prepareValueBytes) { + @NotNull PrepareValueBytes prepareValueBytes) { return super.prepareValueBytesOnAcquire(prepareValueBytes); } } diff --git a/src/main/java/net/openhft/chronicle/map/PrepareValueBytes.java b/src/main/java/net/openhft/chronicle/map/PrepareValueBytes.java index bcaca2470..e2b726fec 100644 --- a/src/main/java/net/openhft/chronicle/map/PrepareValueBytes.java +++ b/src/main/java/net/openhft/chronicle/map/PrepareValueBytes.java @@ -17,10 +17,46 @@ package net.openhft.chronicle.map; import net.openhft.lang.io.Bytes; +import net.openhft.lang.model.Byteable; import java.io.Serializable; -public interface PrepareValueBytes extends Serializable { +/** + * Strategy of preparing bytes of off-heap memory before assigning them into {@link Byteable} + * value during {@link ChronicleMap#acquireUsing(Object, Object) + * chronicleMap.acquireUsing()} call, when the given key is absent in the map. Example: if you + * want {@code 1L} to be the off-heap updatable ChronicleMap's {@linkplain + * OffHeapUpdatableChronicleMapBuilder#defaultValue(Object) default value}, the most simple way + * to achieve this is to {@linkplain OffHeapUpdatableChronicleMapBuilder#prepareValueBytesOnAcquire( + * PrepareValueBytes) configure} custom {@code PrepareValueBytes} strategy in {@link + * OffHeapUpdatableChronicleMapBuilder}:

{@code
+ * OffHeapUpdatableChronicleMapBuilder.of(Key.class, LongValue.class)
+ *     .prepareValueBytesOnAcquire((bytes, k) -> bytes.writeLong(1L))
+ *     ...
+ *     .create();}
+ * + *

Although the value type is not used in the API, {@link PrepareValueBytes} is not intended + * to be generic by value type, because strategy should know the value layout and + * {@linkplain Byteable#maxSize() how much bytes} does it take in memory. + * + * @param the key type of {@link ChronicleMap}, on which {@code acquireUsing()} is queried + * @param the value type of {@link ChronicleMap}, on which {@code acquireUsing()} is queried + * @see OffHeapUpdatableChronicleMapBuilder#prepareValueBytesOnAcquire(PrepareValueBytes) + */ +public interface PrepareValueBytes extends Serializable { + /** + * Prepares bytes before assigning them into {@link Byteable}. The given bytes' position + * corresponds to the start of value bytes to be assigned into. This method should increment + * the given bytes' position by {@linkplain Byteable#maxSize() the value size}. Bytes' contents + * outside of this range shouldn't be altered. + * + * @param bytes the bytes, positioned at the first value byte. Bytes' {@linkplain Bytes#limit( + * long) limit} and {@linkplain Bytes#remaining()} are not specified, but it is guaranteed that + * the latter is not less than {@linkplain Byteable#maxSize() the value size}. + * @param key the key which is absent in the {@link ChronicleMap} during {@link + * ChronicleMap#acquireUsing(Object, Object) acquireUsing()} call and value bytes are prepared + * for + */ void prepare(Bytes bytes, K key); } diff --git a/src/main/java/net/openhft/chronicle/map/PrepareValueBytesAsWriter.java b/src/main/java/net/openhft/chronicle/map/PrepareValueBytesAsWriter.java index 13b7712ed..c4f57ff18 100644 --- a/src/main/java/net/openhft/chronicle/map/PrepareValueBytesAsWriter.java +++ b/src/main/java/net/openhft/chronicle/map/PrepareValueBytesAsWriter.java @@ -26,10 +26,10 @@ final class PrepareValueBytesAsWriter implements BytesWriter, MetaBytesWriter>, Serializable { private static final long serialVersionUID = 0L; - private final PrepareValueBytes prepareValueBytes; + private final PrepareValueBytes prepareValueBytes; private final long valueSize; - PrepareValueBytesAsWriter(PrepareValueBytes prepareValueBytes, long valueSize) { + PrepareValueBytesAsWriter(PrepareValueBytes prepareValueBytes, long valueSize) { this.prepareValueBytes = prepareValueBytes; this.valueSize = valueSize; } diff --git a/src/main/java/net/openhft/chronicle/map/ZeroOutValueBytes.java b/src/main/java/net/openhft/chronicle/map/ZeroOutValueBytes.java index 67a4ea96f..a6e2ce845 100644 --- a/src/main/java/net/openhft/chronicle/map/ZeroOutValueBytes.java +++ b/src/main/java/net/openhft/chronicle/map/ZeroOutValueBytes.java @@ -18,7 +18,7 @@ package net.openhft.chronicle.map; import net.openhft.lang.io.Bytes; -final class ZeroOutValueBytes implements PrepareValueBytes { +final class ZeroOutValueBytes implements PrepareValueBytes { private static final long serialVersionUID = 0L; private final long valueSize; @@ -30,5 +30,6 @@ final class ZeroOutValueBytes implements PrepareValueBytes { public void prepare(Bytes bytes, K key) { long pos = bytes.position(); bytes.zeroOut(pos, pos + valueSize); + bytes.skip(valueSize); } }