mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
Merge branch 'master' of github.com:OpenHFT/Chronicle-Map
Conflicts: src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java
This commit is contained in:
@@ -189,9 +189,7 @@ public interface ChronicleHashBuilder<K, C, B extends ChronicleHashBuilder<K, C,
|
||||
|
||||
B metaDataBytes(int metaDataBytes);
|
||||
|
||||
B addReplicator(Replicator replicator);
|
||||
|
||||
B setReplicators(Replicator... replicators);
|
||||
B replicators(byte identifier, Replicator... replicators);
|
||||
|
||||
B timeProvider(TimeProvider timeProvider);
|
||||
|
||||
|
||||
+9
-9
@@ -45,8 +45,8 @@ import static net.openhft.chronicle.map.Replica.ModificationNotifier.NOP;
|
||||
/**
|
||||
* @author Rob Austin.
|
||||
*/
|
||||
public final class ReplicatingCluster implements Closeable {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReplicatingCluster.class.getName());
|
||||
public final class ChannelProvider implements Closeable {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChannelProvider.class.getName());
|
||||
|
||||
private static final byte BOOTSTRAP_MESSAGE = 'B';
|
||||
final EntryExternalizable asEntryExternalizable = new EntryExternalizable() {
|
||||
@@ -152,7 +152,7 @@ public final class ReplicatingCluster implements Closeable {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
ReplicatingCluster.this.close();
|
||||
ChannelProvider.this.close();
|
||||
}
|
||||
};
|
||||
private final int maxEntrySize;
|
||||
@@ -169,7 +169,7 @@ public final class ReplicatingCluster implements Closeable {
|
||||
private final Set<AbstractChannelReplicator> replicators =
|
||||
new CopyOnWriteArraySet<AbstractChannelReplicator>();
|
||||
|
||||
ReplicatingCluster(ReplicatingClusterBuilder builder) {
|
||||
ChannelProvider(ChannelProviderBuilder builder) {
|
||||
localIdentifier = builder.identifier;
|
||||
maxEntrySize = builder.maxEntrySize;
|
||||
chronicleChannels = new Replica[builder.maxNumberOfChronicles];
|
||||
@@ -206,12 +206,12 @@ public final class ReplicatingCluster implements Closeable {
|
||||
/**
|
||||
* Returns a replicator, dedicated to the specified channel. Channel is basically just a number, that
|
||||
* should correspond on different servers for instances of the same replicated map. Only one replicator
|
||||
* per channel could be obtained from a single {@code ReplicatingCluster}. The returned replicator could
|
||||
* per channel could be obtained from a single {@code ReplicatingChannel}. The returned replicator could
|
||||
* be applied to a map at most once.
|
||||
*
|
||||
* @return a replicator, dedicated to the specified channel
|
||||
*/
|
||||
public Replicator channelReplicator(short channel) {
|
||||
public ChronicleChannel createChannel(short channel) {
|
||||
return new ChronicleChannel(channel);
|
||||
}
|
||||
|
||||
@@ -393,14 +393,14 @@ public final class ReplicatingCluster implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
private class ChronicleChannel extends Replicator implements Closeable {
|
||||
public class ChronicleChannel extends Replicator implements Closeable {
|
||||
|
||||
private final short chronicleChannel;
|
||||
|
||||
private ChronicleChannel(short chronicleChannel) {
|
||||
this.chronicleChannel = chronicleChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte identifier() {
|
||||
return localIdentifier;
|
||||
}
|
||||
@@ -409,7 +409,7 @@ public final class ReplicatingCluster implements Closeable {
|
||||
protected Closeable applyTo(ChronicleMapBuilder builder,
|
||||
Replica map, EntryExternalizable entryExternalizable) {
|
||||
if (builder.entrySize() > maxEntrySize) {
|
||||
throw new IllegalArgumentException("During ReplicatingClusterBuilder setup, " +
|
||||
throw new IllegalArgumentException("During ReplicatingChannelBuilder setup, " +
|
||||
"maxEntrySize=" + maxEntrySize + " was specified, but map with " +
|
||||
"entrySize=" + builder.entrySize() + " is attempted to apply" +
|
||||
"to the replicator");
|
||||
+28
-20
@@ -21,40 +21,48 @@ import java.io.IOException;
|
||||
/**
|
||||
* @author Rob Austin.
|
||||
*/
|
||||
public final class ReplicatingClusterBuilder {
|
||||
public final class ChannelProviderBuilder {
|
||||
|
||||
final byte identifier;
|
||||
final int maxEntrySize;
|
||||
byte identifier;
|
||||
int maxEntrySize = 1024;
|
||||
int maxNumberOfChronicles = 128;
|
||||
private UdpReplicationConfig udpReplicationConfig = null;
|
||||
private TcpReplicationConfig tcpReplicationConfig = null;
|
||||
|
||||
ReplicatingClusterBuilder(byte identifier, final int maxEntrySize) {
|
||||
this.identifier = identifier;
|
||||
|
||||
|
||||
public int maxEntrySize() {
|
||||
return maxEntrySize;
|
||||
}
|
||||
|
||||
public ChannelProviderBuilder maxEntrySize(int maxEntrySize) {
|
||||
this.maxEntrySize = maxEntrySize;
|
||||
if (identifier <= 0) {
|
||||
throw new IllegalArgumentException("Identifier must be positive, identifier=" +
|
||||
identifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChannelProviderBuilder replicators(byte identifier, Config... configs) {
|
||||
this.identifier = identifier;
|
||||
|
||||
|
||||
for (Config config : configs) {
|
||||
|
||||
if (config instanceof TcpReplicationConfig) {
|
||||
this.tcpReplicationConfig = (TcpReplicationConfig) config;
|
||||
} else if (config instanceof UdpReplicationConfig) {
|
||||
this.udpReplicationConfig = (UdpReplicationConfig) config;
|
||||
} else
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public ReplicatingClusterBuilder udpReplication(UdpReplicationConfig replicationConfig) {
|
||||
this.udpReplicationConfig = replicationConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReplicatingClusterBuilder tcpReplication(TcpReplicationConfig replicationConfig) {
|
||||
this.tcpReplicationConfig = replicationConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReplicatingClusterBuilder maxNumberOfChronicles(int maxNumberOfChronicles) {
|
||||
public ChannelProviderBuilder maxNumberOfChronicles(int maxNumberOfChronicles) {
|
||||
this.maxNumberOfChronicles = maxNumberOfChronicles;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReplicatingCluster create() throws IOException {
|
||||
final ReplicatingCluster replicatingCluster = new ReplicatingCluster(this);
|
||||
public ChannelProvider create() throws IOException {
|
||||
final ChannelProvider replicatingCluster = new ChannelProvider(this);
|
||||
if (tcpReplicationConfig != null) {
|
||||
final TcpReplicator tcpReplicator = new TcpReplicator(
|
||||
replicatingCluster.asReplica,
|
||||
@@ -27,9 +27,12 @@ import net.openhft.chronicle.map.serialization.MetaProvider;
|
||||
import net.openhft.chronicle.map.threadlocal.Provider;
|
||||
import net.openhft.chronicle.map.threadlocal.ThreadLocalCopies;
|
||||
import net.openhft.lang.Maths;
|
||||
import net.openhft.lang.io.*;
|
||||
import net.openhft.lang.io.ByteBufferBytes;
|
||||
import net.openhft.lang.io.Bytes;
|
||||
import net.openhft.lang.io.BytesStore;
|
||||
import net.openhft.lang.io.DirectStore;
|
||||
import net.openhft.lang.io.serialization.*;
|
||||
import net.openhft.lang.io.serialization.impl.*;
|
||||
import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
|
||||
import net.openhft.lang.model.Byteable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
@@ -44,8 +47,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import static net.openhft.chronicle.map.Objects.builderEquals;
|
||||
|
||||
/**
|
||||
* {@code ChronicleMapBuilder} manages the whole set of {@link ChronicleMap} configurations, could
|
||||
* be used as a classic builder and/or factory. This means that in addition to the standard builder
|
||||
* {@code ChronicleMapBuilder} manages the whole set of {@link ChronicleMap} configurations, could be used as
|
||||
* a classic builder and/or factory. This means that in addition to the standard builder
|
||||
* usage pattern: <pre>{@code
|
||||
* ChronicleMap<Key, Value> map = ChronicleMapBuilder
|
||||
* .of(Key.class, Value.class)
|
||||
@@ -63,25 +66,22 @@ import static net.openhft.chronicle.map.Objects.builderEquals;
|
||||
*
|
||||
* <p>Use static {@link #of(Class, Class)} method to obtain a {@code ChronicleMapBuilder} instance.
|
||||
*
|
||||
* <p>{@code ChronicleMapBuilder} is mutable. Configuration methods mutate the builder and
|
||||
* return <i>the builder itself</i> back to support chaining pattern, rather than the builder copies
|
||||
* with the corresponding configuration changed. To make an independent configuration,
|
||||
* {@linkplain #clone} the builder.
|
||||
* <p>{@code ChronicleMapBuilder} is mutable. Configuration methods mutate the builder and return <i>the
|
||||
* builder itself</i> back to support chaining pattern, rather than the builder copies with the corresponding
|
||||
* configuration changed. To make an independent configuration, {@linkplain #clone} the builder.
|
||||
*
|
||||
* <p>Later in this documentation, "ChronicleMap" means
|
||||
* "ChronicleMaps, created by {@code ChronicleMapBuilder}", unless specified different, because
|
||||
* theoretically someone might provide {@code ChronicleMap} implementations with completely
|
||||
* different properties.
|
||||
* <p>Later in this documentation, "ChronicleMap" means "ChronicleMaps, created by {@code
|
||||
* ChronicleMapBuilder}", unless specified different, because theoretically someone might provide {@code
|
||||
* ChronicleMap} implementations with completely different properties.
|
||||
*
|
||||
* <p>{@code ChronicleMap} ("ChronicleMaps, created by {@code ChronicleMapBuilder}") currently
|
||||
* doesn't support resizing. That is why you should <i>always</i> configure {@linkplain
|
||||
* #entries(long) number of entries} you are going to insert into the created map <i>at most</i>.
|
||||
* See {@link #entries(long)} method documentation for more information on this.
|
||||
* <p>{@code ChronicleMap} ("ChronicleMaps, created by {@code ChronicleMapBuilder}") currently doesn't support
|
||||
* resizing. That is why you should <i>always</i> configure {@linkplain #entries(long) number of entries} you
|
||||
* are going to insert into the created map <i>at most</i>. See {@link #entries(long)} method documentation
|
||||
* for more information on this.
|
||||
*
|
||||
* <p>{@code ChronicleMap} allocates memory by equally sized chunks. This size is called
|
||||
* {@linkplain #entrySize(int) entry size}, you are strongly recommended to configure it to achieve
|
||||
* least memory consumption and best speed. See {@link #entrySize(int)} method documentation for
|
||||
* more information on this.
|
||||
* <p>{@code ChronicleMap} allocates memory by equally sized chunks. This size is called {@linkplain
|
||||
* #entrySize(int) entry size}, you are strongly recommended to configure it to achieve least memory
|
||||
* consumption and best speed. See {@link #entrySize(int)} method documentation for more information on this.
|
||||
*
|
||||
* @param <K> key type of the maps, produced by this builder
|
||||
* @param <V> value type of the maps, produced by this builder
|
||||
@@ -94,11 +94,12 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
|
||||
public static final short UDP_REPLICATION_MODIFICATION_ITERATOR_ID = 128;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChronicleMapBuilder.class.getName());
|
||||
|
||||
SerializationBuilder<K> keyBuilder;
|
||||
SerializationBuilder<V> valueBuilder;
|
||||
Replicator firstReplicator;
|
||||
Map<Class<? extends Replicator>, Replicator> replicators = new HashMap<Class<? extends Replicator>, Replicator>();
|
||||
boolean forceReplicatedImpl = false;
|
||||
|
||||
private Map<Class<? extends Replicator>, Replicator> replicators = new HashMap<Class<? extends Replicator>, Replicator>();
|
||||
|
||||
// used when configuring the number of segments.
|
||||
private int minSegments = -1;
|
||||
private int actualSegments = -1;
|
||||
@@ -126,6 +127,7 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
MapEventListeners.nop();
|
||||
private V defaultValue = null;
|
||||
private DefaultValueProvider<K, V> defaultValueProvider = null;
|
||||
private byte identifier = -1;
|
||||
|
||||
ChronicleMapBuilder(Class<K> keyClass, Class<V> valueClass) {
|
||||
keyBuilder = new SerializationBuilder<K>(keyClass, SerializationBuilder.Role.KEY);
|
||||
@@ -156,6 +158,7 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ChronicleMapBuilder<K, V> minSegments(int minSegments) {
|
||||
this.minSegments = minSegments;
|
||||
@@ -185,9 +188,9 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
* .keySize(10)
|
||||
* // shouldn't specify valueSize(), because it is statically known
|
||||
* .create();}</pre>
|
||||
* (Note that 10 is chosen as key size in bytes despite strings in Java are UTF-16 encoded
|
||||
* (and each character takes 2 bytes on-heap), because default off-heap {@link String} encoding
|
||||
* is UTF-8 in {@code ChronicleMap}.)
|
||||
* (Note that 10 is chosen as key size in bytes despite strings in Java are UTF-16 encoded (and each
|
||||
* character takes 2 bytes on-heap), because default off-heap {@link String} encoding is UTF-8 in {@code
|
||||
* ChronicleMap}.)
|
||||
*
|
||||
* @see #constantKeySizeBySample(Object)
|
||||
* @see #valueSize(int)
|
||||
@@ -224,17 +227,16 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 or {@link Byteable} subclass, 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 or {@link Byteable} subclass, 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 ChronicleMapBuilder} back
|
||||
@@ -249,15 +251,15 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 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
|
||||
@@ -286,18 +288,18 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>In fully default case you can expect entry size to be about 256 bytes. But it is strongly
|
||||
* recommended always to configure {@linkplain #keySize(int) key size} and
|
||||
* {@linkplain #valueSize(int) value size}, if they couldn't be derived statically.
|
||||
* recommended always to configure {@linkplain #keySize(int) key size} and {@linkplain #valueSize(int)
|
||||
* value size}, if they couldn't be derived statically.
|
||||
*
|
||||
* <p>If entry size is not configured explicitly by calling this method, it is computed
|
||||
* based on {@linkplain #metaDataBytes(int) meta data bytes}, plus {@linkplain #keySize(int) key
|
||||
* size}, plus {@linkplain #valueSize(int) value size}, plus a few bytes required by
|
||||
* implementations, with respect to {@linkplain #entryAndValueAlignment(Alignment) alignment}.
|
||||
* <p>If entry size is not configured explicitly by calling this method, it is computed based on
|
||||
* {@linkplain #metaDataBytes(int) meta data bytes}, plus {@linkplain #keySize(int) key size}, plus
|
||||
* {@linkplain #valueSize(int) value size}, plus a few bytes required by implementations, 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,
|
||||
* the actual entry size will be 32 (30 aligned to 4 bytes). If you don't want entry size
|
||||
* to be aligned, set {@code entryAndValueAlignment(Alignment.NO_ALIGNMENT)}.
|
||||
* #entryAndValueAlignment(Alignment) entry alignment}). I. e. if you set entry size to 30, the actual
|
||||
* entry size will be 32 (30 aligned to 4 bytes). If you don't want entry size to be aligned, set {@code
|
||||
* entryAndValueAlignment(Alignment.NO_ALIGNMENT)}.
|
||||
*
|
||||
* @see #entryAndValueAlignment(Alignment)
|
||||
* @see #entries(long)
|
||||
@@ -317,7 +319,7 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
int keySize = keySize();
|
||||
size += keyBuilder.sizeMarshaller().sizeEncodingSize(keySize);
|
||||
size += keySize;
|
||||
if (replicatedImpl())
|
||||
if (useReplication())
|
||||
size += ReplicatedChronicleMap.ADDITIONAL_ENTRY_BYTES;
|
||||
int valueSize = valueSize();
|
||||
size += valueBuilder.sizeMarshaller().sizeEncodingSize(valueSize);
|
||||
@@ -339,16 +341,16 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*
|
||||
@@ -406,7 +408,6 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
return (int) Maths.nextPower2(Math.max((entries >> 30) + 1, minSegments()), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleMapBuilder<K, V> lockTimeOut(long lockTimeOut, TimeUnit unit) {
|
||||
this.lockTimeOut = lockTimeOut;
|
||||
lockTimeOutUnit = unit;
|
||||
@@ -428,20 +429,20 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures if the maps created by this builder should return {@code null} instead of previous
|
||||
* mapped values on {@link ChronicleMap#put(Object, Object) ChornicleMap.put(key, value)} calls.
|
||||
* Configures if the maps created by this builder should return {@code null} instead of previous mapped
|
||||
* values on {@link ChronicleMap#put(Object, Object) ChornicleMap.put(key, value)} calls.
|
||||
*
|
||||
* <p>{@link Map#put(Object, Object) Map.put()} returns the previous value, functionality which
|
||||
* is rarely used but fairly cheap for {@link HashMap}. In the case, for an off heap collection,
|
||||
* it has to create a new object and deserialize the data from off-heap memory. It's expensive
|
||||
* for something you probably don't use.
|
||||
* <p>{@link Map#put(Object, Object) Map.put()} returns the previous value, functionality which is rarely
|
||||
* used but fairly cheap for {@link HashMap}. In the case, for an off heap collection, it has to create a
|
||||
* new object and deserialize the data from off-heap memory. It's expensive for something you probably
|
||||
* don't use.
|
||||
*
|
||||
* <p>By default, of cause, {@code ChronicleMap} conforms the general {@code Map} contract
|
||||
* and returns the previous mapped value on {@code put()} calls.
|
||||
* <p>By default, of cause, {@code ChronicleMap} conforms the general {@code Map} contract and returns the
|
||||
* previous mapped value on {@code put()} calls.
|
||||
*
|
||||
* @param putReturnsNull {@code true} if you want {@link ChronicleMap#put(Object, Object)
|
||||
* ChronicleMap.put()} to not return the value that was replaced
|
||||
* but instead return {@code null}
|
||||
* ChronicleMap.put()} to not return the value that was replaced but instead return
|
||||
* {@code null}
|
||||
* @return an instance of the map builder back
|
||||
* @see #removeReturnsNull(boolean)
|
||||
*/
|
||||
@@ -455,17 +456,17 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures if the maps created by this builder should return {@code null} instead of
|
||||
* the last mapped value on {@link ChronicleMap#remove(Object) ChronicleMap.remove(key)} calls.
|
||||
* Configures if the maps created by this builder should return {@code null} instead of the last mapped
|
||||
* value on {@link ChronicleMap#remove(Object) ChronicleMap.remove(key)} calls.
|
||||
*
|
||||
* <p>{@link Map#remove(Object) Map.remove()} returns the previous value, functionality which
|
||||
* is rarely used but fairly cheap for {@link HashMap}. In the case, for an off heap collection,
|
||||
* it has to create a new object and deserialize the data from off-heap memory. It's expensive
|
||||
* for something you probably don't use.
|
||||
* <p>{@link Map#remove(Object) Map.remove()} returns the previous value, functionality which is rarely
|
||||
* used but fairly cheap for {@link HashMap}. In the case, for an off heap collection, it has to create a
|
||||
* new object and deserialize the data from off-heap memory. It's expensive for something you probably
|
||||
* don't use.
|
||||
*
|
||||
* @param removeReturnsNull {@code true} if you want {@link ChronicleMap#remove(Object)
|
||||
* ChronicleMap.remove()} to not return the value of the removed entry
|
||||
* but instead return {@code null}
|
||||
* ChronicleMap.remove()} to not return the value of the removed entry but
|
||||
* instead return {@code null}
|
||||
* @return an instance of the map builder back
|
||||
* @see #putReturnsNull(boolean)
|
||||
*/
|
||||
@@ -496,6 +497,7 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
int metaDataBytes() {
|
||||
return metaDataBytes;
|
||||
}
|
||||
@@ -549,32 +551,23 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleMapBuilder<K, V> addReplicator(Replicator replicator) {
|
||||
if (firstReplicator == null) {
|
||||
firstReplicator = replicator;
|
||||
replicators.put(replicator.getClass(), replicator);
|
||||
} else {
|
||||
if (replicator.identifier() != firstReplicator.identifier()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Identifiers of all replicators of the map should be the same");
|
||||
}
|
||||
if (replicators.containsKey(replicator.getClass())) {
|
||||
throw new IllegalArgumentException("Replicator of " + replicator.getClass() +
|
||||
" class has already to the map");
|
||||
}
|
||||
replicators.put(replicator.getClass(), replicator);
|
||||
public ChronicleMapBuilder<K, V> replicators(byte identifier, Replicator... replicators) {
|
||||
|
||||
this.identifier = identifier;
|
||||
this.replicators.clear();
|
||||
for (Replicator replicator : replicators) {
|
||||
this.replicators.put(replicator.getClass(), replicator);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleMapBuilder<K, V> setReplicators(Replicator... replicators) {
|
||||
firstReplicator = null;
|
||||
|
||||
public ChronicleMapBuilder<K, V> channel(ChannelProvider.ChronicleChannel chronicleChannel) {
|
||||
this.identifier = chronicleChannel.identifier();
|
||||
this.replicators.clear();
|
||||
for (Replicator replicator : replicators) {
|
||||
addReplicator(replicator);
|
||||
}
|
||||
replicators.put(chronicleChannel.getClass(), chronicleChannel);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -613,13 +606,6 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
ChronicleMapBuilder<K, V> forceReplicatedImpl() {
|
||||
this.forceReplicatedImpl = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleMapBuilder<K, V> keyMarshaller(@NotNull BytesMarshaller<K> keyMarshaller) {
|
||||
@@ -662,19 +648,18 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the value to be put for each key queried in {@link ChronicleMap#get get()} and
|
||||
* {@link ChronicleMap#getUsing(Object, Object) getUsing()} methods, if the key is absent
|
||||
* in the map. Then this default value is returned from query method.
|
||||
* Specifies the value to be put for each key queried in {@link ChronicleMap#get get()} and {@link
|
||||
* ChronicleMap#getUsing(Object, Object) getUsing()} methods, if the key is absent in the map. Then this
|
||||
* default value is returned from query method.
|
||||
*
|
||||
* <p>Setting default value to {@code null} is interpreted as map shouldn't put any default
|
||||
* value for absent keys. This is by default.
|
||||
* <p>Setting default value to {@code null} is interpreted as map shouldn't put any default value for
|
||||
* absent keys. This is by default.
|
||||
*
|
||||
* <p>This configuration overrides any previous
|
||||
* {@link #defaultValueProvider(DefaultValueProvider)} configuration to this
|
||||
* {@code ChronicleMapBuilder}.
|
||||
* <p>This configuration overrides any previous {@link #defaultValueProvider(DefaultValueProvider)}
|
||||
* configuration to this {@code ChronicleMapBuilder}.
|
||||
*
|
||||
* @param defaultValue the default value to be put to the map for absent keys during
|
||||
* {@code get()} and {@code getUsing()} calls and returned from these calls
|
||||
* @param defaultValue the default value to be put to the map for absent keys during {@code get()} and
|
||||
* {@code getUsing()} calls and returned from these calls
|
||||
* @return this builder object back
|
||||
*/
|
||||
public ChronicleMapBuilder<K, V> defaultValue(V defaultValue) {
|
||||
@@ -684,13 +669,13 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the function to obtain a value for the key during {@link ChronicleMap#get get()}
|
||||
* and {@link ChronicleMap#getUsing(Object, Object) getUsing()} calls, if the key is absent
|
||||
* in the map. If the obtained value is non-null, it is put for the key in the map and then
|
||||
* returned from current {@code get()} or {@code getUsing()} call.
|
||||
* Specifies the function to obtain a value for the key during {@link ChronicleMap#get get()} and {@link
|
||||
* ChronicleMap#getUsing(Object, Object) getUsing()} calls, if the key is absent in the map. If the
|
||||
* obtained value is non-null, it is put for the key in the map and then returned from current {@code
|
||||
* get()} or {@code getUsing()} call.
|
||||
*
|
||||
* <p>This configuration overrides any previous {@link #defaultValue(Object)} configuration
|
||||
* to this {@code ChronicleMapBuilder}.
|
||||
* <p>This configuration overrides any previous {@link #defaultValue(Object)} configuration to this {@code
|
||||
* ChronicleMapBuilder}.
|
||||
*
|
||||
* @param defaultValueProvider the strategy to obtain a default value by the absent key
|
||||
* @return this builder object back
|
||||
@@ -778,7 +763,7 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
|
||||
private VanillaChronicleMap<K, ?, ?, V, ?, ?> newMap() throws IOException {
|
||||
preMapConstruction();
|
||||
if (!replicatedImpl()) {
|
||||
if (!useReplication()) {
|
||||
return new VanillaChronicleMap<K, Object, MetaBytesInterop<K, Object>,
|
||||
V, Object, MetaBytesWriter<V, Object>>(this);
|
||||
} else {
|
||||
@@ -787,8 +772,8 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
}
|
||||
}
|
||||
|
||||
private boolean replicatedImpl() {
|
||||
return firstReplicator != null || forceReplicatedImpl;
|
||||
private boolean useReplication() {
|
||||
return identifier != -1;
|
||||
}
|
||||
|
||||
private void preMapConstruction() {
|
||||
@@ -833,5 +818,9 @@ public class ChronicleMapBuilder<K, V> implements Cloneable,
|
||||
return (int) Math.min(Math.max(2L, entries() >> 10),
|
||||
VanillaChronicleMap.MAX_ENTRY_OVERSIZE_FACTOR);
|
||||
}
|
||||
|
||||
public byte identifier() {
|
||||
return identifier;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
/**
|
||||
* @author Rob Austin.
|
||||
*/
|
||||
public interface Config {
|
||||
}
|
||||
@@ -212,7 +212,7 @@ public class NodeDiscovery {
|
||||
return ChronicleMapBuilder.of(Integer.class,
|
||||
CharSequence.class)
|
||||
.entries(20000L)
|
||||
.addReplicator(tcp(identifier, tcpConfig)).create();
|
||||
.replicators(identifier, tcp(tcpConfig)).create();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -55,14 +55,11 @@ public interface Replica extends Closeable {
|
||||
ModificationNotifier modificationNotifier);
|
||||
|
||||
/**
|
||||
* Returns the timestamp of the last change from the specified remote node, already replicated
|
||||
* to this Replica.
|
||||
* <p/>
|
||||
* <p>Used in conjunction with replication, to back fill data from a remote node. This node
|
||||
* Returns the timestamp of the last change from the specified remote node, already replicated to this
|
||||
* Replica. <p/> <p>Used in conjunction with replication, to back fill data from a remote node. This node
|
||||
* may have missed updates while it was not been running or connected via TCP.
|
||||
*
|
||||
* @param remoteIdentifier the identifier of the remote node to check last replicated update
|
||||
* time from
|
||||
* @param remoteIdentifier the identifier of the remote node to check last replicated update time from
|
||||
* @return a timestamp of the last modification to an entry, or 0 if there are no entries.
|
||||
* @see #identifier()
|
||||
*/
|
||||
@@ -102,7 +99,7 @@ public interface Replica extends Closeable {
|
||||
* A non-blocking call that provides the entry that has changed to {@code callback.onEntry()}.
|
||||
*
|
||||
* @param callback a callback which will be called when a new entry becomes available.
|
||||
* @param chronicleId only assigned when clustering
|
||||
* @param chronicleId only assigned when using chronicle channels
|
||||
* @return {@code true} if the entry was accepted by the {@code callback.onEntry()} method, {@code
|
||||
* false} if the entry was not accepted or was not available
|
||||
*/
|
||||
@@ -111,10 +108,8 @@ public interface Replica extends Closeable {
|
||||
/**
|
||||
* Dirties all entries with a modification time equal to {@code fromTimeStamp} or newer. It means all
|
||||
* these entries will be considered as "new" by this ModificationIterator and iterated once again no
|
||||
* matter if they have already been.
|
||||
* <p/>
|
||||
* <p>This functionality is used to publish recently modified entries to a new remote node as it
|
||||
* connects.
|
||||
* matter if they have already been. <p/> <p>This functionality is used to publish recently modified
|
||||
* entries to a new remote node as it connects.
|
||||
*
|
||||
* @param fromTimeStamp the timestamp from which all entries should be dirty
|
||||
*/
|
||||
@@ -133,7 +128,7 @@ public interface Replica extends Closeable {
|
||||
* @param entry the byte location of the entry to be stored
|
||||
* @param destination a buffer the entry will be written to, the segment may reject this operation and
|
||||
* add zeroBytes, if the identifier in the entry did not match the maps local
|
||||
* @param chronicleId used in cluster into identify the canonical map or queue
|
||||
* @param chronicleId is the channel id used to identify the canonical map or queue
|
||||
*/
|
||||
void writeExternalEntry(@NotNull Bytes entry, @NotNull Bytes destination, int chronicleId);
|
||||
|
||||
@@ -180,20 +175,20 @@ public interface Replica extends Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented typically by a replicator, This interface provides the event, which will get
|
||||
* called whenever a put() or remove() has occurred to the map
|
||||
* Implemented typically by a replicator, This interface provides the event, which will get called
|
||||
* whenever a put() or remove() has occurred to the map
|
||||
*/
|
||||
abstract class EntryCallback {
|
||||
|
||||
/**
|
||||
* Called whenever a put() or remove() has occurred to a replicating map.
|
||||
*
|
||||
* @param entry the entry you will receive, this does not have to be locked,
|
||||
* as locking is already provided from the caller.
|
||||
* @param entry the entry you will receive, this does not have to be locked, as locking is
|
||||
* already provided from the caller.
|
||||
* @param chronicleId only assigned when clustering
|
||||
* @return {@code false} if this entry should be ignored because the identifier
|
||||
* of the source node is not from one of our changes, WARNING even though we check
|
||||
* the identifier in the ModificationIterator the entry may have been updated.
|
||||
* @return {@code false} if this entry should be ignored because the identifier of the source node is
|
||||
* not from one of our changes, WARNING even though we check the identifier in the
|
||||
* ModificationIterator the entry may have been updated.
|
||||
*/
|
||||
public abstract boolean onEntry(final Bytes entry, final int chronicleId);
|
||||
|
||||
|
||||
@@ -18,16 +18,16 @@ package net.openhft.chronicle.map;
|
||||
|
||||
|
||||
import net.openhft.chronicle.TimeProvider;
|
||||
import net.openhft.chronicle.map.serialization.BytesReader;
|
||||
import net.openhft.chronicle.map.serialization.MetaBytesInterop;
|
||||
import net.openhft.chronicle.map.serialization.MetaBytesWriter;
|
||||
import net.openhft.chronicle.map.threadlocal.ThreadLocalCopies;
|
||||
import net.openhft.lang.Maths;
|
||||
import net.openhft.lang.collection.ATSDirectBitSet;
|
||||
import net.openhft.lang.io.Bytes;
|
||||
import net.openhft.lang.io.MultiStoreBytes;
|
||||
import net.openhft.lang.io.NativeBytes;
|
||||
import net.openhft.chronicle.map.serialization.BytesReader;
|
||||
import net.openhft.chronicle.map.serialization.MetaBytesInterop;
|
||||
import net.openhft.chronicle.map.serialization.MetaBytesWriter;
|
||||
import net.openhft.lang.model.Byteable;
|
||||
import net.openhft.chronicle.map.threadlocal.ThreadLocalCopies;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -100,8 +100,13 @@ class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
throws IOException {
|
||||
super(builder);
|
||||
this.timeProvider = builder.timeProvider();
|
||||
Replicator firstReplicator = builder.firstReplicator;
|
||||
this.localIdentifier = firstReplicator != null ? firstReplicator.identifier() : 1;
|
||||
|
||||
this.localIdentifier = builder.identifier();
|
||||
|
||||
if (localIdentifier==-1){
|
||||
throw new IllegalStateException("localIdentifier should not be -1");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int assignedModIterBitSetSizeInBytes() {
|
||||
@@ -882,15 +887,15 @@ class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts entry. If {@code value} implements {@link Byteable} interface and
|
||||
* {@code usingValue} is {@code true}, the value is backed with the bytes of this entry.
|
||||
* Puts entry. If {@code value} implements {@link Byteable} interface and {@code usingValue} is {@code
|
||||
* true}, the value is backed with the bytes of this entry.
|
||||
*
|
||||
* @param hash2 a hash of the {@code keyBytes}. Caller was searching for the key in the
|
||||
* {@code searchedHashLookup} using this hash.
|
||||
* @param value the value to put
|
||||
* @param usingValue {@code true} if the value should be backed with the bytes of the entry,
|
||||
* if it implements {@link Byteable} interface,
|
||||
* {@code false} if it should put itself
|
||||
* if it implements {@link Byteable} interface, {@code false} if it should
|
||||
* put itself
|
||||
* @param identifier the identifier of the outer CHM node
|
||||
* @param timestamp the timestamp when the entry was put <s>(this could be later if it was a
|
||||
* remote put)</s> this method is called only from usual put or acquire
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @see Replicators
|
||||
* @see ChronicleMapBuilder#addReplicator(Replicator)
|
||||
* @see ChronicleMapBuilder#replicator(byte, Replicator)
|
||||
*/
|
||||
public abstract class Replicator {
|
||||
|
||||
@@ -31,14 +31,6 @@ public abstract class Replicator {
|
||||
protected Replicator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this node identifier within the replication topology.
|
||||
*
|
||||
* @return the unique identifier among nodes
|
||||
* @see Replica#identifier()
|
||||
*/
|
||||
public abstract byte identifier();
|
||||
|
||||
/**
|
||||
* Applies the replicator to the map instance and returns a Closeable token to manage resources,
|
||||
* associated with the replication.
|
||||
|
||||
@@ -25,13 +25,8 @@ public final class Replicators {
|
||||
private Replicators() {
|
||||
}
|
||||
|
||||
public static Replicator tcp(final byte identifier,
|
||||
final TcpReplicationConfig replicationConfig) {
|
||||
public static Replicator tcp(final TcpReplicationConfig replicationConfig) {
|
||||
return new Replicator() {
|
||||
@Override
|
||||
public byte identifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Closeable applyTo(ChronicleMapBuilder builder,
|
||||
@@ -43,13 +38,9 @@ public final class Replicators {
|
||||
};
|
||||
}
|
||||
|
||||
public static Replicator udp(final byte identifier,
|
||||
final UdpReplicationConfig replicationConfig) {
|
||||
public static Replicator udp(
|
||||
final UdpReplicationConfig replicationConfig) {
|
||||
return new Replicator() {
|
||||
@Override
|
||||
public byte identifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Closeable applyTo(ChronicleMapBuilder builder,
|
||||
|
||||
@@ -29,7 +29,7 @@ import static java.util.Collections.unmodifiableSet;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
|
||||
public class TcpReplicationConfig {
|
||||
public class TcpReplicationConfig implements Config {
|
||||
|
||||
private static final int DEFAULT_PACKET_SIZE = 1024 * 8;
|
||||
private static final long DEFAULT_HEART_BEAT_INTERVAL = 20;
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
|
||||
|
||||
public abstract class UdpReplicationConfig {
|
||||
public abstract class UdpReplicationConfig implements Config {
|
||||
|
||||
/**
|
||||
* Package-private constructor forbids subclassing from outside of the package
|
||||
@@ -37,7 +37,6 @@ public abstract class UdpReplicationConfig {
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
|
||||
|
||||
return create(address, port, null, ThrottlingConfig.noThrottling());
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ public class ChronicleSetBuilder<E>
|
||||
ChronicleSetBuilder(Class<E> keyClass) {
|
||||
chronicleMapBuilder = ChronicleMapBuilder.of(keyClass, DummyValue.class)
|
||||
.entryAndValueAlignment(Alignment.NO_ALIGNMENT)
|
||||
.valueMarshallerAndFactory(DummyValueMarshaller.INSTANCE, NullObjectFactory.of());
|
||||
.valueMarshallerAndFactory(DummyValueMarshaller.INSTANCE,
|
||||
NullObjectFactory.<DummyValue>of());
|
||||
}
|
||||
|
||||
public static <K> ChronicleSetBuilder<K> of(Class<K> keyClass) {
|
||||
@@ -85,7 +86,8 @@ public class ChronicleSetBuilder<E>
|
||||
* .entries(50000)
|
||||
* .keySize(10)
|
||||
* .create();}</pre>
|
||||
* (Note that 10 is chosen as key size in bytes despite strings in Java are UTF-16 encoded
|
||||
*
|
||||
* <p>(Note that 10 is chosen as key size in bytes despite strings in Java are UTF-16 encoded
|
||||
* (and each character takes 2 bytes on-heap), because default off-heap {@link String} encoding
|
||||
* is UTF-8 in {@code ChronicleSet}.)
|
||||
*
|
||||
@@ -121,9 +123,9 @@ public class ChronicleSetBuilder<E>
|
||||
* strongly recommended always to configure {@linkplain #keySize(int) key size},
|
||||
* if they couldn't be derived statically.
|
||||
*
|
||||
* <p>If entry size is not configured explicitly by calling this method, it is computed
|
||||
* based on {@linkplain #metaDataBytes(int) meta data bytes}, plus {@linkplain #keySize(int) key
|
||||
* size}, plus a few bytes required by implementations.
|
||||
* <p>If entry size is not configured explicitly by calling this method, it is computed based on
|
||||
* {@linkplain #metaDataBytes(int) meta data bytes}, plus {@linkplain #keySize(int) key size},
|
||||
* plus a few bytes required by implementations.
|
||||
*/
|
||||
@Override
|
||||
public ChronicleSetBuilder<E> entrySize(int entrySize) {
|
||||
@@ -161,6 +163,12 @@ public class ChronicleSetBuilder<E>
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleSetBuilder<E> replicators(byte identifier, Replicator... replicators) {
|
||||
chronicleMapBuilder.replicators(identifier, replicators);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return " ChronicleSetBuilder{" +
|
||||
@@ -181,15 +189,11 @@ public class ChronicleSetBuilder<E>
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
public ChronicleSetBuilder<E> addReplicator(Replicator replicator) {
|
||||
chronicleMapBuilder.addReplicator(replicator);
|
||||
public ChronicleSetBuilder<E> replicators(byte identifier, Replicator replicator) {
|
||||
chronicleMapBuilder.replicators(identifier, replicator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChronicleSetBuilder<E> setReplicators(Replicator... replicators) {
|
||||
chronicleMapBuilder.setReplicators(replicators);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronicleSetBuilder<E> timeProvider(TimeProvider timeProvider) {
|
||||
|
||||
Reference in New Issue
Block a user