From 77cb5be05cbcb8dbe03704c9428193f2c69c227f Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 17:11:47 +0100 Subject: [PATCH 01/15] 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()); } From 30a1abef06483b2e7eb31f15b28629301f58e660 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 17:59:54 +0100 Subject: [PATCH 02/15] HCOLL-163 fixed some merge issues. --- .../chronicle/ChronicleHashBuilder.java | 4 +- .../chronicle/map/ChronicleMapBuilder.java | 176 +++++++++--------- .../chronicle/map/ReplicatedChronicleMap.java | 1 + .../chronicle/set/ChronicleSetBuilder.java | 28 +-- .../map/fromdocs/GettingStartedTest.java | 65 ------- 5 files changed, 104 insertions(+), 170 deletions(-) delete mode 100644 src/test/java/net/openhft/chronicle/map/fromdocs/GettingStartedTest.java diff --git a/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java b/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java index 53345e6b9..20cd595b5 100644 --- a/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java +++ b/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java @@ -189,9 +189,7 @@ public interface ChronicleHashBuilder{@code * ChronicleMap map = ChronicleMapBuilder * .of(Key.class, Value.class) @@ -66,25 +65,22 @@ import static net.openhft.chronicle.map.Objects.builderEquals; * *

    Use static {@link #of(Class, Class)} method to obtain a {@code ChronicleMapBuilder} instance. * - *

    {@code ChronicleMapBuilder} is mutable. Configuration methods mutate the builder and - * return the builder itself back to support chaining pattern, rather than the builder copies - * with the corresponding configuration changed. To make an independent configuration, - * {@linkplain #clone} the builder. + *

    {@code ChronicleMapBuilder} is mutable. Configuration methods mutate the builder and return the + * builder itself back to support chaining pattern, rather than the builder copies with the corresponding + * configuration changed. To make an independent configuration, {@linkplain #clone} the builder. * - *

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

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

    {@code ChronicleMap} ("ChronicleMaps, created by {@code ChronicleMapBuilder}") currently - * doesn't support resizing. That is why you should always configure {@linkplain - * #entries(long) number of entries} you are going to insert into the created map at most. - * See {@link #entries(long)} method documentation for more information on this. + *

    {@code ChronicleMap} ("ChronicleMaps, created by {@code ChronicleMapBuilder}") currently doesn't support + * resizing. That is why you should always configure {@linkplain #entries(long) number of entries} you + * are going to insert into the created map at most. See {@link #entries(long)} method documentation + * for more information on this. * - *

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

    {@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 key type of the maps, produced by this builder * @param value type of the maps, produced by this builder @@ -97,10 +93,11 @@ public class ChronicleMapBuilder implements Cloneable, public static final short UDP_REPLICATION_MODIFICATION_ITERATOR_ID = 128; private static final Logger LOG = LoggerFactory.getLogger(ChronicleMapBuilder.class.getName()); + SerializationBuilder keyBuilder; SerializationBuilder valueBuilder; - Map, Replicator> replicators = new HashMap, Replicator>(); + private Map, Replicator> replicators = new HashMap, Replicator>(); // used when configuring the number of segments. private int minSegments = -1; @@ -190,9 +187,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}.) * * @see #constantKeySizeBySample(Object) * @see #valueSize(int) @@ -229,17 +226,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 @@ -254,15 +250,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 @@ -291,18 +287,18 @@ public class ChronicleMapBuilder implements Cloneable, * {@inheritDoc} * *

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

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

    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) @@ -344,16 +340,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}. * @@ -432,20 +428,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) */ @@ -459,17 +455,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) */ @@ -500,6 +496,7 @@ public class ChronicleMapBuilder implements Cloneable, return this; } + int metaDataBytes() { return metaDataBytes; } @@ -643,19 +640,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) { @@ -665,13 +661,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 diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java index 9c9642485..6c768546e 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java @@ -17,6 +17,7 @@ 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; diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java index 251b8c000..ec344ca5b 100644 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java @@ -16,10 +16,9 @@ package net.openhft.chronicle.set; -import net.openhft.chronicle.TimeProvider; -import net.openhft.chronicle.map.Alignment; import net.openhft.chronicle.ChronicleHashBuilder; import net.openhft.chronicle.ChronicleHashErrorListener; +import net.openhft.chronicle.TimeProvider; import net.openhft.chronicle.map.*; import net.openhft.lang.io.serialization.BytesMarshaller; import net.openhft.lang.io.serialization.BytesMarshallerFactory; @@ -33,7 +32,6 @@ import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -90,9 +88,9 @@ public class ChronicleSetBuilder * .entries(50000) * .keySize(10) * .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 ChronicleSet}.) + * (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}.) * * @see #constantKeySizeBySample(Object) * @see #entrySize(int) @@ -122,13 +120,13 @@ public class ChronicleSetBuilder /** * {@inheritDoc} * - *

    In fully default case you can expect entry size to be about 120-130 bytes. But it is - * strongly recommended always to configure {@linkplain #keySize(int) key size}, - * if they couldn't be derived statically. + *

    In fully default case you can expect entry size to be about 120-130 bytes. But it is strongly + * recommended always to configure {@linkplain #keySize(int) key size}, if they couldn't be derived + * statically. * - *

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

    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 entrySize(int entrySize) { @@ -166,6 +164,12 @@ public class ChronicleSetBuilder return this; } + @Override + public ChronicleSetBuilder replicators(byte identifier, Replicator... replicators) { + chronicleMapBuilder.replicators(identifier, replicators); + return this; + } + @Override public String toString() { return " ChronicleSetBuilder{" + diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/GettingStartedTest.java b/src/test/java/net/openhft/chronicle/map/fromdocs/GettingStartedTest.java deleted file mode 100644 index 8e338784a..000000000 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/GettingStartedTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.openhft.chronicle.map.fromdocs; - -import net.openhft.chronicle.map.ChronicleMapBuilder; -import org.junit.Test; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.util.Map; - -import static org.junit.Assert.assertEquals; - -/** - * Created by peter on 28/02/14. - */ -public class GettingStartedTest { - - @Test - public void testTheCodeInGuide() throws IOException { - String tmpdir = System.getProperty("java.io.tmpdir"); - Map map = ChronicleMapBuilder.of(String.class, String.class) - - .create(new File(tmpdir + "/shared.map")); - map.put("some.json", "missing"); - map.get("some.json"); - - map.put("Hello", "World"); - String hi = map.get("Hello"); - map.put("Long String", "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); - String json = "{\"menu\": {\n" + - " \"id\": \"file\",\n" + - " \"value\": \"File\",\n" + - " \"popup\": {\n" + - " \"menuitem\": [\n" + - " {\"value\": \"New\", \"onclick\": \"CreateNew()\"},\n" + - " {\"value\": \"Open\", \"onclick\": \"OpenDoc()\"},\n" + - " {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}\n" + - " ]\n" + - " }\n" + - "}}"; - map.put("some.json", json); - - String s2 = map.get("some.json"); - assertEquals(json, s2); - - ((Closeable) map).close(); - - } -} From d01b5d8c593c6928208252ef056f244e6fbf2835 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:04:38 +0100 Subject: [PATCH 03/15] HCOLL-163 renamed chronicle custer to chronicle channel --- .../chronicle/map/ChronicleMapBuilder.java | 2 +- .../net/openhft/chronicle/map/Replica.java | 33 ++++++++----------- ...ngCluster.java => ReplicatingChannel.java} | 12 +++---- ...er.java => ReplicatingChannelBuilder.java} | 14 ++++---- .../chronicle/map/ClusterReplicationTest.java | 8 ++--- .../map/PostClusterMapCreationTest.java | 10 +++--- .../chronicle/map/SingleMapClusterTest.java | 8 ++--- 7 files changed, 41 insertions(+), 46 deletions(-) rename src/main/java/net/openhft/chronicle/map/{ReplicatingCluster.java => ReplicatingChannel.java} (98%) rename src/main/java/net/openhft/chronicle/map/{ReplicatingClusterBuilder.java => ReplicatingChannelBuilder.java} (83%) diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index 48355137c..a5e8cf385 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -562,7 +562,7 @@ public class ChronicleMapBuilder implements Cloneable, } - public ChronicleMapBuilder channel(ReplicatingCluster.ChronicleChannel replicator) { + public ChronicleMapBuilder channel(ReplicatingChannel.ChronicleChannel replicator) { this.identifier = replicator.identifier(); this.replicators.clear(); replicators.put(replicator.getClass(), replicator); diff --git a/src/main/java/net/openhft/chronicle/map/Replica.java b/src/main/java/net/openhft/chronicle/map/Replica.java index 821d4ab28..fcc698273 100644 --- a/src/main/java/net/openhft/chronicle/map/Replica.java +++ b/src/main/java/net/openhft/chronicle/map/Replica.java @@ -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. - *

    - *

    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.

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

    - *

    This functionality is used to publish recently modified entries to a new remote node as it - * connects. + * matter if they have already been.

    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); diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java b/src/main/java/net/openhft/chronicle/map/ReplicatingChannel.java similarity index 98% rename from src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java rename to src/main/java/net/openhft/chronicle/map/ReplicatingChannel.java index 31dab3118..13ae91e3b 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatingCluster.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatingChannel.java @@ -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 ReplicatingChannel implements Closeable { + private static final Logger LOG = LoggerFactory.getLogger(ReplicatingChannel.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(); + ReplicatingChannel.this.close(); } }; private final int maxEntrySize; @@ -169,7 +169,7 @@ public final class ReplicatingCluster implements Closeable { private final Set replicators = new CopyOnWriteArraySet(); - ReplicatingCluster(ReplicatingClusterBuilder builder) { + ReplicatingChannel(ReplicatingChannelBuilder builder) { localIdentifier = builder.identifier; maxEntrySize = builder.maxEntrySize; chronicleChannels = new Replica[builder.maxNumberOfChronicles]; @@ -206,7 +206,7 @@ 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 @@ -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"); diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatingClusterBuilder.java b/src/main/java/net/openhft/chronicle/map/ReplicatingChannelBuilder.java similarity index 83% rename from src/main/java/net/openhft/chronicle/map/ReplicatingClusterBuilder.java rename to src/main/java/net/openhft/chronicle/map/ReplicatingChannelBuilder.java index c5a85fc82..23e095896 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatingClusterBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatingChannelBuilder.java @@ -21,7 +21,7 @@ import java.io.IOException; /** * @author Rob Austin. */ -public final class ReplicatingClusterBuilder { +public final class ReplicatingChannelBuilder { final byte identifier; final int maxEntrySize; @@ -29,7 +29,7 @@ public final class ReplicatingClusterBuilder { private UdpReplicationConfig udpReplicationConfig = null; private TcpReplicationConfig tcpReplicationConfig = null; - ReplicatingClusterBuilder(byte identifier, final int maxEntrySize) { + ReplicatingChannelBuilder(byte identifier, final int maxEntrySize) { this.identifier = identifier; this.maxEntrySize = maxEntrySize; if (identifier <= 0) { @@ -38,23 +38,23 @@ public final class ReplicatingClusterBuilder { } } - public ReplicatingClusterBuilder udpReplication(UdpReplicationConfig replicationConfig) { + public ReplicatingChannelBuilder udpReplication(UdpReplicationConfig replicationConfig) { this.udpReplicationConfig = replicationConfig; return this; } - public ReplicatingClusterBuilder tcpReplication(TcpReplicationConfig replicationConfig) { + public ReplicatingChannelBuilder tcpReplication(TcpReplicationConfig replicationConfig) { this.tcpReplicationConfig = replicationConfig; return this; } - public ReplicatingClusterBuilder maxNumberOfChronicles(int maxNumberOfChronicles) { + public ReplicatingChannelBuilder maxNumberOfChronicles(int maxNumberOfChronicles) { this.maxNumberOfChronicles = maxNumberOfChronicles; return this; } - public ReplicatingCluster create() throws IOException { - final ReplicatingCluster replicatingCluster = new ReplicatingCluster(this); + public ReplicatingChannel create() throws IOException { + final ReplicatingChannel replicatingCluster = new ReplicatingChannel(this); if (tcpReplicationConfig != null) { final TcpReplicator tcpReplicator = new TcpReplicator( replicatingCluster.asReplica, diff --git a/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java b/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java index 9c56df574..941179aef 100644 --- a/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java +++ b/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java @@ -40,8 +40,8 @@ public class ClusterReplicationTest { private ChronicleMap map1b; private ChronicleMap map2b; - private ReplicatingCluster clusterB; - private ReplicatingCluster clusterA; + private ReplicatingChannel clusterB; + private ReplicatingChannel clusterA; @Before @@ -52,7 +52,7 @@ public class ClusterReplicationTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - clusterA = new ReplicatingClusterBuilder((byte) 1, 1024).tcpReplication(tcpConfig) + clusterA = new ReplicatingChannelBuilder((byte) 1, 1024).tcpReplication(tcpConfig) .create(); map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) @@ -65,7 +65,7 @@ public class ClusterReplicationTest { TcpReplicationConfig tcpConfig = TcpReplicationConfig.of(8087).heartBeatInterval(1, SECONDS); - clusterB = new ReplicatingClusterBuilder((byte) 2, 1024).tcpReplication(tcpConfig) + clusterB = new ReplicatingChannelBuilder((byte) 2, 1024).tcpReplication(tcpConfig) .create(); map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) diff --git a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java b/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java index 76a978389..e9c102f34 100644 --- a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java +++ b/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java @@ -43,10 +43,10 @@ public class PostClusterMapCreationTest { private ChronicleMap map1b; private ChronicleMap map2b; - private ReplicatingCluster clusterB; - private ReplicatingCluster clusterA; + private ReplicatingChannel clusterB; + private ReplicatingChannel clusterA; - private ReplicatingClusterBuilder replicatingClusterBuilder1; + private ReplicatingChannelBuilder replicatingClusterBuilder1; public static File getPersistenceFile() { @@ -66,7 +66,7 @@ public class PostClusterMapCreationTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - clusterA = new ReplicatingClusterBuilder((byte) 1, 1024) + clusterA = new ReplicatingChannelBuilder((byte) 1, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created @@ -87,7 +87,7 @@ public class PostClusterMapCreationTest { .of(8087, new InetSocketAddress("localhost", 8086)) .heartBeatInterval(1, SECONDS); - clusterB = new ReplicatingClusterBuilder((byte) 2, 1024) + clusterB = new ReplicatingChannelBuilder((byte) 2, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created diff --git a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java index 6fd4a9df0..af26c450f 100644 --- a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java +++ b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java @@ -41,8 +41,8 @@ public class SingleMapClusterTest { private ChronicleMap map1b; - private ReplicatingCluster clusterB; - private ReplicatingCluster clusterA; + private ReplicatingChannel clusterB; + private ReplicatingChannel clusterA; public static File getPersistenceFile() { @@ -61,7 +61,7 @@ public class SingleMapClusterTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - clusterA = new ReplicatingClusterBuilder((byte) 1, 1024) + clusterA = new ReplicatingChannelBuilder((byte) 1, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) @@ -76,7 +76,7 @@ public class SingleMapClusterTest { .of(8087, new InetSocketAddress("localhost", 8086)) .heartBeatInterval(1, SECONDS); - clusterB = new ReplicatingClusterBuilder((byte) 2, 1024) + clusterB = new ReplicatingChannelBuilder((byte) 2, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) From 200322d268e78227db803dbec75bdc5921a625be Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:23:24 +0100 Subject: [PATCH 04/15] HCOLL-163 renamed chronicle custer to chronicle channel --- README.md | 37 ++++++++++--------- ...ingChannel.java => ChannelReplicator.java} | 8 ++-- ...der.java => ChannelReplicatorBuilder.java} | 14 +++---- .../chronicle/map/ChronicleMapBuilder.java | 6 +-- ...nTest.java => ChannelReplicationTest.java} | 23 ++++++------ .../map/PostClusterMapCreationTest.java | 21 +++++------ .../chronicle/map/SingleMapClusterTest.java | 15 ++++---- 7 files changed, 62 insertions(+), 62 deletions(-) rename src/main/java/net/openhft/chronicle/map/{ReplicatingChannel.java => ChannelReplicator.java} (98%) rename src/main/java/net/openhft/chronicle/map/{ReplicatingChannelBuilder.java => ChannelReplicatorBuilder.java} (80%) rename src/test/java/net/openhft/chronicle/map/{ClusterReplicationTest.java => ChannelReplicationTest.java} (81%) diff --git a/README.md b/README.md index bcbbbb674..8fee78d4e 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C * [Identifier](https://github.com/OpenHFT/Chronicle-Map#identifier) * [Port](https://github.com/OpenHFT/Chronicle-Map#port) * [Heart Beat Interval](https://github.com/OpenHFT/Chronicle-Map#heart-beat-interval) -* [Clustering](https://github.com/OpenHFT/Chronicle-Map#cluster) +* [Channels](https://github.com/OpenHFT/Chronicle-Map#channels) #### Miscellaneous @@ -512,7 +512,7 @@ A heartbeat will only be send if no data is transmitted, if the maps are constan no heartbeat message is sent. If a map does not receive either data of a heartbeat the connection is dropped and re-established. -# Cluster +# Channels Chronicle Map TCP Replication lets you distribute a single Chronicle Map, to a number of servers across your network. Replication is point to point and the data transfer is bidirectional, so in the @@ -523,34 +523,37 @@ unfortunately with just TCP replication you would have to have two tcp socket co not ideal. This is why we created Chronicle Clustering. Clustering lets you replicate numerous Chronicle Maps via a single point to point socket connection. -Clustering is similar to TCP replication, where each map has to be given a unique identifier, but -when using Chronicle Clustering its the cluster that is given the unique identifier not the map. +Chronicle Channels are similar to TCP replication, where each map has to be given a unique identifier, but +when using Chronicle Channels its the channels that are given the unique identifier not the map. ``` java -ReplicatingClusterBuilder clusterBuilder = new ReplicatingClusterBuilder((byte) 2, 1024); +byte identifier = 2; +ChannelReplicator channelReplicatorA = new ChannelReplicatorBuilder(identifier, 1024) + .create(); ``` -In this example above the cluster is given the identifier of 2 +In this example above the channel is given the identifier of 2 In addition to specifying the identifier we also have to set the maximum entry size, this sets -the size of the memory buffers within the cluster. This has to be set manually, with clusters you -are able to attach additional maps to a cluster once its up and running, so the maximum size of each +the size of the memory buffers within the ChannelReplicator. This has to be set manually, with channels you +are able to attach additional maps to a ChannelReplicator once its up and running, so the maximum size of each entry in the map can not be known in advance and we don’t currently support automatic resizing of buffers. -Once you have created the cluster you should attach your tcpConfig +Once you have created the ChannelReplicator you should attach your tcp configuration ``` java -TcpReplicationConfig tcpConfig = TcpReplicationConfig.of(8087).heartBeatInterval(1, SECONDS); -clusterBuilder.tcpReplication(tcpConfig); -ReplicatingCluster cluster = clusterBuilder.create(); +byte identifier = 2; +ChannelReplicator channelReplicator = new ChannelReplicatorBuilder(identifier, 1024) + .tcpReplication(tcpConfig) + .create();; ``` -Attaching cluster replication to the map: +Attaching ChannelReplicator replication to the map: ``` java ChronicleMap map = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .addReplicator(cluster.channelReplicator((short) 1)) + .channel(channelReplicator.createChannel((short) 1)) .create(file); ``` @@ -567,11 +570,11 @@ If you inadvertently got the chronicle channels around the wrong way, then chron to replicate the wrong maps data. The chronicle channels don't have to be in order but they must be unique for each map you have. -Once you have created the cluster you may wish to hold onto the reference so that you can call close -once you have finished, this will close everything in the cluster +Once you have created the ChannelReplicator you may wish to hold onto the reference so that you can call close +once you have finished, this will close everything in the ChannelReplicator ``` java -cluster.close(); +channelReplicator.close(); ``` #### Known Issues diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatingChannel.java b/src/main/java/net/openhft/chronicle/map/ChannelReplicator.java similarity index 98% rename from src/main/java/net/openhft/chronicle/map/ReplicatingChannel.java rename to src/main/java/net/openhft/chronicle/map/ChannelReplicator.java index 13ae91e3b..4aaa95158 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatingChannel.java +++ b/src/main/java/net/openhft/chronicle/map/ChannelReplicator.java @@ -45,8 +45,8 @@ import static net.openhft.chronicle.map.Replica.ModificationNotifier.NOP; /** * @author Rob Austin. */ -public final class ReplicatingChannel implements Closeable { - private static final Logger LOG = LoggerFactory.getLogger(ReplicatingChannel.class.getName()); +public final class ChannelReplicator implements Closeable { + private static final Logger LOG = LoggerFactory.getLogger(ChannelReplicator.class.getName()); private static final byte BOOTSTRAP_MESSAGE = 'B'; final EntryExternalizable asEntryExternalizable = new EntryExternalizable() { @@ -152,7 +152,7 @@ public final class ReplicatingChannel implements Closeable { @Override public void close() throws IOException { - ReplicatingChannel.this.close(); + ChannelReplicator.this.close(); } }; private final int maxEntrySize; @@ -169,7 +169,7 @@ public final class ReplicatingChannel implements Closeable { private final Set replicators = new CopyOnWriteArraySet(); - ReplicatingChannel(ReplicatingChannelBuilder builder) { + ChannelReplicator(ChannelReplicatorBuilder builder) { localIdentifier = builder.identifier; maxEntrySize = builder.maxEntrySize; chronicleChannels = new Replica[builder.maxNumberOfChronicles]; diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatingChannelBuilder.java b/src/main/java/net/openhft/chronicle/map/ChannelReplicatorBuilder.java similarity index 80% rename from src/main/java/net/openhft/chronicle/map/ReplicatingChannelBuilder.java rename to src/main/java/net/openhft/chronicle/map/ChannelReplicatorBuilder.java index 23e095896..537095985 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatingChannelBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChannelReplicatorBuilder.java @@ -21,7 +21,7 @@ import java.io.IOException; /** * @author Rob Austin. */ -public final class ReplicatingChannelBuilder { +public final class ChannelReplicatorBuilder { final byte identifier; final int maxEntrySize; @@ -29,7 +29,7 @@ public final class ReplicatingChannelBuilder { private UdpReplicationConfig udpReplicationConfig = null; private TcpReplicationConfig tcpReplicationConfig = null; - ReplicatingChannelBuilder(byte identifier, final int maxEntrySize) { + ChannelReplicatorBuilder(byte identifier, final int maxEntrySize) { this.identifier = identifier; this.maxEntrySize = maxEntrySize; if (identifier <= 0) { @@ -38,23 +38,23 @@ public final class ReplicatingChannelBuilder { } } - public ReplicatingChannelBuilder udpReplication(UdpReplicationConfig replicationConfig) { + public ChannelReplicatorBuilder udpReplication(UdpReplicationConfig replicationConfig) { this.udpReplicationConfig = replicationConfig; return this; } - public ReplicatingChannelBuilder tcpReplication(TcpReplicationConfig replicationConfig) { + public ChannelReplicatorBuilder tcpReplication(TcpReplicationConfig replicationConfig) { this.tcpReplicationConfig = replicationConfig; return this; } - public ReplicatingChannelBuilder maxNumberOfChronicles(int maxNumberOfChronicles) { + public ChannelReplicatorBuilder maxNumberOfChronicles(int maxNumberOfChronicles) { this.maxNumberOfChronicles = maxNumberOfChronicles; return this; } - public ReplicatingChannel create() throws IOException { - final ReplicatingChannel replicatingCluster = new ReplicatingChannel(this); + public ChannelReplicator create() throws IOException { + final ChannelReplicator replicatingCluster = new ChannelReplicator(this); if (tcpReplicationConfig != null) { final TcpReplicator tcpReplicator = new TcpReplicator( replicatingCluster.asReplica, diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index a5e8cf385..ff33d1e01 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -562,10 +562,10 @@ public class ChronicleMapBuilder implements Cloneable, } - public ChronicleMapBuilder channel(ReplicatingChannel.ChronicleChannel replicator) { - this.identifier = replicator.identifier(); + public ChronicleMapBuilder channel(ChannelReplicator.ChronicleChannel chronicleChannel) { + this.identifier = chronicleChannel.identifier(); this.replicators.clear(); - replicators.put(replicator.getClass(), replicator); + replicators.put(chronicleChannel.getClass(), chronicleChannel); return this; } diff --git a/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java b/src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.java similarity index 81% rename from src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java rename to src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.java index 941179aef..40344799a 100644 --- a/src/test/java/net/openhft/chronicle/map/ClusterReplicationTest.java +++ b/src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.java @@ -32,7 +32,7 @@ import static org.junit.Assert.assertTrue; * * @author Rob Austin. */ -public class ClusterReplicationTest { +public class ChannelReplicationTest { private ChronicleMap map1a; private ChronicleMap map2a; @@ -40,8 +40,8 @@ public class ClusterReplicationTest { private ChronicleMap map1b; private ChronicleMap map2b; - private ReplicatingChannel clusterB; - private ReplicatingChannel clusterA; + private ChannelReplicator channelReplicatorA; + private ChannelReplicator channelReplicatorB; @Before @@ -52,12 +52,13 @@ public class ClusterReplicationTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - clusterA = new ReplicatingChannelBuilder((byte) 1, 1024).tcpReplication(tcpConfig) - .create(); + channelReplicatorA = new ChannelReplicatorBuilder((byte) 1, 1024) + .tcpReplication(tcpConfig) + .create(); map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterA.createChannel((short) 1)) + .channel(channelReplicatorA.createChannel((short) 1)) .create(getPersistenceFile()); } @@ -65,12 +66,12 @@ public class ClusterReplicationTest { TcpReplicationConfig tcpConfig = TcpReplicationConfig.of(8087).heartBeatInterval(1, SECONDS); - clusterB = new ReplicatingChannelBuilder((byte) 2, 1024).tcpReplication(tcpConfig) + channelReplicatorB = new ChannelReplicatorBuilder((byte) 2, 1024).tcpReplication(tcpConfig) .create(); map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterB.createChannel((short) 1)) + .channel(channelReplicatorB.createChannel((short) 1)) .create(getPersistenceFile()); } } @@ -78,7 +79,7 @@ public class ClusterReplicationTest { @After public void tearDown() throws InterruptedException { - for (final Closeable closeable : new Closeable[]{clusterA, clusterB}) { + for (final Closeable closeable : new Closeable[]{channelReplicatorA, channelReplicatorB}) { try { closeable.close(); } catch (IOException e) { @@ -93,13 +94,13 @@ public class ClusterReplicationTest { map2b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterB.createChannel((short) 2)) + .channel(channelReplicatorB.createChannel((short) 2)) .create(getPersistenceFile()); map2a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterA.createChannel((short) 2)) + .channel(channelReplicatorA.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 e9c102f34..7cabde3c1 100644 --- a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java +++ b/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java @@ -43,11 +43,8 @@ public class PostClusterMapCreationTest { private ChronicleMap map1b; private ChronicleMap map2b; - private ReplicatingChannel clusterB; - private ReplicatingChannel clusterA; - - private ReplicatingChannelBuilder replicatingClusterBuilder1; - + private ChannelReplicator channelReplicatorA; + private ChannelReplicator channelReplicatorB; public static File getPersistenceFile() { String TMP = System.getProperty("java.io.tmpdir"); @@ -66,18 +63,18 @@ public class PostClusterMapCreationTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - clusterA = new ReplicatingChannelBuilder((byte) 1, 1024) + channelReplicatorA = new ChannelReplicatorBuilder((byte) 1, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterA.createChannel((short) 1)) + .channel(channelReplicatorA.createChannel((short) 1)) .create(getPersistenceFile()); map2a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterA.createChannel((short) 2)) + .channel(channelReplicatorA.createChannel((short) 2)) .create(getPersistenceFile()); } @@ -87,18 +84,18 @@ public class PostClusterMapCreationTest { .of(8087, new InetSocketAddress("localhost", 8086)) .heartBeatInterval(1, SECONDS); - clusterB = new ReplicatingChannelBuilder((byte) 2, 1024) + channelReplicatorB = new ChannelReplicatorBuilder((byte) 2, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterB.createChannel((short) 1)) + .channel(channelReplicatorB.createChannel((short) 1)) .create(getPersistenceFile()); map2b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterB.createChannel((short) 2)) + .channel(channelReplicatorB.createChannel((short) 2)) .create(getPersistenceFile()); } @@ -108,7 +105,7 @@ public class PostClusterMapCreationTest { @After public void tearDown() throws InterruptedException { - for (final Closeable closeable : new Closeable[]{clusterA, clusterB}) { + for (final Closeable closeable : new Closeable[]{channelReplicatorA, channelReplicatorB}) { try { closeable.close(); } catch (IOException e) { diff --git a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java index af26c450f..cd0e870d0 100644 --- a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java +++ b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java @@ -41,9 +41,8 @@ public class SingleMapClusterTest { private ChronicleMap map1b; - private ReplicatingChannel clusterB; - private ReplicatingChannel clusterA; - + private ChannelReplicator channelReplicatorA; + private ChannelReplicator channelReplicatorB; public static File getPersistenceFile() { String TMP = System.getProperty("java.io.tmpdir"); @@ -61,12 +60,12 @@ public class SingleMapClusterTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - clusterA = new ReplicatingChannelBuilder((byte) 1, 1024) + channelReplicatorA = new ChannelReplicatorBuilder((byte) 1, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(clusterA.createChannel((short) 1)) + .channel(channelReplicatorA.createChannel((short) 1)) .create(getPersistenceFile()); } @@ -76,11 +75,11 @@ public class SingleMapClusterTest { .of(8087, new InetSocketAddress("localhost", 8086)) .heartBeatInterval(1, SECONDS); - clusterB = new ReplicatingChannelBuilder((byte) 2, 1024) + channelReplicatorB = new ChannelReplicatorBuilder((byte) 2, 1024) .tcpReplication(tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .channel(clusterB.createChannel((short) 1)) + .channel(channelReplicatorB.createChannel((short) 1)) .entries(1000) .create(getPersistenceFile()); } @@ -89,7 +88,7 @@ public class SingleMapClusterTest { @After public void tearDown() throws InterruptedException { - for (final Closeable closeable : new Closeable[]{clusterA, clusterB}) { + for (final Closeable closeable : new Closeable[]{channelReplicatorA, channelReplicatorB}) { try { closeable.close(); } catch (IOException e) { From abcd89ec5efc2f8a97964705bfe365eb62224ad9 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:25:12 +0100 Subject: [PATCH 05/15] HCOLL-163 renamed chronicle custer to chronicle channel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fee78d4e..474dc33d8 100644 --- a/README.md +++ b/README.md @@ -520,7 +520,7 @@ example of just two servers, they only have to be connected via a single tcp soc the data is transferred both ways. Which is great, however what if you wanted to replicate more than just one chronicle map, what if you were going to replicate two chronicle maps across your network, unfortunately with just TCP replication you would have to have two tcp socket connections, which is -not ideal. This is why we created Chronicle Clustering. Clustering lets you replicate numerous +not ideal. This is why we created Chronicle Channels. Channels lets you replicate numerous Chronicle Maps via a single point to point socket connection. Chronicle Channels are similar to TCP replication, where each map has to be given a unique identifier, but From 3dbc62eb369d3175e411fdc91f2460da54a5516a Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:26:32 +0100 Subject: [PATCH 06/15] HCOLL-163 fixed readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 474dc33d8..2fb70de32 100644 --- a/README.md +++ b/README.md @@ -520,7 +520,7 @@ example of just two servers, they only have to be connected via a single tcp soc the data is transferred both ways. Which is great, however what if you wanted to replicate more than just one chronicle map, what if you were going to replicate two chronicle maps across your network, unfortunately with just TCP replication you would have to have two tcp socket connections, which is -not ideal. This is why we created Chronicle Channels. Channels lets you replicate numerous +not ideal. This is why we created Chronicle Channels. Channels let you replicate numerous Chronicle Maps via a single point to point socket connection. Chronicle Channels are similar to TCP replication, where each map has to be given a unique identifier, but From 97e768d8560c7b204247e5efe19262e10d6c8514 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:28:33 +0100 Subject: [PATCH 07/15] HCOLL-163 adde "int maxEntrySize =1024;" --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2fb70de32..1f876c659 100644 --- a/README.md +++ b/README.md @@ -528,7 +528,8 @@ when using Chronicle Channels its the channels that are given the unique identif ``` java byte identifier = 2; -ChannelReplicator channelReplicatorA = new ChannelReplicatorBuilder(identifier, 1024) +int maxEntrySize =1024; +ChannelReplicator channelReplicatorA = new ChannelReplicatorBuilder(identifier, maxEntrySize) .create(); ``` @@ -543,6 +544,7 @@ of buffers. Once you have created the ChannelReplicator you should attach your tcp configuration ``` java byte identifier = 2; +int maxEntrySize =1024; ChannelReplicator channelReplicator = new ChannelReplicatorBuilder(identifier, 1024) .tcpReplication(tcpConfig) .create();; From 7f8f745eca8b6eb85b778b1ee370a379fd768c87 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:29:41 +0100 Subject: [PATCH 08/15] HCOLL-163 renamed to "replicator" --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1f876c659..4a1005d59 100644 --- a/README.md +++ b/README.md @@ -529,7 +529,7 @@ when using Chronicle Channels its the channels that are given the unique identif ``` java byte identifier = 2; int maxEntrySize =1024; -ChannelReplicator channelReplicatorA = new ChannelReplicatorBuilder(identifier, maxEntrySize) +ChannelReplicator replicator = new ChannelReplicatorBuilder(identifier, maxEntrySize) .create(); ``` @@ -545,7 +545,7 @@ Once you have created the ChannelReplicator you should attach your tcp configura ``` java byte identifier = 2; int maxEntrySize =1024; -ChannelReplicator channelReplicator = new ChannelReplicatorBuilder(identifier, 1024) +ChannelReplicator replicator = new ChannelReplicatorBuilder(identifier, 1024) .tcpReplication(tcpConfig) .create();; ``` @@ -555,7 +555,7 @@ Attaching ChannelReplicator replication to the map: ``` java ChronicleMap map = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicator.createChannel((short) 1)) + .channel(replicator.createChannel((short) 1)) .create(file); ``` @@ -576,7 +576,7 @@ Once you have created the ChannelReplicator you may wish to hold onto the refere once you have finished, this will close everything in the ChannelReplicator ``` java -channelReplicator.close(); +replicator.close(); ``` #### Known Issues From 9ca17bc56e3bd9356b869452f40ac769ef4a8f7e Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:30:32 +0100 Subject: [PATCH 09/15] HCOLL-163 renamed to "replicator" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a1005d59..4020c21cb 100644 --- a/README.md +++ b/README.md @@ -528,7 +528,7 @@ when using Chronicle Channels its the channels that are given the unique identif ``` java byte identifier = 2; -int maxEntrySize =1024; +int maxEntrySize = 1024; ChannelReplicator replicator = new ChannelReplicatorBuilder(identifier, maxEntrySize) .create(); ``` From 6a640541fc9680b880b1d603763fe665ddf2b6f6 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:31:34 +0100 Subject: [PATCH 10/15] HCOLL-163 readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4020c21cb..db16d2ca7 100644 --- a/README.md +++ b/README.md @@ -512,7 +512,7 @@ A heartbeat will only be send if no data is transmitted, if the maps are constan no heartbeat message is sent. If a map does not receive either data of a heartbeat the connection is dropped and re-established. -# Channels +# Channels and ChannelReplicator Chronicle Map TCP Replication lets you distribute a single Chronicle Map, to a number of servers across your network. Replication is point to point and the data transfer is bidirectional, so in the From cc9f26bfae2129de9c7b3885f1c8cd67ac2c2972 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:32:16 +0100 Subject: [PATCH 11/15] HCOLL-163 readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db16d2ca7..f730b7679 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C * [Identifier](https://github.com/OpenHFT/Chronicle-Map#identifier) * [Port](https://github.com/OpenHFT/Chronicle-Map#port) * [Heart Beat Interval](https://github.com/OpenHFT/Chronicle-Map#heart-beat-interval) -* [Channels](https://github.com/OpenHFT/Chronicle-Map#channels) +* [Channels and the Channel Replicator](https://github +.com/OpenHFT/Chronicle-Map#channels-and-channelreplicator) #### Miscellaneous From 02072f0e8a4a0c185f2256aa19f3ca812dad6a19 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:33:34 +0100 Subject: [PATCH 12/15] HCOLL-163 readme - https://github.com/OpenHFT/Chronicle-Map#channels-and-channelreplicator --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index f730b7679..338d01678 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,7 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C * [Identifier](https://github.com/OpenHFT/Chronicle-Map#identifier) * [Port](https://github.com/OpenHFT/Chronicle-Map#port) * [Heart Beat Interval](https://github.com/OpenHFT/Chronicle-Map#heart-beat-interval) -* [Channels and the Channel Replicator](https://github -.com/OpenHFT/Chronicle-Map#channels-and-channelreplicator) +* [Channels and the Channel Replicator](https://github.com/OpenHFT/Chronicle-Map#channels-and-channelreplicator) #### Miscellaneous From 72215a67e87ed18e80634454a97d3b30e2323bb3 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 18:35:33 +0100 Subject: [PATCH 13/15] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 338d01678..2135938aa 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C * [Replicating data between process on different servers with UDP] (https://github.com/OpenHFT/Chronicle-Map/blob/master/README.md#example--replicating-data-between-process-on-different-servers-using-udp) * [Creating a Chronicle Set and adding data to it](https://github.com/OpenHFT/Chronicle-Map/blob/master/README.md#example--creating-a-chronicle-set-and-adding-data-to-it) - #### Performance Topics * [Chronicle Map with Large Data ](https://github.com/OpenHFT/Chronicle-Map#chronicle-map-with-large-data) @@ -71,12 +70,10 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C * [Better to use small keys](https://github.com/OpenHFT/Chronicle-Map#better-to-use-small-keys) * [ConcurrentHashMap v ChronicleMap](https://github.com/OpenHFT/Chronicle-Map#concurrenthashmap-v-chroniclemap) - ### Overview Chronicle Map implements the `java.util.concurrent.ConcurrentMap`, however unlike the standard java map, ChronicleMap is able to share your entries accross processes: - ![](http://openhft.net/wp-content/uploads/2014/07/Chronicle-Map-diagram_04.jpg) ## When to use From 2aff5127672cf157e62349684f843c282ac237f5 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 19:03:43 +0100 Subject: [PATCH 14/15] HCOLL-163 renamed channel replicator to channel provider --- README.md | 20 ++++---- ...elReplicator.java => ChannelProvider.java} | 8 ++-- ...ilder.java => ChannelProviderBuilder.java} | 48 +++++++++++-------- .../chronicle/map/ChronicleMapBuilder.java | 2 +- .../net/openhft/chronicle/map/Config.java | 7 +++ .../chronicle/map/TcpReplicationConfig.java | 2 +- .../chronicle/map/UdpReplicationConfig.java | 3 +- .../chronicle/map/ChannelReplicationTest.java | 27 ++++++----- .../map/PostClusterMapCreationTest.java | 26 +++++----- .../chronicle/map/SingleMapClusterTest.java | 19 ++++---- 10 files changed, 90 insertions(+), 72 deletions(-) rename src/main/java/net/openhft/chronicle/map/{ChannelReplicator.java => ChannelProvider.java} (98%) rename src/main/java/net/openhft/chronicle/map/{ChannelReplicatorBuilder.java => ChannelProviderBuilder.java} (67%) create mode 100644 src/main/java/net/openhft/chronicle/map/Config.java diff --git a/README.md b/README.md index 338d01678..d0dfb17bd 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C * [Identifier](https://github.com/OpenHFT/Chronicle-Map#identifier) * [Port](https://github.com/OpenHFT/Chronicle-Map#port) * [Heart Beat Interval](https://github.com/OpenHFT/Chronicle-Map#heart-beat-interval) -* [Channels and the Channel Replicator](https://github.com/OpenHFT/Chronicle-Map#channels-and-channelreplicator) +* [Channels and the Channel Provider](https://github.com/OpenHFT/Chronicle-Map#channels-and-channelprovider) #### Miscellaneous @@ -512,7 +512,7 @@ A heartbeat will only be send if no data is transmitted, if the maps are constan no heartbeat message is sent. If a map does not receive either data of a heartbeat the connection is dropped and re-established. -# Channels and ChannelReplicator +# Channels and ChannelProvider Chronicle Map TCP Replication lets you distribute a single Chronicle Map, to a number of servers across your network. Replication is point to point and the data transfer is bidirectional, so in the @@ -529,28 +529,28 @@ when using Chronicle Channels its the channels that are given the unique identif ``` java byte identifier = 2; int maxEntrySize = 1024; -ChannelReplicator replicator = new ChannelReplicatorBuilder(identifier, maxEntrySize) +ChannelProvider replicator = new ChannelProviderBuilder(identifier, maxEntrySize) .create(); ``` In this example above the channel is given the identifier of 2 In addition to specifying the identifier we also have to set the maximum entry size, this sets -the size of the memory buffers within the ChannelReplicator. This has to be set manually, with channels you -are able to attach additional maps to a ChannelReplicator once its up and running, so the maximum size of each +the size of the memory buffers within the ChannelProvider. This has to be set manually, with channels you +are able to attach additional maps to a ChannelProvider once its up and running, so the maximum size of each entry in the map can not be known in advance and we don’t currently support automatic resizing of buffers. -Once you have created the ChannelReplicator you should attach your tcp configuration +Once you have created the ChannelProvider you should attach your tcp configuration ``` java byte identifier = 2; int maxEntrySize =1024; -ChannelReplicator replicator = new ChannelReplicatorBuilder(identifier, 1024) +ChannelProvider replicator = new ChannelProviderBuilder(identifier, 1024) .tcpReplication(tcpConfig) .create();; ``` -Attaching ChannelReplicator replication to the map: +Attaching ChannelProvider replication to the map: ``` java ChronicleMap map = ChronicleMapBuilder.of(Integer.class, CharSequence.class) @@ -572,8 +572,8 @@ If you inadvertently got the chronicle channels around the wrong way, then chron to replicate the wrong maps data. The chronicle channels don't have to be in order but they must be unique for each map you have. -Once you have created the ChannelReplicator you may wish to hold onto the reference so that you can call close -once you have finished, this will close everything in the ChannelReplicator +Once you have created the ChannelProvider you may wish to hold onto the reference so that you can call close +once you have finished, this will close everything in the ChannelProvider ``` java replicator.close(); diff --git a/src/main/java/net/openhft/chronicle/map/ChannelReplicator.java b/src/main/java/net/openhft/chronicle/map/ChannelProvider.java similarity index 98% rename from src/main/java/net/openhft/chronicle/map/ChannelReplicator.java rename to src/main/java/net/openhft/chronicle/map/ChannelProvider.java index 4aaa95158..c51a56e8c 100644 --- a/src/main/java/net/openhft/chronicle/map/ChannelReplicator.java +++ b/src/main/java/net/openhft/chronicle/map/ChannelProvider.java @@ -45,8 +45,8 @@ import static net.openhft.chronicle.map.Replica.ModificationNotifier.NOP; /** * @author Rob Austin. */ -public final class ChannelReplicator implements Closeable { - private static final Logger LOG = LoggerFactory.getLogger(ChannelReplicator.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 ChannelReplicator implements Closeable { @Override public void close() throws IOException { - ChannelReplicator.this.close(); + ChannelProvider.this.close(); } }; private final int maxEntrySize; @@ -169,7 +169,7 @@ public final class ChannelReplicator implements Closeable { private final Set replicators = new CopyOnWriteArraySet(); - ChannelReplicator(ChannelReplicatorBuilder builder) { + ChannelProvider(ChannelProviderBuilder builder) { localIdentifier = builder.identifier; maxEntrySize = builder.maxEntrySize; chronicleChannels = new Replica[builder.maxNumberOfChronicles]; diff --git a/src/main/java/net/openhft/chronicle/map/ChannelReplicatorBuilder.java b/src/main/java/net/openhft/chronicle/map/ChannelProviderBuilder.java similarity index 67% rename from src/main/java/net/openhft/chronicle/map/ChannelReplicatorBuilder.java rename to src/main/java/net/openhft/chronicle/map/ChannelProviderBuilder.java index 537095985..ca1a00f00 100644 --- a/src/main/java/net/openhft/chronicle/map/ChannelReplicatorBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChannelProviderBuilder.java @@ -21,40 +21,48 @@ import java.io.IOException; /** * @author Rob Austin. */ -public final class ChannelReplicatorBuilder { +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; - ChannelReplicatorBuilder(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 ChannelReplicatorBuilder udpReplication(UdpReplicationConfig replicationConfig) { - this.udpReplicationConfig = replicationConfig; return this; } - public ChannelReplicatorBuilder tcpReplication(TcpReplicationConfig replicationConfig) { - this.tcpReplicationConfig = replicationConfig; - return this; - } - - public ChannelReplicatorBuilder maxNumberOfChronicles(int maxNumberOfChronicles) { + public ChannelProviderBuilder maxNumberOfChronicles(int maxNumberOfChronicles) { this.maxNumberOfChronicles = maxNumberOfChronicles; return this; } - public ChannelReplicator create() throws IOException { - final ChannelReplicator replicatingCluster = new ChannelReplicator(this); + public ChannelProvider create() throws IOException { + final ChannelProvider replicatingCluster = new ChannelProvider(this); if (tcpReplicationConfig != null) { final TcpReplicator tcpReplicator = new TcpReplicator( replicatingCluster.asReplica, diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index ff33d1e01..6582ea539 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -562,7 +562,7 @@ public class ChronicleMapBuilder implements Cloneable, } - public ChronicleMapBuilder channel(ChannelReplicator.ChronicleChannel chronicleChannel) { + public ChronicleMapBuilder channel(ChannelProvider.ChronicleChannel chronicleChannel) { this.identifier = chronicleChannel.identifier(); this.replicators.clear(); replicators.put(chronicleChannel.getClass(), chronicleChannel); diff --git a/src/main/java/net/openhft/chronicle/map/Config.java b/src/main/java/net/openhft/chronicle/map/Config.java new file mode 100644 index 000000000..6e0d9a436 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/map/Config.java @@ -0,0 +1,7 @@ +package net.openhft.chronicle.map; + +/** + * @author Rob Austin. + */ +public interface Config { +} diff --git a/src/main/java/net/openhft/chronicle/map/TcpReplicationConfig.java b/src/main/java/net/openhft/chronicle/map/TcpReplicationConfig.java index b213f4455..5ea8cb1c1 100644 --- a/src/main/java/net/openhft/chronicle/map/TcpReplicationConfig.java +++ b/src/main/java/net/openhft/chronicle/map/TcpReplicationConfig.java @@ -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; diff --git a/src/main/java/net/openhft/chronicle/map/UdpReplicationConfig.java b/src/main/java/net/openhft/chronicle/map/UdpReplicationConfig.java index 0e02d9e9d..a1e8ad0aa 100644 --- a/src/main/java/net/openhft/chronicle/map/UdpReplicationConfig.java +++ b/src/main/java/net/openhft/chronicle/map/UdpReplicationConfig.java @@ -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()); } diff --git a/src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.java b/src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.java index 40344799a..086dffb86 100644 --- a/src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.java +++ b/src/test/java/net/openhft/chronicle/map/ChannelReplicationTest.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.IOException; @@ -40,8 +43,8 @@ public class ChannelReplicationTest { private ChronicleMap map1b; private ChronicleMap map2b; - private ChannelReplicator channelReplicatorA; - private ChannelReplicator channelReplicatorB; + private ChannelProvider channelProviderA; + private ChannelProvider channelProviderB; @Before @@ -52,13 +55,13 @@ public class ChannelReplicationTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - channelReplicatorA = new ChannelReplicatorBuilder((byte) 1, 1024) - .tcpReplication(tcpConfig) - .create(); + channelProviderA = new ChannelProviderBuilder() + .replicators((byte) 1, tcpConfig) + .create(); map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorA.createChannel((short) 1)) + .channel(channelProviderA.createChannel((short) 1)) .create(getPersistenceFile()); } @@ -66,12 +69,12 @@ public class ChannelReplicationTest { TcpReplicationConfig tcpConfig = TcpReplicationConfig.of(8087).heartBeatInterval(1, SECONDS); - channelReplicatorB = new ChannelReplicatorBuilder((byte) 2, 1024).tcpReplication(tcpConfig) + channelProviderB = new ChannelProviderBuilder().replicators((byte) 2, tcpConfig) .create(); map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorB.createChannel((short) 1)) + .channel(channelProviderB.createChannel((short) 1)) .create(getPersistenceFile()); } } @@ -79,7 +82,7 @@ public class ChannelReplicationTest { @After public void tearDown() throws InterruptedException { - for (final Closeable closeable : new Closeable[]{channelReplicatorA, channelReplicatorB}) { + for (final Closeable closeable : new Closeable[]{channelProviderA, channelProviderB}) { try { closeable.close(); } catch (IOException e) { @@ -94,13 +97,13 @@ public class ChannelReplicationTest { map2b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorB.createChannel((short) 2)) + .channel(channelProviderB.createChannel((short) 2)) .create(getPersistenceFile()); map2a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorA.createChannel((short) 2)) + .channel(channelProviderA.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 7cabde3c1..fba74f285 100644 --- a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java +++ b/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java @@ -43,8 +43,8 @@ public class PostClusterMapCreationTest { private ChronicleMap map1b; private ChronicleMap map2b; - private ChannelReplicator channelReplicatorA; - private ChannelReplicator channelReplicatorB; + private ChannelProvider channelProviderA; + private ChannelProvider channelProviderB; public static File getPersistenceFile() { String TMP = System.getProperty("java.io.tmpdir"); @@ -59,43 +59,43 @@ public class PostClusterMapCreationTest { public void setup() throws IOException { { - final TcpReplicationConfig tcpReplicationConfig = TcpReplicationConfig + final TcpReplicationConfig tcpConfig = TcpReplicationConfig .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - channelReplicatorA = new ChannelReplicatorBuilder((byte) 1, 1024) - .tcpReplication(tcpReplicationConfig).create(); + channelProviderA = new ChannelProviderBuilder() + .replicators((byte) 1, tcpConfig).create(); // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorA.createChannel((short) 1)) + .channel(channelProviderA.createChannel((short) 1)) .create(getPersistenceFile()); map2a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorA.createChannel((short) 2)) + .channel(channelProviderA.createChannel((short) 2)) .create(getPersistenceFile()); } { - final TcpReplicationConfig tcpReplicationConfig = TcpReplicationConfig + final TcpReplicationConfig tcpConfig = TcpReplicationConfig .of(8087, new InetSocketAddress("localhost", 8086)) .heartBeatInterval(1, SECONDS); - channelReplicatorB = new ChannelReplicatorBuilder((byte) 2, 1024) - .tcpReplication(tcpReplicationConfig).create(); + channelProviderB = new ChannelProviderBuilder() + .replicators((byte) 2, tcpConfig).create(); // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorB.createChannel((short) 1)) + .channel(channelProviderB.createChannel((short) 1)) .create(getPersistenceFile()); map2b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorB.createChannel((short) 2)) + .channel(channelProviderB.createChannel((short) 2)) .create(getPersistenceFile()); } @@ -105,7 +105,7 @@ public class PostClusterMapCreationTest { @After public void tearDown() throws InterruptedException { - for (final Closeable closeable : new Closeable[]{channelReplicatorA, channelReplicatorB}) { + for (final Closeable closeable : new Closeable[]{channelProviderA, channelProviderB}) { try { closeable.close(); } catch (IOException e) { diff --git a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java index cd0e870d0..82ede45f6 100644 --- a/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java +++ b/src/test/java/net/openhft/chronicle/map/SingleMapClusterTest.java @@ -41,8 +41,8 @@ public class SingleMapClusterTest { private ChronicleMap map1b; - private ChannelReplicator channelReplicatorA; - private ChannelReplicator channelReplicatorB; + private ChannelProvider channelProviderA; + private ChannelProvider channelProviderB; public static File getPersistenceFile() { String TMP = System.getProperty("java.io.tmpdir"); @@ -60,12 +60,12 @@ public class SingleMapClusterTest { .of(8086, new InetSocketAddress("localhost", 8087)) .heartBeatInterval(1, SECONDS); - channelReplicatorA = new ChannelReplicatorBuilder((byte) 1, 1024) - .tcpReplication(tcpReplicationConfig).create(); + channelProviderA = new ChannelProviderBuilder() + .replicators((byte) 1, tcpReplicationConfig).create(); // this is how you add maps after the custer is created map1a = ChronicleMapBuilder.of(Integer.class, CharSequence.class) .entries(1000) - .channel(channelReplicatorA.createChannel((short) 1)) + .channel(channelProviderA.createChannel((short) 1)) .create(getPersistenceFile()); } @@ -75,11 +75,12 @@ public class SingleMapClusterTest { .of(8087, new InetSocketAddress("localhost", 8086)) .heartBeatInterval(1, SECONDS); - channelReplicatorB = new ChannelReplicatorBuilder((byte) 2, 1024) - .tcpReplication(tcpReplicationConfig).create(); + channelProviderB = new ChannelProviderBuilder() + .replicators((byte) 2, tcpReplicationConfig).create(); + // this is how you add maps after the custer is created map1b = ChronicleMapBuilder.of(Integer.class, CharSequence.class) - .channel(channelReplicatorB.createChannel((short) 1)) + .channel(channelProviderB.createChannel((short) 1)) .entries(1000) .create(getPersistenceFile()); } @@ -88,7 +89,7 @@ public class SingleMapClusterTest { @After public void tearDown() throws InterruptedException { - for (final Closeable closeable : new Closeable[]{channelReplicatorA, channelReplicatorB}) { + for (final Closeable closeable : new Closeable[]{channelProviderA, channelProviderB}) { try { closeable.close(); } catch (IOException e) { From 6699ff682e20cd4d29dcf0dd9acf13aec42dd965 Mon Sep 17 00:00:00 2001 From: Rob Austin Date: Mon, 13 Oct 2014 19:06:13 +0100 Subject: [PATCH 15/15] HCOLL-163 renamed channel replicator to channel provider --- ...ClusterMapCreationTest.java => PostChannelCreationTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/net/openhft/chronicle/map/{PostClusterMapCreationTest.java => PostChannelCreationTest.java} (99%) diff --git a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java b/src/test/java/net/openhft/chronicle/map/PostChannelCreationTest.java similarity index 99% rename from src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java rename to src/test/java/net/openhft/chronicle/map/PostChannelCreationTest.java index fba74f285..f5292974c 100644 --- a/src/test/java/net/openhft/chronicle/map/PostClusterMapCreationTest.java +++ b/src/test/java/net/openhft/chronicle/map/PostChannelCreationTest.java @@ -35,7 +35,7 @@ import static org.junit.Assert.assertTrue; * * @author Rob Austin. */ -public class PostClusterMapCreationTest { +public class PostChannelCreationTest { private ChronicleMap map1a; private ChronicleMap map2a;