Merge remote-tracking branch 'origin/master'

Conflicts:
	src/test/java/eg/BGChronicleTest.java
This commit is contained in:
Peter Lawrey
2014-12-09 17:40:10 +00:00
21 changed files with 561 additions and 306 deletions
@@ -34,32 +34,33 @@ public final class BytesReaders {
* from {@link net.openhft.chronicle.hash.serialization} package.
*
* @param marshaller the actual reading implementation
* @param <E> type of the objects marshalled
* @param <E> type of the objects marshalled
* @return a {@code BytesReader} wrapping the given {@code BytesMarshaller}
*/
public static <E> BytesReader<E> fromBytesMarshaller(BytesMarshaller<E> marshaller) {
public static <E> BytesReader<E> fromBytesMarshaller(BytesMarshaller<? super E> marshaller) {
return new SimpleBytesReader<E>(marshaller);
}
private static class SimpleBytesReader<E> implements BytesReader<E> {
private static final long serialVersionUID = 0L;
private final BytesMarshaller<E> marshaller;
private final BytesMarshaller<? super E> marshaller;
public SimpleBytesReader(BytesMarshaller<E> marshaller) {
public SimpleBytesReader(BytesMarshaller<? super E> marshaller) {
this.marshaller = marshaller;
}
@Override
public E read(Bytes bytes, long size) {
return marshaller.read(bytes);
return (E) marshaller.read(bytes);
}
@Override
public E read(Bytes bytes, long size, E toReuse) {
return marshaller.read(bytes, toReuse);
return (E) marshaller.read(bytes, toReuse);
}
}
private BytesReaders() {}
private BytesReaders() {
}
}
@@ -39,7 +39,6 @@ import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
import net.openhft.lang.model.Byteable;
import net.openhft.lang.threadlocal.Provider;
import net.openhft.lang.threadlocal.ThreadLocalCopies;
import net.openhft.lang.values.LongValue;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -985,7 +984,7 @@ abstract class AbstractChronicleMapBuilder<K, V,
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),
return (int) Math.min(Math.max(4L, entries() >> 10),
VanillaChronicleMap.MAX_ENTRY_OVERSIZE_FACTOR);
}
@@ -30,7 +30,6 @@ import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
/**
* Extension of {@link ConcurrentMap} interface, stores the data off-heap.
@@ -202,14 +201,13 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
/**
* Apply a mutator to the value for a key and return a result. A write lock is assumed. <p> If
* there is no entry for this key it will be created and the value empty.
* there is no entry for this key null will be returned
*
* @param key to apply the mapping to
* @param mutator to alter the value and calculate a result
* @param <R> return type.
* @return the result of the function.
*/
<R> R updateForKey(K key, @NotNull Mutator<? super V, R> mutator);
V putWith(K key, @NotNull Mutator<V> mutator);
/**
* exports all the entries to a {@link java.io.File} storing them in JSON format, an attempt is
@@ -37,14 +37,16 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
final ChronicleMapBuilderI<K, V> delegate;
/**
* Returns a new {@code ChronicleMapBuilder} instance which is able to {@linkplain #create() create} maps
* with the specified key and value classes.
* Returns a new {@code ChronicleMapBuilder} instance which is able to {@linkplain #create()
* create} maps with the specified key and value classes.
*
* <p>{@code ChronicleMapBuilder} analyzes provided key and value classes and automatically chooses the
* most specific internal builder.
* <p>{@code ChronicleMapBuilder} analyzes provided key and value classes and automatically
* chooses the most specific internal builder.
*
* @param keyClass class object used to infer key type and discover it's properties via reflection
* @param valueClass class object used to infer value type and discover it's properties via reflection
* @param keyClass class object used to infer key type and discover it's properties via
* reflection
* @param valueClass class object used to infer value type and discover it's properties via
* reflection
* @param <K> key type of the maps, created by the returned builder
* @param <V> value type of the maps, created by the returned builder
* @return a new builder for the given key and value classes
@@ -67,6 +69,26 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
return new ChronicleMapBuilder<K, V>(builder);
}
// todo - work in progress this will be changed me not today, so don't refactor this !
public static <T> T newInstance(Class<T> interfaceClass, boolean isKey) {
if (interfaceClass.isEnum())
return isKey ? DataValueClasses.newDirectReference(interfaceClass) : DataValueClasses
.newDirectInstance(interfaceClass);
else if (!offHeapReference(interfaceClass) && !interfaceClass.isInterface() &&
!builtInType(interfaceClass)) {
// if (())
// interfaceClass = DataValueClasses.directClassFor(interfaceClass);
return DataValueClasses.newInstance(interfaceClass);
}
return DataValueClasses.newDirectInstance(interfaceClass);
}
static boolean builtInType(Class clazz) {
return clazz.getClassLoader() == Class.class.getClassLoader();
}
@@ -83,9 +105,9 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
* {@inheritDoc} With respect to {@linkplain #entryAndValueAlignment(Alignment) alignment}.
*
* <p>Note that the actual entrySize will be aligned to 4 (default {@linkplain
* #entryAndValueAlignment(Alignment) entry alignment}). I. e. if you set entry size to 30, and entry
* alignment is set to {@link Alignment#OF_4_BYTES}, the actual entry size will be 32 (30 aligned to 4
* bytes).
* #entryAndValueAlignment(Alignment) entry alignment}). I. e. if you set entry size to 30, and
* entry alignment is set to {@link Alignment#OF_4_BYTES}, the actual entry size will be 32 (30
* aligned to 4 bytes).
*
* @see #entryAndValueAlignment(Alignment) // * @see #entries(long)
*/
@@ -96,16 +118,16 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* Configures alignment strategy of address in memory of entries and independently of address in memory of
* values within entries in ChronicleMaps, created by this builder.
* Configures alignment strategy of address in memory of entries and independently of address in
* memory of values within entries in ChronicleMaps, created by this builder.
*
* <p>Useful when values of the map are updated intensively, particularly fields with volatile access,
* because it doesn't work well if the value crosses cache lines. Also, on some (nowadays rare)
* architectures any misaligned memory access is more expensive than aligned.
* <p>Useful when values of the map are updated intensively, particularly fields with volatile
* access, because it doesn't work well if the value crosses cache lines. Also, on some
* (nowadays rare) architectures any misaligned memory access is more expensive than aligned.
*
* <p>Note that {@linkplain #entrySize(int) entry size} will be aligned according to this alignment. I. e.
* if you set {@code entrySize(20)} and {@link Alignment#OF_8_BYTES}, actual entry size will be 24 (20
* aligned to 8 bytes).
* <p>Note that {@linkplain #entrySize(int) entry size} will be aligned according to this
* alignment. I. e. if you set {@code entrySize(20)} and {@link Alignment#OF_8_BYTES}, actual
* entry size will be 24 (20 aligned to 8 bytes).
*
* <p>Default is {@link Alignment#OF_4_BYTES} for Byteable values.
*
@@ -119,11 +141,11 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* {@inheritDoc} Also, it overrides any previous {@link #prepareValueBytesOnAcquire} configuration to this
* {@code ChronicleMapBuilder}.
* {@inheritDoc} Also, it overrides any previous {@link #prepareValueBytesOnAcquire}
* configuration to this {@code ChronicleMapBuilder}.
*
* <p>By default, the default value is not specified, default {@linkplain #prepareValueBytesOnAcquire
* prepare value bytes routine} is specified instead.
* <p>By default, the default value is not specified, default {@linkplain
* #prepareValueBytesOnAcquire prepare value bytes routine} is specified instead.
*
* @see #defaultValueProvider(DefaultValueProvider)
* @see #prepareValueBytesOnAcquire(PrepareValueBytes)
@@ -135,15 +157,16 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* 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. See {@link PrepareValueBytes} for more information.
* 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. See {@link PrepareValueBytes} for more
* information.
*
* <p>The default preparation callback zeroes out the value bytes.
*
* @param prepareValueBytes what to do with the value bytes before assigning them into the {@link
* net.openhft.lang.model.Byteable} value to return from {@code acquireUsing()}
* call
* @param prepareValueBytes what to do with the value bytes before assigning them into the
* {@link net.openhft.lang.model.Byteable} value to return from {@code
* acquireUsing()} call
* @return this builder back
* @see PrepareValueBytes
* @see #defaultValue(Object)
@@ -168,16 +191,17 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* Configures the optimal number of bytes, taken by serialized form of values, put into maps, created by
* this builder. If value size is always the same, call {@link #constantValueSizeBySample(Object)} method
* instead of this one.
* Configures the optimal number of bytes, taken by serialized form of values, put into maps,
* created by this builder. If value size is always the same, call {@link
* #constantValueSizeBySample(Object)} method instead of this one.
*
* <p>If value is a boxed primitive type, i. e. if value size is known statically, it is automatically
* accounted and shouldn't be specified by user.
* <p>If value is a boxed primitive type, i. e. if value size is known statically, it is
* automatically accounted and shouldn't be specified by user.
*
* <p>If value size varies moderately, specify the size higher than average, but lower than the maximum
* possible, to minimize average memory overuse. If value size varies in a wide range, it's better to use
* {@linkplain #entrySize(int) entry size} in "chunk" mode and configure it directly.
* <p>If value size varies moderately, specify the size higher than average, but lower than the
* maximum possible, to minimize average memory overuse. If value size varies in a wide range,
* it's better to use {@linkplain #entrySize(int) entry size} in "chunk" mode and configure it
* directly.
*
* @param valueSize number of bytes, taken by serialized form of values
* @return this {@code ChronicleMapOnHeapUpdatableBuilder} back
@@ -192,15 +216,16 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* Configures the constant number of bytes, taken by serialized form of values, put into maps, created by
* this builder. This is done by providing the {@code sampleValue}, all values should take the same number
* of bytes in serialized form, as this sample object.
* Configures the constant number of bytes, taken by serialized form of values, put into maps,
* created by this builder. This is done by providing the {@code sampleValue}, all values should
* take the same number of bytes in serialized form, as this sample object.
*
* <p>If values are of boxed primitive type or {@link net.openhft.lang.model.Byteable} subclass, i. e. if
* value size is known statically, it is automatically accounted and this method shouldn't be called.
* <p>If values are of boxed primitive type or {@link net.openhft.lang.model.Byteable} subclass,
* i. e. if value size is known statically, it is automatically accounted and this method
* shouldn't be called.
*
* <p>If value size varies, method {@link #valueSize(int)} or {@link #entrySize(int)} should be called
* instead of this one.
* <p>If value size varies, method {@link #valueSize(int)} or {@link #entrySize(int)} should be
* called instead of this one.
*
* @param sampleValue the sample value
* @return this builder back
@@ -233,8 +258,8 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
/**
* {@inheritDoc}
*
* @throws IllegalStateException if custom value marshaller is specified or value class is not either
* {@code BytesMarshallable} or {@code Externalizable}
* @throws IllegalStateException if custom value marshaller is specified or value class is not
* either {@code BytesMarshallable} or {@code Externalizable}
*/
@Override
@@ -246,8 +271,8 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
/**
* {@inheritDoc}
*
* <p>By default, default value provider is not specified, {@link #defaultValue(Object) default value} is
* specified instead.
* <p>By default, default value provider is not specified, {@link #defaultValue(Object) default
* value} is specified instead.
*
* @see #defaultValue(Object)
*/
@@ -258,8 +283,8 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* 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
* 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
* section about serialization in ChronicleMap manual</a> for more information.
*
* @param valueMarshaller the marshaller used to serialize values
@@ -271,26 +296,27 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
*/
@Override
public ChronicleMapBuilder<K, V> valueMarshaller(
@NotNull BytesMarshaller<V> valueMarshaller) {
@NotNull BytesMarshaller<? super V> valueMarshaller) {
delegate.valueMarshaller(valueMarshaller);
return this;
}
/**
* Configures the marshallers, 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
* Configures the marshallers, 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
* section about serialization in ChronicleMap manual</a> for more information.
*
* <p>Configuring marshalling this way results to a little bit more compact in-memory layout of the map,
* comparing to a single interface configuration: {@link #valueMarshaller(BytesMarshaller)}.
* <p>Configuring marshalling this way results to a little bit more compact in-memory layout of
* the map, comparing to a single interface configuration: {@link #valueMarshaller(BytesMarshaller)}.
*
* <p>Passing {@link net.openhft.chronicle.hash.serialization.BytesInterop} instead of plain {@link
* net.openhft.chronicle.hash.serialization.BytesWriter} is, of cause, possible, but currently pointless
* for values.
* <p>Passing {@link net.openhft.chronicle.hash.serialization.BytesInterop} instead of plain
* {@link net.openhft.chronicle.hash.serialization.BytesWriter} is, of cause, possible, but
* currently pointless for values.
*
* @param valueWriter the new value object &rarr; {@link net.openhft.lang.io.Bytes} writer (interop)
* @param valueWriter the new value object &rarr; {@link net.openhft.lang.io.Bytes} writer
* (interop) strategy
* @param valueReader the new {@link net.openhft.lang.io.Bytes} &rarr; value object reader
* strategy
* @param valueReader the new {@link net.openhft.lang.io.Bytes} &rarr; value object reader strategy
* @return this builder back
* @see #valueMarshaller(BytesMarshaller)
*/
@@ -301,19 +327,21 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* Configures the marshaller used to serialize actual value sizes to off-heap memory in maps, created by
* this builder.
* Configures the marshaller used to serialize actual value sizes to off-heap memory in maps,
* created by this builder.
*
* <p>Default value size marshaller is so-called {@linkplain net.openhft.chronicle.hash.serialization.SizeMarshallers#stopBit()
* stop bit encoding marshalling}. If {@linkplain #constantValueSizeBySample(Object) constant value size}
* is configured, or defaulted if the value type is always constant and {@code ChronicleHashBuilder}
* implementation knows about it, this configuration takes no effect, because a special {@link
* net.openhft.chronicle.hash.serialization.SizeMarshaller} implementation, which doesn't actually do any
* marshalling, and just returns the known constant size on {@link net.openhft.chronicle.hash.serialization.SizeMarshaller#readSize(
*net.openhft.lang.io.Bytes)} calls, is used instead of any {@code SizeMarshaller} configured using this
* method.
* stop bit encoding marshalling}. If {@linkplain #constantValueSizeBySample(Object) constant
* value size} is configured, or defaulted if the value type is always constant and {@code
* ChronicleHashBuilder} implementation knows about it, this configuration takes no effect,
* because a special {@link net.openhft.chronicle.hash.serialization.SizeMarshaller}
* implementation, which doesn't actually do any marshalling, and just returns the known
* constant size on {@link net.openhft.chronicle.hash.serialization.SizeMarshaller#readSize(
*net.openhft.lang.io.Bytes)} calls, is used instead of any {@code SizeMarshaller} configured
* using this method.
*
* @param valueSizeMarshaller the new marshaller, used to serialize actual value sizes to off-heap memory
* @param valueSizeMarshaller the new marshaller, used to serialize actual value sizes to
* off-heap memory
* @return this builder back
*/
@Override
@@ -498,13 +526,14 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
/**
* @param bootstrapOnlyLocalEntries if set to true - when a new node joins a TCP replication grid, the new
* node will be populated with data, only for the nodes that created that
* data. Otherwise, all the nodes will publish all the data they have (
* potentially swamping the new node with duplicates ) however this does
* guarantee that all the data is replicated over to the new node, and is
* useful especially in the case that the originating node is not
* currently running.
* @param bootstrapOnlyLocalEntries if set to true - when a new node joins a TCP replication
* grid, the new node will be populated with data, only for the
* nodes that created that data. Otherwise, all the nodes will
* publish all the data they have ( potentially swamping the
* new node with duplicates ) however this does guarantee that
* all the data is replicated over to the new node, and is
* useful especially in the case that the originating node is
* not currently running.
*/
public ChronicleMapBuilder<K, V> bootstrapOnlyLocalEntries(boolean bootstrapOnlyLocalEntries) {
delegate.bootstrapOnlyLocalEntries(bootstrapOnlyLocalEntries);
@@ -512,11 +541,13 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
}
public ChronicleMapBuilderI<K, V> checkSerializedValues() {
throw new UnsupportedOperationException("Not implemented");
// throw new UnsupportedOperationException("Not implemented");
return this;
}
public ChronicleMapBuilder<K, V> disableOversizedEntries(boolean disableOversizedEntries) {
// throw an exception rather than use oversized entries to test the size is as expected.
throw new UnsupportedOperationException("Not implemented");
// throw new UnsupportedOperationException("Not implemented");
return this;
}
}
@@ -199,7 +199,7 @@ public interface ChronicleMapBuilderI<K, V> extends Serializable {
* @see #objectSerializer(ObjectSerializer)
*/
ChronicleMapBuilderI<K, V> valueMarshaller(
@NotNull BytesMarshaller<V> valueMarshaller);
@NotNull BytesMarshaller<? super V> valueMarshaller);
/**
* Configures the marshallers, used to serialize/deserialize values to/from off-heap memory in
@@ -8,15 +8,15 @@ import java.io.Serializable;
* <p>This is not functional as it can alter an argument.
*
* @param <T> the type of the mutable input
* @param <R> the type of the result of the mutator
*/
public interface Mutator<T, R> extends Serializable {
public interface Mutator<T> extends Serializable {
/**
* Applies this mutator to the given mutable argument.
*
* @param t the mutator argument
* @return the result
*/
R update(T t);
T update(T t);
}
@@ -148,7 +148,7 @@ final class OffHeapUpdatableChronicleMapBuilder<K, V>
return super.prepareValueBytesOnAcquire(prepareValueBytes);
}
public ChronicleMapBuilderI<K, V> valueMarshaller(@NotNull BytesMarshaller<V> valueMarshaller) {
public ChronicleMapBuilderI<K, V> valueMarshaller(@NotNull BytesMarshaller<? super V> valueMarshaller) {
throw new UnsupportedOperationException("not supported for this combination of key/value type");
}
@@ -210,7 +210,7 @@ final class OnHeapUpdatableChronicleMapBuilder<K, V>
* @see #objectSerializer(ObjectSerializer)
*/
public OnHeapUpdatableChronicleMapBuilder<K, V> valueMarshaller(
@NotNull BytesMarshaller<V> valueMarshaller) {
@NotNull BytesMarshaller<? super V> valueMarshaller) {
valueBuilder.marshaller(valueMarshaller);
return this;
}
@@ -21,8 +21,11 @@ package net.openhft.chronicle.map;
/**
* @author Rob Austin.
*/
public interface ReadContext<K,V> extends Context<K,V> {
public interface ReadContext<K, V> extends Context<K, V> {
/**
* @return true if the entry was present
*/
boolean present();
}
@@ -231,7 +231,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? supe
}
@Override
V put0(@NotNull K key, V value, boolean replaceIfPresent) {
V put1(@NotNull K key, V value, boolean replaceIfPresent) {
return put0(key, value, replaceIfPresent, localIdentifier, currentTime());
}
@@ -289,12 +289,12 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? supe
@Override
<KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>,
RV, VB extends RV, VBI, MVBI extends MetaBytesInterop<RV, ? super VBI>>
RV put(ThreadLocalCopies copies, SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
GetValueInterops<VB, VBI, MVBI> getValueInterops, VB value,
InstanceOrBytesToInstance<? super VB, V> toValue,
boolean replaceIfPresent, ReadValue<RV> readValue, boolean resultUnused) {
RV put2(ThreadLocalCopies copies, SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
GetValueInterops<VB, VBI, MVBI> getValueInterops, VB value,
InstanceOrBytesToInstance<? super VB, V> toValue,
boolean replaceIfPresent, ReadValue<RV> readValue, boolean resultUnused) {
return put(copies, segmentState, metaKeyInterop, keyInterop, key, keySize, toKey,
getValueInterops, value, toValue, replaceIfPresent, readValue, resultUnused,
localIdentifier, currentTime());
@@ -654,7 +654,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? supe
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
ReadValue<RV> readValue, RV usingValue, InstanceOrBytesToInstance<RV, V> toValue,
long hash2, boolean create) {
long hash2, boolean create, MutableLockedEntry lock) {
segmentStateNotNullImpliesCopiesNotNull(copies, segmentState);
SegmentState localSegmentState = segmentState;
try {
@@ -755,9 +755,18 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? supe
}
entry = localSegmentState.tmpBytes;
}
return createEntryOnAcquire(copies, localSegmentState,
RV result = createEntryOnAcquire(copies, localSegmentState,
metaKeyInterop, keyInterop, key, keySize, toKey,
readValue, usingValue, toValue, entry);
// notify the context that the entry was created
if (lock instanceof WriteLocked)
((WriteLocked) lock).created(false);
return result;
} finally {
if (segmentState == null && localSegmentState != null)
localSegmentState.close();
@@ -18,9 +18,6 @@
package net.openhft.chronicle.map;
import net.openhft.lang.model.*;
import net.openhft.lang.threadlocal.Provider;
import net.openhft.lang.threadlocal.ThreadLocalCopies;
import net.openhft.chronicle.hash.serialization.*;
import net.openhft.chronicle.hash.serialization.internal.*;
import net.openhft.lang.io.Bytes;
@@ -29,6 +26,12 @@ import net.openhft.lang.io.serialization.BytesMarshaller;
import net.openhft.lang.io.serialization.ObjectFactory;
import net.openhft.lang.io.serialization.ObjectSerializer;
import net.openhft.lang.io.serialization.impl.*;
import net.openhft.lang.model.Byteable;
import net.openhft.lang.model.DataValueGenerator;
import net.openhft.lang.model.DataValueModel;
import net.openhft.lang.model.DataValueModels;
import net.openhft.lang.threadlocal.Provider;
import net.openhft.lang.threadlocal.ThreadLocalCopies;
import net.openhft.lang.values.LongValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,11 +47,11 @@ import java.util.Arrays;
import java.util.List;
import static net.openhft.chronicle.hash.serialization.SizeMarshallers.constant;
import static net.openhft.chronicle.map.Objects.hash;
import static net.openhft.chronicle.hash.serialization.SizeMarshallers.stopBit;
import static net.openhft.chronicle.map.Objects.hash;
import static net.openhft.chronicle.map.SerializationBuilder.Role.KEY;
final class SerializationBuilder<E> implements Cloneable, Serializable{
final class SerializationBuilder<E> implements Cloneable, Serializable {
private static boolean concreteClass(Class c) {
return !c.isInterface() && !Modifier.isAbstract(c.getModifiers());
@@ -194,7 +197,7 @@ final class SerializationBuilder<E> implements Cloneable, Serializable{
.<E, BytesWriter<E>>forBytesWriter(role));
}
public SerializationBuilder<E> marshaller(BytesMarshaller<E> marshaller) {
public SerializationBuilder<E> marshaller(BytesMarshaller<? super E> marshaller) {
clearDefaults();
return copyingInterop(CopyingInterop.FROM_MARSHALLER)
.reader(BytesReaders.fromBytesMarshaller(marshaller))
@@ -68,8 +68,8 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
private volatile ByteBuffer outBuffer;
private volatile ByteBufferBytes outBytes;
private volatile ByteBuffer inBuffer;
private volatile ByteBufferBytes inBytes;
private ByteBuffer inBuffer;
private ByteBufferBytes inBytes;
@NotNull
private final ReaderWithSize<K> keyReaderWithSize;
@@ -490,7 +490,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
@Nullable
@Override
public <R> R updateForKey(@Nullable K key, @NotNull Mutator<? super V, R> mutator) {
public V putWith(@Nullable K key, @NotNull Mutator<V> mutator) {
if (key == null)
throw keyNotNullNPE();
return fetchObject(UPDATE_FOR_KEY, key, mutator);
@@ -1440,9 +1440,9 @@ class StatelessServerConnector<K, V> {
@Nullable
public Work updateForKey(@NotNull ByteBufferBytes reader, @NotNull Bytes writer, long sizeLocation) {
final K key = keyReaderWithSize.read(reader, null);
final Mutator<V, ?> mutator = (Mutator<V, ?>) reader.readObject();
final Mutator<V> mutator = (Mutator<V>) reader.readObject();
try {
Object result = map.updateForKey(key, mutator);
Object result = map.putWith(key, mutator);
writer.writeObject(result);
} catch (Throwable e) {
LOG.info("", e);
@@ -35,7 +35,7 @@ import net.openhft.chronicle.hash.serialization.internal.*;
import net.openhft.lang.collection.DirectBitSet;
import net.openhft.lang.collection.SingleThreadedDirectBitSet;
import net.openhft.lang.io.*;
import net.openhft.lang.io.serialization.JDKZObjectSerializer;
import net.openhft.lang.io.serialization.JDKObjectSerializer;
import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
import net.openhft.lang.threadlocal.Provider;
import net.openhft.lang.threadlocal.StatefulCopyable;
@@ -220,7 +220,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
final long createMappedStoreAndSegments(File file) throws IOException {
return createMappedStoreAndSegments(new MappedStore(file, FileChannel.MapMode.READ_WRITE,
sizeInBytes(), JDKZObjectSerializer.INSTANCE));
sizeInBytes(), JDKObjectSerializer.INSTANCE));
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
@@ -354,7 +354,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
void putBytes(ThreadLocalCopies copies, SegmentState segmentState, Bytes key, long keySize,
GetRemoteBytesValueInterops getRemoteBytesValueInterops, MultiStoreBytes value,
boolean replaceIfPresent, ReadValue<Bytes> readValue) {
put(copies, segmentState,
put2(copies, segmentState,
DelegatingMetaBytesInterop.<Bytes, BytesInterop<Bytes>>instance(),
BytesBytesInterop.INSTANCE, key, keySize, keyBytesToInstance,
getRemoteBytesValueInterops, value, valueBytesToInstance,
@@ -373,7 +373,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
getRemoteBytesValueInterops.valueSizeMarshaller(valueSizeMarshaller);
ReadValueToBytes readValueToLazyBytes = segmentState.readValueToLazyBytes;
readValueToLazyBytes.valueSizeMarshaller(valueSizeMarshaller);
put(copies, segmentState,
put2(copies, segmentState,
DelegatingMetaBytesInterop.<Bytes, BytesInterop<Bytes>>instance(),
BytesBytesInterop.INSTANCE, entry, keySize, keyBytesToInstance,
getRemoteBytesValueInterops, value, valueBytesToInstance,
@@ -453,15 +453,15 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
@Override
public final V put(K key, V value) {
return put0(key, value, true);
return put1(key, value, true);
}
@Override
public final V putIfAbsent(@net.openhft.lang.model.constraints.NotNull K key, V value) {
return put0(key, value, false);
return put1(key, value, false);
}
V put0(@net.openhft.lang.model.constraints.NotNull K key, V value, boolean replaceIfPresent) {
V put1(@net.openhft.lang.model.constraints.NotNull K key, V value, boolean replaceIfPresent) {
checkKey(key);
checkValue(value);
ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
@@ -470,22 +470,22 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
MKI metaKeyInterop =
metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyInterop, key);
long keySize = metaKeyInterop.size(keyInterop, key);
return put(copies, null, metaKeyInterop, keyInterop, key, keySize, keyIdentity(),
return put2(copies, null, metaKeyInterop, keyInterop, key, keySize, keyIdentity(),
this, value, valueIdentity(), replaceIfPresent, this, putReturnsNull);
}
<KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>,
RV, VB extends RV, VBI, MVBI extends MetaBytesInterop<RV, ? super VBI>>
RV put(ThreadLocalCopies copies, SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
GetValueInterops<VB, VBI, MVBI> getValueInterops, VB value,
InstanceOrBytesToInstance<? super VB, V> toValue,
boolean replaceIfPresent, ReadValue<RV> readValue, boolean resultUnused) {
RV put2(ThreadLocalCopies copies, SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
GetValueInterops<VB, VBI, MVBI> getValueInterops, VB value,
InstanceOrBytesToInstance<? super VB, V> toValue,
boolean replaceIfPresent, ReadValue<RV> readValue, boolean resultUnused) {
long hash = metaKeyInterop.hash(keyInterop, key);
int segmentNum = getSegment(hash);
long segmentHash = segmentHash(hash);
return segments[segmentNum].put(copies, segmentState,
return segments[segmentNum].put3(copies, segmentState,
metaKeyInterop, keyInterop, key, keySize, toKey,
getValueInterops, value, toValue,
segmentHash, replaceIfPresent, readValue, resultUnused);
@@ -521,7 +521,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
DelegatingMetaBytesInterop.<Bytes, BytesInterop<Bytes>>instance(),
BytesBytesInterop.INSTANCE, key, keySizeMarshaller.readSize(key),
keyBytesToInstance, readValueToOutputBytes, null, outputValueBytesToInstance,
false);
false, null);
}
private V lookupUsing(K key, V usingValue, boolean create) {
@@ -532,7 +532,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyInterop, key);
long keySize = metaKeyInterop.size(keyInterop, key);
return lookupUsing(copies, null, metaKeyInterop, keyInterop, key, keySize, keyIdentity(),
this, usingValue, valueIdentity(), create);
this, usingValue, valueIdentity(), create, null);
}
private <KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>, RV>
@@ -540,30 +540,52 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
ReadValue<RV> readValue, RV usingValue, InstanceOrBytesToInstance<RV, V> toValue,
boolean create) {
boolean create, final MutableLockedEntry lock) {
long hash = metaKeyInterop.hash(keyInterop, key);
int segmentNum = getSegment(hash);
long segmentHash = segmentHash(hash);
Segment segment = segments[segmentNum];
return segment.acquire(copies, segmentState,
metaKeyInterop, keyInterop, key, keySize, toKey,
readValue, usingValue, toValue, segmentHash, create);
readValue, usingValue, toValue, segmentHash, create, lock);
}
@Override
public <R> R mapForKey(K key, @NotNull Function<? super V, R> function) {
try (ReadContext<K, V> entry = lookupUsing(key, null,
LockType.READ_LOCK, false)) {
false, false, LockType.READ_LOCK)) {
return entry.present() ? function.apply(entry.value()) : null;
}
}
@Override
public <R> R updateForKey(K key, @NotNull Mutator<? super V, R> mutator) {
try (Context<K, V> entry = lookupUsing(key, null,
LockType.WRITE_LOCK, false)) {
return mutator.update(entry.value());
public V putWith(K key, @NotNull Mutator<V> mutator) {
final V using = (vClass.equals(CharSequence.class)) ? (V) new StringBuilder() : null;
try (WriteContext<K, V> entry = lookupUsing(key, using,
false, false, LockType.WRITE_LOCK)) {
if (CharSequence.class.isAssignableFrom(vClass)) {
CharSequence value = (CharSequence) entry.value();
if (entry.value() == null || value.length() == 0)
return null;
}
if (entry.value() == null)
return null;
V result = mutator.update(entry.value());
if (entry.value() instanceof StringBuilder) {
((StringBuilder) using).setLength(0);
((StringBuilder) using).append((CharSequence) result);
} else
((MutableLockedEntry) entry).value(result);
return result;
}
}
@Override
@@ -737,17 +759,17 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
@NotNull
@Override
public final WriteContext<K, V> acquireUsingLocked(@NotNull K key, @NotNull V usingValue) {
return lookupUsing(key, usingValue, LockType.WRITE_LOCK, true);
return lookupUsing(key, usingValue, true, true, LockType.WRITE_LOCK);
}
@NotNull
@Override
public final ReadContext<K, V> getUsingLocked(@NotNull K key, @NotNull V usingValue) {
return lookupUsing(key, usingValue, LockType.READ_LOCK, true);
return lookupUsing(key, usingValue, true, false, LockType.READ_LOCK);
}
private <T extends Context> T lookupUsing(
K key, V usingValue, LockType lockType, boolean mustReuseValue) {
K key, V usingValue, boolean mustReuseValue, final boolean create, final LockType lockType) {
checkKey(key);
ThreadLocalCopies copies = SegmentState.getCopies(null);
@@ -769,7 +791,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
V v = segment.acquireWithoutLock(copies, segmentState,
metaKeyInterop, keyInterop, key, keySize, keyIdentity(),
this, usingValue, valueIdentity(),
segmentHash, lockType == LockType.WRITE_LOCK);
segmentHash, create, lock);
checkReallyUsingValue(usingValue, mustReuseValue, v);
@@ -1592,15 +1614,15 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
<KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>, RV>
RV acquire(@Nullable ThreadLocalCopies copies, final @Nullable SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
ReadValue<RV> readValue, RV usingValue, InstanceOrBytesToInstance<RV, V> toValue,
long hash2, boolean create) {
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
ReadValue<RV> readValue, RV usingValue, InstanceOrBytesToInstance<RV, V> toValue,
long hash2, boolean create, MutableLockedEntry lock) {
readLock(null);
try {
return acquireWithoutLock(copies, segmentState,
metaKeyInterop, keyInterop, key, keySize, toKey,
readValue, usingValue, toValue, hash2, create);
readValue, usingValue, toValue, hash2, create, lock);
} finally {
if (segmentState != null)
segmentState.close();
@@ -1614,7 +1636,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
ReadValue<RV> readValue, RV usingValue, InstanceOrBytesToInstance<RV, V> toValue,
long hash2, boolean create) {
long hash2, boolean create, MutableLockedEntry lock) {
segmentStateNotNullImpliesCopiesNotNull(copies, segmentState);
SegmentState localSegmentState = segmentState;
try {
@@ -1648,9 +1670,16 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
}
entry = localSegmentState.tmpBytes;
}
return createEntryOnAcquire(copies, localSegmentState,
RV result = createEntryOnAcquire(copies, localSegmentState,
metaKeyInterop, keyInterop, key, keySize, toKey,
readValue, usingValue, toValue, entry);
// notify the context that the entry was created
if (lock instanceof WriteLocked)
((WriteLocked) lock).created(true);
return result;
} finally {
if (segmentState == null && localSegmentState != null)
localSegmentState.close();
@@ -1729,15 +1758,15 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
return v;
}
private <KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>,
<KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>,
RV, VB extends RV, VBI, MVBI extends MetaBytesInterop<RV, ? super VBI>>
RV put(@Nullable ThreadLocalCopies copies, final @Nullable SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
GetValueInterops<VB, VBI, MVBI> getValueInterops, VB value,
InstanceOrBytesToInstance<? super VB, V> toValue,
long hash2, boolean replaceIfPresent,
ReadValue<RV> readValue, boolean resultUnused) {
RV put3(@Nullable ThreadLocalCopies copies, final @Nullable SegmentState segmentState,
MKBI metaKeyInterop, KBI keyInterop, KB key, long keySize,
InstanceOrBytesToInstance<KB, K> toKey,
GetValueInterops<VB, VBI, MVBI> getValueInterops, VB value,
InstanceOrBytesToInstance<? super VB, V> toValue,
long hash2, boolean replaceIfPresent,
ReadValue<RV> readValue, boolean resultUnused) {
shouldNotBeCalledFromReplicatedChronicleMap("Segment.put");
writeLock(null);
try {
@@ -2587,7 +2616,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
}
}
private static abstract class MutableLockedEntry<
static abstract class MutableLockedEntry<
K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
V, VI, MVI extends MetaBytesInterop<V, ? super VI>> implements Context<K, V> {
final SegmentState segmentState;
@@ -2602,6 +2631,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
private K key;
private V value;
boolean present;
MutableLockedEntry(SegmentState segmentState) {
this.segmentState = segmentState;
@@ -2620,8 +2650,10 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
}
void value(V value) {
this.present = value != null;
this.value = value;
}
}
private static class ReadLocked<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
@@ -2629,40 +2661,46 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
extends MutableLockedEntry<K, KI, MKI, V, VI, MVI>
implements ReadContext<K, V> {
private boolean present;
ReadLocked(SegmentState segmentState) {
super(segmentState);
}
void value(V value) {
this.present = value != null;
super.value(value);
}
/**
* @return if the value is not null
*/
@Override
public boolean present() {
return present;
}
@Override
public void close() {
segmentState.close();
segment.readUnlock();
}
/**
* @return if the value is not null
*/
public boolean present() {
return present;
}
}
private static abstract class WriteLocked<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
static abstract class WriteLocked<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
V, VI, MVI extends MetaBytesInterop<V, ? super VI>>
extends MutableLockedEntry<K, KI, MKI, V, VI, MVI>
implements WriteContext<K, V> {
private boolean created = false;
WriteLocked(SegmentState segmentState) {
super(segmentState);
}
/**
* @return if the entry was created
*/
public boolean created() {
return created;
}
public void created(boolean created) {
this.created = created;
}
}
private static class NativeWriteLocked<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
@@ -2673,6 +2711,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
super(segmentState);
}
@Override
public void close() {
segmentState.close();
@@ -2715,6 +2754,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
segment.writeUnlock();
}
@Override
public void dontPutOnClose() {
putOnClose = false;
@@ -30,9 +30,14 @@ public interface WriteContext<K, V> extends Context<K, V> {
void dontPutOnClose();
/**
* this is simular by more efficient than calling map.remove("key") as the entry is already available to
* the WriteContext
* this is similar by more efficient than calling map.remove("key") as the entry is already
* available to the WriteContext
*/
void removeEntry();
/**
* @return true if the entry was previously present
*/
boolean created();
}
+1 -1
View File
@@ -24,7 +24,7 @@ public class BGChronicleTest {
public static final int READ_RATIO = Integer.getInteger("readRatio", 2);
// public static final boolean BUSY_WAIT = Boolean.parseBoolean(System.getProperty("busyWait",
// "" + (CLIENTS < Runtime.getRuntime().availableProcessors())));
public static final int REPLICAS = Integer.getInteger("replicas", 2);
public static final int REPLICAS = Integer.getInteger("replicas", 1);
public static final int CLIENTS = Integer.getInteger("clients", Math.max(1, Runtime.getRuntime().availableProcessors() - REPLICAS));
public static final long KEYS = Long.getLong("keys", 1000_000L);
public static final long MESSAGES = Long.getLong("messages", 1000_000 + KEYS * 2);
@@ -1,7 +1,6 @@
package net.openhft.chronicle.map;
import net.openhft.lang.io.serialization.impl.*;
import net.openhft.lang.model.DataValueClasses;
import net.openhft.lang.values.*;
import org.junit.Ignore;
import org.junit.Test;
@@ -17,14 +16,13 @@ import static org.junit.Assert.*;
*/
// TODO Test for persisted map.
// TODO Test for stateless map.
@Ignore
public class CHMUseCasesTest {
/**
* String is not as efficient as CharSequence as a key or value but easier to use The key can
* only be on heap and variable length serialised.
*/
@Test
@Ignore("Not yet implemented")
public void testStringStringMap() throws ExecutionException, InterruptedException {
/* TODO run the same test for multiple types of map stores
for(ChronicleMapBuilder<String, String> chmb : Arrays.asList(
@@ -53,17 +51,36 @@ public class CHMUseCasesTest {
return "New " + s;
}
}));
try {
map.updateForKey("Hello", new Mutator<String, String>() {
@Override
public String update(String s) {
return "New " + s;
}
});
fail("Operation not supported as value is not mutable");
} catch (Exception ignored) {
// TODO replace with the specific exception.
}
}
}
@Test
public void testStringStringMapMutableValue() throws ExecutionException, InterruptedException {
/* TODO run the same test for multiple types of map stores
for(ChronicleMapBuilder<String, String> chmb : Arrays.asList(
ChronicleMapBuilder.of(String.class, String.class),
ChronicleMapBuilder.of(String.class, String.class).file(TMP_FILE),
ChronicleMapBuilder.of(String.class, String.class).statelessClient(CONFIG)
)) {
try (ChronicleMap<String, String> map = chmb.create()) {
*/
try (ChronicleMap<String, String> map = ChronicleMapBuilder
.of(String.class, String.class)
.checkSerializedValues() // for testing purposes only
.create()) {
map.put("Hello", "World");
map.putWith("Hello", new Mutator<String>() {
@Override
public String update(String s) {
return "New " + s;
}
});
}
}
@@ -73,7 +90,6 @@ public class CHMUseCasesTest {
* and variable length serialised.
*/
@Test
@Ignore("Not yet implemented")
public void testCharSequenceCharSequenceMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<CharSequence, CharSequence> map = ChronicleMapBuilder
.of(CharSequence.class, CharSequence.class)
@@ -92,38 +108,42 @@ public class CHMUseCasesTest {
assertEquals("value-1", value.toString());
map.remove("key-1");
assertNull(map.getUsing(key, value));
map.close();
assertEquals("New World", map.mapForKey("Hello", new Function<CharSequence, CharSequence>() {
@Override
public CharSequence apply(CharSequence s) {
return "New " + s;
}
}));
assertEquals(null, map.mapForKey("No key", new Function<CharSequence, CharSequence>() {
@Override
public CharSequence apply(CharSequence s) {
return "New " + s;
}
}));
assertEquals("New World !!", map.updateForKey("Hello", new Mutator<CharSequence, CharSequence>() {
@Override
public CharSequence update(CharSequence s) {
((StringBuilder) s).append("!!");
return "New " + s;
}
}));
assertEquals("New World", map.mapForKey(new StringBuilder("Hello"), new
Function<CharSequence, CharSequence>() {
@Override
public CharSequence apply(CharSequence s) {
return "New " + s;
}
}));
assertEquals(null, map.mapForKey(new StringBuilder("No key"), new
Function<CharSequence, CharSequence>() {
@Override
public CharSequence apply(CharSequence s) {
return "New " + s;
}
}));
assertEquals("New World !!", map.putWith(new StringBuilder("Hello"), new
Mutator<CharSequence>() {
@Override
public CharSequence update(CharSequence s) {
((StringBuilder) s).append(" !!");
return "New " + s;
}
}));
assertEquals("New World !!", map.get("Hello").toString());
assertEquals(null, map.updateForKey("no-key", new Mutator<CharSequence, CharSequence>() {
@Override
public CharSequence update(CharSequence s) {
((StringBuilder) s).append("!!");
return "New " + s;
}
}));
assertEquals(null, map.putWith(new StringBuilder("no-key"), new
Mutator<CharSequence>() {
@Override
public CharSequence update(CharSequence s) {
((StringBuilder) s).append("!!");
return "New " + s;
}
}));
}
}
@@ -132,16 +152,15 @@ public class CHMUseCasesTest {
* StringValue represents any bean which contains a String Value
*/
@Test
@Ignore("Not yet implemented")
public void testStringValueStringValueMap() {
try (ChronicleMap<StringValue, StringValue> map = ChronicleMapBuilder
.of(StringValue.class, StringValue.class)
.checkSerializedValues() // for testing purposes only
.create()) {
StringValue key1 = DataValueClasses.newDirectInstance(StringValue.class);
StringValue key2 = DataValueClasses.newInstance(StringValue.class);
StringValue value1 = DataValueClasses.newDirectInstance(StringValue.class);
StringValue value2 = DataValueClasses.newInstance(StringValue.class);
StringValue key1 = ChronicleMapBuilder.newInstance(StringValue.class, true);
StringValue key2 = ChronicleMapBuilder.newInstance(StringValue.class, true);
StringValue value1 = ChronicleMapBuilder.newInstance(StringValue.class, false);
StringValue value2 = ChronicleMapBuilder.newInstance(StringValue.class, false);
key1.setValue(new StringBuilder("1"));
value1.setValue("11");
@@ -224,7 +243,6 @@ public class CHMUseCasesTest {
}
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntegerIntegerMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<Integer, Integer> map = ChronicleMapBuilder
.of(Integer.class, Integer.class)
@@ -265,13 +283,12 @@ public class CHMUseCasesTest {
}));
try {
map.updateForKey(1, new Mutator<Integer, Integer>() {
map.putWith(1, new Mutator<Integer>() {
@Override
public Integer update(Integer s) {
return s + 1;
}
});
fail("Update of Integer not supported");
} catch (Exception todoMoreSpecificException) {
}
@@ -280,7 +297,6 @@ public class CHMUseCasesTest {
}
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testLongLongMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<Long, Long> map = ChronicleMapBuilder
.of(Long.class, Long.class)
@@ -310,13 +326,12 @@ public class CHMUseCasesTest {
}));
try {
map.updateForKey(1L, new Mutator<Long, Long>() {
map.putWith(1L, new Mutator<Long>() {
@Override
public Long update(Long s) {
return s + 1;
}
});
fail("Update of Long not supported");
} catch (Exception todoMoreSpecificException) {
}
@@ -325,7 +340,6 @@ public class CHMUseCasesTest {
}
@Test
@Ignore("Not yet implemented")
public void testDoubleDoubleMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<Double, Double> map = ChronicleMapBuilder
.of(Double.class, Double.class)
@@ -355,13 +369,13 @@ public class CHMUseCasesTest {
}));
try {
map.updateForKey(1.0, new Mutator<Double, Double>() {
map.putWith(1.0, new Mutator<Double>() {
@Override
public Double update(Double s) {
return s + 1;
}
});
fail("Update of Double not supported");
} catch (Exception todoMoreSpecificException) {
}
@@ -370,7 +384,6 @@ public class CHMUseCasesTest {
}
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testByteArrayByteArrayMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<byte[], byte[]> map = ChronicleMapBuilder
.of(byte[].class, byte[].class)
@@ -383,9 +396,12 @@ public class CHMUseCasesTest {
byte[] value2 = {22, 22, 22, 22};
assertNull(map.put(key1, value1));
assertTrue(Arrays.equals(value1, map.put(key1, value2)));
assertTrue(Arrays.equals(value1, map.get(key1)));
assertTrue(Arrays.equals(value2, map.get(key1)));
assertNull(map.get(key2));
map.put(key1, value1);
assertTrue(Arrays.equals(new byte[]{11, 11}, map.mapForKey(key1, new Function<byte[], byte[]>() {
@Override
public byte[] apply(byte[] s) {
@@ -399,7 +415,7 @@ public class CHMUseCasesTest {
}
}));
assertTrue(Arrays.equals(new byte[]{12, 10}, map.updateForKey(key1, new Mutator<byte[], byte[]>() {
assertTrue(Arrays.equals(new byte[]{12, 10}, map.putWith(key1, new Mutator<byte[]>() {
@Override
public byte[] update(byte[] s) {
s[0]++;
@@ -408,16 +424,15 @@ public class CHMUseCasesTest {
}
})));
assertTrue(Arrays.equals(new byte[]{12, 10, 11, 11}, map.get(key1)));
byte[] a2 = map.get(key1);
assertTrue(Arrays.equals(new byte[]{12, 10}, a2));
byte[] key3 = {3, 3, 3, 3};
byte[] value3 = {4, 4, 4, 4};
}
}
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
@Ignore("Not enough available space")
public void testByteBufferByteBufferMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<ByteBuffer, ByteBuffer> map = ChronicleMapBuilder
.of(ByteBuffer.class, ByteBuffer.class)
@@ -446,7 +461,7 @@ public class CHMUseCasesTest {
assertBBEquals(ByteBuffer.wrap(new byte[]{11, 11}), map.mapForKey(key1, function));
assertEquals(null, map.mapForKey(key2, function));
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.updateForKey(key1, new Mutator<ByteBuffer, ByteBuffer>() {
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.putWith(key1, new Mutator<ByteBuffer>() {
@Override
public ByteBuffer update(ByteBuffer s) {
s.put(0, (byte) (s.get(0) + 1));
@@ -510,7 +525,7 @@ public class CHMUseCasesTest {
}
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
@Ignore("Not enough available space")
public void testByteBufferDirectByteBufferMap() throws ExecutionException, InterruptedException {
try (ChronicleMap<ByteBuffer, ByteBuffer> map = ChronicleMapBuilder
.of(ByteBuffer.class, ByteBuffer.class)
@@ -541,7 +556,7 @@ public class CHMUseCasesTest {
assertBBEquals(ByteBuffer.wrap(new byte[]{11, 11}), map.mapForKey(key1, function));
assertEquals(null, map.mapForKey(key2, function));
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.updateForKey(key1, new Mutator<ByteBuffer, ByteBuffer>() {
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.putWith(key1, new Mutator<ByteBuffer>() {
@Override
public ByteBuffer update(ByteBuffer s) {
s.put(0, (byte) (s.get(0) + 1));
@@ -562,17 +577,16 @@ public class CHMUseCasesTest {
}
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntValueIntValueMap() {
try (ChronicleMap<IntValue, IntValue> map = ChronicleMapBuilder
.of(IntValue.class, IntValue.class)
.disableOversizedEntries(true) // disabled for testing purposes only.
.entrySize(8)
.create()) {
IntValue key1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue key2 = DataValueClasses.newInstance(IntValue.class);
IntValue value1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue value2 = DataValueClasses.newInstance(IntValue.class);
IntValue key1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue key2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue value1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue value2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
key1.setValue(1);
value1.setValue(11);
@@ -645,17 +659,16 @@ public class CHMUseCasesTest {
* For unsigned int -> unsigned int entries, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testUnsignedIntValueUnsignedIntValueMap() {
try (ChronicleMap<UnsignedIntValue, UnsignedIntValue> map = ChronicleMapBuilder
.of(UnsignedIntValue.class, UnsignedIntValue.class)
.disableOversizedEntries(true) // disabled for testing purposes only.
.entrySize(8)
.create()) {
UnsignedIntValue key1 = DataValueClasses.newDirectInstance(UnsignedIntValue.class);
UnsignedIntValue key2 = DataValueClasses.newInstance(UnsignedIntValue.class);
UnsignedIntValue value1 = DataValueClasses.newDirectInstance(UnsignedIntValue.class);
UnsignedIntValue value2 = DataValueClasses.newInstance(UnsignedIntValue.class);
UnsignedIntValue key1 = ChronicleMapBuilder.newInstance(UnsignedIntValue.class, true);
UnsignedIntValue key2 = ChronicleMapBuilder.newInstance(UnsignedIntValue.class, true);
UnsignedIntValue value1 = ChronicleMapBuilder.newInstance(UnsignedIntValue.class, false);
UnsignedIntValue value2 = ChronicleMapBuilder.newInstance(UnsignedIntValue.class, false);
key1.setValue(1);
value1.setValue(11);
@@ -728,17 +741,16 @@ public class CHMUseCasesTest {
* For int values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntValueShortValueMap() {
try (ChronicleMap<IntValue, ShortValue> map = ChronicleMapBuilder
.of(IntValue.class, ShortValue.class)
.disableOversizedEntries(true) // disabled for testing purposes only.
.entrySize(6)
.create()) {
IntValue key1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue key2 = DataValueClasses.newInstance(IntValue.class);
ShortValue value1 = DataValueClasses.newDirectInstance(ShortValue.class);
ShortValue value2 = DataValueClasses.newInstance(ShortValue.class);
IntValue key1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue key2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
ShortValue value1 = ChronicleMapBuilder.newInstance(ShortValue.class, false);
ShortValue value2 = ChronicleMapBuilder.newInstance(ShortValue.class, false);
key1.setValue(1);
value1.setValue((short) 11);
@@ -811,17 +823,18 @@ public class CHMUseCasesTest {
* For int -> unsigned short values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntValueUnsignedShortValueMap() {
try (ChronicleMap<IntValue, UnsignedShortValue> map = ChronicleMapBuilder
.of(IntValue.class, UnsignedShortValue.class)
.entrySize(6)
.disableOversizedEntries(true) // disabled for testing purposes only.
.create()) {
IntValue key1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue key2 = DataValueClasses.newInstance(IntValue.class);
UnsignedShortValue value1 = DataValueClasses.newDirectInstance(UnsignedShortValue.class);
UnsignedShortValue value2 = DataValueClasses.newInstance(UnsignedShortValue.class);
IntValue key1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue key2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
UnsignedShortValue value1 = ChronicleMapBuilder.newInstance(UnsignedShortValue.class, false);
UnsignedShortValue value2 = ChronicleMapBuilder.newInstance(UnsignedShortValue.class, false);
//key direct instance, rather direct ref
key1.setValue(1);
value1.setValue(11);
@@ -894,17 +907,16 @@ public class CHMUseCasesTest {
* For int values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntValueCharValueMap() {
try (ChronicleMap<IntValue, CharValue> map = ChronicleMapBuilder
.of(IntValue.class, CharValue.class)
.disableOversizedEntries(true) // disabled for testing purposes only.
.entrySize(6)
.create()) {
IntValue key1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue key2 = DataValueClasses.newInstance(IntValue.class);
CharValue value1 = DataValueClasses.newDirectInstance(CharValue.class);
CharValue value2 = DataValueClasses.newInstance(CharValue.class);
IntValue key1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue key2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
CharValue value1 = ChronicleMapBuilder.newInstance(CharValue.class, false);
CharValue value2 = ChronicleMapBuilder.newInstance(CharValue.class, false);
key1.setValue(1);
value1.setValue((char) 11);
@@ -977,17 +989,16 @@ public class CHMUseCasesTest {
* For int-> byte entries, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntValueUnsignedByteMap() {
try (ChronicleMap<IntValue, UnsignedByteValue> map = ChronicleMapBuilder
.of(IntValue.class, UnsignedByteValue.class)
.entrySize(5)
.disableOversizedEntries(true) // disabled for testing purposes only.
.create()) {
IntValue key1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue key2 = DataValueClasses.newInstance(IntValue.class);
UnsignedByteValue value1 = DataValueClasses.newDirectInstance(UnsignedByteValue.class);
UnsignedByteValue value2 = DataValueClasses.newInstance(UnsignedByteValue.class);
IntValue key1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue key2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
UnsignedByteValue value1 = ChronicleMapBuilder.newInstance(UnsignedByteValue.class, false);
UnsignedByteValue value2 = ChronicleMapBuilder.newInstance(UnsignedByteValue.class, false);
key1.setValue(1);
value1.setValue(11);
@@ -1060,17 +1071,16 @@ public class CHMUseCasesTest {
* For int values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testIntValueBooleanValueMap() {
try (ChronicleMap<IntValue, BooleanValue> map = ChronicleMapBuilder
.of(IntValue.class, BooleanValue.class)
.disableOversizedEntries(true) // disabled for testing purposes only.
.entrySize(5)
.create()) {
IntValue key1 = DataValueClasses.newDirectInstance(IntValue.class);
IntValue key2 = DataValueClasses.newInstance(IntValue.class);
BooleanValue value1 = DataValueClasses.newDirectInstance(BooleanValue.class);
BooleanValue value2 = DataValueClasses.newInstance(BooleanValue.class);
IntValue key1 = ChronicleMapBuilder.newInstance(IntValue.class, false);
IntValue key2 = ChronicleMapBuilder.newInstance(IntValue.class, false);
BooleanValue value1 = ChronicleMapBuilder.newInstance(BooleanValue.class, false);
BooleanValue value2 = ChronicleMapBuilder.newInstance(BooleanValue.class, false);
key1.setValue(1);
value1.setValue(true);
@@ -1143,17 +1153,16 @@ public class CHMUseCasesTest {
* For float values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testFloatValueFloatValueMap() {
try (ChronicleMap<FloatValue, FloatValue> map = ChronicleMapBuilder
.of(FloatValue.class, FloatValue.class)
.entrySize(8)
.disableOversizedEntries(true) // disabled for testing purposes only.
.create()) {
FloatValue key1 = DataValueClasses.newDirectInstance(FloatValue.class);
FloatValue key2 = DataValueClasses.newInstance(FloatValue.class);
FloatValue value1 = DataValueClasses.newDirectInstance(FloatValue.class);
FloatValue value2 = DataValueClasses.newInstance(FloatValue.class);
FloatValue key1 = ChronicleMapBuilder.newInstance(FloatValue.class, false);
FloatValue key2 = ChronicleMapBuilder.newInstance(FloatValue.class, false);
FloatValue value1 = ChronicleMapBuilder.newInstance(FloatValue.class, false);
FloatValue value2 = ChronicleMapBuilder.newInstance(FloatValue.class, false);
key1.setValue(1);
value1.setValue(11);
@@ -1226,17 +1235,16 @@ public class CHMUseCasesTest {
* For double values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-225 Add support for heap and native object in the same map")
public void testDoubleValueDoubleValueMap() {
try (ChronicleMap<DoubleValue, DoubleValue> map = ChronicleMapBuilder
.of(DoubleValue.class, DoubleValue.class)
.entrySize(16)
.create()) {
DoubleValue key1 = DataValueClasses.newDirectInstance(DoubleValue.class);
DoubleValue key2 = DataValueClasses.newInstance(DoubleValue.class);
DoubleValue value1 = DataValueClasses.newDirectInstance(DoubleValue.class);
DoubleValue value2 = DataValueClasses.newInstance(DoubleValue.class);
DoubleValue key1 = ChronicleMapBuilder.newInstance(DoubleValue.class, false);
DoubleValue key2 = ChronicleMapBuilder.newInstance(DoubleValue.class, false);
DoubleValue value1 = ChronicleMapBuilder.newInstance(DoubleValue.class, false);
DoubleValue value2 = ChronicleMapBuilder.newInstance(DoubleValue.class, false);
key1.setValue(1);
@@ -1312,21 +1320,22 @@ public class CHMUseCasesTest {
* For long values, the key can be on heap or off heap.
*/
@Test
@Ignore("HCOLL-226 implement disableOversizedEntries()")
public void testLongValueLongValueMap() {
try (ChronicleMap<LongValue, LongValue> map = ChronicleMapBuilder
.of(LongValue.class, LongValue.class)
.entrySize(16)
.disableOversizedEntries(true) // disabled for testing purposes only.
.create()) {
LongValue key1 = DataValueClasses.newDirectInstance(LongValue.class);
LongValue key2 = DataValueClasses.newInstance(LongValue.class);
LongValue value1 = DataValueClasses.newDirectInstance(LongValue.class);
LongValue value2 = DataValueClasses.newInstance(LongValue.class);
LongValue key1 = ChronicleMapBuilder.newInstance(LongValue.class, false);
LongValue key2 = ChronicleMapBuilder.newInstance(LongValue.class, false);
LongValue value1 = ChronicleMapBuilder.newInstance(LongValue.class, false);
LongValue value2 = ChronicleMapBuilder.newInstance(LongValue.class, false);
key1.setValue(1);
value1.setValue(11);
assertEquals(value1, map.get(key1));
assertEquals(null, map.get(key1));
map.put(key1, value1);
key2.setValue(2);
value2.setValue(22);
@@ -1408,25 +1417,35 @@ public class CHMUseCasesTest {
List<String> list1 = new ArrayList<>();
try (WriteContext wc = map.acquireUsingLocked("1", list1)) {
assertEquals(Collections.EMPTY_LIST, list1);
list1.add("one");
assertEquals(Arrays.asList("one"), list1);
}
List<String> list2 = new ArrayList<>();
try (ReadContext rc = map.getUsingLocked("1", list2)) {
assertTrue(rc.present());
assertEquals(Arrays.asList("one"), list2);
}
try (ReadContext rc = map.getUsingLocked("2", list2)) {
assertTrue(rc.present());
list2.add("two-B"); // this is not written as it only a read context
assertEquals(Arrays.asList("two-A", "two-B"), list2);
}
try (WriteContext wc = map.acquireUsingLocked("2", list1)) {
list1.add("two-C");
assertEquals(Arrays.asList("two-A", "two-C"), list1);
}
try (ReadContext rc = map.getUsingLocked("2", list2)) {
assertTrue(rc.present());
assertEquals(Arrays.asList("two-A"), list2);
assertEquals(Arrays.asList("two-A", "two-C"), list2);
}
}
}
@Test
@Ignore("Fix LinkedHashSet Marshaller")
public void testSetValue() {
try (ChronicleMap<String, Set<String>> map = ChronicleMapBuilder
.of(String.class, (Class<Set<String>>) (Class) Set.class)
@@ -1447,7 +1466,7 @@ public class CHMUseCasesTest {
}
try (WriteContext wc = map.acquireUsingLocked("2", list1)) {
list1.add("three");
assertEquals(new LinkedHashSet<String>(Arrays.asList("three")), list1);
assertEquals(new LinkedHashSet<String>(Arrays.asList("one", "three")), list1);
}
try (ReadContext rc = map.getUsingLocked("2", list2)) {
assertTrue(rc.present());
@@ -0,0 +1,147 @@
/*
* 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.lang.io.DirectBytes;
import net.openhft.lang.io.DirectStore;
import net.openhft.lang.io.serialization.impl.SnappyStringMarshaller;
import org.junit.Ignore;
import org.junit.Test;
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Created by peter on 06/12/14.
*/
public class LargeEntriesTest {
static final int ENTRIES = 640;
static final int ENTRY_SIZE = 1024;
@Test
@Ignore
public void testLargeStrings() throws ExecutionException, InterruptedException {
final ChronicleMap<String, String> map = ChronicleMapBuilder
.of(String.class, String.class)
.valueMarshaller(SnappyStringMarshaller.INSTANCE)
.actualSegments(1) // to force an error.
.entries(ENTRIES * 2)
.entrySize(ENTRY_SIZE / 4)
.putReturnsNull(true)
.create();
{
int threads = 2; //Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(threads);
final int block = ENTRIES / threads;
for (int i = 0; i < 3; i++) {
long start = System.currentTimeMillis();
List<Future<?>> futureList = new ArrayList<>();
for (int t = 0; t < threads; t++) {
final int finalT = t;
final int finalI = i;
futureList.add(es.submit(new Runnable() {
@Override
public void run() {
exerciseLargeStrings(map, finalI, finalT * block, finalT * block + block, ENTRY_SIZE);
}
}));
}
for (Future<?> future : futureList) {
future.get();
}
long time = System.currentTimeMillis() - start;
long operations = 3;
System.out.printf("Put/Get rate was %.1f MB/s%n", operations * ENTRIES * ENTRY_SIZE / 1e6 / (time / 1e3));
}
es.shutdown();
if (es.isTerminated())
map.close();
}
}
void exerciseLargeStrings(ChronicleMap<String, String> map, int run, int start, int finish, int entrySize) {
/*
final Thread thisThread = Thread.currentThread();
Thread monitor = new Thread(new Runnable() {
@Override
public void run() {
StringBuilder sb = new StringBuilder();
sb.append(thisThread).append("\n");
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(50);
StackTraceElement[] stackTrace = thisThread.getStackTrace();
for (int i = 0; i < 4 && i < stackTrace.length; i++)
sb.append("\tat ").append(stackTrace[i]).append("\n");
sb.append("\n");
}
} catch (InterruptedException e) {
}
System.out.println(sb);
}
});
monitor.start();
*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLEncoder xml = new XMLEncoder(baos);
Map<String, String> map2 = new HashMap<>();
Random rand = new Random(1);
for (int i = 0; i < entrySize / 80; i++)
map2.put("key-" + i, "value-" + rand.nextInt(1000));
xml.writeObject(map2);
xml.close();
String value = baos.toString().substring(0, entrySize);
// warmup to compression.
if (run == 0) {
DirectBytes bytes = DirectStore.allocate(entrySize).bytes();
SnappyStringMarshaller.INSTANCE.write(bytes, value);
bytes.flip();
SnappyStringMarshaller.INSTANCE.read(bytes);
bytes.release();
}
for (int i = start; i < finish; i++) {
String key = "key-" + i;
map.put(key, value);
String object = map.get(key);
assertNotNull(key, object);
assertEquals(key, entrySize, object.length());
}
// monitor.interrupt();
for (int i = start; i < finish; i++) {
// System.out.println(i);
String key = "key-" + i;
String object = map.get(key);
assertNotNull(key, object);
assertEquals(key, entrySize, object.length());
}
}
}
@@ -18,7 +18,7 @@
package net.openhft.chronicle.map;
import net.openhft.lang.io.serialization.JDKZObjectSerializer;
import net.openhft.lang.io.serialization.JDKObjectSerializer;
import org.junit.Test;
import java.io.*;
@@ -35,7 +35,7 @@ public class RecursiveRefereneChMapTest {
file.deleteOnExit();
Map<String, StupidCycle> map = ChronicleMapBuilder.of(String.class, StupidCycle.class)
.entries(64)
.objectSerializer(JDKZObjectSerializer.INSTANCE).create();
.objectSerializer(JDKObjectSerializer.INSTANCE).create();
map.put("Test", new StupidCycle());
map.put("Test2", new StupidCycle2());
StupidCycle cycle = (StupidCycle) map.get("Test");
@@ -223,8 +223,8 @@ public class ReplicationCheckingMap<K, V> implements ChronicleMap<K, V> {
}
@Override
public <R> R updateForKey(K key, @NotNull Mutator<? super V, R> mutator) {
return map1.updateForKey(key, mutator);
public V putWith(K key, @NotNull Mutator<V> mutator) {
return map1.putWith(key, mutator);
}
@Override
@@ -175,8 +175,8 @@ public class StatelessChronicleMapTest extends JSR166TestCase {
}
@Override
public <R> R updateForKey(K key, @NotNull Mutator<? super V, R> mutator) {
return d.updateForKey(key, mutator);
public V putWith(K key, @NotNull Mutator<V> mutator) {
return d.putWith(key, mutator);
}
@Override