diff --git a/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java b/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java index e4a21799a..107ab10c9 100644 --- a/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java +++ b/src/main/java/net/openhft/chronicle/ChronicleHashBuilder.java @@ -1,17 +1,14 @@ package net.openhft.chronicle; -import net.openhft.chronicle.map.ChannelProvider; -import net.openhft.chronicle.map.ChronicleMap; -import net.openhft.chronicle.map.ChronicleMapBuilder; -import net.openhft.chronicle.map.ReplicationConfig; +import net.openhft.chronicle.map.*; import net.openhft.chronicle.set.ChronicleSet; import net.openhft.chronicle.set.ChronicleSetBuilder; -import net.openhft.lang.io.serialization.BytesMarshaller; -import net.openhft.lang.io.serialization.BytesMarshallerFactory; -import net.openhft.lang.io.serialization.ObjectSerializer; +import net.openhft.lang.io.serialization.*; +import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory; import net.openhft.lang.model.Byteable; import org.jetbrains.annotations.NotNull; +import java.io.Externalizable; import java.io.File; import java.io.IOException; import java.util.HashMap; @@ -22,20 +19,35 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** - * This interface defines the meaning of configurations, common to {@link ChronicleMapBuilder} and {@link - * ChronicleSetBuilder}, i. e. Chronicle hash container configurations. + * This interface defines the meaning of configurations, common to {@link ChronicleMapBuilder} + * and {@link ChronicleSetBuilder}, i. e. Chronicle hash container configurations. + * + *

