mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -168,7 +168,7 @@ and define the snapshot version in your pom.xml, for example:
|
||||
<dependency>
|
||||
<groupId>net.openhft</groupId>
|
||||
<artifactId>chronicle-map</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<version><!--replace with the latest version--></version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -599,6 +599,9 @@ entries are no where near the max entry size.
|
||||
|
||||
## Serialization
|
||||
|
||||

|
||||
|
||||
|
||||
Chronicle Map stores your data into off heap memory, so when you give it a Key or Value, it will
|
||||
serialise these objects into bytes.
|
||||
|
||||
@@ -1117,6 +1120,9 @@ click [here](https://github.com/OpenHFT/Chronicle-Map#sharing-data-between-two-o
|
||||
|
||||
### How to speed up the Chronicle Map Stateless Client
|
||||
|
||||

|
||||

|
||||
|
||||
By default when you make a method call to a `ChronicleMap` stateless client,
|
||||
your method call is wrapped into an event which is sent over tcp and processed by the server,
|
||||
your stateless client will block until an acknowledgement has been received from the server that
|
||||
|
||||
@@ -17,20 +17,18 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>net.openhft</groupId>
|
||||
<artifactId>java-parent-pom</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<relativePath/>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>chronicle-map</artifactId>
|
||||
<version>2.0.12b-SNAPSHOT</version>
|
||||
<version>2.0.14b-SNAPSHOT</version>
|
||||
<name>OpenHFT/Chronicle-Map</name>
|
||||
<description>Chronicle-Map</description>
|
||||
|
||||
@@ -48,7 +46,7 @@
|
||||
<dependency>
|
||||
<groupId>net.openhft</groupId>
|
||||
<artifactId>lang</artifactId>
|
||||
<version>6.4.16-SNAPSHOT</version>
|
||||
<version>6.4.17-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public final class TcpTransportAndNetworkConfig implements Serializable {
|
||||
return new TcpTransportAndNetworkConfig(
|
||||
serverPort, unmodifiableSet(s),
|
||||
DEFAULT_PACKET_SIZE,
|
||||
false, // autoReconnectedUponDroppedConnection
|
||||
true, // autoReconnectedUponDroppedConnection
|
||||
ThrottlingConfig.noThrottling(),
|
||||
DEFAULT_HEART_BEAT_INTERVAL,
|
||||
DEFAULT_HEART_BEAT_INTERVAL_UNIT);
|
||||
|
||||
@@ -143,6 +143,7 @@ abstract class AbstractChronicleMapBuilder<K, V,
|
||||
private SingleChronicleHashReplication singleHashReplication = null;
|
||||
private InetSocketAddress[] pushToAddresses;
|
||||
public boolean bootstrapOnlyLocalEntries = false;
|
||||
private boolean disableOversizedEntries = false;
|
||||
|
||||
AbstractChronicleMapBuilder(Class<K> keyClass, Class<V> valueClass) {
|
||||
keyBuilder = new SerializationBuilder<K>(keyClass, SerializationBuilder.Role.KEY);
|
||||
@@ -933,7 +934,7 @@ abstract class AbstractChronicleMapBuilder<K, V,
|
||||
keyBuilder.objectSerializer(acquireObjectSerializer(JDKObjectSerializer.INSTANCE));
|
||||
valueBuilder.objectSerializer(acquireObjectSerializer(JDKObjectSerializer.INSTANCE));
|
||||
|
||||
long maxSize = (long) entrySize(replicated) * figureBufferAllocationFactor();
|
||||
long maxSize = (long) entrySize(replicated) * Math.min(maxEntryOversizeFactor(), figureBufferAllocationFactor());
|
||||
keyBuilder.maxSize(maxSize);
|
||||
valueBuilder.maxSize(maxSize);
|
||||
|
||||
@@ -984,8 +985,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(4L, entries() >> 10),
|
||||
VanillaChronicleMap.MAX_ENTRY_OVERSIZE_FACTOR);
|
||||
return (int) Math.max(4L, entries() >> 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1003,5 +1003,15 @@ abstract class AbstractChronicleMapBuilder<K, V,
|
||||
public String name() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleMapBuilderI<K, V> disableOversizedEntries() {
|
||||
this.disableOversizedEntries = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int maxEntryOversizeFactor() {
|
||||
return disableOversizedEntries ? 1 : VanillaChronicleMap.MAX_ENTRY_OVERSIZE_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -197,17 +197,17 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
|
||||
* @param <R> return type.
|
||||
* @return the result of the function, or null if there is no entry for the key.
|
||||
*/
|
||||
<R> R mapForKey(K key, @NotNull Function<? super V, R> function);
|
||||
<R> R getMapped(K key, @NotNull Function<? super V, R> function);
|
||||
|
||||
/**
|
||||
* Apply a mutator to the value for a key and return a result. A write lock is assumed. <p> If
|
||||
* Apply a unaryOperator to the value for a key and return a result. A write lock is assumed. <p> If
|
||||
* 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 unaryOperator to alter the value and calculate a result
|
||||
* @return the result of the function.
|
||||
*/
|
||||
V putWith(K key, @NotNull Mutator<V> mutator);
|
||||
V putMapped(K key, @NotNull UnaryOperator<V> unaryOperator);
|
||||
|
||||
/**
|
||||
* exports all the entries to a {@link java.io.File} storing them in JSON format, an attempt is
|
||||
@@ -247,5 +247,14 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
|
||||
*/
|
||||
void putAll(File fromFile) throws IOException;
|
||||
|
||||
/**
|
||||
* @return a new empty instance based on the Value type
|
||||
*/
|
||||
V newValueInstance();
|
||||
|
||||
/**
|
||||
* @return a new empty instance based on the Key type
|
||||
*/
|
||||
K newKeyInstance();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,26 +69,8 @@ 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();
|
||||
}
|
||||
@@ -97,7 +79,7 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
private static boolean offHeapReference(Class valueClass) {
|
||||
static boolean offHeapReference(Class valueClass) {
|
||||
return Byteable.class.isAssignableFrom(valueClass);
|
||||
}
|
||||
|
||||
@@ -540,14 +522,8 @@ public final class ChronicleMapBuilder<K, V> implements ChronicleMapBuilderI<K,
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChronicleMapBuilderI<K, V> checkSerializedValues() {
|
||||
// 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");
|
||||
public ChronicleMapBuilder<K, V> disableOversizedEntries() {
|
||||
delegate.disableOversizedEntries();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,4 +315,5 @@ public interface ChronicleMapBuilderI<K, V> extends Serializable {
|
||||
|
||||
String name();
|
||||
|
||||
ChronicleMapBuilderI<K, V> disableOversizedEntries();
|
||||
}
|
||||
|
||||
@@ -718,7 +718,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? supe
|
||||
throw defaultValueOrPrepareBytesShouldBeSpecified();
|
||||
}
|
||||
putValue(pos, offset, entry, valueSizePos, entryEndAddr,
|
||||
copies, localSegmentState, metaElemWriter, elemWriter, elem,
|
||||
localSegmentState, metaElemWriter, elemWriter, elem,
|
||||
metaElemWriter.size(elemWriter, elem), hashLookup);
|
||||
pos = localSegmentState.pos;
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.nio.ByteBuffer.allocateDirect;
|
||||
import static net.openhft.chronicle.map.AbstractChannelReplicator.*;
|
||||
import static net.openhft.chronicle.map.AbstractChannelReplicator.SIZE_OF_SIZE;
|
||||
import static net.openhft.chronicle.map.AbstractChannelReplicator.SIZE_OF_TRANSACTION_ID;
|
||||
import static net.openhft.chronicle.map.StatelessChronicleMap.EventId.*;
|
||||
|
||||
/**
|
||||
@@ -68,8 +69,8 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
private volatile ByteBuffer outBuffer;
|
||||
private volatile ByteBufferBytes outBytes;
|
||||
|
||||
private ByteBuffer inBuffer;
|
||||
private ByteBufferBytes inBytes;
|
||||
private volatile ByteBuffer inBuffer;
|
||||
private volatile ByteBufferBytes inBytes;
|
||||
|
||||
@NotNull
|
||||
private final ReaderWithSize<K> keyReaderWithSize;
|
||||
@@ -123,7 +124,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
PUT_ALL_WITHOUT_ACC,
|
||||
HASH_CODE,
|
||||
MAP_FOR_KEY,
|
||||
UPDATE_FOR_KEY
|
||||
PUT_MAPPED
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +178,16 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V newValueInstance() {
|
||||
return VanillaChronicleMap.newInstance(vClass, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K newKeyInstance() {
|
||||
return VanillaChronicleMap.newInstance(kClass, true);
|
||||
}
|
||||
|
||||
private ExecutorService lazyExecutorService() {
|
||||
if (executorService == null) {
|
||||
synchronized (this) {
|
||||
@@ -225,16 +236,14 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
}
|
||||
|
||||
/**
|
||||
* attempts a single connect without a timeout and eat any IOException used typically in the
|
||||
* constructor, its possible the server is not running with this instance is created, {@link
|
||||
* net.openhft.chronicle.map.StatelessChronicleMap#lazyConnect(long,
|
||||
* java.net.InetSocketAddress)} will attempt to establish the connection when the client make
|
||||
* the first map method call.
|
||||
* attempts a single connect without a timeout and eat any IOException used typically in the constructor, its
|
||||
* possible the server is not running with this instance is created, {@link net.openhft.chronicle.map.StatelessChronicleMap#lazyConnect(long,
|
||||
* java.net.InetSocketAddress)} will attempt to establish the connection when the client make the first map method
|
||||
* call.
|
||||
*
|
||||
* @param remoteAddress the Inet Socket Address
|
||||
* @throws java.io.IOException
|
||||
* @see net.openhft.chronicle.map.StatelessChronicleMap#lazyConnect(long,
|
||||
* java.net.InetSocketAddress)
|
||||
* @see net.openhft.chronicle.map.StatelessChronicleMap#lazyConnect(long, java.net.InetSocketAddress)
|
||||
*/
|
||||
|
||||
private synchronized void attemptConnect(final InetSocketAddress remoteAddress) {
|
||||
@@ -263,9 +272,8 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
}
|
||||
|
||||
/**
|
||||
* initiates a very simple level of handshaking with the remote server, we send a special ID of
|
||||
* -127 ( when the server receives this it knows its dealing with a stateless client, receive
|
||||
* back an identifier from the server
|
||||
* initiates a very simple level of handshaking with the remote server, we send a special ID of -127 ( when the
|
||||
* server receives this it knows its dealing with a stateless client, receive back an identifier from the server
|
||||
*
|
||||
* @param clientChannel clientChannel
|
||||
* @throws java.io.IOException
|
||||
@@ -331,13 +339,14 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
* @return a unique transactionId
|
||||
*/
|
||||
private long nextUniqueTransaction(long time) {
|
||||
long old = transactionID.getAndSet(time);
|
||||
|
||||
if (old == time)
|
||||
return transactionID.incrementAndGet();
|
||||
else
|
||||
return time;
|
||||
|
||||
long id = time * TcpReplicator.TIMESTAMP_FACTOR;
|
||||
for (; ; ) {
|
||||
long old = transactionID.get();
|
||||
if (old >= id) id = old + 1;
|
||||
if (transactionID.compareAndSet(old, id))
|
||||
break;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@@ -382,10 +391,9 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
}
|
||||
|
||||
/**
|
||||
* calling this method should be avoided at all cost, as the entire {@code object} is
|
||||
* serialized. This equals can be used to compare map that extends ChronicleMap. So two
|
||||
* Chronicle Maps that contain the same data are considered equal, even if the instances of the
|
||||
* chronicle maps were of different types
|
||||
* calling this method should be avoided at all cost, as the entire {@code object} is serialized. This equals can be
|
||||
* used to compare map that extends ChronicleMap. So two Chronicle Maps that contain the same data are considered
|
||||
* equal, even if the instances of the chronicle maps were of different types
|
||||
*
|
||||
* @param object the object that you are comparing against
|
||||
* @return true if the contain the same data
|
||||
@@ -481,7 +489,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <R> R mapForKey(@Nullable K key, @NotNull Function<? super V, R> function) {
|
||||
public <R> R getMapped(@Nullable K key, @NotNull Function<? super V, R> function) {
|
||||
if (key == null)
|
||||
throw keyNotNullNPE();
|
||||
return fetchObject(MAP_FOR_KEY, key, function);
|
||||
@@ -490,10 +498,10 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V putWith(@Nullable K key, @NotNull Mutator<V> mutator) {
|
||||
public V putMapped(@Nullable K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
if (key == null)
|
||||
throw keyNotNullNPE();
|
||||
return fetchObject(UPDATE_FOR_KEY, key, mutator);
|
||||
return fetchObject(PUT_MAPPED, key, unaryOperator);
|
||||
}
|
||||
|
||||
|
||||
@@ -814,8 +822,8 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
|
||||
// skips for the transaction id
|
||||
outBytes.skip(SIZE_OF_TRANSACTION_ID);
|
||||
outBytes.skip(SIZE_OF_TIME_SHIFT);
|
||||
outBytes.writeByte(identifier);
|
||||
outBytes.writeInt(0);
|
||||
return sizeLocation;
|
||||
}
|
||||
|
||||
@@ -997,13 +1005,15 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
receive(SIZE_OF_SIZE + SIZE_OF_TRANSACTION_ID, timeoutTime);
|
||||
|
||||
final int messageSize = inBytes.readInt();
|
||||
assert messageSize > 0 : "Invalid message size " + messageSize;
|
||||
assert messageSize < 16 << 20 : "Invalid message size " + messageSize;
|
||||
|
||||
final int remainingBytes0 = messageSize - (SIZE_OF_SIZE + SIZE_OF_TRANSACTION_ID);
|
||||
final long transactionId0 = inBytes.readLong();
|
||||
|
||||
assert transactionId0 != 0;
|
||||
|
||||
// check the transaction id is reasonable
|
||||
assert String.valueOf(transactionId0).startsWith("14");
|
||||
assert transactionId0 > 1410000000000L * TcpReplicator.TIMESTAMP_FACTOR : "TransactionId too small " + transactionId0 + " messageSize " + messageSize;
|
||||
assert transactionId0 < 2100000000000L * TcpReplicator.TIMESTAMP_FACTOR : "TransactionId too large " + transactionId0 + " messageSize " + messageSize;
|
||||
|
||||
// if the transaction id is for this thread process it
|
||||
if (transactionId0 == transactionId) {
|
||||
@@ -1130,7 +1140,6 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable, Clon
|
||||
outBytes.writeInt(size0);
|
||||
assert transactionId != 0;
|
||||
outBytes.writeLong(transactionId);
|
||||
outBytes.writeUnsignedShort((int) (transactionId - startTime));
|
||||
|
||||
outBytes.position(pos);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ interface Work {
|
||||
*/
|
||||
final class TcpReplicator extends AbstractChannelReplicator implements Closeable {
|
||||
|
||||
public static final long TIMESTAMP_FACTOR = 10000;
|
||||
private static final int STATELESS_CLIENT = -127;
|
||||
private static final byte NOT_SET = (byte) HEARTBEAT.ordinal();
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TcpReplicator.class.getName());
|
||||
@@ -413,8 +414,8 @@ final class TcpReplicator extends AbstractChannelReplicator implements Closeable
|
||||
// so these nodes will establish the connection when they come back up,
|
||||
// hence under these circumstances, polling a dropped node to attempt to reconnect is no-longer
|
||||
// required as the remote node will establish the connection its self on startup.
|
||||
if (replicationConfig.autoReconnectedUponDroppedConnection())
|
||||
attached.connector.connect();
|
||||
|
||||
attached.connector.connect();
|
||||
|
||||
throw e;
|
||||
}
|
||||
@@ -592,7 +593,11 @@ final class TcpReplicator extends AbstractChannelReplicator implements Closeable
|
||||
final long approxTime) throws IOException {
|
||||
final SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
final Attached attached = (Attached) key.attachment();
|
||||
if (attached == null) throw new NullPointerException("No attached");
|
||||
if (attached == null) {
|
||||
LOG.info("Closing connection " + socketChannel + ", nothing attached");
|
||||
socketChannel.close();
|
||||
return;
|
||||
}
|
||||
TcpSocketChannelEntryWriter entryWriter = attached.entryWriter;
|
||||
if (entryWriter == null) throw new NullPointerException("No entryWriter");
|
||||
if (entryWriter.isWorkIncomplete()) {
|
||||
@@ -1332,10 +1337,10 @@ class StatelessServerConnector<K, V> {
|
||||
long transactionId = reader.readLong();
|
||||
|
||||
// the time stamp and the transaction are usually the same, or out by the shift
|
||||
int timestampShift = reader.readUnsignedShort();
|
||||
long timestamp = transactionId - timestampShift;
|
||||
|
||||
long timestamp = transactionId / TcpReplicator.TIMESTAMP_FACTOR;
|
||||
byte identifier = reader.readByte();
|
||||
int headerSize = reader.readInt();
|
||||
reader.skip(headerSize);
|
||||
|
||||
|
||||
// these methods don't return a result to the client or don't return a result to the
|
||||
@@ -1413,8 +1418,8 @@ class StatelessServerConnector<K, V> {
|
||||
case MAP_FOR_KEY:
|
||||
return mapForKey(reader, writer, sizeLocation);
|
||||
|
||||
case UPDATE_FOR_KEY:
|
||||
return updateForKey(reader, writer, sizeLocation);
|
||||
case PUT_MAPPED:
|
||||
return putMapped(reader, writer, sizeLocation);
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("unsupported event=" + event);
|
||||
@@ -1426,7 +1431,7 @@ class StatelessServerConnector<K, V> {
|
||||
final K key = keyReaderWithSize.read(reader, null);
|
||||
final Function<V, ?> function = (Function<V, ?>) reader.readObject();
|
||||
try {
|
||||
Object result = map.mapForKey(key, function);
|
||||
Object result = map.getMapped(key, function);
|
||||
writer.writeObject(result);
|
||||
} catch (Throwable e) {
|
||||
LOG.info("", e);
|
||||
@@ -1438,11 +1443,11 @@ class StatelessServerConnector<K, V> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Work updateForKey(@NotNull ByteBufferBytes reader, @NotNull Bytes writer, long sizeLocation) {
|
||||
public Work putMapped(@NotNull ByteBufferBytes reader, @NotNull Bytes writer, long sizeLocation) {
|
||||
final K key = keyReaderWithSize.read(reader, null);
|
||||
final Mutator<V> mutator = (Mutator<V>) reader.readObject();
|
||||
final UnaryOperator<V> unaryOperator = (UnaryOperator<V>) reader.readObject();
|
||||
try {
|
||||
Object result = map.putWith(key, mutator);
|
||||
Object result = map.putMapped(key, unaryOperator);
|
||||
writer.writeObject(result);
|
||||
} catch (Throwable e) {
|
||||
LOG.info("", e);
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import java.io.Serializable;
|
||||
|
||||
*/
|
||||
|
||||
public interface Mutator<T> extends Serializable {
|
||||
public interface UnaryOperator<T> extends Serializable {
|
||||
/**
|
||||
* Applies this mutator to the given mutable argument.
|
||||
*
|
||||
@@ -36,14 +36,13 @@ import net.openhft.lang.collection.DirectBitSet;
|
||||
import net.openhft.lang.collection.SingleThreadedDirectBitSet;
|
||||
import net.openhft.lang.io.*;
|
||||
import net.openhft.lang.io.serialization.JDKObjectSerializer;
|
||||
import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
|
||||
import net.openhft.lang.io.serialization.ObjectSerializer;
|
||||
import net.openhft.lang.model.DataValueClasses;
|
||||
import net.openhft.lang.threadlocal.Provider;
|
||||
import net.openhft.lang.threadlocal.StatefulCopyable;
|
||||
import net.openhft.lang.threadlocal.ThreadLocalCopies;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
@@ -51,6 +50,9 @@ import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import static java.lang.Class.forName;
|
||||
import static java.lang.Long.numberOfTrailingZeros;
|
||||
@@ -58,6 +60,8 @@ import static java.lang.Math.max;
|
||||
import static java.lang.Thread.currentThread;
|
||||
import static java.nio.ByteBuffer.allocateDirect;
|
||||
import static net.openhft.chronicle.map.Asserts.assertNotNull;
|
||||
import static net.openhft.chronicle.map.ChronicleMapBuilder.builtInType;
|
||||
import static net.openhft.chronicle.map.ChronicleMapBuilder.offHeapReference;
|
||||
import static net.openhft.lang.MemoryUnit.*;
|
||||
|
||||
class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
@@ -65,11 +69,10 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
implements ChronicleMap<K, V>, Serializable, ReadValue<V>, InstanceOrBytesToInstance,
|
||||
GetValueInterops<V, VI, MVI> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VanillaChronicleMap.class);
|
||||
// private static final Logger LOG = LoggerFactory.getLogger(VanillaChronicleMap.class);
|
||||
|
||||
/**
|
||||
* Because DirectBitSet implementations couldn't find more than 64 continuous clear or set
|
||||
* bits.
|
||||
* Because DirectBitSet implementations couldn't find more than 64 continuous clear or set bits.
|
||||
*/
|
||||
static final int MAX_ENTRY_OVERSIZE_FACTOR = 64;
|
||||
private static final long serialVersionUID = 2L;
|
||||
@@ -105,6 +108,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
private final HashSplitting hashSplitting;
|
||||
final boolean isNativeValueClass;
|
||||
final MultiMapFactory multiMapFactory;
|
||||
final int maxEntryOversizeFactor;
|
||||
transient Provider<BytesReader<K>> keyReaderProvider;
|
||||
transient Provider<KI> keyInteropProvider;
|
||||
transient Provider<BytesReader<V>> valueReaderProvider;
|
||||
@@ -113,7 +117,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
// non-final for close() and because it is initialized out of constructor
|
||||
transient BytesStore ms;
|
||||
transient long headerSize;
|
||||
private transient Set<Map.Entry<K, V>> entrySet;
|
||||
transient Set<Map.Entry<K, V>> entrySet;
|
||||
|
||||
public VanillaChronicleMap(AbstractChronicleMapBuilder<K, V, ?> builder) throws IOException {
|
||||
|
||||
@@ -156,6 +160,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
this.eventListener = builder.eventListener();
|
||||
this.bytesEventListener = builder.bytesEventListener();
|
||||
this.segmentHeaderSize = builder.segmentHeaderSize();
|
||||
this.maxEntryOversizeFactor = builder.maxEntryOversizeFactor();
|
||||
|
||||
hashSplitting = HashSplitting.Splitting.forSegments(actualSegments);
|
||||
initTransients();
|
||||
@@ -551,7 +556,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R mapForKey(K key, @NotNull Function<? super V, R> function) {
|
||||
public <R> R getMapped(K key, @NotNull Function<? super V, R> function) {
|
||||
try (ReadContext<K, V> entry = lookupUsing(key, null,
|
||||
false, false, LockType.READ_LOCK)) {
|
||||
return entry.present() ? function.apply(entry.value()) : null;
|
||||
@@ -559,45 +564,58 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putWith(K key, @NotNull Mutator<V> mutator) {
|
||||
public V putMapped(K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
|
||||
return (vClass.equals(CharSequence.class) || vClass.equals(StringBuilder.class))
|
||||
? putMappedSB(key, unaryOperator)
|
||||
: putMapped0(key, unaryOperator);
|
||||
}
|
||||
|
||||
final V using = (vClass.equals(CharSequence.class)) ? (V) new StringBuilder() : null;
|
||||
V putMappedSB(K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
|
||||
try (WriteContext<K, V> entry = lookupUsing(key, using,
|
||||
false, false, LockType.WRITE_LOCK)) {
|
||||
StringBuilder usingSB = new StringBuilder("\uFFFF");
|
||||
try (WriteContext<K, V> entry = lookupUsing(key, (V) usingSB,
|
||||
false, true, LockType.WRITE_LOCK)) {
|
||||
|
||||
if (CharSequence.class.isAssignableFrom(vClass)) {
|
||||
CharSequence value = (CharSequence) entry.value();
|
||||
if (entry.value() == null || value.length() == 0)
|
||||
return null;
|
||||
usingSB = (StringBuilder) entry.value();
|
||||
if (usingSB.length() == 1 && usingSB.charAt(0) == '\uFFFF')
|
||||
return null;
|
||||
|
||||
V result = unaryOperator.update((V) usingSB);
|
||||
if (usingSB != result) {
|
||||
usingSB.setLength(0);
|
||||
usingSB.append((CharSequence) result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
V putMapped0(K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
try (WriteContext<K, V> entry = lookupUsing(key, null,
|
||||
false, true, LockType.WRITE_LOCK)) {
|
||||
|
||||
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);
|
||||
V result = unaryOperator.update(entry.value());
|
||||
((MutableLockedEntry) entry).value(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void getAll(File toFile) throws IOException {
|
||||
|
||||
final XStream xstream = new XStream(new JettisonMappedXmlDriver());
|
||||
xstream.setMode(XStream.NO_REFERENCES);
|
||||
xstream.alias("chronicle-entries", VanillaChronicleMap.EntrySet.class);
|
||||
// ideally we will use java serialization if we can
|
||||
lazyXStreamConverter().registerConverter(xstream);
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream(toFile)) {
|
||||
OutputStream outputStream = new FileOutputStream(toFile);
|
||||
if (toFile.getName().toLowerCase().endsWith(".gz"))
|
||||
outputStream = new GZIPOutputStream(outputStream);
|
||||
try (OutputStream out = outputStream) {
|
||||
xstream.toXML(entrySet(), out);
|
||||
}
|
||||
}
|
||||
@@ -611,11 +629,44 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
// ideally we will use java serialization if we can
|
||||
lazyXStreamConverter().registerConverter(xstream);
|
||||
|
||||
try (FileInputStream out = new FileInputStream(fromFile)) {
|
||||
InputStream inputStream = new FileInputStream(fromFile);
|
||||
if (fromFile.getName().toLowerCase().endsWith(".gz"))
|
||||
inputStream = new GZIPInputStream(inputStream);
|
||||
try (InputStream out = inputStream) {
|
||||
xstream.fromXML(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V newValueInstance() {
|
||||
return newInstance(vClass, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K newKeyInstance() {
|
||||
return newInstance(kClass, true);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
private XStreamConverter xStreamConverter;
|
||||
|
||||
/**
|
||||
@@ -1007,9 +1058,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
/**
|
||||
* removes ( if there exists ) an entry from the map, if the {@param key} and {@param
|
||||
* expectedValue} match that of a maps.entry. If the {@param expectedValue} equals null then (
|
||||
* if there exists ) an entry whose key equals {@param key} this is removed.
|
||||
* removes ( if there exists ) an entry from the map, if the {@param key} and {@param expectedValue} match that of a
|
||||
* maps.entry. If the {@param expectedValue} equals null then ( if there exists ) an entry whose key equals {@param
|
||||
* key} this is removed.
|
||||
*
|
||||
* @param k the key of the entry to remove
|
||||
* @param expectedValue null if not required
|
||||
@@ -1141,8 +1192,8 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
* replace the value in a map, only if the existing entry equals {@param expectedValue}
|
||||
*
|
||||
* @param key the key into the map
|
||||
* @param expectedValue the expected existing value in the map ( could be null when we don't
|
||||
* wish to do this check )
|
||||
* @param expectedValue the expected existing value in the map ( could be null when we don't wish to do this check
|
||||
* )
|
||||
* @param newValue the new value you wish to store in the map
|
||||
* @return the value that was replaced
|
||||
*/
|
||||
@@ -1427,7 +1478,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
*/
|
||||
static final long LOCK_OFFSET = 0L; // 64-bit
|
||||
static final long SIZE_OFFSET = LOCK_OFFSET + 8L; // 32-bit
|
||||
|
||||
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
final NativeBytes segmentHeader;
|
||||
final NativeBytes bytes;
|
||||
final long entriesOffset;
|
||||
@@ -1468,11 +1519,11 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
|
||||
private MultiMap createMultiMap(long start) {
|
||||
final NativeBytes multiMapBytes =
|
||||
new NativeBytes(new VanillaBytesMarshallerFactory(), start,
|
||||
new NativeBytes((ObjectSerializer) null, start,
|
||||
start = start + sizeOfMultiMap(), null);
|
||||
|
||||
final NativeBytes sizeOfMultiMapBitSetBytes =
|
||||
new NativeBytes(new VanillaBytesMarshallerFactory(), start,
|
||||
new NativeBytes((ObjectSerializer) null, start,
|
||||
start + sizeOfMultiMapBitSet(), null);
|
||||
// multiMapBytes.load();
|
||||
return multiMapFactory.create(multiMapBytes, sizeOfMultiMapBitSetBytes);
|
||||
@@ -1516,7 +1567,16 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
public final ReadLocked<K, KI, MKI, V, VI, MVI> readLock(
|
||||
@Nullable SegmentState segmentState) {
|
||||
while (true) {
|
||||
final boolean success = segmentHeader.tryRWReadLock(LOCK_OFFSET, lockTimeOutNS);
|
||||
// final boolean success = segmentHeader.tryRWReadLock(LOCK_OFFSET, lockTimeOutNS);
|
||||
final boolean success = segmentHeader.tryRWWriteLock(LOCK_OFFSET, lockTimeOutNS);
|
||||
/*
|
||||
boolean success = false;
|
||||
try {
|
||||
success = lock.readLock().tryLock(lockTimeOutNS, TimeUnit.NANOSECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
*/
|
||||
if (success) {
|
||||
if (segmentState != null) {
|
||||
return segmentState.readLocked(this);
|
||||
@@ -1542,6 +1602,14 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
startWriteLock = System.nanoTime();
|
||||
while (true) {
|
||||
final boolean success = segmentHeader.tryRWWriteLock(LOCK_OFFSET, lockTimeOutNS);
|
||||
/*
|
||||
boolean success = false;
|
||||
try {
|
||||
success = lock.writeLock().tryLock(lockTimeOutNS, TimeUnit.NANOSECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
*/
|
||||
if (success) {
|
||||
if (segmentState != null) {
|
||||
if (isNativeValueClass) {
|
||||
@@ -1567,7 +1635,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
@Override
|
||||
public final void readUnlock() {
|
||||
try {
|
||||
segmentHeader.unlockRWReadLock(LOCK_OFFSET);
|
||||
// segmentHeader.unlockRWReadLock(LOCK_OFFSET);
|
||||
segmentHeader.unlockRWWriteLock(LOCK_OFFSET);
|
||||
// lock.readLock().unlock();
|
||||
} catch (IllegalMonitorStateException e) {
|
||||
errorListener.errorOnUnlock(e);
|
||||
}
|
||||
@@ -1577,6 +1647,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
public final void writeUnlock() {
|
||||
try {
|
||||
segmentHeader.unlockRWWriteLock(LOCK_OFFSET);
|
||||
// lock.writeLock().unlock();
|
||||
} catch (IllegalMonitorStateException e) {
|
||||
errorListener.errorOnUnlock(e);
|
||||
}
|
||||
@@ -1873,7 +1944,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
// putValue may relocate entry and change offset
|
||||
putValue(pos, offset, entry, valueSizePos, entryEndAddr, copies, segmentState,
|
||||
putValue(pos, offset, entry, valueSizePos, entryEndAddr, segmentState,
|
||||
metaValueInterop, valueInterop, value, valueSize, searchedHashLookup);
|
||||
|
||||
// put callbacks
|
||||
@@ -1897,9 +1968,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value size, writes the entry (key, value, sizes) to the entry, after this method
|
||||
* call entry positioned after value bytes written (i. e. at the end of entry), sets entry
|
||||
* position (in segment) and value size position in the given segmentState
|
||||
* Returns value size, writes the entry (key, value, sizes) to the entry, after this method call entry
|
||||
* positioned after value bytes written (i. e. at the end of entry), sets entry position (in segment) and value
|
||||
* size position in the given segmentState
|
||||
*/
|
||||
final <KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>, E, EW>
|
||||
long putEntry(SegmentState segmentState,
|
||||
@@ -1942,9 +2013,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
|
||||
//TODO refactor/optimize
|
||||
private long alloc(int blocks) {
|
||||
if (blocks > MAX_ENTRY_OVERSIZE_FACTOR)
|
||||
if (blocks > maxEntryOversizeFactor)
|
||||
throw new IllegalArgumentException("Entry is too large: requires " + blocks +
|
||||
" entry size chucks, " + MAX_ENTRY_OVERSIZE_FACTOR + " is maximum.");
|
||||
" entry size chucks, " + maxEntryOversizeFactor + " is maximum.");
|
||||
long ret = freeList.setNextNContinuousClearBits(nextPosToSearchFrom, blocks);
|
||||
if (ret == DirectBitSet.NOT_FOUND || ret + blocks > entriesPerSegment) {
|
||||
if (ret + blocks > entriesPerSegment)
|
||||
@@ -2023,10 +2094,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
/**
|
||||
* - if expectedValue is not null, returns Boolean.TRUE (removed) or Boolean.FALSE (entry
|
||||
* not found), regardless the expectedValue object is Bytes instance (RPC call) or the value
|
||||
* instance - if expectedValue is null: - if resultUnused is false, null or removed value is
|
||||
* returned - if resultUnused is true, null is always returned
|
||||
* - if expectedValue is not null, returns Boolean.TRUE (removed) or Boolean.FALSE (entry not found), regardless
|
||||
* the expectedValue object is Bytes instance (RPC call) or the value instance - if expectedValue is null: - if
|
||||
* resultUnused is false, null or removed value is returned - if resultUnused is true, null is always returned
|
||||
*/
|
||||
<KB, KBI, MKBI extends MetaBytesInterop<KB, ? super KBI>,
|
||||
RV, VB extends RV, VBI, MVBI extends MetaBytesInterop<? super VB, ? super VBI>>
|
||||
@@ -2170,9 +2240,8 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the specified value for the key with the given value. {@code newValue} is set
|
||||
* only if the existing value corresponding to the specified key is equal to {@code
|
||||
* expectedValue} or {@code expectedValue == null}.
|
||||
* Replaces the specified value for the key with the given value. {@code newValue} is set only if the existing
|
||||
* value corresponding to the specified key is equal to {@code expectedValue} or {@code expectedValue == null}.
|
||||
*
|
||||
* @param hash2 a hash code related to the {@code keyBytes}
|
||||
* @return the replaced value or {@code null} if the value was not replaced
|
||||
@@ -2252,7 +2321,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
MVBI metaValueInterop = getNewValueInterops.getMetaValueInterop(
|
||||
copies, valueInterop, newValue);
|
||||
long newValueSize = metaValueInterop.size(valueInterop, newValue);
|
||||
putValue(pos, offset, entry, valueSizePos, entryEndAddr, copies, segmentState,
|
||||
putValue(pos, offset, entry, valueSizePos, entryEndAddr, segmentState,
|
||||
metaValueInterop, valueInterop, newValue, newValueSize, searchedHashLookup);
|
||||
|
||||
// put callbacks
|
||||
@@ -2270,21 +2339,19 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces value in existing entry. May cause entry relocation, because there may be not
|
||||
* enough space for new value in location already allocated for this entry.
|
||||
* Replaces value in existing entry. May cause entry relocation, because there may be not enough space for new
|
||||
* value in location already allocated for this entry.
|
||||
*
|
||||
* @param pos index of the first block occupied by the entry
|
||||
* @param offset relative offset of the entry in Segment bytes (before, i. e.
|
||||
* including metaData)
|
||||
* @param offset relative offset of the entry in Segment bytes (before, i. e. including metaData)
|
||||
* @param entry relative pointer in Segment bytes
|
||||
* @param valueSizePos relative position of value size in entry
|
||||
* @param entryEndAddr absolute address of the entry end
|
||||
* @return relative offset of the entry in Segment bytes after putting value (that may cause
|
||||
* entry relocation)
|
||||
* @return relative offset of the entry in Segment bytes after putting value (that may cause entry relocation)
|
||||
*/
|
||||
final <E, EW> long putValue(
|
||||
long pos, long offset, MultiStoreBytes entry, long valueSizePos, long entryEndAddr,
|
||||
ThreadLocalCopies copies, SegmentState segmentState,
|
||||
SegmentState segmentState,
|
||||
MetaBytesWriter<E, ? super EW> metaElemWriter, EW elemWriter, E newElem,
|
||||
long newElemSize,
|
||||
MultiMap searchedHashLookup) {
|
||||
@@ -2299,10 +2366,10 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
int oldSizeInBlocks = inBlocks(oldEntrySize);
|
||||
int newSizeInBlocks = inBlocks(newEntryEndAddr - entryStartAddr);
|
||||
if (newSizeInBlocks > oldSizeInBlocks) {
|
||||
if (newSizeInBlocks > MAX_ENTRY_OVERSIZE_FACTOR) {
|
||||
if (newSizeInBlocks > maxEntryOversizeFactor) {
|
||||
throw new IllegalArgumentException("Value too large: " +
|
||||
"entry takes " + newSizeInBlocks + " blocks, " +
|
||||
MAX_ENTRY_OVERSIZE_FACTOR + " is maximum.");
|
||||
maxEntryOversizeFactor + " is maximum.");
|
||||
}
|
||||
if (realloc(pos, oldSizeInBlocks, newSizeInBlocks))
|
||||
break newValueDoesNotFit;
|
||||
@@ -2631,7 +2698,6 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
|
||||
private K key;
|
||||
private V value;
|
||||
boolean present;
|
||||
|
||||
MutableLockedEntry(SegmentState segmentState) {
|
||||
this.segmentState = segmentState;
|
||||
@@ -2650,7 +2716,6 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
|
||||
void value(V value) {
|
||||
this.present = value != null;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@@ -2676,7 +2741,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
* @return if the value is not null
|
||||
*/
|
||||
public boolean present() {
|
||||
return present;
|
||||
return value() != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.lang.io.serialization.impl.*;
|
||||
import net.openhft.lang.values.*;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -18,8 +19,8 @@ import static org.junit.Assert.*;
|
||||
|
||||
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.
|
||||
* 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
|
||||
public void testStringStringMap() throws ExecutionException, InterruptedException {
|
||||
@@ -32,19 +33,18 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<String, String> map = chmb.create()) {
|
||||
*/
|
||||
try (ChronicleMap<String, String> map = ChronicleMapBuilder
|
||||
.of(String.class, String.class)
|
||||
.checkSerializedValues() // for testing purposes only
|
||||
.of(String.class, String.class) // for testing purposes only
|
||||
.create()) {
|
||||
map.put("Hello", "World");
|
||||
assertEquals("World", map.get("Hello"));
|
||||
|
||||
assertEquals("New World", map.mapForKey("Hello", new Function<String, String>() {
|
||||
assertEquals("New World", map.getMapped("Hello", new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String s) {
|
||||
return "New " + s;
|
||||
}
|
||||
}));
|
||||
assertEquals(null, map.mapForKey("No key", new Function<String, String>() {
|
||||
assertEquals(null, map.getMapped("No key", new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String s) {
|
||||
return "New " + s;
|
||||
@@ -67,32 +67,29 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<String, String> map = chmb.create()) {
|
||||
*/
|
||||
try (ChronicleMap<String, String> map = ChronicleMapBuilder
|
||||
.of(String.class, String.class)
|
||||
.checkSerializedValues() // for testing purposes only
|
||||
.of(String.class, String.class) // for testing purposes only
|
||||
.create()) {
|
||||
map.put("Hello", "World");
|
||||
|
||||
|
||||
map.putWith("Hello", new Mutator<String>() {
|
||||
map.putMapped("Hello", new UnaryOperator<String>() {
|
||||
@Override
|
||||
public String update(String s) {
|
||||
return "New " + s;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CharSequence is more efficient when object creation is avoided. The key can only be on heap
|
||||
* and variable length serialised.
|
||||
* CharSequence is more efficient when object creation is avoided. The key can only be on heap and variable length
|
||||
* serialised.
|
||||
*/
|
||||
@Test
|
||||
public void testCharSequenceCharSequenceMap() throws ExecutionException, InterruptedException {
|
||||
try (ChronicleMap<CharSequence, CharSequence> map = ChronicleMapBuilder
|
||||
.of(CharSequence.class, CharSequence.class)
|
||||
.checkSerializedValues() // for testing purposes only
|
||||
.of(CharSequence.class, CharSequence.class) // for testing purposes only
|
||||
.defaultValue("")
|
||||
.create()) {
|
||||
map.put("Hello", "World");
|
||||
StringBuilder key = new StringBuilder();
|
||||
@@ -109,14 +106,14 @@ public class CHMUseCasesTest {
|
||||
assertNull(map.getUsing(key, value));
|
||||
|
||||
|
||||
assertEquals("New World", map.mapForKey("Hello", new
|
||||
assertEquals("New World", map.getMapped("Hello", new
|
||||
Function<CharSequence, CharSequence>() {
|
||||
@Override
|
||||
public CharSequence apply(CharSequence s) {
|
||||
return "New " + s;
|
||||
}
|
||||
}));
|
||||
assertEquals(null, map.mapForKey("No key", new
|
||||
assertEquals(null, map.getMapped("No key", new
|
||||
Function<CharSequence, CharSequence>() {
|
||||
@Override
|
||||
public CharSequence apply(CharSequence s) {
|
||||
@@ -124,8 +121,8 @@ public class CHMUseCasesTest {
|
||||
}
|
||||
}));
|
||||
|
||||
assertEquals("New World !!", map.putWith("Hello", new
|
||||
Mutator<CharSequence>() {
|
||||
assertEquals("New World !!", map.putMapped("Hello", new
|
||||
UnaryOperator<CharSequence>() {
|
||||
@Override
|
||||
public CharSequence update(CharSequence s) {
|
||||
((StringBuilder) s).append(" !!");
|
||||
@@ -135,8 +132,8 @@ public class CHMUseCasesTest {
|
||||
|
||||
assertEquals("New World !!", map.get("Hello").toString());
|
||||
|
||||
assertEquals(null, map.putWith("no-key", new
|
||||
Mutator<CharSequence>() {
|
||||
assertEquals("New !!", map.putMapped("no-key", new
|
||||
UnaryOperator<CharSequence>() {
|
||||
@Override
|
||||
public CharSequence update(CharSequence s) {
|
||||
((StringBuilder) s).append("!!");
|
||||
@@ -153,13 +150,12 @@ public class CHMUseCasesTest {
|
||||
@Test
|
||||
public void testStringValueStringValueMap() {
|
||||
try (ChronicleMap<StringValue, StringValue> map = ChronicleMapBuilder
|
||||
.of(StringValue.class, StringValue.class)
|
||||
.checkSerializedValues() // for testing purposes only
|
||||
.of(StringValue.class, StringValue.class) // for testing purposes only
|
||||
.create()) {
|
||||
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);
|
||||
StringValue key1 = map.newKeyInstance();
|
||||
StringValue key2 = map.newKeyInstance();
|
||||
StringValue value1 = map.newValueInstance();
|
||||
StringValue value2 = map.newValueInstance();
|
||||
|
||||
key1.setValue(new StringBuilder("1"));
|
||||
value1.setValue("11");
|
||||
@@ -246,7 +242,7 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<Integer, Integer> map = ChronicleMapBuilder
|
||||
.of(Integer.class, Integer.class)
|
||||
.entrySize(8)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.create()) {
|
||||
Integer key1;
|
||||
Integer key2;
|
||||
@@ -268,13 +264,13 @@ public class CHMUseCasesTest {
|
||||
assertEquals(null, map.get(3));
|
||||
assertEquals(null, map.get(4));
|
||||
|
||||
assertEquals((Integer) 110, map.mapForKey(1, new Function<Integer, Integer>() {
|
||||
assertEquals((Integer) 110, map.getMapped(1, new Function<Integer, Integer>() {
|
||||
@Override
|
||||
public Integer apply(Integer s) {
|
||||
return 10 * s;
|
||||
}
|
||||
}));
|
||||
assertEquals(null, map.mapForKey(-1, new Function<Integer, Integer>() {
|
||||
assertEquals(null, map.getMapped(-1, new Function<Integer, Integer>() {
|
||||
@Override
|
||||
public Integer apply(Integer s) {
|
||||
return 10 * s;
|
||||
@@ -282,7 +278,7 @@ public class CHMUseCasesTest {
|
||||
}));
|
||||
|
||||
try {
|
||||
map.putWith(1, new Mutator<Integer>() {
|
||||
map.putMapped(1, new UnaryOperator<Integer>() {
|
||||
@Override
|
||||
public Integer update(Integer s) {
|
||||
return s + 1;
|
||||
@@ -300,7 +296,7 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<Long, Long> map = ChronicleMapBuilder
|
||||
.of(Long.class, Long.class)
|
||||
.entrySize(16)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.create()) {
|
||||
map.put(1L, 11L);
|
||||
assertEquals((Long) 11L, map.get(1L));
|
||||
@@ -311,13 +307,13 @@ public class CHMUseCasesTest {
|
||||
assertEquals(null, map.get(3L));
|
||||
assertEquals(null, map.get(4L));
|
||||
|
||||
assertEquals((Long) 110L, map.mapForKey(1L, new Function<Long, Long>() {
|
||||
assertEquals((Long) 110L, map.getMapped(1L, new Function<Long, Long>() {
|
||||
@Override
|
||||
public Long apply(Long s) {
|
||||
return 10 * s;
|
||||
}
|
||||
}));
|
||||
assertEquals(null, map.mapForKey(-1L, new Function<Long, Long>() {
|
||||
assertEquals(null, map.getMapped(-1L, new Function<Long, Long>() {
|
||||
@Override
|
||||
public Long apply(Long s) {
|
||||
return 10 * s;
|
||||
@@ -325,7 +321,7 @@ public class CHMUseCasesTest {
|
||||
}));
|
||||
|
||||
try {
|
||||
map.putWith(1L, new Mutator<Long>() {
|
||||
map.putMapped(1L, new UnaryOperator<Long>() {
|
||||
@Override
|
||||
public Long update(Long s) {
|
||||
return s + 1;
|
||||
@@ -342,7 +338,7 @@ public class CHMUseCasesTest {
|
||||
public void testDoubleDoubleMap() throws ExecutionException, InterruptedException {
|
||||
try (ChronicleMap<Double, Double> map = ChronicleMapBuilder
|
||||
.of(Double.class, Double.class)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(16)
|
||||
.create()) {
|
||||
map.put(1.0, 11.0);
|
||||
@@ -354,13 +350,13 @@ public class CHMUseCasesTest {
|
||||
assertEquals(null, map.get(3.0));
|
||||
assertEquals(null, map.get(4.0));
|
||||
|
||||
assertEquals((Double) 110.0, map.mapForKey(1.0, new Function<Double, Double>() {
|
||||
assertEquals((Double) 110.0, map.getMapped(1.0, new Function<Double, Double>() {
|
||||
@Override
|
||||
public Double apply(Double s) {
|
||||
return 10 * s;
|
||||
}
|
||||
}));
|
||||
assertEquals(null, map.mapForKey(-1.0, new Function<Double, Double>() {
|
||||
assertEquals(null, map.getMapped(-1.0, new Function<Double, Double>() {
|
||||
@Override
|
||||
public Double apply(Double s) {
|
||||
return 10 * s;
|
||||
@@ -368,7 +364,7 @@ public class CHMUseCasesTest {
|
||||
}));
|
||||
|
||||
try {
|
||||
map.putWith(1.0, new Mutator<Double>() {
|
||||
map.putMapped(1.0, new UnaryOperator<Double>() {
|
||||
@Override
|
||||
public Double update(Double s) {
|
||||
return s + 1;
|
||||
@@ -386,7 +382,7 @@ public class CHMUseCasesTest {
|
||||
public void testByteArrayByteArrayMap() throws ExecutionException, InterruptedException {
|
||||
try (ChronicleMap<byte[], byte[]> map = ChronicleMapBuilder
|
||||
.of(byte[].class, byte[].class)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(12)
|
||||
.create()) {
|
||||
byte[] key1 = {1, 1, 1, 1};
|
||||
@@ -401,20 +397,20 @@ public class CHMUseCasesTest {
|
||||
map.put(key1, value1);
|
||||
|
||||
|
||||
assertTrue(Arrays.equals(new byte[]{11, 11}, map.mapForKey(key1, new Function<byte[], byte[]>() {
|
||||
assertTrue(Arrays.equals(new byte[]{11, 11}, map.getMapped(key1, new Function<byte[], byte[]>() {
|
||||
@Override
|
||||
public byte[] apply(byte[] s) {
|
||||
return Arrays.copyOf(s, 2);
|
||||
}
|
||||
})));
|
||||
assertEquals(null, map.mapForKey(key2, new Function<byte[], byte[]>() {
|
||||
assertEquals(null, map.getMapped(key2, new Function<byte[], byte[]>() {
|
||||
@Override
|
||||
public byte[] apply(byte[] s) {
|
||||
return Arrays.copyOf(s, 2);
|
||||
}
|
||||
}));
|
||||
|
||||
assertTrue(Arrays.equals(new byte[]{12, 10}, map.putWith(key1, new Mutator<byte[]>() {
|
||||
assertTrue(Arrays.equals(new byte[]{12, 10}, map.putMapped(key1, new UnaryOperator<byte[]>() {
|
||||
@Override
|
||||
public byte[] update(byte[] s) {
|
||||
s[0]++;
|
||||
@@ -434,10 +430,11 @@ public class CHMUseCasesTest {
|
||||
public void testByteBufferByteBufferMap() throws ExecutionException, InterruptedException {
|
||||
try (ChronicleMap<ByteBuffer, ByteBuffer> map = ChronicleMapBuilder
|
||||
.of(ByteBuffer.class, ByteBuffer.class)
|
||||
.valueMarshaller(ByteBufferMarshaller.INSTANCE)
|
||||
.keyMarshaller(ByteBufferMarshaller.INSTANCE)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.entrySize(20)
|
||||
.valueMarshaller(ByteBufferMarshaller.INSTANCE)
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
// TODO does this have to be 14 bytes?
|
||||
.entrySize(14)
|
||||
.create()) {
|
||||
ByteBuffer key1 = ByteBuffer.wrap(new byte[]{1, 1, 1, 1});
|
||||
ByteBuffer key2 = ByteBuffer.wrap(new byte[]{2, 2, 2, 2});
|
||||
@@ -458,10 +455,10 @@ public class CHMUseCasesTest {
|
||||
};
|
||||
|
||||
map.put(key1, value1);
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{11, 11}), map.mapForKey(key1, function));
|
||||
assertEquals(null, map.mapForKey(key2, function));
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{11, 11}), map.getMapped(key1, function));
|
||||
assertEquals(null, map.getMapped(key2, function));
|
||||
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.putWith(key1, new Mutator<ByteBuffer>() {
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.putMapped(key1, new UnaryOperator<ByteBuffer>() {
|
||||
@Override
|
||||
public ByteBuffer update(ByteBuffer s) {
|
||||
s.put(0, (byte) (s.get(0) + 1));
|
||||
@@ -510,7 +507,6 @@ public class CHMUseCasesTest {
|
||||
|
||||
|
||||
try (WriteContext wc = map.acquireUsingLocked(key1, valueB)) {
|
||||
|
||||
assertBBEquals(value1, valueB);
|
||||
appendMode(valueB);
|
||||
valueB.putShort((short) 12345);
|
||||
@@ -522,7 +518,7 @@ public class CHMUseCasesTest {
|
||||
|
||||
ByteBuffer bb1 = ByteBuffer.allocate(8);
|
||||
bb1.put(value1);
|
||||
bb1.putShort((short)12345);
|
||||
bb1.putShort((short) 12345);
|
||||
bb1.flip();
|
||||
assertBBEquals(bb1, valueA);
|
||||
}
|
||||
@@ -543,7 +539,7 @@ public class CHMUseCasesTest {
|
||||
.of(ByteBuffer.class, ByteBuffer.class)
|
||||
.valueMarshaller(ByteBufferMarshaller.INSTANCE) // we should not have to to this !
|
||||
.keyMarshaller(ByteBufferMarshaller.INSTANCE) // we should not have to to this !
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(12)
|
||||
.create()) {
|
||||
ByteBuffer key1 = ByteBuffer.wrap(new byte[]{1, 1, 1, 1});
|
||||
@@ -568,10 +564,10 @@ public class CHMUseCasesTest {
|
||||
return slice;
|
||||
}
|
||||
};
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{11, 11}), map.mapForKey(key1, function));
|
||||
assertEquals(null, map.mapForKey(key2, function));
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{11, 11}), map.getMapped(key1, function));
|
||||
assertEquals(null, map.getMapped(key2, function));
|
||||
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.putWith(key1, new Mutator<ByteBuffer>() {
|
||||
assertBBEquals(ByteBuffer.wrap(new byte[]{12, 10}), map.putMapped(key1, new UnaryOperator<ByteBuffer>() {
|
||||
@Override
|
||||
public ByteBuffer update(ByteBuffer s) {
|
||||
s.put(0, (byte) (s.get(0) + 1));
|
||||
@@ -595,13 +591,18 @@ public class CHMUseCasesTest {
|
||||
public void testIntValueIntValueMap() {
|
||||
try (ChronicleMap<IntValue, IntValue> map = ChronicleMapBuilder
|
||||
.of(IntValue.class, IntValue.class)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(8)
|
||||
.create()) {
|
||||
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);
|
||||
IntValue key1 = map.newKeyInstance();
|
||||
IntValue key2 = map.newKeyInstance();
|
||||
IntValue value1 = map.newValueInstance();
|
||||
IntValue value2 = map.newValueInstance();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(11);
|
||||
@@ -670,6 +671,26 @@ public class CHMUseCasesTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Generated code creates a field too large ie. it ignores the @Range")
|
||||
public void testUnsignedIntValueUnsignedIntValueMapEntrySize() {
|
||||
// TODO once this is working, merge the next test.
|
||||
try (ChronicleMap<UnsignedIntValue, UnsignedIntValue> map = ChronicleMapBuilder
|
||||
.of(UnsignedIntValue.class, UnsignedIntValue.class)
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(8)
|
||||
.create()) {
|
||||
UnsignedIntValue key1 = map.newKeyInstance();
|
||||
UnsignedIntValue value1 = map.newValueInstance();
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(11);
|
||||
map.put(key1, value1);
|
||||
assertEquals(value1, map.get(key1));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For unsigned int -> unsigned int entries, the key can be on heap or off heap.
|
||||
*/
|
||||
@@ -677,13 +698,14 @@ public class CHMUseCasesTest {
|
||||
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 = 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);
|
||||
|
||||
|
||||
|
||||
UnsignedIntValue key1 = map.newKeyInstance();
|
||||
UnsignedIntValue key2 = map.newKeyInstance();
|
||||
UnsignedIntValue value1 = map.newValueInstance();
|
||||
UnsignedIntValue value2 = map.newValueInstance();
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(11);
|
||||
@@ -759,13 +781,13 @@ public class CHMUseCasesTest {
|
||||
public void testIntValueShortValueMap() {
|
||||
try (ChronicleMap<IntValue, ShortValue> map = ChronicleMapBuilder
|
||||
.of(IntValue.class, ShortValue.class)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(6)
|
||||
.create()) {
|
||||
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);
|
||||
IntValue key1 = map.newKeyInstance();
|
||||
IntValue key2 = map.newKeyInstance();
|
||||
ShortValue value1 = map.newValueInstance();
|
||||
ShortValue value2 = map.newValueInstance();
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue((short) 11);
|
||||
@@ -842,12 +864,13 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<IntValue, UnsignedShortValue> map = ChronicleMapBuilder
|
||||
.of(IntValue.class, UnsignedShortValue.class)
|
||||
.entrySize(6)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.create()) {
|
||||
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);
|
||||
|
||||
IntValue key1 = map.newKeyInstance();
|
||||
IntValue key2 = map.newKeyInstance();
|
||||
UnsignedShortValue value1 = map.newValueInstance();
|
||||
UnsignedShortValue value2 = map.newValueInstance();
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(11);
|
||||
@@ -923,13 +946,14 @@ public class CHMUseCasesTest {
|
||||
public void testIntValueCharValueMap() {
|
||||
try (ChronicleMap<IntValue, CharValue> map = ChronicleMapBuilder
|
||||
.of(IntValue.class, CharValue.class)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(6)
|
||||
.create()) {
|
||||
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);
|
||||
|
||||
IntValue key1 = map.newKeyInstance();
|
||||
IntValue key2 = map.newKeyInstance();
|
||||
CharValue value1 = map.newValueInstance();
|
||||
CharValue value2 = map.newValueInstance();
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue((char) 11);
|
||||
@@ -1006,12 +1030,16 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<IntValue, UnsignedByteValue> map = ChronicleMapBuilder
|
||||
.of(IntValue.class, UnsignedByteValue.class)
|
||||
.entrySize(5)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.create()) {
|
||||
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);
|
||||
|
||||
|
||||
IntValue key1 = map.newKeyInstance();
|
||||
IntValue key2 = map.newKeyInstance();
|
||||
UnsignedByteValue value1 = map.newValueInstance();
|
||||
UnsignedByteValue value2 = map.newValueInstance();
|
||||
|
||||
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(11);
|
||||
@@ -1087,13 +1115,17 @@ public class CHMUseCasesTest {
|
||||
public void testIntValueBooleanValueMap() {
|
||||
try (ChronicleMap<IntValue, BooleanValue> map = ChronicleMapBuilder
|
||||
.of(IntValue.class, BooleanValue.class)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.entrySize(5)
|
||||
.create()) {
|
||||
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);
|
||||
|
||||
|
||||
|
||||
IntValue key1 = map.newKeyInstance();
|
||||
IntValue key2 = map.newKeyInstance();
|
||||
BooleanValue value1 = map.newValueInstance();
|
||||
BooleanValue value2 = map.newValueInstance();
|
||||
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(true);
|
||||
@@ -1170,12 +1202,14 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<FloatValue, FloatValue> map = ChronicleMapBuilder
|
||||
.of(FloatValue.class, FloatValue.class)
|
||||
.entrySize(8)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.create()) {
|
||||
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);
|
||||
|
||||
FloatValue key1 = map.newKeyInstance();
|
||||
FloatValue key2 = map.newKeyInstance();
|
||||
FloatValue value1 = map.newValueInstance();
|
||||
FloatValue value2 = map.newValueInstance();
|
||||
|
||||
|
||||
key1.setValue(1);
|
||||
value1.setValue(11);
|
||||
@@ -1254,10 +1288,10 @@ public class CHMUseCasesTest {
|
||||
.entrySize(16)
|
||||
.create()) {
|
||||
|
||||
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);
|
||||
DoubleValue key1 = map.newKeyInstance();
|
||||
DoubleValue key2 = map.newKeyInstance();
|
||||
DoubleValue value1 = map.newValueInstance();
|
||||
DoubleValue value2 = map.newValueInstance();
|
||||
|
||||
|
||||
key1.setValue(1);
|
||||
@@ -1337,12 +1371,14 @@ public class CHMUseCasesTest {
|
||||
try (ChronicleMap<LongValue, LongValue> map = ChronicleMapBuilder
|
||||
.of(LongValue.class, LongValue.class)
|
||||
.entrySize(16)
|
||||
.disableOversizedEntries(true) // disabled for testing purposes only.
|
||||
.disableOversizedEntries() // disabled for testing purposes only.
|
||||
.create()) {
|
||||
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);
|
||||
|
||||
LongValue key1 = map.newKeyInstance();
|
||||
LongValue key2 = map.newKeyInstance();
|
||||
LongValue value1 = map.newValueInstance();
|
||||
LongValue value2 = map.newValueInstance();
|
||||
|
||||
|
||||
|
||||
key1.setValue(1);
|
||||
|
||||
@@ -27,7 +27,7 @@ package net.openhft.chronicle.map;
|
||||
/*import junit.framework.Test;
|
||||
import junit.framework.TestSuite;*/
|
||||
|
||||
import net.openhft.chronicle.map.jrs166.JSR166TestCase;
|
||||
import net.openhft.chronicle.map.jsr166.JSR166TestCase;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
|
||||
@@ -26,36 +26,39 @@ import org.junit.Test;
|
||||
|
||||
import java.beans.XMLEncoder;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public void testLargeStrings() throws ExecutionException, InterruptedException, IOException {
|
||||
final int ENTRIES = 250;
|
||||
final int ENTRY_SIZE = 100 * 1024;
|
||||
|
||||
File file = File.createTempFile("largeEntries", ".deleteme");
|
||||
file.deleteOnExit();
|
||||
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)
|
||||
.entries(ENTRIES)
|
||||
.entrySize(ENTRY_SIZE / 6)
|
||||
.putReturnsNull(true)
|
||||
.create();
|
||||
.createPersistedTo(file);
|
||||
{
|
||||
int threads = 2; //Runtime.getRuntime().availableProcessors();
|
||||
warmUpCompression(ENTRY_SIZE);
|
||||
int threads = 4; //Runtime.getRuntime().availableProcessors();
|
||||
ExecutorService es = Executors.newFixedThreadPool(threads);
|
||||
final int block = ENTRIES / threads;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
@@ -63,11 +66,10 @@ public class LargeEntriesTest {
|
||||
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);
|
||||
exerciseLargeStrings(map, finalT * block, finalT * block + block, ENTRY_SIZE);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -84,7 +86,70 @@ public class LargeEntriesTest {
|
||||
}
|
||||
}
|
||||
|
||||
void exerciseLargeStrings(ChronicleMap<String, String> map, int run, int start, int finish, int entrySize) {
|
||||
private void warmUpCompression(int entrySize) {
|
||||
String value = generateValue(entrySize);
|
||||
DirectBytes bytes = DirectStore.allocate(entrySize / 6).bytes();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// warmup to compression.
|
||||
bytes.clear();
|
||||
SnappyStringMarshaller.INSTANCE.write(bytes, value);
|
||||
bytes.flip();
|
||||
SnappyStringMarshaller.INSTANCE.read(bytes);
|
||||
}
|
||||
bytes.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testLargeStringsPerf() throws ExecutionException, InterruptedException, IOException {
|
||||
doLargeEntryPerf(10000, 100 * 1024);
|
||||
doLargeEntryPerf(100000, 10 * 1024);
|
||||
doLargeEntryPerf(10000, 100 * 1024);
|
||||
doLargeEntryPerf(3000, 1024 * 1024);
|
||||
}
|
||||
|
||||
private void doLargeEntryPerf(int ENTRIES, final int ENTRY_SIZE) throws IOException, InterruptedException, ExecutionException {
|
||||
System.out.printf("Testing %,d entries of %,d KB%n", ENTRIES, ENTRY_SIZE);
|
||||
File file = File.createTempFile("largeEntries", ".deleteme");
|
||||
file.deleteOnExit();
|
||||
final ChronicleMap<String, String> map = ChronicleMapBuilder
|
||||
.of(String.class, String.class)
|
||||
.valueMarshaller(SnappyStringMarshaller.INSTANCE)
|
||||
.entries(ENTRIES * 2)
|
||||
.entrySize(ENTRY_SIZE / 6)
|
||||
.putReturnsNull(true)
|
||||
.createPersistedTo(file);
|
||||
{
|
||||
warmUpCompression(ENTRY_SIZE);
|
||||
int threads = 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;
|
||||
futureList.add(es.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
exerciseLargeStrings(map, 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 start, int finish, int entrySize) {
|
||||
/*
|
||||
final Thread thisThread = Thread.currentThread();
|
||||
Thread monitor = new Thread(new Runnable() {
|
||||
@@ -107,28 +172,15 @@ public class LargeEntriesTest {
|
||||
});
|
||||
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();
|
||||
}
|
||||
String value = generateValue(entrySize);
|
||||
|
||||
for (int i = start; i < finish; i++) {
|
||||
String key = "key-" + i;
|
||||
String object;
|
||||
|
||||
map.put(key, value);
|
||||
String object = map.get(key);
|
||||
object = map.get(key);
|
||||
assertTrue(key, map.containsKey(key));
|
||||
|
||||
assertNotNull(key, object);
|
||||
assertEquals(key, entrySize, object.length());
|
||||
@@ -138,10 +190,23 @@ public class LargeEntriesTest {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
private String generateValue(int entrySize) {
|
||||
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();
|
||||
return baos.toString().substring(0, entrySize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.map.jrs166.JSR166TestCase;
|
||||
import net.openhft.chronicle.map.jsr166.JSR166TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -218,13 +218,13 @@ public class ReplicationCheckingMap<K, V> implements ChronicleMap<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R mapForKey(K key, @NotNull Function<? super V, R> function) {
|
||||
return map1.mapForKey(key, function);
|
||||
public <R> R getMapped(K key, @NotNull Function<? super V, R> function) {
|
||||
return map1.getMapped(key, function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putWith(K key, @NotNull Mutator<V> mutator) {
|
||||
return map1.putWith(key, mutator);
|
||||
public V putMapped(K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
return map1.putMapped(key, unaryOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -237,6 +237,16 @@ public class ReplicationCheckingMap<K, V> implements ChronicleMap<K, V> {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V newValueInstance() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K newKeyInstance() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V acquireUsing(@NotNull K key, V usingValue) {
|
||||
return map1.acquireUsing(key, usingValue);
|
||||
|
||||
@@ -41,7 +41,7 @@ import static org.junit.Assert.assertTrue;
|
||||
public class StatelessClientTest {
|
||||
|
||||
public static final int SIZE = 2500;
|
||||
static int s_port = 9050;
|
||||
static int s_port = 9070;
|
||||
|
||||
enum ToString implements Function<Object, String> {
|
||||
INSTANCE;
|
||||
@@ -114,7 +114,7 @@ public class StatelessClientTest {
|
||||
.class, StringBuilder.class)
|
||||
.putReturnsNull(true)
|
||||
.statelessClient(new InetSocketAddress("localhost", port)).create()) {
|
||||
String actual = statelessMap.mapForKey(10, ToString.INSTANCE);
|
||||
String actual = statelessMap.getMapped(10, ToString.INSTANCE);
|
||||
|
||||
assertEquals("Hello World", actual);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class StatelessClientTest {
|
||||
try (ChronicleMap<Integer, StringBuilder> statelessMap = ChronicleMapBuilder.of(Integer
|
||||
.class, StringBuilder.class)
|
||||
.statelessClient(new InetSocketAddress("localhost", port)).create()) {
|
||||
String actual = statelessMap.mapForKey(11, ToString.INSTANCE);
|
||||
String actual = statelessMap.getMapped(11, ToString.INSTANCE);
|
||||
|
||||
assertEquals(null, actual);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.hash.replication.TimeProvider;
|
||||
import net.openhft.chronicle.map.jrs166.JSR166TestCase;
|
||||
import net.openhft.chronicle.map.jsr166.JSR166TestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.map.jrs166;
|
||||
package net.openhft.chronicle.map.jsr166;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import org.junit.After;
|
||||
+2
-2
@@ -16,11 +16,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.map.jrs166.map;
|
||||
package net.openhft.chronicle.map.jsr166.map;
|
||||
|
||||
import net.openhft.chronicle.map.ChronicleMap;
|
||||
import net.openhft.chronicle.map.ChronicleMapBuilder;
|
||||
import net.openhft.chronicle.map.jrs166.JSR166TestCase;
|
||||
import net.openhft.chronicle.map.jsr166.JSR166TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.map.jrs166.map;
|
||||
package net.openhft.chronicle.map.jsr166.map;
|
||||
|
||||
/*
|
||||
* Written by Doug Lea with assistance from members of JCP JSR-166
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.map.jrs166.map;
|
||||
package net.openhft.chronicle.map.jsr166.map;
|
||||
|
||||
import net.openhft.chronicle.map.ChronicleMap;
|
||||
import net.openhft.chronicle.map.ChronicleMapBuilder;
|
||||
+16
-6
@@ -16,11 +16,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.map.jrs166.map;
|
||||
package net.openhft.chronicle.map.jsr166.map;
|
||||
|
||||
import net.openhft.chronicle.hash.replication.TcpTransportAndNetworkConfig;
|
||||
import net.openhft.chronicle.map.*;
|
||||
import net.openhft.chronicle.map.jrs166.JSR166TestCase;
|
||||
import net.openhft.chronicle.map.jsr166.JSR166TestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -170,13 +170,13 @@ public class StatelessChronicleMapTest extends JSR166TestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R mapForKey(K key, @NotNull Function<? super V, R> function) {
|
||||
return d.mapForKey(key, function);
|
||||
public <R> R getMapped(K key, @NotNull Function<? super V, R> function) {
|
||||
return d.getMapped(key, function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putWith(K key, @NotNull Mutator<V> mutator) {
|
||||
return d.putWith(key, mutator);
|
||||
public V putMapped(K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
return d.putMapped(key, unaryOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -189,6 +189,16 @@ public class StatelessChronicleMapTest extends JSR166TestCase {
|
||||
d.putAll(fromFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V newValueInstance() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K newKeyInstance() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
return d.putIfAbsent(key, value);
|
||||
Reference in New Issue
Block a user