From 77cb5be05cbcb8dbe03704c9428193f2c69c227f Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 17:11:47 +0100 Subject: [PATCH] HCOLL-163 Initial checking of - ( Move the identifier configuration from TCP/UDP Replication, back to the builder.), more on this JIRA coming soon... --- .../chronicle/map/ChronicleMapBuilder.java | 361 ++++++++---------- .../openhft/chronicle/map/NodeDiscovery.java | 2 +- .../chronicle/map/ReplicatedChronicleMap.java | 25 +- .../chronicle/map/ReplicatingCluster.java | 6 +- .../net/openhft/chronicle/map/Replicator.java | 10 +- .../openhft/chronicle/map/Replicators.java | 15 +- .../chronicle/set/ChronicleSetBuilder.java | 8 +- .../net/openhft/chronicle/map/Builder.java | 2 +- .../chronicle/map/ClusterReplicationTest.java | 8 +- .../map/PostClusterMapCreationTest.java | 13 +- .../map/ReplicatedChronicleMapTest.java | 19 +- .../chronicle/map/SingleMapClusterTest.java | 4 +- ...cketReplicationTest3wayPutReturnsNull.java | 2 +- .../map/TimeBasedReplicationTests.java | 46 +-- .../map/TwoMapOnDifferentServers.java | 4 +- .../map/UDPSocketReplicationTest.java | 2 +- .../SetForTCPSocketReplicationTest3way.java | 2 +- 17 files changed, 244 insertions(+), 285 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index 64d52cfc0..d35f0857f 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -22,9 +22,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; @@ -34,7 +37,6 @@ import java.io.*; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import static net.openhft.chronicle.map.Objects.builderEquals; @@ -48,9 +50,9 @@ public class ChronicleMapBuilder implements Cloneable { private static final Logger LOG = LoggerFactory.getLogger(ChronicleMapBuilder.class.getName()); SerializationBuilder keyBuilder; SerializationBuilder valueBuilder; - Replicator firstReplicator; + Map, Replicator> replicators = new HashMap, Replicator>(); - boolean forceReplicatedImpl = false; + // used when configuring the number of segments. private int minSegments = -1; private int actualSegments = -1; @@ -78,6 +80,7 @@ public class ChronicleMapBuilder implements Cloneable { MapEventListeners.nop(); private V defaultValue = null; private DefaultValueProvider defaultValueProvider = null; + private byte identifier = -1; ChronicleMapBuilder(Class keyClass, Class valueClass) { keyBuilder = new SerializationBuilder(keyClass, SerializationBuilder.Role.KEY); @@ -109,8 +112,7 @@ public class ChronicleMapBuilder implements Cloneable { } /** - * Set minimum number of segments. See concurrencyLevel - * in {@link java.util.concurrent.ConcurrentHashMap}. + * Set minimum number of segments. See concurrencyLevel in {@link java.util.concurrent.ConcurrentHashMap}. * * @param minSegments the minimum number of segments in maps, constructed by this builder * @return this builder object back @@ -133,14 +135,13 @@ public class ChronicleMapBuilder implements Cloneable { } /** - * Configures the optimal number of bytes, taken by serialized form of keys, put into maps, - * created by this builder. If key size is always the same, call - * {@link #constantKeySizeBySample(Object)} method instead of this one. + * Configures the optimal number of bytes, taken by serialized form of keys, put into maps, created by + * this builder. If key size is always the same, call {@link #constantKeySizeBySample(Object)} method + * instead of this one. * - *

If key size varies moderately, specify the size higher than average, but lower than - * the maximum possible, to minimize average memory overuse. If key size varies in a wide range, - * it's better to use {@linkplain #entrySize(int) entry size} in "chunk" mode and configure it - * directly. + *

If key size varies moderately, specify the size higher than average, but lower than the maximum + * possible, to minimize average memory overuse. If key size varies in a wide range, it's better to use + * {@linkplain #entrySize(int) entry size} in "chunk" mode and configure it directly. * *

Example: if keys in your map(s) are English words in {@link String} form, keys size 10 * (a bit more than average English word length) would be a good choice:

{@code
@@ -150,9 +151,9 @@ public class ChronicleMapBuilder implements Cloneable {
      *     .keySize(10)
      *     // shouldn't specify valueSize(), because it is statically known
      *     .create();}
- * (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}.) * * @param keySize number of bytes, taken by serialized form of keys * @return this {@code ChronicleMapBuilder} back @@ -168,9 +169,9 @@ public class ChronicleMapBuilder implements Cloneable { } /** - * Configures the constant number of bytes, taken by serialized form of keys, put into maps, - * created by this builder. This is done by providing the {@code sampleKey}, all keys 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 keys, put into maps, created by + * this builder. This is done by providing the {@code sampleKey}, all keys should take the same number of + * bytes in serialized form, as this sample object. * *

For example, if your keys are Git commit hashes:

{@code
      * Map gitCommitMessagesByHash =
@@ -179,11 +180,11 @@ public class ChronicleMapBuilder implements Cloneable {
      *     .create();
      * }
* - *

If keys are of boxed primitive type or {@link Byteable} subclass, i. e. if key size - * is known statically, it is automatically accounted and this method shouldn't be called. + *

If keys are of boxed primitive type or {@link Byteable} subclass, i. e. if key size is known + * statically, it is automatically accounted and this method shouldn't be called. * - *

If key size varies, method {@link #keySize(int)} or {@link #entrySize(int)} should be - * called instead of this one. + *

If key size varies, method {@link #keySize(int)} or {@link #entrySize(int)} should be called instead + * of this one. * * @param sampleKey the sample key * @return this builder back @@ -200,17 +201,16 @@ public class ChronicleMapBuilder 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. * - *

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. + *

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. * - *

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. + *

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 @@ -225,15 +225,15 @@ public class ChronicleMapBuilder 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. * - *

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. + *

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. * - *

If value size varies, method {@link #valueSize(int)} or {@link #entrySize(int)} should be - * called instead of this one. + *

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 @@ -259,60 +259,50 @@ public class ChronicleMapBuilder implements Cloneable { } /** - * Configures the size in bytes of allocation unit of {@code ChronicleMap} instances, created by - * this builder. + * Configures the size in bytes of allocation unit of {@code ChronicleMap} instances, created by this + * builder. * - *

{@code ChronicleMap} stores it's data off-heap, so it is required to serialize - * key and values (unless they are direct {@link Byteable} instances). Serialized key bytes + - * serialized value bytes + some metadata bytes comprise "entry space", which - * {@code ChronicleMap} should allocate. So entry size is a minimum allocation portion - * in the maps, created by this builder. E. g. if entry size is 100, the created map could only - * allocate 100, 200, 300... bytes for an entry. If say 150 bytes of entry space are required - * by the entry, 200 bytes will be allocated, 150 used and 50 wasted. To minimize memory overuse - * and improve speed, you should pay decent attention to this configuration. + *

{@code ChronicleMap} stores it's data off-heap, so it is required to serialize key and values + * (unless they are direct {@link Byteable} instances). Serialized key bytes + serialized value bytes + + * some metadata bytes comprise "entry space", which {@code ChronicleMap} should allocate. So entry + * size is a minimum allocation portion in the maps, created by this builder. E. g. if entry size is + * 100, the created map could only allocate 100, 200, 300... bytes for an entry. If say 150 bytes of entry + * space are required by the entry, 200 bytes will be allocated, 150 used and 50 wasted. To minimize + * memory overuse and improve speed, you should pay decent attention to this configuration. * *

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. * - *

If entry size is not {@linkplain #entrySize(int) configured} explicitly, it is computed - * based on {@linkplain #metaDataBytes() 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}. + *

If entry size is not {@linkplain #entrySize(int) configured} explicitly, it is computed based on + * {@linkplain #metaDataBytes() 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}. * - *

There are three major patterns of this configuration usage: - *

    - *
  1. Key and value sizes are constant. Configure them via {@link #constantKeySizeBySample( - * Object)} and {@link #constantValueSizeBySample(Object)} methods, and you will experience - * no memory waste at all.
  2. - *
  3. Key and/or value size varies moderately. Specify them using corresponding methods, - * or {@linkplain #entrySize(int) specify entry size} directly, by values somewhere between - * average and maximum possible. The idea is to have most (90% or more) entries to fit - * a single "entry size" with moderate memory waste (10-20% on average), rest 10% or less of - * entries should take 2 "entry sizes", thus with ~50% memory overuse.
  4. - *
  5. Key and/or value size varies in a wide range. Then it's best to use entry size - * configuration in chunk mode. Specify entry size so that most entries should take - * from 5 to several dozens of "chunks". With this approach, average memory waste should be - * very low. + *

    There are three major patterns of this configuration usage:

    1. Key and value sizes are + * constant. Configure them via {@link #constantKeySizeBySample(Object)} and {@link + * #constantValueSizeBySample(Object)} methods, and you will experience no memory waste at all.
    2. + *
    3. Key and/or value size varies moderately. Specify them using corresponding methods, or {@linkplain + * #entrySize(int) specify entry size} directly, by values somewhere between average and maximum possible. + * The idea is to have most (90% or more) entries to fit a single "entry size" with moderate memory waste + * (10-20% on average), rest 10% or less of entries should take 2 "entry sizes", thus with ~50% memory + * overuse.
    4. Key and/or value size varies in a wide range. Then it's best to use entry size + * configuration in chunk mode. Specify entry size so that most entries should take from 5 to + * several dozens of "chunks". With this approach, average memory waste should be very low. * - *

      However, remember that - *

        - *
      • Operations with entries that span several "entry sizes" are a bit slower, than - * entries which take a single "entry size". That is why "chunk" approach - * is not recommended, when key and/or value size varies moderately.
      • - *
      • The maximum number of chunks could be taken by an entry is 64. - * {@link IllegalArgumentException} is thrown on attempt to insert too large entry, - * compared to the configured or computed entry size.
      • - *
      • The number of "entries" {@linkplain #entries(long) in the whole map} and - * {@linkplain #actualEntriesPerSegment(int) per segment} is actually the number - * "chunks".
      • - *
      + *

      However, remember that

      • Operations with entries that span several "entry sizes" are a bit + * slower, than entries which take a single "entry size". That is why "chunk" approach is not recommended, + * when key and/or value size varies moderately.
      • The maximum number of chunks could be taken by + * an entry is 64. {@link IllegalArgumentException} is thrown on attempt to insert too large entry, + * compared to the configured or computed entry size.
      • The number of "entries" {@linkplain + * #entries(long) in the whole map} and {@linkplain #actualEntriesPerSegment(int) per segment} is actually + * the number "chunks".
      * - *

      Example: if values in your map are adjacency lists of some social graph, where nodes - * are represented as {@code long} ids, and adjacency lists are serialized in efficient - * manner, for example as {@code long[]} arrays. Typical number of connections is 100-300, - * maximum is 3000. In this case entry size of 50 * (8 bytes for each id) = 400 bytes would - * be a good choice:

      {@code
      +     * 

      Example: if values in your map are adjacency lists of some social graph, where nodes are represented + * as {@code long} ids, and adjacency lists are serialized in efficient manner, for example as {@code + * long[]} arrays. Typical number of connections is 100-300, maximum is 3000. In this case entry size of + * 50 * (8 bytes for each id) = 400 bytes would + * be a good choice:

      {@code
            * Map socialGraph = ChronicleMapBuilder
            *     .of(Long.class, long[].class)
            *     // given that graph should have of 1 billion nodes, and 150 average adjacency list size
      @@ -320,16 +310,13 @@ public class ChronicleMapBuilder implements Cloneable {
            *     .entries(1_000_000_000L * (150 / 50))
            *     .entrySize(50 * 8)
            *     .create();}
      - * It is minimum possible (because 3000 friends / 50 friends = 60 is close to 64 "max - * chunks by single entry" limit, and ensures moderate average memory overuse (not more - * than 20%). - *
    5. - *
    + * It is minimum possible (because 3000 friends / 50 friends = 60 is close to 64 "max chunks by single + * entry" limit, and ensures moderate average memory overuse (not more than 20%).
* *

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)}. * * @param entrySize the size in bytes * @return this {@code ChronicleMapBuilder} back @@ -350,7 +337,7 @@ public class ChronicleMapBuilder 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); @@ -372,16 +359,16 @@ public class ChronicleMapBuilder 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. * - *

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. + *

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. * - *

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). + *

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). * *

Default is {@link Alignment#OF_4_BYTES}. * @@ -398,32 +385,28 @@ public class ChronicleMapBuilder implements Cloneable { } /** - * Configures the maximum number of {@linkplain #entrySize(int) "entry size chunks"}, which - * could be taken by the maximum number of entries, inserted into the maps, created by this - * builder. If you try to insert more data, {@link IllegalStateException} might be thrown, - * because currently {@code ChronicleMap} doesn't support resizing. + * Configures the maximum number of {@linkplain #entrySize(int) "entry size chunks"}, which could be taken + * by the maximum number of entries, inserted into the maps, created by this builder. If you try to insert + * more data, {@link IllegalStateException} might be thrown, because currently {@code ChronicleMap} + * doesn't support resizing. * - *

    - *
  1. If key and value sizes are constant, this number is equal to the maximum number - * of entries (because each entry takes exactly one "entry size" memory unit).
  2. - *
  3. If key and/or value size varies moderately, you should pass to this method - * the maximum number of entries + 5-25%, depending on your data properties and configured - * {@linkplain #keySize(int) key}/{@linkplain #valueSize(int) value}/{@linkplain - * #entrySize(int) entry} sizes.
  4. - *
  5. If your data size varies in a wide range, pass the maximum number of entries - * multiplied by average data size and divided by the configured "entry size" (i. e. chunk - * size). See an example in the documentation to {@link #entrySize(int)} method.
  6. + *
    1. If key and value sizes are constant, this number is equal to the maximum number of entries + * (because each entry takes exactly one "entry size" memory unit).
    2. If key and/or value size + * varies moderately, you should pass to this method the maximum number of entries + 5-25%, depending on + * your data properties and configured {@linkplain #keySize(int) key}/{@linkplain #valueSize(int) + * value}/{@linkplain #entrySize(int) entry} sizes.
    3. If your data size varies in a wide range, + * pass the maximum number of entries multiplied by average data size and divided by the configured "entry + * size" (i. e. chunk size). See an example in the documentation to {@link #entrySize(int)} method.
    4. *
    * - *

    You shouldn't put additional margin over the number, computed according the rules above. - * This bad practice was popularized by {@link HashMap#HashMap(int)} constructor, which accept - * "capacity", that should be multiplied by "load factor" to obtain actual maximum expected - * number of entries. {@code ChronicleMap} doesn't have a notion of load factor. + *

    You shouldn't put additional margin over the number, computed according the rules above. This bad + * practice was popularized by {@link HashMap#HashMap(int)} constructor, which accept "capacity", that + * should be multiplied by "load factor" to obtain actual maximum expected number of entries. {@code + * ChronicleMap} doesn't have a notion of load factor. * *

    Default value is 2^20 (~ 1 million). * - * @param entries maximum size of the created maps, in memory allocation units, - * so-called "entry size" + * @param entries maximum size of the created maps, in memory allocation units, so-called "entry size" * @return this builder back * @see #entrySize(int) */ @@ -486,20 +469,20 @@ public class ChronicleMapBuilder 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. * - *

    {@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. + *

    {@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. * - *

    By default, of cause, {@code ChronicleMap} conforms the general {@code Map} contract - * and returns the previous mapped value on {@code put()} calls. + *

    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) */ @@ -513,17 +496,17 @@ public class ChronicleMapBuilder 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. * - *

    {@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. + *

    {@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) */ @@ -605,30 +588,23 @@ public class ChronicleMapBuilder implements Cloneable { return toString().hashCode(); } - public ChronicleMapBuilder 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 replicators(byte identifier, Replicator... replicators) { + + this.identifier = identifier; + this.replicators.clear(); + for (Replicator replicator : replicators) { + this.replicators.put(replicator.getClass(), replicator); } + return this; } - public ChronicleMapBuilder setReplicators(Replicator... replicators) { - firstReplicator = null; + + public ChronicleMapBuilder channel(ReplicatingCluster.ChronicleChannel replicator) { + this.identifier = replicator.identifier(); this.replicators.clear(); - for (Replicator replicator : replicators) { - addReplicator(replicator); - } + replicators.put(replicator.getClass(), replicator); + return this; } @@ -664,27 +640,19 @@ public class ChronicleMapBuilder implements Cloneable { return this; } - /** - * For testing - */ - ChronicleMapBuilder forceReplicatedImpl() { - this.forceReplicatedImpl = true; - return this; - } - public ChronicleMapBuilder keyMarshaller(@NotNull BytesMarshaller keyMarshaller) { keyBuilder.marshaller(keyMarshaller, null); return this; } /** - * Specifies that key objects, queried with the maps created by this builder, are inherently - * immutable. Keys in {@code ChronicleMap} are not required to be immutable, as in ordinary - * {@link Map} implementations, because they are serialized off-heap. However, - * {@code ChronicleMap} implementations can benefit from the knowledge that keys are not mutated - * between queries. By default, {@code ChronicleMapBuilder} detects immutability automatically - * only for very few standard JDK types (for example, for {@link String}), it is not recommended - * to rely on {@code ChronicleMapBuilder} to be smart enough about this. + * Specifies that key objects, queried with the maps created by this builder, are inherently immutable. + * Keys in {@code ChronicleMap} are not required to be immutable, as in ordinary {@link Map} + * implementations, because they are serialized off-heap. However, {@code ChronicleMap} implementations + * can benefit from the knowledge that keys are not mutated between queries. By default, {@code + * ChronicleMapBuilder} detects immutability automatically only for very few standard JDK types (for + * example, for {@link String}), it is not recommended to rely on {@code ChronicleMapBuilder} to be smart + * enough about this. * * @return this builder back */ @@ -715,19 +683,18 @@ public class ChronicleMapBuilder 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. * - *

    Setting default value to {@code null} is interpreted as map shouldn't put any default - * value for absent keys. This is by default. + *

    Setting default value to {@code null} is interpreted as map shouldn't put any default value for + * absent keys. This is by default. * - *

    This configuration overrides any previous - * {@link #defaultValueProvider(DefaultValueProvider)} configuration to this - * {@code ChronicleMapBuilder}. + *

    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 defaultValue(V defaultValue) { @@ -737,13 +704,13 @@ public class ChronicleMapBuilder 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. * - *

    This configuration overrides any previous {@link #defaultValue(Object)} configuration - * to this {@code ChronicleMapBuilder}. + *

    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 @@ -829,7 +796,7 @@ public class ChronicleMapBuilder implements Cloneable { private VanillaChronicleMap newMap() throws IOException { preMapConstruction(); - if (!replicatedImpl()) { + if (!useReplication()) { return new VanillaChronicleMap, V, Object, MetaBytesWriter>(this); } else { @@ -838,8 +805,8 @@ public class ChronicleMapBuilder implements Cloneable { } } - private boolean replicatedImpl() { - return firstReplicator != null || forceReplicatedImpl; + private boolean useReplication() { + return identifier != -1; } private void preMapConstruction() { @@ -884,5 +851,9 @@ public class ChronicleMapBuilder implements Cloneable { return (int) Math.min(Math.max(2L, entries() >> 10), VanillaChronicleMap.MAX_ENTRY_OVERSIZE_FACTOR); } + + public byte identifier() { + return identifier; + } } diff --git a/src/main/java/net/openhft/chronicle/map/NodeDiscovery.java b/src/main/java/net/openhft/chronicle/map/NodeDiscovery.java index 90b15382b..26736295c 100644 --- a/src/main/java/net/openhft/chronicle/map/NodeDiscovery.java +++ b/src/main/java/net/openhft/chronicle/map/NodeDiscovery.java @@ -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(); } diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java index 55d982d99..9c9642485 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java @@ -17,16 +17,16 @@ package net.openhft.chronicle.map; +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; @@ -99,8 +99,13 @@ class ReplicatedChronicleMap, 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() { @@ -881,15 +886,15 @@ class ReplicatedChronicleMap, } /** - * 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 (this could be later if it was a * remote put) this method is called only from usual put or acquire diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java b/src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java index 7b205d8a7..31dab3118 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java @@ -211,7 +211,7 @@ public final class ReplicatingCluster implements Closeable { * * @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; } diff --git a/src/main/java/net/openhft/chronicle/map/Replicator.java b/src/main/java/net/openhft/chronicle/map/Replicator.java index 0911c8ba0..86ef2ed82 100644 --- a/src/main/java/net/openhft/chronicle/map/Replicator.java +++ b/src/main/java/net/openhft/chronicle/map/Replicator.java @@ -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. diff --git a/src/main/java/net/openhft/chronicle/map/Replicators.java b/src/main/java/net/openhft/chronicle/map/Replicators.java index f8b44bf52..faa766e85 100644 --- a/src/main/java/net/openhft/chronicle/map/Replicators.java +++ b/src/main/java/net/openhft/chronicle/map/Replicators.java @@ -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, diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java index 6b37d2fb7..34754c425 100644 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java @@ -172,15 +172,11 @@ public class ChronicleSetBuilder implements Cloneable { return toString().hashCode(); } - public ChronicleSetBuilder addReplicator(Replicator replicator) { - chronicleMapBuilder.addReplicator(replicator); + public ChronicleSetBuilder replicators(byte identifier, Replicator replicator) { + chronicleMapBuilder.replicators(identifier, replicator); return this; } - public ChronicleSetBuilder setReplicators(Replicator... replicators) { - chronicleMapBuilder.setReplicators(replicators); - return this; - } public ChronicleSetBuilder timeProvider(TimeProvider timeProvider) { chronicleMapBuilder.timeProvider(timeProvider); diff --git a/src/test/java/net/openhft/chronicle/map/Builder.java b/src/test/java/net/openhft/chronicle/map/Builder.java index bf60a5ac2..1799e16c3 100644 --- a/src/test/java/net/openhft/chronicle/map/Builder.java +++ b/src/test/java/net/openhft/chronicle/map/Builder.java @@ -73,7 +73,7 @@ public class Builder { .heartBeatInterval(1L, SECONDS); return ChronicleMapBuilder.of(kClass, vClass) .entries(20000L) - .addReplicator(tcp(identifier, tcpConfig)); + .replicators(identifier, tcp( tcpConfig)); } diff --git a/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java b/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java index 935661045..9c56df574 100644 --- a/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java +++ b/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java @@ -57,7 +57,7 @@ public class ClusterReplicationTest { map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterA.channelReplicator((short) 1)) + .channel(clusterA.createChannel((short) 1)) .create(getPersistenceFile()); } @@ -70,7 +70,7 @@ public class ClusterReplicationTest { map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterB.channelReplicator((short) 1)) + .channel(clusterB.createChannel((short) 1)) .create(getPersistenceFile()); } } @@ -93,13 +93,13 @@ public class ClusterReplicationTest { map2b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterB.channelReplicator((short) 2)) + .channel(clusterB.createChannel((short) 2)) .create(getPersistenceFile()); map2a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterA.channelReplicator((short) 2)) + .channel(clusterA.createChannel((short) 2)) .create(getPersistenceFile()); map2a.put(1, "EXAMPLE-2"); diff --git a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java b/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java index 09a491cb2..76a978389 100644 --- a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java +++ b/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java @@ -17,7 +17,10 @@ package net.openhft.chronicle.map; -import org.junit.*; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; import java.io.Closeable; import java.io.File; @@ -69,12 +72,12 @@ public class PostClusterMapCreationTest { // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterA.channelReplicator((short) 1)) + .channel(clusterA.createChannel((short) 1)) .create(getPersistenceFile()); map2a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterA.channelReplicator((short) 2)) + .channel(clusterA.createChannel((short) 2)) .create(getPersistenceFile()); } @@ -90,12 +93,12 @@ public class PostClusterMapCreationTest { // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterB.channelReplicator((short) 1)) + .channel(clusterB.createChannel((short) 1)) .create(getPersistenceFile()); map2b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterB.channelReplicator((short) 2)) + .channel(clusterB.createChannel((short) 2)) .create(getPersistenceFile()); } diff --git a/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java b/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java index 404bb4ef1..39738c5d3 100644 --- a/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java @@ -18,8 +18,6 @@ package net.openhft.chronicle.map; import net.openhft.chronicle.map.jrs166.JSR166TestCase; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.io.File; import java.io.IOException; @@ -44,48 +42,51 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase { } ChronicleMap newShmIntString(int size) throws IOException { + ChronicleMapBuilder.of(Integer.class, CharSequence.class) + .entries(size).replicators((byte) 1); return ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(size) - .forceReplicatedImpl() .create(getPersistenceFile()); } ChronicleMap newShmListBoolean(int size) throws IOException { + ChronicleMapBuilder.of(ArrayList.class, CharSequence.class) + .entries(size).replicators((byte) 1); return ChronicleMapBuilder.of(ArrayList.class, CharSequence.class) .entries(size) - .forceReplicatedImpl() .create(getPersistenceFile()); } ChronicleMap newShmListBoolean() throws IOException { + ChronicleMapBuilder.of(ArrayList.class, CharSequence.class).replicators((byte) 1); return ChronicleMapBuilder.of(ArrayList.class, CharSequence.class) - .forceReplicatedImpl() .create(getPersistenceFile()); } ChronicleMap newShmStringString(int size) throws IOException { + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) + .entries(size).replicators((byte) 1); return ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) .entries(size) - .forceReplicatedImpl() .create(getPersistenceFile()); } ChronicleMap newShmIntString() throws IOException { + ChronicleMapBuilder.of(Integer.class, CharSequence.class).replicators((byte) 1); return ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .forceReplicatedImpl() .create(getPersistenceFile()); } ChronicleMap newShmBiBoolean() throws IOException { - return ChronicleMapBuilder.of(BI.class, Boolean.class) - .forceReplicatedImpl().create(getPersistenceFile()); + ChronicleMapBuilder.of(BI.class, Boolean.class).replicators((byte) 1); + return ChronicleMapBuilder.of(BI.class, Boolean.class).create(getPersistenceFile()); } diff --git a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java index 21d1ffa8d..6fd4a9df0 100644 --- a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java +++ b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java @@ -66,7 +66,7 @@ public class SingleMapClusterTest { // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(clusterA.channelReplicator((short) 1)) + .channel(clusterA.createChannel((short) 1)) .create(getPersistenceFile()); } @@ -80,7 +80,7 @@ public class SingleMapClusterTest { .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .addReplicator(clusterB.channelReplicator((short) 1)) + .channel(clusterB.createChannel((short) 1)) .entries(1000) .create(getPersistenceFile()); } diff --git a/src/test/java/net/openhft/chronicle/map/TCPSocketReplicationTest3wayPutReturnsNull.java b/src/test/java/net/openhft/chronicle/map/TCPSocketReplicationTest3wayPutReturnsNull.java index 922fd26f2..d4bd0a076 100644 --- a/src/test/java/net/openhft/chronicle/map/TCPSocketReplicationTest3wayPutReturnsNull.java +++ b/src/test/java/net/openhft/chronicle/map/TCPSocketReplicationTest3wayPutReturnsNull.java @@ -49,7 +49,7 @@ public class TCPSocketReplicationTest3wayPutReturnsNull { .entries(1000) .putReturnsNull(true) - .addReplicator(Replicators.tcp(identifier, tcpConfig)) + .replicators(identifier, Replicators.tcp(tcpConfig)) .create(Builder.getPersistenceFile()); } diff --git a/src/test/java/net/openhft/chronicle/map/TimeBasedReplicationTests.java b/src/test/java/net/openhft/chronicle/map/TimeBasedReplicationTests.java index 6635b84cf..6bd5beb8e 100644 --- a/src/test/java/net/openhft/chronicle/map/TimeBasedReplicationTests.java +++ b/src/test/java/net/openhft/chronicle/map/TimeBasedReplicationTests.java @@ -47,9 +47,10 @@ public class TimeBasedReplicationTests extends JSR166TestCase { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) + .entries(10).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - .entries(10) - .forceReplicatedImpl() + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -77,10 +78,10 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testIgnoreALatePutIfAbsent() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) + .entries(10).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - .entries(10) - .forceReplicatedImpl() - .entries(10) + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -109,10 +110,10 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testIgnoreALateReplace() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) + .entries(10).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - .entries(10) - .forceReplicatedImpl() - .entries(10) + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -144,10 +145,10 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testIgnoreALateReplaceWithValue() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) + .entries(10).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - .entries(10) - .forceReplicatedImpl() - .entries(10) + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -176,9 +177,9 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testIgnoreALateRemoveWithValue() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - - .forceReplicatedImpl() + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -206,9 +207,9 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testIgnoreALateRemove() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - - .forceReplicatedImpl() + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -236,10 +237,9 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testIgnoreWithRemoteRemove() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class).replicators((byte) 1); ReplicatedChronicleMap map = (ReplicatedChronicleMap) ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - - .forceReplicatedImpl() - .entries(10) + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -268,10 +268,9 @@ public class TimeBasedReplicationTests extends JSR166TestCase { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class).replicators((byte) 1); ReplicatedChronicleMap map = (ReplicatedChronicleMap) ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - - .forceReplicatedImpl() - .entries(10) + .replicators((byte) 1) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -302,7 +301,7 @@ public class TimeBasedReplicationTests extends JSR166TestCase { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); ReplicatedChronicleMap map = (ReplicatedChronicleMap) ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) .entries(10) - .forceReplicatedImpl() + .replicators((byte) 1) .entries(10) .timeProvider(timeProvider) .create(getPersistenceFile()); @@ -330,9 +329,10 @@ public class TimeBasedReplicationTests extends JSR166TestCase { public void testPutRemovePut() throws IOException { final TimeProvider timeProvider = Mockito.mock(TimeProvider.class); + ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) + .entries(10).replicators((byte) 1); ChronicleMap map = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) .entries(10) - .forceReplicatedImpl() .entries(10) .timeProvider(timeProvider) .create(getPersistenceFile()); diff --git a/src/test/java/net/openhft/chronicle/map/TwoMapOnDifferentServers.java b/src/test/java/net/openhft/chronicle/map/TwoMapOnDifferentServers.java index 91671206d..59199827d 100644 --- a/src/test/java/net/openhft/chronicle/map/TwoMapOnDifferentServers.java +++ b/src/test/java/net/openhft/chronicle/map/TwoMapOnDifferentServers.java @@ -51,12 +51,12 @@ public class TwoMapOnDifferentServers { File persistenceFile = getPersistenceFile(); map1 = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(20000) - .addReplicator(tcp((byte) 1, tcpReplicationConfig)) + .replicators((byte) 1, tcp(tcpReplicationConfig)) .create(persistenceFile); map2 = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(20000) - .addReplicator(tcp((byte) 2, + .replicators((byte) 2, tcp( TcpReplicationConfig.of(8077).heartBeatInterval(1, SECONDS))) .create(persistenceFile); } diff --git a/src/test/java/net/openhft/chronicle/map/UDPSocketReplicationTest.java b/src/test/java/net/openhft/chronicle/map/UDPSocketReplicationTest.java index f95cf91e4..8bec68d2c 100644 --- a/src/test/java/net/openhft/chronicle/map/UDPSocketReplicationTest.java +++ b/src/test/java/net/openhft/chronicle/map/UDPSocketReplicationTest.java @@ -44,7 +44,7 @@ public class UDPSocketReplicationTest { return ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(udp((byte) identifier, udpConfig)) + .replicators((byte) identifier, udp(udpConfig)) .create(Builder.getPersistenceFile()); } diff --git a/src/test/java/net/openhft/chronicle/set/SetForTCPSocketReplicationTest3way.java b/src/test/java/net/openhft/chronicle/set/SetForTCPSocketReplicationTest3way.java index c62a03e5c..0212db7f6 100644 --- a/src/test/java/net/openhft/chronicle/set/SetForTCPSocketReplicationTest3way.java +++ b/src/test/java/net/openhft/chronicle/set/SetForTCPSocketReplicationTest3way.java @@ -51,7 +51,7 @@ public class SetForTCPSocketReplicationTest3way { final int serverPort, final InetSocketAddress... endpoints) throws IOException { return (T) ChronicleSetBuilder.of(Integer.class) - .addReplicator(tcp(identifier, of(serverPort, endpoints). + .replicators(identifier, tcp(of(serverPort, endpoints). heartBeatInterval(1L, SECONDS))).create(getPersistenceFile()); }