{@code ChronicleHashBuilder} 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. * * @param the type of keys in hash containers, created by this builder - * @param the container type, created by this builder, i. e. {@link ChronicleMap} or {@link ChronicleSet} - * @param the concrete builder type, i. e. {@link ChronicleMapBuilder} or {@link ChronicleSetBuilder} + * @param the container type, created by this builder, i. e. {@link ChronicleMap} + * or {@link ChronicleSet} + * @param the concrete builder type, i. e. {@link ChronicleMapBuilder} + * or {@link ChronicleSetBuilder} */ public interface ChronicleHashBuilder> extends Cloneable { + /** + * Clones this builder. Useful for configuration persisting, because + * {@code ChronicleHashBuilder}s are mutable and changed on each configuration method call. + * Original and cloned builders are independent. + * + * @return a new clone of this builder + */ B clone(); /** - * Set minimum number of segments. See concurrencyLevel in {@link ConcurrentHashMap}. + * Set minimum number of segments in hash containers, constructed by this builder. + * See concurrencyLevel in {@link ConcurrentHashMap}. * * @param minSegments the minimum number of segments in containers, constructed by this builder * @return this builder object back @@ -43,13 +55,14 @@ public interface ChronicleHashBuilderIf 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. * * @param keySize number of bytes, taken by serialized form of keys * @return this builder back @@ -59,15 +72,15 @@ public interface ChronicleHashBuilderIf 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 @@ -76,43 +89,55 @@ public interface ChronicleHashBuilder{@link ChronicleMap} and {@link ChronicleSet} store their data off-heap, so it is required to - * serialize key (and values, in {@code ChronicleMap} case) (unless they are direct {@link Byteable} - * instances). Serialized key bytes (+ serialized value bytes, in {@code ChronicleMap} case) + some - * metadata bytes comprise "entry space", which {@code ChronicleMap} or {@code ChronicleSet} should - * allocate. So entry size is a minimum allocation portion in the hash containers, created by this - * builder. E. g. if entry size is 100, the created container 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. + *

{@link ChronicleMap} and {@link ChronicleSet} store their data off-heap, so it is required + * to serialize key (and values, in {@code ChronicleMap} case) (unless they are direct + * {@link Byteable} instances). Serialized key bytes (+ serialized value bytes, + * in {@code ChronicleMap} case) + some metadata bytes comprise "entry space", which + * {@code ChronicleMap} or {@code ChronicleSet} should allocate. So entry size + * is a minimum allocation portion in the hash containers, created by this builder. + * E. g. if entry size is 100, the created container 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. * - *

There are three major patterns of this configuration usage:

  1. Key (and value, in {@code - * ChronicleMap} case) sizes are constant. Configure them via {@link #constantKeySizeBySample(Object)} and - * {@link ChronicleMapBuilder#constantValueSizeBySample(Object)} methods, and you will experience no - * memory waste at all.
  2. Key (and/or value size, in {@code ChronicleMap} case) varies moderately. - * Specify them using corresponding methods, or specify entry size directly by calling this method, by - * sizes 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.
  3. Key (and/or value size, in {@code - * ChronicleMap} case) 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, in {@code ChronicleMap} case) sizes are constant. Configure them + * via {@link #constantKeySizeBySample(Object)} and + * {@link ChronicleMapBuilder#constantValueSizeBySample(Object)} methods, and you will + * experience no memory waste at all.
    2. + *
    3. Key (and/or value size, in {@code ChronicleMap} case) varies moderately. Specify them + * using corresponding methods, or specify entry size directly by calling this method, + * by sizes 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, in {@code ChronicleMap} case) 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 {@code ChronicleMap} 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 {@code ChronicleMap} 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
      @@ -120,8 +145,11 @@ public interface ChronicleHashBuilder
      -     * 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%). 
    + * 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%). + *
  4. + *
* * @param entrySize the "chunk size" in bytes * @return this builder back @@ -130,28 +158,35 @@ public interface ChronicleHashBuilder
  • If key size (and value size, in {@code ChronicleMap} case) is constant, this number is equal - * to the maximum number of entries (because each entry takes exactly one "entry size" memory unit).
  • - *
  • If key (and/or value, in {@code ChronicleMap} case) 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 ChronicleMapBuilder#valueSize(int) value}/{@linkplain - * #entrySize(int) entry} sizes.
  • 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.
  • + *
      + *
    1. If key size (and value size, in {@code ChronicleMap} case) is 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, in {@code ChronicleMap} case) 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 + * ChronicleMapBuilder#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. + *
    * - *

    You shouldn't put additional margin over the number, computed according the rules above. This bad - * practice was popularized by {@link HashMap#HashMap(int)} and {@link HashSet#HashSet(int)} constructors, - * which accept "capacity", that should be multiplied by "load factor" to obtain actual maximum expected - * number of entries. {@code ChronicleMap} and {@code ChronicleSet} don'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)} + * and {@link HashSet#HashSet(int)} constructors, which accept "capacity", that should + * be multiplied by "load factor" to obtain actual maximum expected number of entries. + * {@code ChronicleMap} and {@code ChronicleSet} don'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) */ @@ -161,6 +196,22 @@ public interface ChronicleHashBuilderDefault lock time out is 2 seconds. + * + * @param lockTimeOut new lock timeout for segments of containers created by this builder, + * in the given time units + * @param unit time unit of the given lock timeout + * @return this builder back + */ B lockTimeOut(long lockTimeOut, TimeUnit unit); B errorListener(ChronicleHashErrorListener errorListener); @@ -169,34 +220,182 @@ public interface ChronicleHashBuilder + * the section about replication in ChronicleMap manual for more information. + * + *

    Another way to establish replication is {@link #channel(ChannelProvider.ChronicleChannel)} + * method. + * + *

    By default, hash containers, created by this builder doesn't replicate their data. + * + *

    This method call overrides all previous replication configurations of this builder, made + * either by this method or {@link #channel(ChannelProvider.ChronicleChannel)} method. + * + * @param identifier the new {@linkplain Replica#identifier() identifier} of the containers, + * created by this builder + * @param replicators several replicators, used to sync the data across replicating nodes + * independently + * @return this builder back + * @see #channel(ChannelProvider.ChronicleChannel) + * @see #disableReplication() + */ B replicators(byte identifier, ReplicationConfig... replicators); + /** + * Configures replication of the hash containers, created by this builder, + * via so called "channels". See the section + * about Channels and ChannelProvider in ChronicleMap manual for more information. + * + *

    Another way to establish replication if {@link #replicators(byte, ReplicationConfig[])} + * method. + * + *

    By default, hash containers, created by this builder doesn't replicate their data. + * + *

    This method call overrides all previous replication configurations of this builder, made + * either by means of this method or {@link #replicators(byte, ReplicationConfig[])} method + * calls. + * + * @param chronicleChannel the channel responsible for gathering updates of hash containers, + * created by this builder, and replicating them over network + * @return this builder object back + * @see #replicators(byte, ReplicationConfig[]) + * @see #disableReplication() + */ B channel(ChannelProvider.ChronicleChannel chronicleChannel); + /** + * Specifies that hash containers, created by this builder, shouldn't replicate their data over + * network. This method call clears any replication configurations, made via {@link + * #replicators(byte, ReplicationConfig[])} or {@link #channel( + * ChannelProvider.ChronicleChannel)} method call. + * + *

    By default replication is not configured, so this method is useful only to ensure + * that hash containers, created by some inherited or passed builder, wouldn't replicate. I. e. + * in rare cases. + * + * @return this builder back + * @see #replicators(byte, ReplicationConfig[]) + * @see #channel(ChannelProvider.ChronicleChannel) + */ + B disableReplication(); + + /** + * Configures a time provider, used by hash containers, created by this builder, for needs of + * replication consensus protocol (conflicting data updates resolution). + * + *

    Default time provider is {@link TimeProvider#SYSTEM}. + * @param timeProvider a new time provider for replication needs + * @return this builder back + * @see #replicators(byte, ReplicationConfig[]) + * @see #channel(ChannelProvider.ChronicleChannel) + */ B timeProvider(TimeProvider timeProvider); + /** + * Configures a {@link BytesMarshallerFactory} to be used with + * {@link BytesMarshallableSerializer}, which is a default {@link #objectSerializer + * ObjectSerializer}, to serialize/deserialize data to/from off-heap memory in hash containers, + * created by this builder. + * + *

    Default {@code BytesMarshallerFactory} is an instance of {@link + * VanillaBytesMarshallerFactory}. This is a convenience configuration method, it has no effect + * on the resulting hash containers, if {@linkplain #keyMarshaller(BytesMarshaller) custom data + * marshallers} are configured, data types extends one of specific serialization interfaces, + * recognized by this builder (e. g. {@code Externalizable} or {@code BytesMarshallable}), + * or {@code ObjectSerializer} is configured. + * + * @param bytesMarshallerFactory the marshaller factory to be used with the default + * {@code ObjectSerializer}, i. e. {@code BytesMarshallableSerializer} + * @return this builder back + * @see #objectSerializer(ObjectSerializer) + */ B bytesMarshallerFactory(BytesMarshallerFactory bytesMarshallerFactory); + /** + * Configures the serializer used to serialize/deserialize data to/from off-heap memory, when + * specified class doesn't implement a specific serialization interface like {@link + * Externalizable} or {@link BytesMarshallable} (for example, if data is loosely typed and just + * {@code Object} is specified as the data class), or nullable data, and if custom marshaller + * is not {@linkplain #keyMarshaller(BytesMarshaller) configured}, in hash containers, created + * by this builder. Please read {@link ObjectSerializer} docs for more info and available + * options. + * + *

    Default serializer is {@link BytesMarshallableSerializer}, configured with the specified + * or default {@link #bytesMarshallerFactory(BytesMarshallerFactory) BytesMarshallerFactory}. + * + * @param objectSerializer the serializer used to serialize loosely typed or nullable data + * if custom marshaller is not configured + * @return this builder back + * @see #bytesMarshallerFactory(BytesMarshallerFactory) + * @see #keyMarshaller(BytesMarshaller) + */ B objectSerializer(ObjectSerializer objectSerializer); + /** + * Configures the {@code BytesMarshaller} used to serialize/deserialize keys to/from off-heap + * memory in hash containers, created by this builder. See the section about serialization + * in ChronicleMap manual for more information. + * + * @param keyMarshaller the marshaller used to serialize keys + * @return this builder back + * @see #objectSerializer(ObjectSerializer) + */ B keyMarshaller(@NotNull BytesMarshaller keyMarshaller); /** - * Specifies that key objects, queried with the hash containers, created by this builder, are inherently - * immutable. Keys in {@link ChronicleMap} or {@link ChronicleSet} are not required to be immutable, as in - * ordinary {@link Map} or {@link Set} implementations, because they are serialized off-heap. However, - * {@code ChronicleMap} and {@code ChronicleSet} implementations can benefit from the knowledge that keys - * are not mutated between queries. + * Specifies that key objects, queried with the hash containers, created by this builder, + * are inherently immutable. Keys in {@link ChronicleMap} or {@link ChronicleSet} + * are not required to be immutable, as in ordinary {@link Map} or {@link Set} implementations, + * because they are serialized off-heap. However, {@code ChronicleMap} and {@code ChronicleSet} + * implementations can benefit from the knowledge that keys are not mutated between queries. * - *

    By default, {@code ChronicleHashBuilder}s detects immutability automatically only for very few - * standard JDK types (for example, for {@link String}), it is not recommended to rely on {@code - * ChronicleHashBuilder} to be smart enough about this. + *

    By default, {@code ChronicleHashBuilder}s detects immutability automatically + * only for very few standard JDK types (for example, for {@link String}), it is not recommended + * to rely on {@code ChronicleHashBuilder} to be smart enough about this. * * @return this builder back */ B immutableKeys(); + /** + * Opens a hash container residing the specified file, or creates a new one if the file not yet + * exists and maps its off-heap memory to the file. All changes to the map are persisted to disk + * (this is an operating system guarantee) independently from JVM process lifecycle. + * + *

    Multiple containers could give access to the same data simultaneously, either inside + * a single JVM or across processes. Access is synchronized correctly across all instances, + * i. e. hash container mapping the data from the first JVM isn't able to modify the data, + * concurrently accessed from the second JVM by another hash container instance, mapping + * the same data. + * + *

    On container's {@link ChronicleHash#close() close()} the data isn't removed, it remains + * on disk and available to be opened again (given the same file name) or during different JVM + * run. + * + * @param file the file with existing hash container or a desired location of a new off-heap + * persisted hash container + * @return a hash container mapped to the given file + * @throws IOException if any IO error, related to off-heap memory allocation or file mapping + * occurs + * @see ChronicleHash#file() + * @see ChronicleHash#close() + * @see #create() + */ C create(File file) throws IOException; + /** + * Creates a new hash container, storing it's data in off-heap memory, not mapped to any file. + * On {@link ChronicleHash#close()} called on the returned container, or after the container + * object is collected during GC, or on JVM shutdown the off-heap memory used by the returned + * container is freed. + * + * @return a new off-heap hash container + * @throws IOException if any IO error relates to off-heap memory allocation occurs + * @see #create() + */ C create() throws IOException; } diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ChronicleMap.java index 3e69ead86..fc28db0f2 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMap.java @@ -24,8 +24,6 @@ import net.openhft.lang.io.serialization.ObjectFactory; import net.openhft.lang.model.Byteable; import java.io.Closeable; -import java.io.File; -import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentMap; diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index b55e7db2f..b2d016bfc 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -24,6 +24,7 @@ import net.openhft.chronicle.serialization.AgileBytesMarshaller; import net.openhft.chronicle.serialization.MetaBytesInterop; import net.openhft.chronicle.serialization.MetaBytesWriter; import net.openhft.chronicle.serialization.MetaProvider; +import net.openhft.chronicle.set.ChronicleSetBuilder; import net.openhft.chronicle.threadlocal.Provider; import net.openhft.chronicle.threadlocal.ThreadLocalCopies; import net.openhft.lang.Maths; @@ -66,9 +67,8 @@ 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, see a note in {@link ChronicleHashBuilder} interface + * documentation. * *

    Later in this documentation, "ChronicleMap" means "ChronicleMaps, created by {@code * ChronicleMapBuilder}", unless specified different, because theoretically someone might provide {@code @@ -85,6 +85,8 @@ import static net.openhft.chronicle.map.Objects.builderEquals; * * @param key type of the maps, produced by this builder * @param value type of the maps, produced by this builder + * @see ChronicleMap + * @see ChronicleSetBuilder */ public class ChronicleMapBuilder implements Cloneable, ChronicleHashBuilder, ChronicleMapBuilder> { @@ -586,6 +588,13 @@ public class ChronicleMapBuilder implements Cloneable, return this; } + @Override + public ChronicleMapBuilder disableReplication() { + identifier = -1; + replicators.clear(); + return this; + } + @Override public ChronicleMapBuilder timeProvider(TimeProvider timeProvider) { this.timeProvider = timeProvider; @@ -615,6 +624,22 @@ public class ChronicleMapBuilder implements Cloneable, objectSerializer; } + /** + * {@inheritDoc} + * + *

    Example:

    {@code Map map =
    +     *     ChronicleMapBuilder.of(Key.class, Value.class)
    +     *     .entries(1_000_000)
    +     *     .keySize(50).valueSize(200)
    +     *     // this class hasn't implemented yet, just for example
    +     *     .objectSerializer(new KryoObjectSerializer())
    +     *     .create();}
    + * + *

    This serializer is used to serialize both keys and values, if they both require this: + * loosely typed, nullable, and custom {@linkplain #keyMarshaller(BytesMarshaller) key} + * and {@linkplain #valueMarshallerAndFactory(BytesMarshaller, ObjectFactory) value} marshallers + * are not configured. + */ @Override public ChronicleMapBuilder objectSerializer(ObjectSerializer objectSerializer) { this.objectSerializer = objectSerializer; @@ -622,6 +647,11 @@ public class ChronicleMapBuilder implements Cloneable, } + /** + * {@inheritDoc} + * + *

    Example: + */ @Override public ChronicleMapBuilder keyMarshaller(@NotNull BytesMarshaller keyMarshaller) { keyBuilder.marshaller(keyMarshaller, null); diff --git a/src/main/java/net/openhft/chronicle/map/MapEventListener.java b/src/main/java/net/openhft/chronicle/map/MapEventListener.java index 8bde8ff79..36a6450d7 100644 --- a/src/main/java/net/openhft/chronicle/map/MapEventListener.java +++ b/src/main/java/net/openhft/chronicle/map/MapEventListener.java @@ -21,10 +21,29 @@ import net.openhft.lang.io.Bytes; import java.io.Serializable; /** - * This event listener is called when key events occur. - *

    All these calls are synchronous while a lock is held so make them as quick as possible

    - *

    - * TODO specify more clearly in which cases methods are called. + * Contains methods which are called when {@link ChronicleMap} key events occur. Typical use cases: + *

      + *
    • Map data backup / replication.
    • + *
    • Logging, monitoring, debugging.
    • + *
    + * + *

    This is an adapter class - all methods have default implementations as no-ops. Extend this + * class and override only methods corresponding the events you are interested in. + * + *

    To configure {@code MapEventListener} for {@code ChronicleMap}, use + * {@link ChronicleMapBuilder#eventListener(MapEventListener)} method. + * + *

    {@link MapEventListeners} uninstantiable class contains several logging implementations and + * the default {@linkplain MapEventListeners#nop() no-op implementation}. + * + *

    All these calls are synchronous while a {@code ChronicleMap} lock is held so make them + * as quick as possible. + * + * @param key type of the maps, trackable by this event listener + * @param value type of the maps, trackable by this event listener + * @param {@code ChronicleMap} subtype, trackable by this event listener + * @see ChronicleMapBuilder#eventListener(MapEventListener) + * @see MapEventListeners */ public abstract class MapEventListener> implements Serializable { @@ -51,14 +70,23 @@ public abstract class MapEventListener> } /** - * This method is called if a key/value is put in the map. + * This method is call whenever a new value is put for the key in the map during calls of such + * methods as {@link ChronicleMap#put put}, {@link ChronicleMap#putIfAbsent putIfAbsent}, + * {@link ChronicleMap#replace(Object, Object, Object) replace}, etc. When a new value is + * {@linkplain ChronicleMapBuilder#defaultValue(Object) default} for the map or obtained during + * {@link ChronicleMap#acquireUsing acquireUsing} call is put for the key, this method is called + * as well. * - * @param map accessed - * @param entry added/modified - * @param metaDataBytes length of the meta data - * @param added if this is a new entry - * @param key looked up - * @param value set for key + *

    This method is called when put is already happened. + * + * @param map the accessed map + * @param entry bytes of the entry (with the value already written to) + * @param metaDataBytes length of meta data for this map + * @param added {@code true} is the key was absent in the map before current + * {@code ChronicleMap} method call, led to putting a value and inherently + * calling this listener method + * @param key the key the value is put for + * @param value the value which was associated with the key */ public void onPut(M map, Bytes entry, int metaDataBytes, boolean added, K key, V value) { // do nothing @@ -85,6 +113,4 @@ public abstract class MapEventListener> void onRelocation(int pos, SharedSegment segment) { // do nothing } - - } diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index aadec9d79..495c01d95 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -969,8 +969,10 @@ class VanillaChronicleMap, } /** - * Removes a key (or key-value pair) from the Segment.

    The entry will only be removed if {@code - * expectedValue} equals to {@code null} or the value previously corresponding to the specified key. + * Removes a key (or key-value pair) from the Segment. + * + *

    The entry will only be removed if {@code expectedValue} equals to {@code null} + * or the value previously corresponding to the specified key. * * @param hash2 a hash code related to the {@code keyBytes} * @return the value of the entry that was removed if the entry corresponding to the {@code keyBytes} diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java index 1b2571609..30fa67ca6 100644 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java @@ -30,7 +30,17 @@ import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; - +/** + * {@code ChronicleSetBuilder} manages the whole set of {@link ChronicleSet} configurations, + * could be used as a classic builder and/or factory. + * + *

    {@code ChronicleMapBuilder} is mutable, see a note in {@link ChronicleHashBuilder} interface + * documentation. + * + * @param element type of the sets, created by this builder + * @see ChronicleSet + * @see ChronicleMapBuilder + */ public class ChronicleSetBuilder implements ChronicleHashBuilder, ChronicleSetBuilder> { @@ -175,6 +185,12 @@ public class ChronicleSetBuilder return this; } + @Override + public ChronicleSetBuilder disableReplication() { + chronicleMapBuilder.disableReplication(); + return this; + } + @Override public String toString() { @@ -209,6 +225,16 @@ public class ChronicleSetBuilder return this; } + /** + * {@inheritDoc} + * + *

    Example:

    {@code Set set = ChronicleSetBuilder.of(Key.class)
    +     *     .entries(1_000_000)
    +     *     .keySize(100)
    +     *     // this class hasn't implemented yet, just for example
    +     *     .objectSerializer(new KryoObjectSerializer())
    +     *     .create();}
    + */ @Override public ChronicleSetBuilder objectSerializer(ObjectSerializer objectSerializer) { chronicleMapBuilder.objectSerializer(objectSerializer);