diff --git a/LICENSE b/LICENSE index 02bbb60bc..84337b4c5 100644 --- a/LICENSE +++ b/LICENSE @@ -5,7 +5,6 @@ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. diff --git a/docs/CM_Compatibility_and_Versioning.adoc b/docs/CM_Compatibility_and_Versioning.adoc index a8c7a31a1..0f8d827a6 100755 --- a/docs/CM_Compatibility_and_Versioning.adoc +++ b/docs/CM_Compatibility_and_Versioning.adoc @@ -74,7 +74,6 @@ The versioning format is as follows: For example: `3.14.1` - === The number should be updated, when: - **a feature, or public API** method is added. @@ -117,6 +116,5 @@ incompatible, its revision should be set to `-pre` until the next productio Releases and updates to the `` number in the library version should be synchronized with updates to the specification revision number. - ''' <<../ReadMe.adoc#,Back to ReadMe>> diff --git a/docs/CM_Download.adoc b/docs/CM_Download.adoc index 9da022f8e..3a8611f4a 100755 --- a/docs/CM_Download.adoc +++ b/docs/CM_Download.adoc @@ -26,7 +26,6 @@ license, please contact mailto:sales@chronicle.software. [caption="", link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-map] image::https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-map/badge.svg[] - ``` xml net.openhft diff --git a/docs/CM_FAQs.adoc b/docs/CM_FAQs.adoc index 19810ede6..27746cfd3 100755 --- a/docs/CM_FAQs.adoc +++ b/docs/CM_FAQs.adoc @@ -22,6 +22,5 @@ You would not gain a performance benefit by using batches, unless you are compre NOTE: Under high load, the Chronicle Map stateless client consolidates many small TCP requests into a single request when run with a number of threads. - ''' <<../ReadMe.adoc#,Back to ReadMe>> diff --git a/docs/CM_Features.adoc b/docs/CM_Features.adoc index fe2b87358..421807e33 100755 --- a/docs/CM_Features.adoc +++ b/docs/CM_Features.adoc @@ -29,7 +29,6 @@ applications, such as trading and financial market applications. - Replication *without logs*, with constant footprint cost, guarantees progress even if the network doesn't sustain write rates. - NOTE: See <> for more information. **Chronicle Map** has two meanings: @@ -143,6 +142,5 @@ NOTE: For access to commercially available features please contact mailto:sales@ - https://plus.google.com/communities/111431452027706917722[Chronicle User's group] - http://jrvis.com/red-dwarf/?user=openhft&repo=Chronicle-Map[Chronicle Map usage heatmap] - ''' <<../ReadMe.adoc#,Back to ReadMe>> diff --git a/docs/CM_Replication.adoc b/docs/CM_Replication.adoc index bfaa590cc..d2aa1ae46 100755 --- a/docs/CM_Replication.adoc +++ b/docs/CM_Replication.adoc @@ -188,7 +188,6 @@ now contains 200 entries. This example is available in the repository, https://github.com/ChronicleEnterprise/Chronicle-Map-Enterprise/blob/master/src/test/java/software/chronicle/enterprise/map/example/MultiMasterMapReplicationExampleMain.java[MultiMasterMapReplicationExampleMain.java] - == Replication event logging Chronicle Map Enterprise can be configured to log all replication events to a Chronicle Queue for auditing purposes. diff --git a/docs/CM_Replication_Stress_Test.adoc b/docs/CM_Replication_Stress_Test.adoc index dbc7cfb78..0c4159907 100755 --- a/docs/CM_Replication_Stress_Test.adoc +++ b/docs/CM_Replication_Stress_Test.adoc @@ -46,7 +46,6 @@ Checking maps for equality All maps contained the same data .... - == Running the test in multiple JVMs To spread the workload over multiple JVMs, use the `-h` parameter, which specifies the nodes that should be started in a particular JVM. The `singleMasterStressTest.yaml` configuration file contains 4 nodes (1 master, 3 slaves). The example below spreads these nodes across two processes. @@ -131,7 +130,6 @@ Hosts within the cluster: NOTE: Substitute your own settings as appropriate. - **TCP port used for replication**; this port will need to be open on all hosts: `13000` @@ -140,10 +138,8 @@ NOTE: Substitute your own settings as appropriate. `multiHost.yaml` - The cluster configuration in `multiHost.yaml` would be: - [source,yaml] .... clusterConfig: !Clusters { @@ -187,7 +183,6 @@ The cluster configuration in `multiHost.yaml` would be: } .... - === Packaging the test To run the test on remote machines, the stress test can be packaged up using the following command: @@ -217,7 +212,6 @@ To run the example multi-machine configuration described above, the following co | **D** | `4` |`10.0.2.22` | `./run_stress_test.sh -c multiHost.yaml -h 4` |======================================= - == Destructive testing There are two ways of recovering from node failure: @@ -274,7 +268,6 @@ the slave map receives the entire data-set from the master: Node 3 received 1646 events/sec, 234KB/sec from remote 1 .... - === Recover existing data and rejoin (Option 2) The stress test can be configured, using the `-r` parameter, to recover from existing data on startup. diff --git a/docs/CM_Tutorial.adoc b/docs/CM_Tutorial.adoc index 2a035f1ce..a72976525 100755 --- a/docs/CM_Tutorial.adoc +++ b/docs/CM_Tutorial.adoc @@ -10,7 +10,6 @@ toc::[] This document describes the Chronicle Map tutorial supplied with the project. - == Create a `ChronicleMap` Instance Creating an instance of `ChronicleMap` is a little more complex than just calling a constructor. @@ -21,7 +20,6 @@ The following code snippet creates an in-memory Chronicle Map store, to store ab It is accessible within a single JVM process; the process in which it was created. The data is accessible while the process is alive. When the process is terminated, the data is cleared. - ``` java import net.openhft.chronicle.map.* ..... @@ -69,7 +67,6 @@ NOTE: When you create a `ChronicleMap` instance with `.createPersistedTo(file)`, file already exists in the system, you open a view to the existing Chronicle Map data store from this JVM process, rather than creating a new Chronicle Map data store. That means that the data store may already contain some entries. No special action with the data is performed during such an operation. If you want to clean up corrupted entries, and ensure that the data store is in correct state, see the <> section. - == ChronicleMap instance vs Chronicle Map data store In this tutorial, the term `ChronicleMap` instance (or simply `ChronicleMap`) is used to refer to an on-heap object providing access to a Chronicle Map data store (or Chronicle Map key-value store, or Chronicle Map store, or simply Chronicle Map, with space between two words in contrast to `ChronicleMap`), which could be purely in-memory, or persisted to disk. @@ -84,7 +81,6 @@ even to another server. It could even run on different operating systems. When o If you don't need the Chronicle Map instance to survive the server restart (that is, you don't need persistence to disk; only multi-process access), mount the file on http://en.wikipedia.org/wiki/Tmpfs[tmpfs]. For example, on `Linux` it is as easy as placing you file in `/dev/shm` directory. - == Configure entries You must configure .entries(entries) -- to support the maximum number of entries in the Chronicle Map. Try to configure the entries so that the created Chronicle Map is going to serve about 99% of requests. @@ -96,7 +92,6 @@ See `ChronicleMapBuilder#entries()` in http://www.javadoc.io/doc/net.openhft/chr Once a `ChronicleMap` instance is created, its configurations are sealed and cannot be changed using the `ChronicleMapBuilder` instance. - == Single `ChronicleMap` instance per JVM If you want to access a Chronicle Map data store concurrently within a Java process, you should not create a separate `ChronicleMap` instance for each thread. Within the JVM environment, a `ChronicleMap` instance is a `ConcurrentMap`, and could be accessed concurrently the same way as, for example, a `ConcurrentHashMap`. @@ -606,7 +601,6 @@ You can customize the behaviour of Chronicle Map. See <> for more details. - == Entry checksums Chronicle Map is able to store entry checksums along with entries. With entry checksums it is diff --git a/docs/CM_Tutorial_Bytes.adoc b/docs/CM_Tutorial_Bytes.adoc index feec46569..556c0ea32 100755 --- a/docs/CM_Tutorial_Bytes.adoc +++ b/docs/CM_Tutorial_Bytes.adoc @@ -399,6 +399,5 @@ Some notes on this form of custom serialization: - Both writer and reader classes have some "cache" fields; their contents are mutated during writing and reading. That is why they have to implement the `StatefulCopyable` interface. - ''' <> diff --git a/docs/CM_Tutorial_DataAccess.adoc b/docs/CM_Tutorial_DataAccess.adoc index 2ed00f063..22adcac44 100755 --- a/docs/CM_Tutorial_DataAccess.adoc +++ b/docs/CM_Tutorial_DataAccess.adoc @@ -159,6 +159,5 @@ public final class ByteArraySizedReader NOTE: If you configure `byte[]` key, or value type, then this pair of serializers is used as the default. - ''' <> \ No newline at end of file diff --git a/docs/CM_Tutorial_Understanding.adoc b/docs/CM_Tutorial_Understanding.adoc index 4521678d0..9bd83b7d1 100755 --- a/docs/CM_Tutorial_Understanding.adoc +++ b/docs/CM_Tutorial_Understanding.adoc @@ -64,6 +64,5 @@ Typically this is the case when the serializer is configured with sub-serializers, which might be `StatefulCopyable`, or not. For example, the https://github.com/OpenHFT/Chronicle-Map/blob/master/src/main/java/net/openhft/chronicle/hash/serialization/ListMarshaller.java[`ListMarshaller`] class. - ''' <> diff --git a/docs/CM_Updates.adoc b/docs/CM_Updates.adoc index eda140f89..1bfbda862 100755 --- a/docs/CM_Updates.adoc +++ b/docs/CM_Updates.adoc @@ -38,6 +38,5 @@ Changes between Chronicle Map 3 and the previous Chronicle Map version are detai - Chronicle Map 3 has <>. - ''' <<../ReadMe.adoc#,Back to ReadMe>> diff --git a/docs/archived/README.md b/docs/archived/README.md index 6bb5b5aea..dfeaaf77f 100755 --- a/docs/archived/README.md +++ b/docs/archived/README.md @@ -2034,7 +2034,6 @@ try (ChronicleMap map = ChronicleMap } ``` - ## FAQ's ### Question diff --git a/pom.xml b/pom.xml index 0c9f2e4a2..006d05b5f 100755 --- a/pom.xml +++ b/pom.xml @@ -15,13 +15,14 @@ ~ along with this program. If not, see . --> - + net.openhft java-parent-pom 1.1.16 - + 4.0.0 @@ -374,7 +375,6 @@ - diff --git a/spec/6-queries.md b/spec/6-queries.md index b4e909fad..fe904a83c 100644 --- a/spec/6-queries.md +++ b/spec/6-queries.md @@ -87,7 +87,6 @@ in the segment it belongs to). > ../src/main/java/net/openhft/chronicle/hash/impl/stage/query/KeySearch.java), [`HashQuery`]( > ../src/main/java/net/openhft/chronicle/hash/impl/stage/query/HashQuery.java) classes. - ## Entry insertion 1. Perform a [key lookup](#key-lookup) for the key that is going to be inserted, ensuring that the @@ -182,7 +181,6 @@ in the segment it belongs to). > The reference Java implementation: [`MapAbsent.putEntry()`]( > ../src/main/java/net/openhft/chronicle/map/impl/stage/query/MapAbsent.java) method. - ## Value update Steps 4-5 are *in-place* value update. Steps from 6 to the end of the operation are called @@ -369,7 +367,6 @@ Steps 4-5 are *in-place* value update. Steps from 6 to the end of the operation > The reference Java implementation: mostly [`MapEntryStages.innerDefaultReplaceValue()`]( > ../src/main/java/net/openhft/chronicle/map/impl/stage/entry/MapEntryStages.java) method. - ## Entry removal 1. Perform a [key lookup](#key-lookup) for the key that is going to be removed, ensuring that the @@ -387,7 +384,6 @@ Steps 4-5 are *in-place* value update. Steps from 6 to the end of the operation > The reference Java implementation: [`HashQuery.doRemove()`]( > ../src/main/java/net/openhft/chronicle/hash/impl/stage/query/HashQuery.java) method. - Supplementary operations: #### Locate empty slot @@ -460,6 +456,3 @@ some segment. > The reference Java implementation: [`SegmentStages.nextTier()`]( > ../src/main/java/net/openhft/chronicle/hash/impl/stage/entry/SegmentStages.java) method. - - - diff --git a/src/main/java/net/openhft/chronicle/hash/AbstractData.java b/src/main/java/net/openhft/chronicle/hash/AbstractData.java index c666cb365..4c6af5d55 100644 --- a/src/main/java/net/openhft/chronicle/hash/AbstractData.java +++ b/src/main/java/net/openhft/chronicle/hash/AbstractData.java @@ -26,9 +26,10 @@ package net.openhft.chronicle.hash; public abstract class AbstractData implements Data { /** - * Constructor for use by subclasses. + * Constructor for use by subclasses. */ - protected AbstractData() {} + protected AbstractData() { + } /** * Computes value's hash code by applying a hash function to {@code Data}'s bytes diff --git a/src/main/java/net/openhft/chronicle/hash/Beta.java b/src/main/java/net/openhft/chronicle/hash/Beta.java index f0bb11d81..226edf67f 100644 --- a/src/main/java/net/openhft/chronicle/hash/Beta.java +++ b/src/main/java/net/openhft/chronicle/hash/Beta.java @@ -29,13 +29,13 @@ import static java.lang.annotation.ElementType.*; * or even removal, in a future release. An API bearing this annotation is exempt from any * compatibility guarantees. Note that the presence of this annotation implies nothing about the * quality or performance of the API in question, only the fact that it is not "API-frozen." - * + *

*

This annotation is a copy of Guava's * {@code Beta}. */ @Retention(value = RetentionPolicy.CLASS) -@Target(value = {ANNOTATION_TYPE, CONSTRUCTOR, FIELD,METHOD, TYPE}) +@Target(value = {ANNOTATION_TYPE, CONSTRUCTOR, FIELD, METHOD, TYPE}) @Documented @Beta public @interface Beta { diff --git a/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java b/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java index 5146b5b56..9f51a091f 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/ChecksumEntry.java @@ -26,7 +26,7 @@ import net.openhft.chronicle.set.SetEntry; * with {@link ChronicleHashBuilder#checksumEntries(boolean)} configured to {@code true}. There is * no method that returns {@code ChecksumEntry}, {@link MapEntry} or {@link SetEntry} could be * casted to {@code ChecksumEntry} to access it's methods. - * + *

*

See Entry checksums * section in the Chronicle Map tutorial for usage examples of this interface. */ @@ -41,11 +41,11 @@ public interface ChecksumEntry { * interface. * * @throws UnsupportedOperationException if checksums are not stored in the containing Chronicle - * Hash - * @throws RuntimeException if the context of this entry is locked improperly, e. g. on the - * {@linkplain HashQueryContext#readLock() read} level, that is not upgradable to the - * {@linkplain HashQueryContext#updateLock() update} level. Calling {@code updateChecksum()} - * method is enabled when at least update lock is held. + * Hash + * @throws RuntimeException if the context of this entry is locked improperly, e. g. on the + * {@linkplain HashQueryContext#readLock() read} level, that is not upgradable to the + * {@linkplain HashQueryContext#updateLock() update} level. Calling {@code updateChecksum()} + * method is enabled when at least update lock is held. */ void updateChecksum(); @@ -54,11 +54,11 @@ public interface ChecksumEntry { * * @return {@code true} if stored checksum equals to checksum computed from the entry bytes * @throws UnsupportedOperationException if checksums are not stored in the containing Chronicle - * Hash - * @throws RuntimeException if the context of this entry is locked improperly, e. g. on the - * {@linkplain HashQueryContext#readLock() read} level, that is not upgradable to the - * {@linkplain HashQueryContext#updateLock() update} level. Calling {@code checkSum()} method is - * enabled when at least update lock is held. + * Hash + * @throws RuntimeException if the context of this entry is locked improperly, e. g. on the + * {@linkplain HashQueryContext#readLock() read} level, that is not upgradable to the + * {@linkplain HashQueryContext#updateLock() update} level. Calling {@code checkSum()} method is + * enabled when at least update lock is held. */ boolean checkSum(); } diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java index 551527a2f..8a7d7a264 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java @@ -42,7 +42,7 @@ public interface ChronicleHash, SC extends HashSegment * i. e. if it is created by {@link ChronicleHashBuilder#create()} call. * * @return the file this {@link ChronicleMap} or {@link ChronicleSet} is mapped to, - * or {@code null} if it is not mapped to any file + * or {@code null} if it is not mapped to any file * @see ChronicleHashBuilder#createPersistedTo(File) */ File file(); @@ -62,7 +62,7 @@ public interface ChronicleHash, SC extends HashSegment * Map#toString()} and {@link Set#toString()} contracts respectively, making it not always * useful (or even impossible to use, if this {@code ChronicleHash} contains a lot of entries) * for the purposes listed above. - * + *

*

This method return a string of the form:

* [ChronicleMap|ChronicleSet]{name={@link #name()}, file={@link #file()}, * identityHashCode={@link System#identityHashCode System.identityHashCode(thisChronicleHash)}} @@ -85,7 +85,7 @@ public interface ChronicleHash, SC extends HashSegment /** * Returns the amount of off-heap memory (in bytes), allocated by this {@code ChronicleHash} or * shared with with other ChronicleHashes, persisting to the same {@link #file()}. - * + *

*

After {@link #close()} this method returns 0. * * @return the amount of off-heap memory, used by this {@code ChronicleHash} (in bytes) @@ -103,7 +103,7 @@ public interface ChronicleHash, SC extends HashSegment * try (ExternalHashQueryContext q = hash.queryContext(key)) { * // ... do something * }} - * + *

*

See documentation to {@link HashQueryContext} interface and methods in {@link MapMethods} * interface for examples of using contexts. Also see @@ -125,7 +125,7 @@ public interface ChronicleHash, SC extends HashSegment * instead of object key. This method is useful, when you already have {@code Data}, calling * this method instead of {@link #queryContext(Object)} might help to avoid unnecessary * deserialization. - * + *

*

See documentation to {@link HashQueryContext} interface and methods in {@link MapMethods} * interface for examples of using contexts. Also see @@ -134,7 +134,8 @@ public interface ChronicleHash, SC extends HashSegment * @param key the queried key as {@code Data} * @return the context to perform operations with the key */ - @NotNull EQC queryContext(Data key); + @NotNull + EQC queryContext(Data key); /** * Returns a context to perform arbitrary operations with the given key, provided in the @@ -142,11 +143,12 @@ public interface ChronicleHash, SC extends HashSegment * information on contexts semantics and usage patterns. * * @param keyBytes the bytes store with the key bytes to query - * @param offset actual offset of the key bytes within the given BytesStore - * @param size length of the key bytes sequence within the given BytesStore + * @param offset actual offset of the key bytes within the given BytesStore + * @param size length of the key bytes sequence within the given BytesStore * @return the context to perform operations with the key */ - @NotNull EQC queryContext(BytesStore keyBytes, long offset, long size); + @NotNull + EQC queryContext(BytesStore keyBytes, long offset, long size); /** * Returns a context of the segment with the given index. Segments are indexed from 0 to @@ -168,11 +170,11 @@ public interface ChronicleHash, SC extends HashSegment * Checks the given predicate on each entry in this {@code ChronicleHash} until all entries * have been processed or the predicate returns {@code false} for some entry, or throws * an {@code Exception}. Exceptions thrown by the predicate are relayed to the caller. - * + *

*

The order in which the entries will be processed is unspecified. It might differ from * the order of iteration via {@code Iterator} returned by any method of this * {@code ChronicleHash} or it's collection view. - * + *

*

If the {@code ChronicleHash} is empty, this method returns {@code true} immediately. * * @param predicate the predicate to be checked for each entry @@ -185,7 +187,7 @@ public interface ChronicleHash, SC extends HashSegment * Performs the given action for each entry in this {@code ChronicleHash} until all entries have * been processed or the action throws an {@code Exception}. Exceptions thrown by the action are * relayed to the caller. - * + *

*

The order in which the entries will be processed is unspecified. It might differ from * the order of iteration via {@code Iterator} returned by any method of this * {@code ChronicleHash} or it's collection view. @@ -200,11 +202,11 @@ public interface ChronicleHash, SC extends HashSegment * and there are other instances mapping the same data on the server across JVMs, the memory * won't be actually freed on operating system level. I. e. this method call doesn't affect * other {@link ChronicleMap} or {@link ChronicleSet} instances mapping the same data. - * + *

*

If you won't call this method, memory would be held at least until next garbage * collection. This could be a problem if, for example, you target rare garbage collections, * but load and drop {@code ChronicleHash}es regularly. - * + *

*

After this method call, all methods, querying the {@code ChronicleHash}'s entries, {@link * #longSize()} and {@code size()}), throw {@link ChronicleHashClosedException}. {@link * #isOpen()} returns {@code false}, {@code close()} itself returns immediately without effects diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java index 737863e26..19331e46d 100755 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilder.java @@ -36,15 +36,15 @@ import java.util.concurrent.ConcurrentHashMap; /** * Base interface for {@link ChronicleMapBuilder} and {@link ChronicleSetBuilder}, i. e. defines * 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. - * + *

*

{@code ChronicleHashBuilder} instances are not safe for concurrent use from multiple threads, * if at least one of the threads mutates the {@code ChronicleHashBuilder}'s state. - * + *

*

There are some "low-level" configurations in this builder, * that require deep understanding of the Chronicle implementation design to be properly used. * Know what you do. These configurations are applied as-is, without extra round-ups, adjustments, @@ -73,7 +73,7 @@ public interface ChronicleHashBuilder, * recommended to give some distinctive name to each created {@code ChronicleHash}, because this * name is used when logging errors and warnings inside Chronicle Map library itself, so having * the concrete {@code ChronicleHash} name in logs may help to debug. - * + *

*

{@code name()} is a JVM-level configuration, it is not stored in the persistence file (or * the other way to say this: they are not parts of the Chronicle Map data store @@ -102,25 +102,25 @@ public interface ChronicleHashBuilder, * containers, created by this builder. However, in many cases {@link #averageKey(Object)} might * be easier to use and more reliable. If key size is always the same, call {@link * #constantKeySizeBySample(Object)} method instead of this one. - * + *

*

{@code ChronicleHashBuilder} implementation heuristically chooses * {@linkplain #actualChunkSize(int) the actual chunk size} based on this configuration, that, * however, might result to quite high internal fragmentation, i. e. losses because only * integral number of chunks could be allocated for the entry. If you want to avoid this, you * should manually configure the actual chunk size in addition to this average key size * configuration, which is anyway needed. - * + *

*

If key is a boxed primitive type, a value interface or {@link Byteable} subclass, i. e. if * key size is known statically, it is automatically accounted and shouldn't be specified by * user. - * + *

*

Calling this method clears any previous {@link #constantKeySizeBySample(Object)} and * {@link #averageKey(Object)} configurations. * * @param averageKeySize the average number of bytes, taken by serialized form of keys * @return this builder back - * @throws IllegalStateException if key size is known statically and shouldn't be configured - * by user + * @throws IllegalStateException if key size is known statically and shouldn't be configured + * by user * @throws IllegalArgumentException if the given {@code keySize} is non-positive * @see #averageKey(Object) * @see #constantKeySizeBySample(Object) @@ -134,18 +134,18 @@ public interface ChronicleHashBuilder, * the configured {@link #keyMarshallers(SizedReader, SizedWriter) keys marshallers}. * In some cases, {@link #averageKeySize(double)} might be easier to use, than constructing the * "average key". If key size is always the same, call {@link #constantKeySizeBySample( - * Object)} method instead of this one. - * + *Object)} method instead of this one. + *

*

{@code ChronicleHashBuilder} implementation heuristically chooses * {@linkplain #actualChunkSize(int) the actual chunk size} based on this configuration, that, * however, might result to quite high internal fragmentation, i. e. losses because only * integral number of chunks could be allocated for the entry. If you want to avoid this, you * should manually configure the actual chunk size in addition to this average key size * configuration, which is anyway needed. - * + *

*

If key is a boxed primitive type or {@link Byteable} subclass, i. e. if key size is known * statically, it is automatically accounted and shouldn't be specified by user. - * + *

*

Calling this method clears any previous {@link #constantKeySizeBySample(Object)} and * {@link #averageKeySize(double)} configurations. * @@ -163,13 +163,13 @@ public interface ChronicleHashBuilder, * Configures the constant number of bytes, taken by serialized form of keys, put into hash * containers, 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. - * + *

*

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 #averageKeySize(double)} should be called instead of * this one. - * + *

*

Calling this method clears any previous {@link #averageKey(Object)} and * {@link #averageKeySize(double)} configurations. * @@ -182,7 +182,7 @@ public interface ChronicleHashBuilder, /** * Configures the size in bytes of allocation unit of hash container instances, created by this * builder. - * + *

*

{@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} @@ -192,16 +192,16 @@ public interface ChronicleHashBuilder, * 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. This is called * internal fragmentation. - * + *

*

To minimize memory overuse and improve speed, you should pay decent attention to this * configuration. Alternatively, you can just trust the heuristics and doesn't configure * the chunk size. - * + *

*

Specify chunk size so that most entries would take from 5 to several dozens of chunks. * However, remember that operations with entries that span several chunks are a bit slower, * than with entries which take a single chunk. Particularly avoid entries to take more than * 64 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 @@ -213,7 +213,7 @@ public interface ChronicleHashBuilder, * .averageValueSize(150 * 8) // 150 is average adjacency list size * .actualChunkSize(30 * 8) // average 5-6 chunks per entry * .create();} - * + *

*

This is a low-level configuration. The configured number * of bytes is used as-is, without anything like round-up to the multiple of 8 or 16, or any * other adjustment. @@ -238,7 +238,7 @@ public interface ChronicleHashBuilder, * @param maxChunksPerEntry how many chunks a single entry could span at most * @return this builder back * @throws IllegalArgumentException if the given {@code maxChunksPerEntry} is lesser than 1 - * or greater than 64 + * or greater than 64 * @see #actualChunkSize(int) */ B maxChunksPerEntry(int maxChunksPerEntry); @@ -249,21 +249,21 @@ public interface ChronicleHashBuilder, * (and this is by default), this number of entries is also the maximum. If you try to insert * more entries, than the configured {@code maxBloatFactor}, multiplied by the given number of * {@code entries}, {@link IllegalStateException} might be thrown. - * + *

*

This configuration should represent the expected maximum number of entries in a stable * state, {@link #maxBloatFactor(double) maxBloatFactor} - the maximum bloat up coefficient, * during exceptional bursts. - * + *

*

To be more precise - try to configure the {@code entries} so, that the created hash * container is going to serve about 99% requests being less or equal than this number * of entries in size. - * + *

*

You shouldn't put additional margin over the actual target number of entries. * 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 the actual maximum expected number of entries. * {@code ChronicleMap} and {@code ChronicleSet} don't have a notion of load factor. - * + *

*

The default target number of entries is 2^20 (~ 1 million). * * @param entries the target size of the maps or sets, created by this builder @@ -277,10 +277,10 @@ public interface ChronicleHashBuilder, * Configures the maximum number of times, the hash containers, created by this builder, * are allowed to grow in size beyond the configured {@linkplain #entries(long) target number * of entries}. - * + *

*

{@link #entries(long)} should represent the expected maximum number of entries in a stable * state, {@code maxBloatFactor} - the maximum bloat up coefficient, during exceptional bursts. - * + *

*

This configuration should be used for self-checking. Even if you configure impossibly * large {@code maxBloatFactor}, the created {@code ChronicleHash}, of cause, will be still * operational, and even won't allocate any extra resources before they are actually needed. @@ -291,9 +291,9 @@ public interface ChronicleHashBuilder, * will have a terribly slow and fat, but operational application, instead of a fail with * {@code IllegalStateException}, which will quickly show you, that there is a bug in you * application. - * + *

*

The default maximum bloat factor factor is {@code 1.0} - i. e. "no bloat is expected". - * + *

*

It is strongly advised not to configure {@code maxBloatFactor} to more than {@code 10.0}, * almost certainly, you either should configure {@code ChronicleHash}es completely differently, * or this data store doesn't fit to your case. @@ -302,7 +302,7 @@ public interface ChronicleHashBuilder, * to bloat up beyond the {@link #entries(long)} * @return this builder back * @throws IllegalArgumentException if the given {@code maxBloatFactor} is NaN, lesser than 1.0 - * or greater than 1000.0 (one thousand) + * or greater than 1000.0 (one thousand) * @see #entries(long) */ B maxBloatFactor(double maxBloatFactor); @@ -312,16 +312,16 @@ public interface ChronicleHashBuilder, * guarantee that segments won't tier (due to bad hash distribution or natural variance), * configuring {@code allowSegmentTiering(false)} makes Chronicle Hashes, created by this * builder, to throw {@code IllegalStateException} immediately when some segment overflows. - * + *

*

Useful exactly for testing hash distribution and variance of segment filling. - * + *

*

Default is {@code true}, segments are allowed to tier. - * + *

*

When configured to {@code false}, {@link #maxBloatFactor(double)} configuration becomes * irrelevant, because effectively no bloat is allowed. * * @param allowSegmentTiering if {@code true}, when a segment overflows a next tier - * is allocated to accommodate new entries + * is allocated to accommodate new entries * @return this builder back */ B allowSegmentTiering(boolean allowSegmentTiering); @@ -330,20 +330,20 @@ public interface ChronicleHashBuilder, * Configures probabilistic fraction of segments, which shouldn't become tiered, if Chronicle * Hash size is {@link #entries(long)}, assuming hash code distribution of the keys, inserted * into configured Chronicle Hash, is good. - * + *

*

The last caveat means that the configured percentile and affects segment size relying on * Poisson distribution law, if inserted entries (keys) fall into all segments randomly. If * e. g. the keys, inserted into the Chronicle Hash, are purposely selected to collide by * a certain range of hash code bits, so that they all fall into the same segment (a DOS * attacker might do this), this segment is obviously going to be tiered. - * + *

*

This configuration affects the actual number of segments, if {@link #entries(long)} and * {@link #entriesPerSegment(long)} or {@link #actualChunksPerSegmentTier(long)} are configured. * It affects the actual number of entries per segment/chunks per segment tier, if {@link * #entries(long)} and {@link #actualSegments(int)} are configured. If all 4 configurations, * mentioned in this paragraph, are specified, {@code nonTieredSegmentsPercentile} doesn't make * any effect. - * + *

*

Default value is 0.99999, i. e. if hash code distribution of the keys is good, only one * segment of 100K is tiered on average. If your segment size is small and you want to improve * memory footprint of Chronicle Hash (probably compromising latency percentiles), you might @@ -352,7 +352,7 @@ public interface ChronicleHashBuilder, * @param nonTieredSegmentsPercentile Fraction of segments which shouldn't be tiered * @return this builder back * @throws IllegalArgumentException if {@code nonTieredSegmentsPercentile} is out of (0.5, 1.0) - * range (both bounds are excluded) + * range (both bounds are excluded) */ B nonTieredSegmentsPercentile(double nonTieredSegmentsPercentile); @@ -361,7 +361,7 @@ public interface ChronicleHashBuilder, * of the hash containers, created by this builder. Configuring both the actual number of * entries per segment and {@linkplain #actualSegments(int) actual segments} replaces a single * {@link #entries(long)} configuration. - * + *

*

This is a low-level configuration. * * @param entriesPerSegment the actual maximum number entries per segment in the @@ -389,7 +389,7 @@ public interface ChronicleHashBuilder, * Configures the actual number of segments in the hash containers, created by this builder. * With {@linkplain #entriesPerSegment(long) actual number of segments}, this * configuration replaces a single {@link #entries(long)} call. - * + *

*

This is a low-level configuration. The configured number * is used as-is, without anything like round-up to the closest power of 2. * @@ -405,7 +405,7 @@ public interface ChronicleHashBuilder, * Configures the {@code DataAccess} and {@code SizedReader} used to serialize and deserialize * keys to and from off-heap memory in hash containers, created by this builder. * - * @param keyReader the new bytes → key object reader strategy + * @param keyReader the new bytes → key object reader strategy * @param keyDataAccess the new strategy of accessing the keys' bytes for writing * @return this builder back * @see #keyMarshallers(SizedReader, SizedWriter) @@ -453,7 +453,7 @@ public interface ChronicleHashBuilder, /** * Configures the marshaller used to serialize actual key sizes to off-heap memory in hash * containers, created by this builder. - * + *

*

Default key size marshaller is so-called "stop bit encoding" marshalling. If {@linkplain * #constantKeySizeBySample(Object) constant key size} is configured, or defaulted if the key * type is always constant and {@code ChronicleHashBuilder} implementation knows about it, this @@ -474,7 +474,7 @@ public interface ChronicleHashBuilder, * net.openhft.chronicle.core.OS#is64Bit()}. * * @param aligned64BitMemoryOperationsAtomic {@code true} if aligned 8-byte memory operations - * are atomic + * are atomic * @return this builder back */ B aligned64BitMemoryOperationsAtomic(boolean aligned64BitMemoryOperationsAtomic); @@ -484,7 +484,7 @@ public interface ChronicleHashBuilder, * checksums. It is used to detect data corruption during recovery after crashes. See the * Entry Checksums section * in the Chronicle Map tutorial for more information. - * + *

*

By default, {@linkplain #createPersistedTo(File) persisted} hash containers, created by * {@code ChronicleMapBuilder} do compute and store entry checksums, but hash containers, * created in the process memory via {@link #create()} - don't. @@ -512,25 +512,25 @@ public interface ChronicleHashBuilder, * if the file doesn't yet exist 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. - * + *

*

This method is shortcut for {@code instance().persistedTo(file).create()}. * * @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 NullPointerException if the given file is null - * @throws IOException if any IO error, related to off-heap memory allocation or file mapping, - * or establishing replication connections, occurs + * @throws IOException if any IO error, related to off-heap memory allocation or file mapping, + * or establishing replication connections, occurs * @see ChronicleHash#file() * @see ChronicleHash#close() * @see #create() @@ -544,7 +544,7 @@ public interface ChronicleHashBuilder, * from this builder, if the file doesn't exist yet, and maps its off-heap memory to the file. * This method is equivalent to {@link #createOrRecoverPersistedTo(File, boolean) * createOrRecoverPersistedTo(file, true)}. - * + *

*

This method couldn't be used, if the Chronicle Map was created using an older version * of the Chronicle Map library, and then {@code createOrRecoverPersistedTo()} is called with * a newer version of the Chronicle Map library. In this case, {@link @@ -553,11 +553,11 @@ public interface ChronicleHashBuilder, * * @param file the persistence file for existing of future hash container * @return a {@code ChronicleHash} instance, mapped to the given instance - * @throws NullPointerException if the given file is null - * @throws IOException if any IO error occurs on reading data from the file, or related to - * off-heap memory allocation or file mapping, or establishing replication connections. Probably - * the file is corrupted on OS level, and should be recovered on that level first, before - * calling this procedure. + * @throws NullPointerException if the given file is null + * @throws IOException if any IO error occurs on reading data from the file, or related to + * off-heap memory allocation or file mapping, or establishing replication connections. Probably + * the file is corrupted on OS level, and should be recovered on that level first, before + * calling this procedure. * @throws ChronicleHashRecoveryFailedException if recovery is impossible * @see #createPersistedTo(File) * @see #createOrRecoverPersistedTo(File, boolean) @@ -572,23 +572,23 @@ public interface ChronicleHashBuilder, * In other words, this methods behaves like {@link #createPersistedTo(File)}, if the given * file doesn't exist, and {@link #recoverPersistedTo(File, boolean) * recoverPersistedTo(file, sameLibraryVersion)}, if the file exists. - * + *

*

The difference between this method and {@link #createOrRecoverPersistedTo(File, boolean, * ChronicleHashCorruption.Listener)} is that this method just logs the encountered corruptions, * instead of passing them to the specified corruption listener. * - * @param file the persistence file for existing of future hash container + * @param file the persistence file for existing of future hash container * @param sameLibraryVersion if this builder is configured with the same configurations, as the - * builder, which created the Chronicle Map in the given file initially, and the same version - * of the Chronicle Map library was used. In this case, the header of the file is overridden - * (with presumably the same configurations), protecting from {@link - * ChronicleHashRecoveryFailedException}, if the header is corrupted. + * builder, which created the Chronicle Map in the given file initially, and the same version + * of the Chronicle Map library was used. In this case, the header of the file is overridden + * (with presumably the same configurations), protecting from {@link + * ChronicleHashRecoveryFailedException}, if the header is corrupted. * @return a {@code ChronicleHash} instance, mapped to the given instance - * @throws NullPointerException if the given file is null - * @throws IOException if any IO error occurs on reading data from the file, or related to - * off-heap memory allocation or file mapping, or establishing replication connections. Probably - * the file is corrupted on OS level, and should be recovered on that level first, before - * calling this procedure. + * @throws NullPointerException if the given file is null + * @throws IOException if any IO error occurs on reading data from the file, or related to + * off-heap memory allocation or file mapping, or establishing replication connections. Probably + * the file is corrupted on OS level, and should be recovered on that level first, before + * calling this procedure. * @throws ChronicleHashRecoveryFailedException if recovery is impossible * @see #createPersistedTo(File) * @see #recoverPersistedTo(File, boolean) @@ -603,23 +603,23 @@ public interface ChronicleHashBuilder, * file doesn't exist, and {@link * #recoverPersistedTo(File, boolean, ChronicleHashCorruption.Listener) * recoverPersistedTo(file, sameLibraryVersion, corruptionListener)}, if the file exists. - * + *

*

If this procedure encounters corruptions, it fixes them (recovers from them) and * notifies the provided corruption listener with the details about the corruption. See the * documentation for {@link ChronicleHashCorruption} for more information. * - * @param file the persistence file for existing of future hash container + * @param file the persistence file for existing of future hash container * @param sameLibraryVersion if this builder is configured with the same configurations, as the - * builder, which created the Chronicle Map in the given file initially, and the same version - * of the Chronicle Map library was used. In this case, the header of the file is overridden - * (with presumably the same configurations), protecting from {@link - * ChronicleHashRecoveryFailedException}, if the header is corrupted. + * builder, which created the Chronicle Map in the given file initially, and the same version + * of the Chronicle Map library was used. In this case, the header of the file is overridden + * (with presumably the same configurations), protecting from {@link + * ChronicleHashRecoveryFailedException}, if the header is corrupted. * @return a {@code ChronicleHash} instance, mapped to the given instance - * @throws NullPointerException if the given file or corruptionListener is null - * @throws IOException if any IO error occurs on reading data from the file, or related to - * off-heap memory allocation or file mapping, or establishing replication connections. Probably - * the file is corrupted on OS level, and should be recovered on that level first, before - * calling this procedure. + * @throws NullPointerException if the given file or corruptionListener is null + * @throws IOException if any IO error occurs on reading data from the file, or related to + * off-heap memory allocation or file mapping, or establishing replication connections. Probably + * the file is corrupted on OS level, and should be recovered on that level first, before + * calling this procedure. * @throws ChronicleHashRecoveryFailedException if recovery is impossible * @see #createOrRecoverPersistedTo(File, boolean) * @see #recoverPersistedTo(File, boolean) @@ -637,11 +637,11 @@ public interface ChronicleHashBuilder, * Chronicle Hash memory), or a sudden power loss, or a file corruption (that, in addition to * the already mentioned consequences, might lead to data corruption, i. e. presence of entries * which were never put into the Chronicle Hash). - * + *

*

This method, unlike {@link #createPersistedTo(File)} or {@link * #createOrRecoverPersistedTo(File, boolean)} methods, expects that the given file already * exists. - * + *

*

"Recovery" of the hash container is changing the memory of the data structure so that * after the recovery the hash container is in some correct state: with "clean" locks, coherent * entry counters, not containing provably corrupt entries, etc. If {@link @@ -650,17 +650,17 @@ public interface ChronicleHashBuilder, * it assumes the entry is corrupt and deletes it from the Chronicle Hash. See the * Recovery section in the * Chronicle Map tutorial for more information. - * + *

*

The difference between this method and {@link #recoverPersistedTo(File, boolean, * ChronicleHashCorruption.Listener)} is that this method just logs the encountered corruptions, * instead of passing them to the specified corruption listener. - * + *

*

At the moment this method is called and executed, no other thread or process should be * mapping to the given file, and trying to access the given file. Otherwise the outcomes of * the {@code recoverPersistedTo()} call, as well as the behaviour of the concurrent thread or * process, accessing the same Chronicle Map, are unspecified: exception or error could be * thrown, the Chronicle Map persisted to the given file could be further corrupted. - * + *

*

It is strongly recommended to configure this builder with the same configurations, as * the builder, that created the given file for the first time, and pass {@code true} as the * {@code sameBuilderConfigAndLibraryVersion} argument (another requirement is running @@ -670,19 +670,19 @@ public interface ChronicleHashBuilder, * further. Fortunately, the header should never be corrupted on an "ordinary" process * crash/termination or power loss, only on direct file corruption. * - * @param file a hash container was mapped to the given file + * @param file a hash container was mapped to the given file * @param sameBuilderConfigAndLibraryVersion if this builder is configured with the same - * configurations, as the builder, which created the file (the persisted Chronicle Hash - * instance) for the first time, and with the same version of the Chronicle Map library. - * In this case, the header of the file is overridden (with presumably the same configurations), - * protecting from {@link ChronicleHashRecoveryFailedException}, if the header is corrupted. + * configurations, as the builder, which created the file (the persisted Chronicle Hash + * instance) for the first time, and with the same version of the Chronicle Map library. + * In this case, the header of the file is overridden (with presumably the same configurations), + * protecting from {@link ChronicleHashRecoveryFailedException}, if the header is corrupted. * @return a recovered Chronicle Hash instance, mapped to the given file - * @throws NullPointerException if the given file is null - * @throws FileNotFoundException if the file doesn't exist - * @throws IOException if any IO error occurs on reading data from the file, or related to - * off-heap memory allocation or file mapping, or establishing replication connections. Probably - * the file is corrupted on OS level, and should be recovered on that level first, before - * calling this procedure. + * @throws NullPointerException if the given file is null + * @throws FileNotFoundException if the file doesn't exist + * @throws IOException if any IO error occurs on reading data from the file, or related to + * off-heap memory allocation or file mapping, or establishing replication connections. Probably + * the file is corrupted on OS level, and should be recovered on that level first, before + * calling this procedure. * @throws ChronicleHashRecoveryFailedException if recovery is impossible * @see #createOrRecoverPersistedTo(File, boolean) * @see #createPersistedTo(File) @@ -698,11 +698,11 @@ public interface ChronicleHashBuilder, * Chronicle Hash memory), or a sudden power loss, or a file corruption (that, in addition to * the already mentioned consequences, might lead to data corruption, i. e. presence of entries * which were never put into the Chronicle Hash). - * + *

*

This method, unlike {@link #createPersistedTo(File)} or {@link * #createOrRecoverPersistedTo(File, boolean, ChronicleHashCorruption.Listener)} methods, * expects that the given file already exists. - * + *

*

"Recovery" of the hash container is changing the memory of the data structure so that * after the recovery the hash container is in some correct state: with "clean" locks, coherent * entry counters, not containing provably corrupt entries, etc. If {@link @@ -711,30 +711,30 @@ public interface ChronicleHashBuilder, * it assumes the entry is corrupt and deletes it from the Chronicle Hash. See the * Recovery section in the * Chronicle Map tutorial for more information. - * + *

*

If this procedure encounters corruptions, it fixes them (recovers from them) and * notifies the provided corruption listener with the details about the corruption. See the * documentation for {@link ChronicleHashCorruption} for more information. - * + *

*

At the moment this method is called and executed, no other thread or process should be * mapping to the given file, and trying to access the given file. Otherwise the outcomes of * the {@code recoverPersistedTo()} call, as well as the behaviour of the concurrent thread or * process, accessing the same Chronicle Map, are unspecified: exception or error could be * thrown, the Chronicle Map persisted to the given file could be further corrupted. * - * @param file a hash container was mapped to the given file + * @param file a hash container was mapped to the given file * @param sameBuilderConfigAndLibraryVersion if this builder is configured with the same - * configurations, as the builder, which created the file (the persisted Chronicle Hash - * instance) for the first time, and with the same version of the Chronicle Map library. - * In this case, the header of the file is overridden (with presumably the same configurations), - * protecting from {@link ChronicleHashRecoveryFailedException}, if the header is corrupted. + * configurations, as the builder, which created the file (the persisted Chronicle Hash + * instance) for the first time, and with the same version of the Chronicle Map library. + * In this case, the header of the file is overridden (with presumably the same configurations), + * protecting from {@link ChronicleHashRecoveryFailedException}, if the header is corrupted. * @return a recovered Chronicle Hash instance, mapped to the given file - * @throws NullPointerException if the given file or corruptionListener is null - * @throws FileNotFoundException if the file doesn't exist - * @throws IOException if any IO error occurs on reading data from the file, or related to - * off-heap memory allocation or file mapping, or establishing replication connections. Probably - * the file is corrupted on OS level, and should be recovered on that level first, before - * calling this procedure. + * @throws NullPointerException if the given file or corruptionListener is null + * @throws FileNotFoundException if the file doesn't exist + * @throws IOException if any IO error occurs on reading data from the file, or related to + * off-heap memory allocation or file mapping, or establishing replication connections. Probably + * the file is corrupted on OS level, and should be recovered on that level first, before + * calling this procedure. * @throws ChronicleHashRecoveryFailedException if recovery is impossible * @see #recoverPersistedTo(File, boolean) * @see #createOrRecoverPersistedTo(File, boolean, ChronicleHashCorruption.Listener) diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java index 3174388e1..4907578f0 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashBuilderPrivateAPI.java @@ -55,8 +55,8 @@ public interface ChronicleHashBuilderPrivateAPI { /** * Configures if replicated Chronicle Hashes, constructed by this builder, should * completely erase entries, removed some time ago. See {@link #removedEntryCleanupTimeout( - * long, TimeUnit)} for more details on this mechanism. - * + *long, TimeUnit)} for more details on this mechanism. + *

*

Default value is {@code true} -- old removed entries are erased with 1 second timeout. * * @param cleanupRemovedEntries if stale removed entries should be purged from Chronicle Hash @@ -76,12 +76,12 @@ public interface ChronicleHashBuilderPrivateAPI { * in any way for this {@code removedEntryCleanupTimeout}, Chronicle is allowed to remove this * entry completely from the data store. This timeout should depend on your distributed * system topology, and typical replication latencies, that should be determined experimentally. - * + *

*

Default timeout is 1 minute. * * @param removedEntryCleanupTimeout timeout, after which stale removed entries could be erased * from Chronicle Hash data store completely - * @param unit time unit, in which the timeout is given + * @param unit time unit, in which the timeout is given * @return this builder back * @throws IllegalArgumentException is the specified timeout is less than 1 millisecond * @see #cleanupRemovedEntries(boolean) diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashCorruption.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashCorruption.java index 46ff75ee5..1fb8def08 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashCorruption.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashCorruption.java @@ -23,21 +23,21 @@ import java.io.File; /** * Information about a corruption, encountered in a persisted Chronicle Map during recovery. - * + *

*

Recovery procedure doesn't guarantee accuracy of the corruption events. Only two things are * guaranteed: *

    - *
  1. if {@link Listener} didn't receive any corruption events, the recovered Chronicle Map - * was not corrupted; - *
  2. - *
  3. if {@link Listener} received some corruption events, the recovered Chronicle Map was - * corrupted.
  4. + *
  5. if {@link Listener} didn't receive any corruption events, the recovered Chronicle Map + * was not corrupted; + *
  6. + *
  7. if {@link Listener} received some corruption events, the recovered Chronicle Map was + * corrupted.
  8. *
- * + *

*

{@code ChronicleHashCorruption} objects, passed to {@link Listener}, shouldn't be saved and * used outside of the {@link Listener#onCorruption(ChronicleHashCorruption)} method body, because * {@code ChronicleHashCorruption} objects could be reused during the recovery procedure. - * + *

*

During a recovery procedure, {@link Listener#onCorruption(ChronicleHashCorruption)} might * be called concurrently from multiple threads. If the implementation of this method calls some * methods on some objects, that are not safe for concurrent use from multiple threads, the @@ -79,7 +79,7 @@ public interface ChronicleHashCorruption { /** * Called when recovery * procedure encounters a corruption of a persisted Chronicle Map. - * + *

*

During a recovery procedure, this method might be called concurrently from multiple * threads. If the implementation of this method calls some methods on some objects, * that are not safe for concurrent use from multiple threads, the implementation must diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashRecoveryFailedException.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashRecoveryFailedException.java index 1a07d2203..f1dc4e277 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHashRecoveryFailedException.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashRecoveryFailedException.java @@ -43,7 +43,7 @@ public final class ChronicleHashRecoveryFailedException extends RuntimeException * message. * * @param message the detail message. The detail message is saved for later retrieval by the - * {@link #getMessage()} method. + * {@link #getMessage()} method. */ public ChronicleHashRecoveryFailedException(String message) { super(message); diff --git a/src/main/java/net/openhft/chronicle/hash/Data.java b/src/main/java/net/openhft/chronicle/hash/Data.java index d87ccdb0d..49a3b7e17 100644 --- a/src/main/java/net/openhft/chronicle/hash/Data.java +++ b/src/main/java/net/openhft/chronicle/hash/Data.java @@ -36,11 +36,11 @@ import static net.openhft.chronicle.algo.bytes.Access.checkedRandomDataInputAcce /** * Dual bytes/object access to keys or values (for {@link ChronicleMap}) and elements (for {@link * ChronicleSet}) throughout the Chronicle Map library. - * + *

*

Bytes access: {@link #bytes()} + {@link #offset()} + {@link #size()}. - * - *

Object access: {@link #get()}. - * + *

+ *

Object access: {@link #get()}. + *

*

In most cases, each particular {@code Data} wraps either some object or some bytes. Object * is marshalled to bytes lazily on demand, and bytes are lazily deserialized to object, * accordingly. @@ -49,15 +49,28 @@ import static net.openhft.chronicle.algo.bytes.Access.checkedRandomDataInputAcce */ public interface Data { + /** + * Utility method, compares two {@code Data} instances represent equivalent bytes sequences: + * by comparing {@linkplain #size() their sizes}, then calling {@link + * #equivalent(RandomDataInput, long) d1.equivalent(d2.bytes(), d2.offset())}. + * + * @param d1 the first {@code Data} to compare + * @param d2 the second {@code Data} to compare + * @return if the given {@code Data} instances represent equivalent bytes sequences + */ + static boolean bytesEquivalent(Data d1, Data d2) { + return d1.size() == d2.size() && d1.equivalent(d2.bytes(), d2.offset()); + } + /** * Returns the accessor object to the {@code Data}'s bytes. - * + *

*

If this {@code Data} wraps some bytes, this method just returns a reference to that bytes. - * + *

*

If this {@code Data} wraps an object, this method performs serialization internally and * returns a reference to the output buffer, caching the result for subsequent calls of this * method. - * + *

*

For safety, this interface returns read-only object, because it could expose bytes source * that must be immutable, e. g. a `char[]` array behind a {@code String}. But in cases when the * {@code Data} instance wraps off-heap bytes, e. g. {@link MapEntry#value()}, it is allowed to @@ -95,13 +108,13 @@ public interface Data { /** * Compares bytes of this {@code Data} to the given bytes {@code source}, starting from the * given offset. - * + *

*

Default implementation compares {@link #bytes()} of this {@code Data}, but custom * implementation may only check if {@linkplain #get() object} of this {@code Data} would * be serialized to the same bytes sequence, if this {@code Data} wraps an object and obtaining * {@link #bytes()} requires serialization internally. * - * @param source the bytes source, to compare this {@code Data}'s bytes with + * @param source the bytes source, to compare this {@code Data}'s bytes with * @param sourceOffset the offset in the bytes source, the bytes sequence starts from * @return {@code true} if the given bytes sequence is equivalent to this {@code Data}'s bytes, * byte-by-byte @@ -113,14 +126,14 @@ public interface Data { /** * Writes bytes of this {@code Data} to the given {@code target} from the given {@code * targetOffset}. - * + *

*

Default implementation copies {@link #bytes()} of this {@code Data} using standard IO * methods of {@code RandomDataInput} and {@code RandomDataOutput}, but custom implementation * may write directly from {@linkplain #get() object}, if this {@code Data} is object-based and * obtaining {@link #bytes()} requires serialization internally. This allows to avoid double * copy. * - * @param target the destination to write this data bytes to + * @param target the destination to write this data bytes to * @param targetOffset the offset in the target, to write the bytes from. */ default void writeTo(RandomDataOutput target, long targetOffset) { @@ -129,9 +142,9 @@ public interface Data { /** * Returns object view of this {@code Data}. - * + *

*

If this {@code Data} wraps some object, this method just returns that object. - * + *

*

If this {@code Data} wraps some bytes, this method performs deserialization internally * and returns the resulting on-heap object, caching it for subsequent calls of this method. The * returned object could be reused, therefore it is generally disallowed to use the @@ -150,19 +163,6 @@ public interface Data { */ T getUsing(@Nullable T using); - /** - * Utility method, compares two {@code Data} instances represent equivalent bytes sequences: - * by comparing {@linkplain #size() their sizes}, then calling {@link - * #equivalent(RandomDataInput, long) d1.equivalent(d2.bytes(), d2.offset())}. - * - * @param d1 the first {@code Data} to compare - * @param d2 the second {@code Data} to compare - * @return if the given {@code Data} instances represent equivalent bytes sequences - */ - static boolean bytesEquivalent(Data d1, Data d2) { - return d1.size() == d2.size() && d1.equivalent(d2.bytes(), d2.offset()); - } - /** * {@code Data} implementations should override {@link Object#hashCode()} with delegation to * this method. Computes {@code Data}'s hash code by applying a hash function to {@code Data}'s diff --git a/src/main/java/net/openhft/chronicle/hash/ExternalHashQueryContext.java b/src/main/java/net/openhft/chronicle/hash/ExternalHashQueryContext.java index 0c23a1c97..8ac8173cc 100644 --- a/src/main/java/net/openhft/chronicle/hash/ExternalHashQueryContext.java +++ b/src/main/java/net/openhft/chronicle/hash/ExternalHashQueryContext.java @@ -19,8 +19,8 @@ package net.openhft.chronicle.hash; /** * {@link HashQueryContext} + {@link AutoCloseable}, for external {@link ChronicleHash} queries - * in try-with-resources blocks. - * + * in try-with-resources blocks. + * * @param the hash key type * @see ChronicleHash#queryContext(Object) */ diff --git a/src/main/java/net/openhft/chronicle/hash/HashAbsentEntry.java b/src/main/java/net/openhft/chronicle/hash/HashAbsentEntry.java index e58d0417c..730e8a43a 100644 --- a/src/main/java/net/openhft/chronicle/hash/HashAbsentEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/HashAbsentEntry.java @@ -24,20 +24,20 @@ import org.jetbrains.annotations.NotNull; /** * Low-level operational context for the situations, when the new entry is going to be inserted * into the {@link ChronicleHash}. - * + *

*

This interface is not usable by itself; it merely defines the common base for {@link * MapAbsentEntry} and {@link SetAbsentEntry}. - * - * @param the hash key type + * + * @param the hash key type * @see HashQueryContext#absentEntry() */ public interface HashAbsentEntry { - + /** * Returns the context, in which the entry is going to be inserted into the hash. */ HashContext context(); - + /** * Returns the key is going to be inserted into the {@code ChronicleHash}. */ diff --git a/src/main/java/net/openhft/chronicle/hash/HashContext.java b/src/main/java/net/openhft/chronicle/hash/HashContext.java index 84cf7b618..96fd7b7b2 100644 --- a/src/main/java/net/openhft/chronicle/hash/HashContext.java +++ b/src/main/java/net/openhft/chronicle/hash/HashContext.java @@ -19,7 +19,7 @@ package net.openhft.chronicle.hash; /** * Root interface for contexts, in which {@link HashEntry HashEntries} could be accessed. - * + * * @param the key type of accessed {@link ChronicleHash} */ public interface HashContext { diff --git a/src/main/java/net/openhft/chronicle/hash/HashEntry.java b/src/main/java/net/openhft/chronicle/hash/HashEntry.java index 1b3eb77d8..94948dd6b 100644 --- a/src/main/java/net/openhft/chronicle/hash/HashEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/HashEntry.java @@ -23,10 +23,10 @@ import org.jetbrains.annotations.NotNull; /** * A context of a present entry in the {@code ChronicleHash}. - * + *

*

This interface is not usable by itself; it merely defines the common base for {@link MapEntry} * and {@link SetEntry}. - * + * * @param type of the key in {@code ChronicleHash} * @see HashQueryContext#entry() */ @@ -35,7 +35,7 @@ public interface HashEntry { * Returns the context, in which the entry is accessed. */ HashContext context(); - + /** * Returns the entry key. */ @@ -44,9 +44,9 @@ public interface HashEntry { /** * Removes the entry from the {@code ChronicleHash}. - * + * * @throws IllegalStateException if some locking/state conditions required to perform remove - * operation are not met + * operation are not met */ void doRemove(); } diff --git a/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java b/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java index 46399fd52..5a3b7e28c 100644 --- a/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java +++ b/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java @@ -28,17 +28,17 @@ import org.jetbrains.annotations.Nullable; /** * Context of {@link ChronicleHash} operations with individual keys. - * + *

*

This context provides access to {@link InterProcessReadWriteUpdateLock}, governing access * to the entry. Your have no chance to perform any actions under race with other threads, because * all required locks are acquired automatically on each operation, you should deal with locks * manually in the following cases: *

    - *
  • You should perform some read operation, and then write. On first operation, the context - * will automatically acquire the read lock; on the second, it will try to acquire the update - * or write lock, but it will fail with {@link IllegalMonitorStateException}, because this is - * dead lock prone. (See {@link InterProcessReadWriteUpdateLock} documentation for explanation. - * So, such context code is incorrect:
    {@code
    + * 
  • You should perform some read operation, and then write. On first operation, the context + * will automatically acquire the read lock; on the second, it will try to acquire the update + * or write lock, but it will fail with {@link IllegalMonitorStateException}, because this is + * dead lock prone. (See {@link InterProcessReadWriteUpdateLock} documentation for explanation. + * So, such context code is incorrect:
    {@code
      * // INCORRECT
      * try (ExternalMapQueryContext q = map.queryContext(key)) {
      *     // q.entry(), checks if the entry is present in the map, and acquires
    @@ -50,9 +50,9 @@ import org.jetbrains.annotations.Nullable;
      *         q.remove(entry);
      *     }
      * }}
    - * So, to workaround this, you should acquire the {@linkplain #updateLock() update lock}, - * which is upgradable to the write lock, before performing any reading in the context: - *
    {@code
    + * So, to workaround this, you should acquire the {@linkplain #updateLock() update lock},
    + * which is upgradable to the write lock, before performing any reading in the context:
    + * 
    {@code
      * // CORRECT
      * try (ExternalMapQueryContext q = map.queryContext(key)) {
      *     q.updateLock().lock(); // acquire the update lock before checking the entry presence.
    @@ -60,11 +60,11 @@ import org.jetbrains.annotations.Nullable;
      *     if (entry != null)
      *         q.remove(entry);
      * }}
    - *
  • - *
  • You want to try to acquire some lock heuristically, in order to improve total {@code - * ChronicleHash} concurrency. You should base on probabilities of making some reading or - * writing operations. For example, see how {@link MapMethods#acquireUsing} might be - * implemented:
    {@code
    + * 
  • + *
  • You want to try to acquire some lock heuristically, in order to improve total {@code + * ChronicleHash} concurrency. You should base on probabilities of making some reading or + * writing operations. For example, see how {@link MapMethods#acquireUsing} might be + * implemented:
    {@code
      * default void acquireUsing(MapQueryContext q, ReturnValue returnValue) {
      *     // For acquireUsing(), it is assumed to be very probable, that the entry is already
      *     // present in the map, so we will perform the whole acquireUsing() without exclusive locking
    @@ -96,9 +96,9 @@ import org.jetbrains.annotations.Nullable;
      *     q.insert(q.absentEntry(), q.defaultValue(q.absentEntry()));
      *     returnValue.returnValue(q.entry().value());
      * }}
  • - *
  • If the default {@link InterProcessLock#lock()} policy of trying to acquire the - * lock for some time, and then throw {@code RuntimeException}, or need a custom timeout: - *
    {@code
    + * 
  • If the default {@link InterProcessLock#lock()} policy of trying to acquire the + * lock for some time, and then throw {@code RuntimeException}, or need a custom timeout: + *
    {@code
      * try (ExternalHashQueryContext q = hash.queryContext(key)) {
      *     if (q.writeLock().tryLock(5, TimeUnit.SECONDS)) {
      *         // do something
    @@ -146,12 +146,12 @@ import org.jetbrains.annotations.Nullable;
      *         return offHeapPoint;
      *     }
      * }}
    - * + *

    *

    {@code HashQueryContext} is the base interface defining the structure, but it has no methods * to anything "interesting" with {@code entry()} or {@code absentEntry()}. Use {@link * MapQueryContext} or {@link SetQueryContext} interfaces, which provide access to {@link * MapEntryOperations} and {@link SetEntryOperations} respectively. - * + * * @param the hash key type * @see ChronicleHash#queryContext(Object) */ @@ -160,7 +160,7 @@ public interface HashQueryContext extends HashContext, SegmentLock { /** * Returns the index of the accessed segment, where the queried key is located (or to which * the key is going to be put). - * + *

    *

    This index might also be used as the {@code InterProcessReadWriteUpdateLock} identifier, * because {@code ChronicleHashes} has per-segment locks. */ @@ -175,7 +175,7 @@ public interface HashQueryContext extends HashContext, SegmentLock { /** * Returns the entry context, if the entry with the queried key is present * in the {@code ChronicleHash}, returns {@code null} is the entry is absent. - * + * * @implNote Might acquire {@link #readLock} before searching for the key, if the context * is not locked yet. */ @@ -184,7 +184,7 @@ public interface HashQueryContext extends HashContext, SegmentLock { /** * Returns the special absent entry object, if the entry with the queried key * is absent in the hash, returns {@code null}, if the entry is present. - * + * * @implNote Might acquire {@link #readLock} before searching for the key, if the context * is not locked yet. */ diff --git a/src/main/java/net/openhft/chronicle/hash/HashSegmentContext.java b/src/main/java/net/openhft/chronicle/hash/HashSegmentContext.java index e09e4ef7a..a451992f4 100644 --- a/src/main/java/net/openhft/chronicle/hash/HashSegmentContext.java +++ b/src/main/java/net/openhft/chronicle/hash/HashSegmentContext.java @@ -44,7 +44,7 @@ public interface HashSegmentContext> extends HashConte * Checks the given predicate on each present entry in this segment until all entries * have been processed or the predicate returns {@code false} for some entry, or throws * an {@code Exception}. Exceptions thrown by the predicate are relayed to the caller. - * + *

    *

    If this segment is empty (i. e. {@link #size()} call returns 0), this method returns * {@code true} immediately. * diff --git a/src/main/java/net/openhft/chronicle/hash/SegmentLock.java b/src/main/java/net/openhft/chronicle/hash/SegmentLock.java index d08d7b488..a895a6ad7 100644 --- a/src/main/java/net/openhft/chronicle/hash/SegmentLock.java +++ b/src/main/java/net/openhft/chronicle/hash/SegmentLock.java @@ -21,7 +21,7 @@ import net.openhft.chronicle.hash.locks.InterProcessReadWriteUpdateLock; /** * {@link InterProcessReadWriteUpdateLock} of a segment in {@code ChronicleHash}. - * + *

    *

    In Chronicle-Map off-heap design, locks (and concurrency) are per-segment. * * @see ChronicleHashBuilder#minSegments(int) diff --git a/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState$$Native.java b/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState$$Native.java index ebd0c52df..a99c2f0d2 100644 --- a/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState$$Native.java +++ b/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState$$Native.java @@ -17,17 +17,7 @@ package net.openhft.chronicle.hash; -import java.lang.IllegalArgumentException; -import java.lang.IllegalStateException; -import java.lang.Object; -import java.lang.Override; -import java.lang.String; -import java.lang.StringBuilder; -import net.openhft.chronicle.bytes.Byteable; -import net.openhft.chronicle.bytes.BytesIn; -import net.openhft.chronicle.bytes.BytesMarshallable; -import net.openhft.chronicle.bytes.BytesOut; -import net.openhft.chronicle.bytes.BytesStore; +import net.openhft.chronicle.bytes.*; import net.openhft.chronicle.values.Copyable; /** diff --git a/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState.java b/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState.java index afdc5fbd6..1dfe2f891 100644 --- a/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState.java +++ b/src/main/java/net/openhft/chronicle/hash/VanillaGlobalMutableState.java @@ -24,34 +24,40 @@ import net.openhft.chronicle.values.Values; /** *

    This interface is a private API, don't use in client code

    - * + *

    * Excluding global mutable state lock */ public interface VanillaGlobalMutableState extends Byteable { - @Group(1) - int getAllocatedExtraTierBulks(); - void setAllocatedExtraTierBulks(@Range(min = 0, max = 16777215) int allocatedExtraTierBulks); - - @Group(2) - long getFirstFreeTierIndex(); - void setFirstFreeTierIndex(@Range(min = 0, max = 1099511627775L) long firstFreeTierIndex); - - @Group(3) - long getExtraTiersInUse(); - void setExtraTiersInUse(@Range(min = 0, max = 1099511627775L) long extraTiersInUse); - - @Group(4) - long getSegmentHeadersOffset(); - void setSegmentHeadersOffset(@Range(min = 0, max = 4294967295L) long segmentHeadersOffset); - - @Group(5) - long getDataStoreSize(); - void setDataStoreSize(@Range(min = 0, max = Long.MAX_VALUE) long dataStoreSize); - long addDataStoreSize(long addition); - public static void main(String[] args) { System.setProperty("chronicle.values.dumpCode", "true"); Values.nativeClassFor(VanillaGlobalMutableState.class); } + + @Group(1) + int getAllocatedExtraTierBulks(); + + void setAllocatedExtraTierBulks(@Range(min = 0, max = 16777215) int allocatedExtraTierBulks); + + @Group(2) + long getFirstFreeTierIndex(); + + void setFirstFreeTierIndex(@Range(min = 0, max = 1099511627775L) long firstFreeTierIndex); + + @Group(3) + long getExtraTiersInUse(); + + void setExtraTiersInUse(@Range(min = 0, max = 1099511627775L) long extraTiersInUse); + + @Group(4) + long getSegmentHeadersOffset(); + + void setSegmentHeadersOffset(@Range(min = 0, max = 4294967295L) long segmentHeadersOffset); + + @Group(5) + long getDataStoreSize(); + + void setDataStoreSize(@Range(min = 0, max = Long.MAX_VALUE) long dataStoreSize); + + long addDataStoreSize(long addition); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java b/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java index b295cd3bf..0364221b4 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/BigSegmentHeader.java @@ -44,7 +44,7 @@ public final class BigSegmentHeader implements SegmentHeader { */ private static final VanillaReadWriteUpdateWithWaitsLockingStrategy LOCK = (VanillaReadWriteUpdateWithWaitsLockingStrategy) - VanillaReadWriteUpdateWithWaitsLockingStrategy.instance(); + VanillaReadWriteUpdateWithWaitsLockingStrategy.instance(); private static final NativeAccess A = (NativeAccess) Access.nativeAccess(); private static final int TRY_LOCK_NANOS_THRESHOLD = 2_000_000; @@ -56,8 +56,7 @@ public final class BigSegmentHeader implements SegmentHeader { int timeout = 60; try { timeout = Integer.parseInt(System.getProperty("net.openhft.chronicle.map.lockTimeoutSeconds", String.valueOf(timeout))); - } - catch (NumberFormatException ex) { + } catch (NumberFormatException ex) { // ignore } @@ -70,29 +69,29 @@ public final class BigSegmentHeader implements SegmentHeader { private static InterProcessDeadLockException deadLock() { return new InterProcessDeadLockException( "Failed to acquire the lock in " + LOCK_TIMEOUT_SECONDS + " seconds.\n" + - "Possible reasons:\n" + - " - The lock was not released by the previous holder. If you use contexts API,\n" + - " for example map.queryContext(key), in a try-with-resources block.\n" + - " - This Chronicle Map (or Set) instance is persisted to disk, and the previous\n" + - " process (or one of parallel accessing processes) has crashed while holding\n" + - " this lock. In this case you should use ChronicleMapBuilder.recoverPersistedTo()" + - " procedure\n" + - " to access the Chronicle Map instance.\n" + - " - A concurrent thread or process, currently holding this lock, spends\n" + - " unexpectedly long time (more than " + LOCK_TIMEOUT_SECONDS + " seconds) in\n" + - " the context (try-with-resource block) or one of overridden interceptor\n" + - " methods (or MapMethods, or MapEntryOperations, or MapRemoteOperations)\n" + - " while performing an ordinary Map operation or replication. You should either\n" + - " redesign your logic to spend less time in critical sections (recommended) or\n" + - " acquire this lock with tryLock(time, timeUnit) method call, with sufficient\n" + - " time specified.\n" + - " - Segment(s) in your Chronicle Map are very large, and iteration over them\n" + - " takes more than " + LOCK_TIMEOUT_SECONDS + " seconds. In this case you should\n" + - " acquire this lock with tryLock(time, timeUnit) method call, with longer\n" + - " timeout specified.\n" + - " - This is a dead lock. If you perform multi-key queries, ensure you acquire\n" + - " segment locks in the order (ascending by segmentIndex()), you can find\n" + - " an example here: https://github.com/OpenHFT/Chronicle-Map#multi-key-queries\n"); + "Possible reasons:\n" + + " - The lock was not released by the previous holder. If you use contexts API,\n" + + " for example map.queryContext(key), in a try-with-resources block.\n" + + " - This Chronicle Map (or Set) instance is persisted to disk, and the previous\n" + + " process (or one of parallel accessing processes) has crashed while holding\n" + + " this lock. In this case you should use ChronicleMapBuilder.recoverPersistedTo()" + + " procedure\n" + + " to access the Chronicle Map instance.\n" + + " - A concurrent thread or process, currently holding this lock, spends\n" + + " unexpectedly long time (more than " + LOCK_TIMEOUT_SECONDS + " seconds) in\n" + + " the context (try-with-resource block) or one of overridden interceptor\n" + + " methods (or MapMethods, or MapEntryOperations, or MapRemoteOperations)\n" + + " while performing an ordinary Map operation or replication. You should either\n" + + " redesign your logic to spend less time in critical sections (recommended) or\n" + + " acquire this lock with tryLock(time, timeUnit) method call, with sufficient\n" + + " time specified.\n" + + " - Segment(s) in your Chronicle Map are very large, and iteration over them\n" + + " takes more than " + LOCK_TIMEOUT_SECONDS + " seconds. In this case you should\n" + + " acquire this lock with tryLock(time, timeUnit) method call, with longer\n" + + " timeout specified.\n" + + " - This is a dead lock. If you perform multi-key queries, ensure you acquire\n" + + " segment locks in the order (ascending by segmentIndex()), you can find\n" + + " an example here: https://github.com/OpenHFT/Chronicle-Map#multi-key-queries\n"); } private static long roundUpNanosToMillis(long nanos) { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/ChronicleHashCloseOnExitHook.java b/src/main/java/net/openhft/chronicle/hash/impl/ChronicleHashCloseOnExitHook.java index fc9fdb0fd..8c8a3601a 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/ChronicleHashCloseOnExitHook.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/ChronicleHashCloseOnExitHook.java @@ -16,7 +16,6 @@ package net.openhft.chronicle.hash.impl; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +37,9 @@ final class ChronicleHashCloseOnExitHook { }); } + private ChronicleHashCloseOnExitHook() { + } + static synchronized void add(VanillaChronicleHash hash) { if (maps == null) throw new IllegalStateException("Shutdown in progress"); @@ -85,6 +87,4 @@ final class ChronicleHashCloseOnExitHook { } } } - - private ChronicleHashCloseOnExitHook() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/CompactOffHeapLinearHashTable.java b/src/main/java/net/openhft/chronicle/hash/impl/CompactOffHeapLinearHashTable.java index 9427f32c6..243a162ce 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/CompactOffHeapLinearHashTable.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/CompactOffHeapLinearHashTable.java @@ -26,14 +26,42 @@ public abstract class CompactOffHeapLinearHashTable { // to fit 64 bits per slot. public static final int MAX_TIER_CHUNKS = 1 << 30; public static final int MAX_TIER_ENTRIES = 1 << 29; - /** Normally, hashLookup capacity is chosen so that the lf varies from 1/3 to 2/3, at most */ - public static final double MAX_UPPER_BOUND_LOAD_FACTOR = .2/.3; + /** + * Normally, hashLookup capacity is chosen so that the lf varies from 1/3 to 2/3, at most + */ + public static final double MAX_UPPER_BOUND_LOAD_FACTOR = .2 / .3; /** * If average key/value sizes are configured wrong, and Chronicle Hash bloats up (size grows * beyond configured .entries()), hashLookup might become too full. Stop insertion and trigger * segment tiering, when hashLookup load factor > 0.8, because collision chains become too long. */ public static final double MAX_LOAD_FACTOR = 0.8; + public static final long UNSET_KEY = 0L; + public static final long UNSET_ENTRY = 0L; + final long capacityMask2; + private final long capacityMask; + private final int keyBits; + private final long keyMask; + private final long valueMask; + + CompactOffHeapLinearHashTable(long capacity, int slotSize, int keyBits, int valueBits) { + this.capacityMask = capacity - 1L; + + this.capacityMask2 = capacityMask * slotSize; + + this.keyBits = keyBits; + this.keyMask = mask(keyBits); + this.valueMask = mask(valueBits); + } + /** + * Must not store {@code h} in a field, to avoid memory leaks. + * + * @see net.openhft.chronicle.hash.impl.stage.hash.Chaining#initMap + */ + CompactOffHeapLinearHashTable(VanillaChronicleHash h) { + this(h.tierHashLookupCapacity, h.tierHashLookupSlotSize, h.tierHashLookupKeyBits, + h.tierHashLookupValueBits); + } public static int valueBits(long actualChunksPerSegment) { return 64 - Long.numberOfLeadingZeros(actualChunksPerSegment - 1L); @@ -73,35 +101,6 @@ public abstract class CompactOffHeapLinearHashTable { return (1L << bits) - 1L; } - public static final long UNSET_KEY = 0L; - public static final long UNSET_ENTRY = 0L; - - private final long capacityMask; - final long capacityMask2; - private final int keyBits; - private final long keyMask; - private final long valueMask; - - CompactOffHeapLinearHashTable(long capacity, int slotSize, int keyBits, int valueBits) { - this.capacityMask = capacity - 1L; - - this.capacityMask2 = capacityMask * slotSize; - - this.keyBits = keyBits; - this.keyMask = mask(keyBits); - this.valueMask = mask(valueBits); - } - - /** - * Must not store {@code h} in a field, to avoid memory leaks. - * - * @see net.openhft.chronicle.hash.impl.stage.hash.Chaining#initMap - */ - CompactOffHeapLinearHashTable(VanillaChronicleHash h) { - this(h.tierHashLookupCapacity, h.tierHashLookupSlotSize, h.tierHashLookupKeyBits, - h.tierHashLookupValueBits); - } - abstract long indexToPos(long index); public long maskUnsetKey(long key) { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/ContextHolder.java b/src/main/java/net/openhft/chronicle/hash/impl/ContextHolder.java index 522de85af..9541757c9 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/ContextHolder.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/ContextHolder.java @@ -20,7 +20,7 @@ import net.openhft.chronicle.hash.impl.stage.hash.ChainingInterface; /** * A simple wrapper of {@link ChainingInterface}, the ChainingInterface field could be set to null. - * + *

    *

    Motivation

    *

    {@link net.openhft.chronicle.map.ChronicleMap}'s context objects are huge and reference their * own instances of key and value marshallers, which usually have buffers for serialization (e. g. @@ -29,7 +29,7 @@ import net.openhft.chronicle.hash.impl.stage.hash.ChainingInterface; * (see {@link net.openhft.chronicle.map.VanillaChronicleMap#cxt}). We want the context objects to * be eligible for garbage collection as soon as possible after the ChronicleMap object is closed * or becomes unreachable. - * + *

    *

    In JDK 8 ThreadLocals are implemented using {@link java.lang.ThreadLocal.ThreadLocalMap}, * a hash table with ThreadLocal objects themselves as the keys, weak-referenced. So after * ChronicleMap (hence it's ThreadLocal cxt field) becomes unreachable, context objects should be @@ -38,11 +38,11 @@ import net.openhft.chronicle.hash.impl.stage.hash.ChainingInterface; * remove(), but not on the hot path of ThreadLocal.get(). I. e. if there is not enough "ThreadLocal * activity" within a thread, stale ChronicleMap contexts may not be removed from ThreadLocalMaps * forever, effectively this is a memory leak. - * + *

    *

    Moreover, if the user of the library closes ChronicleMap with close(), but has ChronicleMap * object leaked, ChronicleMap's ThreadLocal field doesn't become unreachable and the leak of * context objects is "legitimate". - * + *

    *

    Solution for this is to reference from {@link * net.openhft.chronicle.map.VanillaChronicleMap#cxt} not huge context object directly, but small * ContextHolder object, and clear the reference to context via {@link #clear()} on diff --git a/src/main/java/net/openhft/chronicle/hash/impl/HashSplitting.java b/src/main/java/net/openhft/chronicle/hash/impl/HashSplitting.java index 13800db47..9cac0d9a8 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/HashSplitting.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/HashSplitting.java @@ -38,12 +38,14 @@ public interface HashSplitting extends Marshallable { } int segmentIndex(long hash); + long segmentHash(long hash); final class ForSingleSegment implements HashSplitting, EnumMarshallable { public static final ForSingleSegment INSTANCE = new ForSingleSegment(); - private ForSingleSegment() {} + private ForSingleSegment() { + } @Override public int segmentIndex(long hash) { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/InMemoryChronicleHashResources.java b/src/main/java/net/openhft/chronicle/hash/impl/InMemoryChronicleHashResources.java index c3fc5701d..6466a2934 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/InMemoryChronicleHashResources.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/InMemoryChronicleHashResources.java @@ -18,9 +18,6 @@ package net.openhft.chronicle.hash.impl; import net.openhft.chronicle.core.OS; -import net.openhft.chronicle.hash.impl.util.Throwables; - -import java.util.List; public final class InMemoryChronicleHashResources extends ChronicleHashResources { @Override diff --git a/src/main/java/net/openhft/chronicle/hash/impl/PersistedChronicleHashResources.java b/src/main/java/net/openhft/chronicle/hash/impl/PersistedChronicleHashResources.java index e9ca85e61..a666863fa 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/PersistedChronicleHashResources.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/PersistedChronicleHashResources.java @@ -23,7 +23,6 @@ import net.openhft.chronicle.hash.impl.util.CanonicalRandomAccessFiles; import java.io.File; import java.io.IOException; - public final class PersistedChronicleHashResources extends ChronicleHashResources { private File file; diff --git a/src/main/java/net/openhft/chronicle/hash/impl/SegmentHeader.java b/src/main/java/net/openhft/chronicle/hash/impl/SegmentHeader.java index b9b18deb1..db9c665d2 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/SegmentHeader.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/SegmentHeader.java @@ -21,52 +21,75 @@ import java.util.concurrent.TimeUnit; public interface SegmentHeader { long entries(long address); + void entries(long address, long size); long deleted(long address); + void deleted(long address, long deleted); long lowestPossiblyFreeChunk(long address); + void lowestPossiblyFreeChunk(long address, long lowestPossiblyFreeChunk); long nextTierIndex(long address); + void nextTierIndex(long address, long nextTierIndex); void readLock(long address); + void readLockInterruptibly(long address) throws InterruptedException; + boolean tryReadLock(long address); + boolean tryReadLock(long address, long time, TimeUnit unit) throws InterruptedException; void updateLock(long address); + void updateLockInterruptibly(long address) throws InterruptedException; + boolean tryUpdateLock(long address); + boolean tryUpdateLock(long address, long time, TimeUnit unit) throws InterruptedException; void writeLock(long address); + void writeLockInterruptibly(long address) throws InterruptedException; + boolean tryWriteLock(long address); + boolean tryWriteLock(long address, long time, TimeUnit unit) throws InterruptedException; boolean tryUpgradeReadToUpdateLock(long address); + boolean tryUpgradeReadToWriteLock(long address); void upgradeUpdateToWriteLock(long address); + void upgradeUpdateToWriteLockInterruptibly(long address) throws InterruptedException; + boolean tryUpgradeUpdateToWriteLock(long address); + boolean tryUpgradeUpdateToWriteLock(long address, long time, TimeUnit unit) throws InterruptedException; void readUnlock(long address); void updateUnlock(long address); + void downgradeUpdateToReadLock(long address); void writeUnlock(long address); + void downgradeWriteToUpdateLock(long address); + void downgradeWriteToReadLock(long address); void resetLock(long address); + long resetLockState(); + long getLockState(long address); + String lockStateToString(long lockState); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/SizePrefixedBlob.java b/src/main/java/net/openhft/chronicle/hash/impl/SizePrefixedBlob.java index b999642a5..8324e728c 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/SizePrefixedBlob.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/SizePrefixedBlob.java @@ -31,6 +31,9 @@ public final class SizePrefixedBlob { public static final int SIZE_MASK = (1 << 30) - 1; + private SizePrefixedBlob() { + } + public static boolean isReady(int sizeWord) { return sizeWord > 0; } @@ -38,6 +41,4 @@ public final class SizePrefixedBlob { public static int extractSize(int sizeWord) { return sizeWord & SIZE_MASK; } - - private SizePrefixedBlob() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/TierCountersArea.java b/src/main/java/net/openhft/chronicle/hash/impl/TierCountersArea.java index eb07b5f3c..83f2e566f 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/TierCountersArea.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/TierCountersArea.java @@ -29,9 +29,6 @@ import net.openhft.chronicle.core.OS; public enum TierCountersArea { ; - private static Memory memory = OS.memory(); - private static final long UNSIGNED_INT_MASK = 0xFFFFFFFFL; - public static final long NEXT_TIER_INDEX_OFFSET = 0L; public static final long PREV_TIER_INDEX_OFFSET = NEXT_TIER_INDEX_OFFSET + 8L; public static final long LOWEST_POSSIBLY_FREE_CHUNK_TIERED_OFFSET = PREV_TIER_INDEX_OFFSET + 8L; @@ -39,6 +36,8 @@ public enum TierCountersArea { public static final long TIER_OFFSET = SEGMENT_INDEX_OFFSET + 4L; public static final long ENTRIES_OFFSET = TIER_OFFSET + 4L; public static final long DELETED_OFFSET = ENTRIES_OFFSET + 4L; + private static final long UNSIGNED_INT_MASK = 0xFFFFFFFFL; + private static Memory memory = OS.memory(); public static long nextTierIndex(long address) { return memory.readLong(address + NEXT_TIER_INDEX_OFFSET); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java index 0422e3e9a..e969833ae 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java @@ -71,112 +71,83 @@ public abstract class VanillaChronicleHash globalMutableStateLockTryAcquireOperation = + TryAcquireOperations.lock(); + static final + AcquisitionStrategy + globalMutableStateLockAcquisitionStrategy = + AcquisitionStrategies.spinLoopOrFail(2, TimeUnit.SECONDS); + private static final long GLOBAL_MUTABLE_STATE_LOCK_OFFSET = 0L; + private static final long GLOBAL_MUTABLE_STATE_VALUE_OFFSET = 8L; ///////////////////////////////////////////////// // If the hash was created in the first place, or read from disk public transient boolean createdOrInMemory; - ///////////////////////////////////////////////// // Key Data model public Class keyClass; public SizeMarshaller keySizeMarshaller; public SizedReader keyReader; public DataAccess keyDataAccess; - ///////////////////////////////////////////////// public boolean checksumEntries; - ///////////////////////////////////////////////// // Concurrency (number of segments), memory management and dependent fields public int actualSegments; public HashSplitting hashSplitting; - public long chunkSize; public int maxChunksPerEntry; public long actualChunksPerSegmentTier; - - ///////////////////////////////////////////////// - // Precomputed offsets and sizes for fast Context init - int segmentHeaderSize; - public int tierHashLookupValueBits; public int tierHashLookupKeyBits; public int tierHashLookupSlotSize; public long tierHashLookupCapacity; public long maxEntriesPerHashLookup; - long tierHashLookupInnerSize; public long tierHashLookupOuterSize; - public long tierFreeListInnerSize; public long tierFreeListOuterSize; - - long tierEntrySpaceInnerSize; public int tierEntrySpaceInnerOffset; - long tierEntrySpaceOuterSize; - public long tierSize; - + public long tiersInBulk; + public transient List tierBulkOffsets; + public transient long headerSize; + public transient long segmentHeadersOffset; + ///////////////////////////////////////////////// + // Miscellaneous fields + public transient CompactOffHeapLinearHashTable hashLookup; + public transient Identity identity; + protected int log2TiersInBulk; + ///////////////////////////////////////////////// + // Bytes Store (essentially, the base address) and serialization-dependent offsets + protected transient BytesStore bs; + ///////////////////////////////////////////////// + // Precomputed offsets and sizes for fast Context init + int segmentHeaderSize; + long tierHashLookupInnerSize; + long tierEntrySpaceInnerSize; + long tierEntrySpaceOuterSize; long maxExtraTiers; long tierBulkSizeInBytes; long tierBulkInnerOffsetToTiers; - public long tiersInBulk; - protected int log2TiersInBulk; - + transient long segmentsOffset; + ///////////////////////////////////////////////// + private String dataFileVersion; ///////////////////////////////////////////////// // Resources private transient File file; private transient RandomAccessFile raf; - private transient ChronicleHashResources resources; - private transient Cleaner cleaner; - - ///////////////////////////////////////////////// - // Bytes Store (essentially, the base address) and serialization-dependent offsets - protected transient BytesStore bs; - - public static class TierBulkData { - public final BytesStore bytesStore; - public final long offset; - - public TierBulkData(BytesStore bytesStore, long offset) { - this.bytesStore = bytesStore; - this.offset = offset; - } - - public TierBulkData(TierBulkData data, long offset) { - this.bytesStore = data.bytesStore; - this.offset = offset; - } - } - - public transient List tierBulkOffsets; - - public transient long headerSize; - public transient long segmentHeadersOffset; - transient long segmentsOffset; - - ///////////////////////////////////////////////// - // Miscellaneous fields - public transient CompactOffHeapLinearHashTable hashLookup; - - private transient VanillaGlobalMutableState globalMutableState; - - /** - * {@link ChronicleHashCloseOnExitHook} needs to use {@code VanillaChronicleHash}es as - * WeakHashMap keys, but with identity comparison, not Map's equals() and hashCode(). - */ - public class Identity { - public VanillaChronicleHash hash() { - return VanillaChronicleHash.this; - } - } - - public transient Identity identity; // --- End of instance fields --- - + private transient ChronicleHashResources resources; + private transient Cleaner cleaner; + private transient VanillaGlobalMutableState globalMutableState; public VanillaChronicleHash(ChronicleMapBuilder builder) { // Version @@ -238,6 +209,20 @@ public abstract class VanillaChronicleHash globalMutableStateLockTryAcquireOperation = - TryAcquireOperations.lock(); - static final - AcquisitionStrategy - globalMutableStateLockAcquisitionStrategy = - AcquisitionStrategies.spinLoopOrFail(2, TimeUnit.SECONDS); - - private static final long GLOBAL_MUTABLE_STATE_LOCK_OFFSET = 0L; - private static final long GLOBAL_MUTABLE_STATE_VALUE_OFFSET = 8L; - private long globalMutableStateAddress() { return bsAddress() + headerSize; } @@ -773,7 +726,9 @@ public abstract class VanillaChronicleHash 0; } @@ -1041,8 +996,35 @@ public abstract class VanillaChronicleHash> allContexts() { return Collections.unmodifiableList(resources.contexts()); } + + public static class TierBulkData { + public final BytesStore bytesStore; + public final long offset; + + public TierBulkData(BytesStore bytesStore, long offset) { + this.bytesStore = bytesStore; + this.offset = offset; + } + + public TierBulkData(TierBulkData data, long offset) { + this.bytesStore = data.bytesStore; + this.offset = offset; + } + } + + /** + * {@link ChronicleHashCloseOnExitHook} needs to use {@code VanillaChronicleHash}es as + * WeakHashMap keys, but with identity comparison, not Map's equals() and hashCode(). + */ + public class Identity { + public VanillaChronicleHash hash() { + return VanillaChronicleHash.this; + } + } } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/EntryKeyBytesData.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/EntryKeyBytesData.java index d26323b57..32d85e65c 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/EntryKeyBytesData.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/EntryKeyBytesData.java @@ -35,15 +35,22 @@ import net.openhft.sg.Staged; @Staged public class EntryKeyBytesData extends AbstractData { - @StageRef VanillaChronicleHashHolder hh; - @StageRef KeyBytesInterop ki; - @StageRef SegmentStages s; - @StageRef HashEntryStages entry; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + VanillaChronicleHashHolder hh; + @StageRef + KeyBytesInterop ki; + @StageRef + SegmentStages s; + @StageRef + HashEntryStages entry; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + + @Stage("CachedEntryKey") + private K cachedEntryKey; + @Stage("CachedEntryKey") + private boolean cachedEntryKeyRead = false; - @Stage("CachedEntryKey") private K cachedEntryKey; - @Stage("CachedEntryKey") private boolean cachedEntryKeyRead = false; - private void initCachedEntryKey() { cachedEntryKey = innerGetUsing(cachedEntryKey); cachedEntryKeyRead = true; @@ -89,7 +96,7 @@ public class EntryKeyBytesData extends AbstractData { checkOnEachPublicOperation.checkOnEachPublicOperation(); return innerGetUsing(using); } - + private K innerGetUsing(K usingKey) { Bytes bytes = s.segmentBytesForRead(); bytes.readPosition(entry.keyOffset); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/InputKeyBytesData.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/InputKeyBytesData.java index 70213fd20..f39bc4351 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/InputKeyBytesData.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/data/bytes/InputKeyBytesData.java @@ -17,7 +17,9 @@ package net.openhft.chronicle.hash.impl.stage.data.bytes; -import net.openhft.chronicle.bytes.*; +import net.openhft.chronicle.bytes.BytesStore; +import net.openhft.chronicle.bytes.RandomDataInput; +import net.openhft.chronicle.bytes.VanillaBytes; import net.openhft.chronicle.hash.AbstractData; import net.openhft.chronicle.hash.impl.stage.hash.CheckOnEachPublicOperation; import net.openhft.chronicle.hash.impl.stage.hash.KeyBytesInterop; @@ -30,12 +32,25 @@ import static net.openhft.chronicle.bytes.NoBytesStore.NO_BYTES_STORE; @Staged public class InputKeyBytesData extends AbstractData { - @StageRef KeyBytesInterop ki; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - - @Stage("InputKeyBytesStore") private BytesStore inputKeyBytesStore = null; - @Stage("InputKeyBytesStore") private long inputKeyBytesOffset; - @Stage("InputKeyBytesStore") private long inputKeyBytesSize; + @Stage("InputKeyBytes") + private final VanillaBytes inputKeyBytes = + new VanillaBytes(NO_BYTES_STORE); + @StageRef + KeyBytesInterop ki; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @Stage("InputKeyBytesStore") + private BytesStore inputKeyBytesStore = null; + @Stage("InputKeyBytesStore") + private long inputKeyBytesOffset; + @Stage("InputKeyBytesStore") + private long inputKeyBytesSize; + @Stage("InputKeyBytes") + private boolean inputKeyBytesUsed = false; + @Stage("CachedInputKey") + private K cachedInputKey; + @Stage("CachedInputKey") + private boolean cachedInputKeyRead = false; public void initInputKeyBytesStore(BytesStore bytesStore, long offset, long size) { inputKeyBytesStore = bytesStore; @@ -43,10 +58,6 @@ public class InputKeyBytesData extends AbstractData { inputKeyBytesSize = size; } - @Stage("InputKeyBytes") private final VanillaBytes inputKeyBytes = - new VanillaBytes(NO_BYTES_STORE); - @Stage("InputKeyBytes") private boolean inputKeyBytesUsed = false; - boolean inputKeyBytesInit() { return inputKeyBytesUsed; } @@ -61,9 +72,6 @@ public class InputKeyBytesData extends AbstractData { inputKeyBytesUsed = false; } - @Stage("CachedInputKey") private K cachedInputKey; - @Stage("CachedInputKey") private boolean cachedInputKeyRead = false; - private void initCachedInputKey() { cachedInputKey = innerGetUsing(cachedInputKey); cachedInputKeyRead = true; @@ -98,7 +106,7 @@ public class InputKeyBytesData extends AbstractData { checkOnEachPublicOperation.checkOnEachPublicOperation(); return innerGetUsing(using); } - + private K innerGetUsing(K usingKey) { inputKeyBytes.readPosition(inputKeyBytesOffset); return ki.keyReader.read(inputKeyBytes, inputKeyBytesSize, usingKey); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/Alloc.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/Alloc.java index ef1b079de..9b7a5ee84 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/Alloc.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/Alloc.java @@ -23,8 +23,8 @@ public interface Alloc { * Allocates a block of specified number of chunks in a segment tier, optionally clears the * previous allocation. * - * @param chunks chunks to allocate - * @param prevPos the previous position to clear, -1 if not needed + * @param chunks chunks to allocate + * @param prevPos the previous position to clear, -1 if not needed * @param prevChunks the size of the previous allocation to clear, 0 if not needed * @return the new allocation position * @throws RuntimeException if fails to allocate a block diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/AllocatedChunks.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/AllocatedChunks.java index f2f406f96..506edf704 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/AllocatedChunks.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/AllocatedChunks.java @@ -24,13 +24,17 @@ import net.openhft.sg.Staged; @Staged public class AllocatedChunks { - @StageRef public VanillaChronicleHashHolder hh; - @StageRef public SegmentStages s; - @StageRef public HashEntryStages entry; - @StageRef public Alloc alloc; + @StageRef + public VanillaChronicleHashHolder hh; + @StageRef + public SegmentStages s; + @StageRef + public HashEntryStages entry; + @StageRef + public Alloc alloc; public int allocatedChunks = 0; - + public void initAllocatedChunks(int allocatedChunks) { this.allocatedChunks = allocatedChunks; } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryChecksumStrategy.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryChecksumStrategy.java index 28f7a9269..06cd61206 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryChecksumStrategy.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryChecksumStrategy.java @@ -26,9 +26,12 @@ import static net.openhft.chronicle.hash.impl.stage.entry.ChecksumHashing.hash8T @Staged public class HashEntryChecksumStrategy implements ChecksumStrategy { - @StageRef SegmentStages s; - @StageRef HashEntryStages e; - @StageRef KeyHashCode h; + @StageRef + SegmentStages s; + @StageRef + HashEntryStages e; + @StageRef + KeyHashCode h; @Override public void computeAndStoreChecksum() { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java index 231dbcf11..9df52529a 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashEntryStages.java @@ -37,12 +37,29 @@ import static net.openhft.chronicle.algo.bytes.Access.nativeAccess; @Staged public abstract class HashEntryStages implements HashEntry, ChecksumEntry { - @StageRef public VanillaChronicleHashHolder hh; - @StageRef public SegmentStages s; - @StageRef public CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef public HashLookupPos hlp; + @StageRef + public VanillaChronicleHashHolder hh; + @StageRef + public SegmentStages s; + @StageRef + public CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + public HashLookupPos hlp; public long pos = -1; + @Stage("EntryOffset") + public long keySizeOffset = -1; + public long keySize = -1; + public long keyOffset = -1; + public boolean delayedUpdateChecksum = false; + @StageRef + public EntryKeyBytesData entryKey; + @Stage("EntrySizeInChunks") + public int entrySizeInChunks = 0; + @StageRef + HashEntryChecksumStrategy hashEntryChecksumStrategy; + public final ChecksumStrategy checksumStrategy = hh.h().checksumEntries ? + hashEntryChecksumStrategy : NoChecksumStrategy.INSTANCE; public void initPos(long pos) { this.pos = pos; @@ -50,8 +67,6 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry public abstract void closePos(); - @Stage("EntryOffset") public long keySizeOffset = -1; - public abstract boolean entryOffsetInit(); public void initEntryOffset(long keySizeOffset) { @@ -64,16 +79,12 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry public abstract void closeEntryOffset(); - public long keySize = -1; - public void initKeySize(long keySize) { this.keySize = keySize; } public abstract void closeKeySize(); - public long keyOffset = -1; - public void initKeyOffset(long keyOffset) { this.keyOffset = keyOffset; } @@ -134,12 +145,6 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry return keyEnd(); } - @StageRef HashEntryChecksumStrategy hashEntryChecksumStrategy; - public final ChecksumStrategy checksumStrategy = hh.h().checksumEntries ? - hashEntryChecksumStrategy : NoChecksumStrategy.INSTANCE; - - public boolean delayedUpdateChecksum = false; - public void initDelayedUpdateChecksum(boolean delayedUpdateChecksum) { // makes delayedUpdateChecksum dependent on keySizeOffset and Locks stages, to trigger // delayedUpdateChecksum close on these stages' close @@ -186,8 +191,6 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry return checksumStrategy.extraEntryBytes() + entryEnd() - keySizeOffset; } - @StageRef public EntryKeyBytesData entryKey; - @NotNull @Override public Data key() { @@ -195,8 +198,6 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry return entryKey; } - @Stage("EntrySizeInChunks") public int entrySizeInChunks = 0; - void initEntrySizeInChunks() { entrySizeInChunks = hh.h().inChunks(entrySize()); } @@ -204,7 +205,7 @@ public abstract class HashEntryStages implements HashEntry, ChecksumEntry public void initEntrySizeInChunks(int actuallyUsedChunks) { entrySizeInChunks = actuallyUsedChunks; } - + public void innerRemoveEntryExceptHashLookupUpdate() { s.free(pos, entrySizeInChunks); s.incrementModCount(); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupPos.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupPos.java index f6d75d73d..b0d96abd7 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupPos.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupPos.java @@ -24,10 +24,11 @@ import net.openhft.sg.Staged; @Staged public abstract class HashLookupPos { - @StageRef HashLookupSearch hls; - @StageRef SegmentStages s; - public long hashLookupPos = -1; + @StageRef + HashLookupSearch hls; + @StageRef + SegmentStages s; public abstract boolean hashLookupPosInit(); @@ -50,6 +51,6 @@ public abstract class HashLookupPos { public void setHashLookupPos(long hashLookupPos) { this.hashLookupPos = hashLookupPos; } - + public abstract void closeHashLookupPos(); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupSearch.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupSearch.java index 28d8ccfd7..1664d41fb 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupSearch.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/HashLookupSearch.java @@ -29,15 +29,21 @@ import static net.openhft.chronicle.hash.impl.CompactOffHeapLinearHashTable.UNSE @Staged public abstract class HashLookupSearch { - - @StageRef SegmentStages s; - @StageRef public VanillaChronicleHashHolder hh; - @StageRef HashLookupPos hlp; - @StageRef KeySearch ks; - @StageRef MapEntryStages e; - - @Stage("SearchKey") long searchKey = UNSET_KEY; - @Stage("SearchKey") public long searchStartPos; + + @StageRef + public VanillaChronicleHashHolder hh; + @Stage("SearchKey") + public long searchStartPos; + @StageRef + SegmentStages s; + @StageRef + HashLookupPos hlp; + @StageRef + KeySearch ks; + @StageRef + MapEntryStages e; + @Stage("SearchKey") + long searchKey = UNSET_KEY; public CompactOffHeapLinearHashTable hl() { return hh.h().hashLookup; @@ -99,7 +105,7 @@ public abstract class HashLookupSearch { hl().checkValueForPut(entryPos); hl().writeEntryVolatile(addr(), hlp.hashLookupPos, searchKey, entryPos); } - + public boolean checkSlotContainsExpectedKeyAndValue(long value) { // volatile read not needed here because this method is for verifying within-thread // invariants diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/InputKeyHashCode.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/InputKeyHashCode.java index 3780f5a95..f21687a1c 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/InputKeyHashCode.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/InputKeyHashCode.java @@ -25,7 +25,8 @@ import net.openhft.sg.Staged; @Staged public class InputKeyHashCode implements KeyHashCode { - @StageRef public KeySearch ks; + @StageRef + public KeySearch ks; public long keyHash = 0; diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/ReadLock.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/ReadLock.java index 9e5e6d6d8..c81c22681 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/ReadLock.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/ReadLock.java @@ -32,11 +32,15 @@ import static net.openhft.chronicle.hash.impl.LocalLockState.UNLOCKED; @Staged public class ReadLock implements InterProcessLock { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef SegmentStages s; - @StageRef HashEntryStages entry; - @StageRef HashLookupPos hlp; - + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + SegmentStages s; + @StageRef + HashEntryStages entry; + @StageRef + HashLookupPos hlp; + @Override public boolean isHeldByCurrentThread() { checkOnEachPublicOperation.checkOnEachLockOperation(); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/SegmentStages.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/SegmentStages.java index c364db7f3..bd4642877 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/SegmentStages.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/SegmentStages.java @@ -49,22 +49,75 @@ import static net.openhft.chronicle.hash.impl.VanillaChronicleHash.TIER_COUNTERS @Staged public abstract class SegmentStages implements SegmentLock, LocksInterface { - @StageRef LogHolder log; - @StageRef Chaining chaining; - @StageRef public VanillaChronicleHashHolder hh; - @StageRef public CheckOnEachPublicOperation checkOnEachPublicOperation; - + @Stage("Segment") + public final PointerBytesStore segmentBS = new PointerBytesStore(); + @Stage("Segment") + public final Bytes segmentBytes = new VanillaBytes(segmentBS); + @StageRef + public VanillaChronicleHashHolder hh; + @Stage("Segment") + public final ReusableBitSet freeList = new ReusableBitSet( + new SingleThreadedFlatBitSetFrame(LONGS.align(hh.h().actualChunksPerSegmentTier, BITS)), + Access.nativeAccess(), null, 0); + @StageRef + public CheckOnEachPublicOperation checkOnEachPublicOperation; public int segmentIndex = -1; - + @Stage("SegmentHeader") + public long segmentHeaderAddress; + @Stage("SegmentHeader") + public SegmentHeader segmentHeader = null; + @Stage("Locks") + public LocksInterface rootContextLockedOnThisSegment = null; + /** + * See the ChMap Ops spec, considerations of nested same-thread concurrent contexts. + * Once context enters the segment, and observes concurrent same-thread context, + * it sets nestedContextsLockedOnSameSegment = true for itself and that concurrent context. + * This flag is not dropped on exit of one of these contexts, because between calls of + * this context, nested one could be initialized, does some changes that break our thread-local + * assumptions _and exit_, that is why on exit concurrent context should remain "dirty". + */ + @Stage("Locks") + public boolean nestedContextsLockedOnSameSegment; + @Stage("Locks") + public int latestSameThreadSegmentModCount; + @Stage("Locks") + public int contextModCount; + @StageRef + public ReadLock innerReadLock; + @StageRef + public UpdateLock innerUpdateLock; + @StageRef + public WriteLock innerWriteLock; + @Stage("SegmentTier") + public int tier = -1; + @Stage("SegmentTier") + public long tierIndex; + @Stage("SegmentTier") + public long tierBaseAddr; + @Stage("Segment") + public long entrySpaceOffset = 0; + @StageRef + LogHolder log; + @StageRef + Chaining chaining; + // chain + @Stage("Locks") + LocksInterface nextNode; + @Stage("Locks") + LocalLockState localLockState; + @Stage("Locks") + int totalReadLockCount; + @Stage("Locks") + int totalUpdateLockCount; + @Stage("Locks") + int totalWriteLockCount; + public void initSegmentIndex(int segmentIndex) { this.segmentIndex = segmentIndex; } public abstract boolean segmentIndexInit(); - @Stage("SegmentHeader") public long segmentHeaderAddress; - @Stage("SegmentHeader") public SegmentHeader segmentHeader = null; - private void initSegmentHeader() { segmentHeaderAddress = hh.h().segmentHeaderAddress(segmentIndex); segmentHeader = BigSegmentHeader.INSTANCE; @@ -145,53 +198,30 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface { return size; } - @Stage("Locks") public LocksInterface rootContextLockedOnThisSegment = null; - /** - * See the ChMap Ops spec, considerations of nested same-thread concurrent contexts. - * Once context enters the segment, and observes concurrent same-thread context, - * it sets nestedContextsLockedOnSameSegment = true for itself and that concurrent context. - * This flag is not dropped on exit of one of these contexts, because between calls of - * this context, nested one could be initialized, does some changes that break our thread-local - * assumptions _and exit_, that is why on exit concurrent context should remain "dirty". - */ - @Stage("Locks") public boolean nestedContextsLockedOnSameSegment; - @Override @Stage("Locks") public void setNestedContextsLockedOnSameSegment(boolean nestedContextsLockedOnSameSegment) { this.nestedContextsLockedOnSameSegment = nestedContextsLockedOnSameSegment; } - @Stage("Locks") public int latestSameThreadSegmentModCount; - @Override @Stage("Locks") public int changeAndGetLatestSameThreadSegmentModCount(int change) { return this.latestSameThreadSegmentModCount += change; } - @Stage("Locks") public int contextModCount; - @Stage("Locks") public void incrementModCount() { contextModCount = rootContextLockedOnThisSegment.changeAndGetLatestSameThreadSegmentModCount(1); } - // chain - @Stage("Locks") LocksInterface nextNode; - @Override @Stage("Locks") public void setNextNode(LocksInterface nextNode) { this.nextNode = nextNode; } - @Stage("Locks") LocalLockState localLockState; - @Stage("Locks") int totalReadLockCount; - @Stage("Locks") int totalUpdateLockCount; - @Stage("Locks") int totalWriteLockCount; - @Stage("Locks") public boolean readZero() { return rootContextLockedOnThisSegment.totalReadLockCount() == 0; @@ -509,10 +539,6 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface { return s; } - @StageRef public ReadLock innerReadLock; - @StageRef public UpdateLock innerUpdateLock; - @StageRef public WriteLock innerWriteLock; - @NotNull @Override public InterProcessLock readLock() { @@ -534,10 +560,6 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface { return innerWriteLock; } - @Stage("SegmentTier") public int tier = -1; - @Stage("SegmentTier") public long tierIndex; - @Stage("SegmentTier") public long tierBaseAddr; - public abstract boolean segmentTierInit(); public void initSegmentTier() { @@ -617,13 +639,6 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface { prevTier(); } } - - @Stage("Segment") public final PointerBytesStore segmentBS = new PointerBytesStore(); - @Stage("Segment") public final Bytes segmentBytes = new VanillaBytes(segmentBS); - @Stage("Segment") public final ReusableBitSet freeList = new ReusableBitSet( - new SingleThreadedFlatBitSetFrame(LONGS.align(hh.h().actualChunksPerSegmentTier, BITS)), - Access.nativeAccess(), null, 0); - @Stage("Segment") public long entrySpaceOffset = 0; boolean segmentInit() { return entrySpaceOffset > 0; @@ -654,7 +669,7 @@ public abstract class SegmentStages implements SegmentLock, LocksInterface { segmentBytes.readPosition(0); return segmentBytes; } - + void closeSegment() { entrySpaceOffset = 0; } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/UpdateLock.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/UpdateLock.java index 0083f565a..4376b0d1d 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/UpdateLock.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/UpdateLock.java @@ -33,11 +33,15 @@ import static net.openhft.chronicle.hash.impl.LocalLockState.UPDATE_LOCKED; @Staged public class UpdateLock implements InterProcessLock { - @StageRef VanillaChronicleHashHolder hh; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef SegmentStages s; - @StageRef HashEntryStages entry; - + @StageRef + VanillaChronicleHashHolder hh; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + SegmentStages s; + @StageRef + HashEntryStages entry; + @Override public boolean isHeldByCurrentThread() { checkOnEachPublicOperation.checkOnEachLockOperation(); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/WriteLock.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/WriteLock.java index 7f43ba21a..0d9ce3437 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/WriteLock.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/entry/WriteLock.java @@ -33,11 +33,15 @@ import static net.openhft.chronicle.hash.impl.LocalLockState.WRITE_LOCKED; @Staged public class WriteLock implements InterProcessLock { - @StageRef VanillaChronicleHashHolder hh; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef SegmentStages s; - @StageRef HashEntryStages entry; - + @StageRef + VanillaChronicleHashHolder hh; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + SegmentStages s; + @StageRef + HashEntryStages entry; + @Override public boolean isHeldByCurrentThread() { checkOnEachPublicOperation.checkOnEachLockOperation(); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/Chaining.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/Chaining.java index 95c081ee9..45ab5c2a9 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/Chaining.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/Chaining.java @@ -34,6 +34,10 @@ public abstract class Chaining extends ChainingInterface { * First context, ever created in this thread. rootContextInThisThread === contextChain.get(0). */ public final ChainingInterface rootContextInThisThread; + @Stage("Used") + public boolean used; + @Stage("Used") + private boolean firstContextLockedInThisThread; public Chaining(VanillaChronicleMap map) { contextChain = new ArrayList<>(); @@ -42,7 +46,7 @@ public abstract class Chaining extends ChainingInterface { rootContextInThisThread = this; initMap(map); } - + public Chaining(ChainingInterface rootContextInThisThread, VanillaChronicleMap map) { contextChain = rootContextInThisThread.getContextChain(); indexInContextChain = contextChain.size(); @@ -51,6 +55,22 @@ public abstract class Chaining extends ChainingInterface { initMap(map); } + private static T initUsedAndReturn( + VanillaChronicleMap map, ChainingInterface context) { + try { + context.initUsed(true, map); + //noinspection unchecked + return (T) context; + } catch (Throwable throwable) { + try { + ((AutoCloseable) context).close(); + } catch (Throwable t) { + throwable.addSuppressed(t); + } + throw throwable; + } + } + @Override public List getContextChain() { return contextChain; @@ -67,7 +87,7 @@ public abstract class Chaining extends ChainingInterface { * set only once during context creation. It was preventing ChronicleMap objects from becoming * dead and collected by the GC, while any thread, from which the ChronicleMap was accessed * (hence a thread local context created), is alive. - * + *

    *

    The chain of strong references: * 1) Thread -> * 2) ThreadLocalMap -> @@ -77,15 +97,12 @@ public abstract class Chaining extends ChainingInterface { * 4) final reference to the owner {@link VanillaChronicleMap} -> * 5) ThreadLocal {@link net.openhft.chronicle.map.VanillaChronicleMap#cxt} (a strong reference * this time! note that this ThreadLocal is an instance field of VanillaChronicleMap) - * + *

    *

    So in order to break this chain at step 4), contexts store references to their owner * ChronicleMaps only when contexts are used. */ public abstract void initMap(VanillaChronicleMap map); - @Stage("Used") public boolean used; - @Stage("Used") private boolean firstContextLockedInThisThread; - @Override public boolean usedInit() { return used; @@ -133,20 +150,4 @@ public abstract class Chaining extends ChainingInterface { T context = createChaining.apply(this, map); return initUsedAndReturn(map, context); } - - private static T initUsedAndReturn( - VanillaChronicleMap map, ChainingInterface context) { - try { - context.initUsed(true, map); - //noinspection unchecked - return (T) context; - } catch (Throwable throwable) { - try { - ((AutoCloseable) context).close(); - } catch (Throwable t) { - throwable.addSuppressed(t); - } - throw throwable; - } - } } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/CheckOnEachPublicOperation.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/CheckOnEachPublicOperation.java index 6f8842114..2dea8989e 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/CheckOnEachPublicOperation.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/CheckOnEachPublicOperation.java @@ -26,9 +26,10 @@ import net.openhft.sg.Staged; @Staged public abstract class CheckOnEachPublicOperation { - - @StageRef OwnerThreadHolder holder; - + + @StageRef + OwnerThreadHolder holder; + public void checkOnEachPublicOperation() { checkOnEachLockOperation(); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/KeyBytesInterop.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/KeyBytesInterop.java index 9868eff78..505100022 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/KeyBytesInterop.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/KeyBytesInterop.java @@ -27,7 +27,8 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe @Staged public class KeyBytesInterop { - @StageRef VanillaChronicleHashHolder hh; + @StageRef + VanillaChronicleHashHolder hh; public final SizedReader keyReader = copyIfNeeded(hh.h().keyReader); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/OwnerThreadHolder.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/OwnerThreadHolder.java index eb3f90673..6c1ccb4de 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/OwnerThreadHolder.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/OwnerThreadHolder.java @@ -26,9 +26,9 @@ import java.util.ConcurrentModificationException; @Staged public class OwnerThreadHolder { - @StageRef VanillaChronicleHashHolder hh; - final Thread owner = Thread.currentThread(); + @StageRef + VanillaChronicleHashHolder hh; public void checkAccessingFromOwnerThread() { if (owner != Thread.currentThread()) { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/ThreadLocalState.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/ThreadLocalState.java index 0a272b429..35727ce7a 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/ThreadLocalState.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/hash/ThreadLocalState.java @@ -46,8 +46,8 @@ public abstract class ThreadLocalState { } } - private volatile int contextLock = CONTEXT_UNLOCKED; public boolean iterationContextLockedInThisThread; + private volatile int contextLock = CONTEXT_UNLOCKED; /** * Returns {@code true} if this is the outer context lock in this thread, {@code false} if this @@ -98,7 +98,7 @@ public abstract class ThreadLocalState { if (owner() == Thread.currentThread()) { throw new IllegalStateException(chronicleHashIdentityString + ": Attempt to close a Chronicle Hash in the context " + - "of not yet finished query or iteration"); + "of not yet finished query or iteration"); } // If the context belongs to a different thread, wait until that thread finishes it's work // with the context: diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/HashSegmentIteration.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/HashSegmentIteration.java index 3c6c74b46..aa575ae9f 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/HashSegmentIteration.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/HashSegmentIteration.java @@ -33,13 +33,20 @@ import java.util.function.Predicate; @Staged public abstract class HashSegmentIteration> implements HashEntry, HashSegmentContext { - - @StageRef public IterationSegmentStages s; - @StageRef HashEntryStages e; - @StageRef VanillaChronicleHashHolder hh; - @StageRef public CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef protected HashLookupPos hlp; - + + @StageRef + public IterationSegmentStages s; + @StageRef + public CheckOnEachPublicOperation checkOnEachPublicOperation; + public boolean entryRemovedOnThisIteration = false; + public long hashLookupEntry = 0; + @StageRef + protected HashLookupPos hlp; + @StageRef + HashEntryStages e; + @StageRef + VanillaChronicleHashHolder hh; + public boolean shouldTestEntry() { return true; } @@ -52,16 +59,12 @@ public abstract class HashSegmentIteration> return s.tierEntries(); } - public boolean entryRemovedOnThisIteration = false; - abstract boolean entryRemovedOnThisIterationInit(); - + protected void initEntryRemovedOnThisIteration(boolean entryRemovedOnThisIteration) { this.entryRemovedOnThisIteration = entryRemovedOnThisIteration; } - public long hashLookupEntry = 0; - public abstract boolean hashLookupEntryInit(); public void initHashLookupEntry(long entry) { @@ -181,7 +184,7 @@ public abstract class HashSegmentIteration> return true; }); } - + public void checkEntryNotRemovedOnThisIteration() { if (entryRemovedOnThisIterationInit()) { throw new IllegalStateException( diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationAlloc.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationAlloc.java index 6b5881a94..f5d2b065a 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationAlloc.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationAlloc.java @@ -25,7 +25,8 @@ import net.openhft.sg.Staged; @Staged public class IterationAlloc implements Alloc { - @StageRef public SegmentStages s; + @StageRef + public SegmentStages s; /** * Move only to next tiers, to avoid double visiting of relocated entries during iteration diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationKeyHashCode.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationKeyHashCode.java index 4a9f2f200..936f24cd8 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationKeyHashCode.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationKeyHashCode.java @@ -31,9 +31,12 @@ import net.openhft.sg.Staged; @Staged public class IterationKeyHashCode implements KeyHashCode { - @StageRef VanillaChronicleHashHolder hh; - @StageRef SegmentStages s; - @StageRef HashEntryStages e; + @StageRef + VanillaChronicleHashHolder hh; + @StageRef + SegmentStages s; + @StageRef + HashEntryStages e; long keyHash = 0; diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationSegmentStages.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationSegmentStages.java index 69d064c57..80b4bf7c0 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationSegmentStages.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/IterationSegmentStages.java @@ -28,9 +28,12 @@ import net.openhft.sg.Staged; @Staged public abstract class IterationSegmentStages extends SegmentStages { - @StageRef VanillaChronicleHashHolder hh; - @StageRef HashSegmentIteration it; - @StageRef HashLookupSearch hls; + @StageRef + VanillaChronicleHashHolder hh; + @StageRef + HashSegmentIteration it; + @StageRef + HashLookupSearch hls; /** * During iteration, nextTier() is called in doReplaceValue() -> relocation() -> alloc(). diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/SegmentsRecovery.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/SegmentsRecovery.java index 7bccfd2fa..f195637ea 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/SegmentsRecovery.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/SegmentsRecovery.java @@ -153,7 +153,7 @@ public abstract class SegmentsRecovery implements IterationContext { if (lockState != s.segmentHeader.resetLockState()) { report(corruptionListener, corruption, s.segmentIndex, () -> format("lock of segment {} is not clear: {}", - s.segmentIndex, s.segmentHeader.lockStateToString(lockState)) + s.segmentIndex, s.segmentHeader.lockStateToString(lockState)) ); s.segmentHeader.resetLock(s.segmentHeaderAddress); } @@ -174,14 +174,14 @@ public abstract class SegmentsRecovery implements IterationContext { if (TierCountersArea.segmentIndex(tierCountersAreaAddr) != 0) { report(corruptionListener, corruption, s.segmentIndex, () -> format("stored segment index in first tier of segment {}: {}, should be 0", - s.segmentIndex, TierCountersArea.segmentIndex(tierCountersAreaAddr)) + s.segmentIndex, TierCountersArea.segmentIndex(tierCountersAreaAddr)) ); TierCountersArea.segmentIndex(tierCountersAreaAddr, 0); } if (TierCountersArea.tier(tierCountersAreaAddr) != 0) { report(corruptionListener, corruption, s.segmentIndex, () -> format("stored tier in first tier of segment {}: {}, should be 0", - s.segmentIndex, TierCountersArea.tier(tierCountersAreaAddr)) + s.segmentIndex, TierCountersArea.tier(tierCountersAreaAddr)) ); TierCountersArea.tier(tierCountersAreaAddr, 0); } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/TierRecovery.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/TierRecovery.java index f52637e19..a7a3b3936 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/TierRecovery.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/iter/TierRecovery.java @@ -38,10 +38,14 @@ import static net.openhft.chronicle.map.ChronicleHashCorruptionImpl.*; @Staged public class TierRecovery { - @StageRef VanillaChronicleMapHolder mh; - @StageRef SegmentStages s; - @StageRef MapEntryStages e; - @StageRef IterationKeyHashCode khc; + @StageRef + VanillaChronicleMapHolder mh; + @StageRef + SegmentStages s; + @StageRef + MapEntryStages e; + @StageRef + IterationKeyHashCode khc; public int recoverTier( int segmentIndex, ChronicleHashCorruption.Listener corruptionListener, @@ -63,7 +67,7 @@ public class TierRecovery { if (validEntries >= h.maxEntriesPerHashLookup) { report(corruptionListener, corruption, segmentIndex, () -> format("Too many entries in tier with index {}, max is {}", - s.tierIndex, h.maxEntriesPerHashLookup) + s.tierIndex, h.maxEntriesPerHashLookup) ); break nextHlPos; } @@ -120,8 +124,8 @@ public class TierRecovery { s.segmentBS, e.keyOffset, currentKeySize)) { report(corruptionListener, corruption, segmentIndex, () -> format("Entries with duplicate keys within a tier: " + - "at pos {} and {} with key {}, first value is {}", - entryPos, anotherEntryPos, e.key(), e.value()) + "at pos {} and {} with key {}, first value is {}", + entryPos, anotherEntryPos, e.key(), e.value()) ); s.freeList.clearRange( entryPos, entryPos + currentEntrySizeInChunks); @@ -200,10 +204,10 @@ public class TierRecovery { if (key2Address != keyAddress) { report(corruptionListener, corruption, s.segmentIndex, () -> format("entries with duplicate key {} in segment {}: " + - "with values {} and {}, removing the latter", - key, c.segmentIndex(), - entry2 != null ? ((MapEntry) c).value() : "", - !e.entryDeleted() ? e.value() : "") + "with values {} and {}, removing the latter", + key, c.segmentIndex(), + entry2 != null ? ((MapEntry) c).value() : "", + !e.entryDeleted() ? e.value() : "") ); if (hashLookup.remove(currentTierBaseAddr, hlPos) != hlPos) { hlPos = hashLookup.stepBack(hlPos); @@ -230,7 +234,7 @@ public class TierRecovery { if (s.tierEntries() != entries) { report(corruptionListener, corruption, s.segmentIndex, () -> format("Wrong number of entries counter for tier with index {}, " + - "stored: {}, should be: {}", s.tierIndex, s.tierEntries(), entries) + "stored: {}, should be: {}", s.tierIndex, s.tierEntries(), entries) ); s.tierEntries(entries); } @@ -246,8 +250,8 @@ public class TierRecovery { long finalLowestFreeChunk = lowestFreeChunk; report(corruptionListener, corruption, s.segmentIndex, () -> format("wrong lowest free chunk for tier with index {}, " + - "stored: {}, should be: {}", - s.tierIndex, s.lowestPossiblyFreeChunk(), finalLowestFreeChunk) + "stored: {}, should be: {}", + s.tierIndex, s.lowestPossiblyFreeChunk(), finalLowestFreeChunk) ); s.lowestPossiblyFreeChunk(lowestFreeChunk); } @@ -261,7 +265,7 @@ public class TierRecovery { if (entryPos < 0 || entryPos >= h.actualChunksPerSegmentTier) { report(corruptionListener, corruption, segmentIndex, () -> format("Entry pos is out of range: {}, should be 0-{}", - entryPos, h.actualChunksPerSegmentTier - 1) + entryPos, h.actualChunksPerSegmentTier - 1) ); return -1; } @@ -284,8 +288,8 @@ public class TierRecovery { if (segmentIndexFromKey < 0 || segmentIndexFromKey >= h.actualSegments) { report(corruptionListener, corruption, segmentIndex, () -> format("Segment index from the entry key hash code is out of range: {}, " + - "should be 0-{}, entry key: {}", - segmentIndexFromKey, h.actualSegments - 1, e.key()) + "should be 0-{}, entry key: {}", + segmentIndexFromKey, h.actualSegments - 1, e.key()) ); return -1; } @@ -295,8 +299,8 @@ public class TierRecovery { if (searchKey != searchKeyFromKey) { report(corruptionListener, corruption, segmentIndex, () -> format("HashLookup searchKey: {}, HashLookup searchKey " + - "from the entry key hash code: {}, entry key: {}, entry pos: {}", - searchKey, searchKeyFromKey, e.key(), entryPos) + "from the entry key hash code: {}, entry key: {}, entry pos: {}", + searchKey, searchKeyFromKey, e.key(), entryPos) ); return -1; } @@ -321,8 +325,8 @@ public class TierRecovery { if (storedChecksum != checksumFromEntry) { report(corruptionListener, corruption, segmentIndex, () -> format("Checksum doesn't match, stored: {}, should be from " + - "the entry bytes: {}, key: {}, value: {}", - storedChecksum, checksumFromEntry, e.key(), e.value()) + "the entry bytes: {}, key: {}, value: {}", + storedChecksum, checksumFromEntry, e.key(), e.value()) ); return -1; } @@ -330,7 +334,7 @@ public class TierRecovery { if (!s.freeList.isRangeClear(entryPos, entryPos + e.entrySizeInChunks)) { report(corruptionListener, corruption, segmentIndex, () -> format("Overlapping entry: positions {}-{}, key: {}, value: {}", - entryPos, entryPos + e.entrySizeInChunks - 1, e.key(), e.value()) + entryPos, entryPos + e.entrySizeInChunks - 1, e.key(), e.value()) ); return -1; } @@ -340,9 +344,9 @@ public class TierRecovery { } else { if (segmentIndex != segmentIndexFromKey) { report(corruptionListener, corruption, segmentIndex, () -> - format("Expected segment index: {}, segment index from the entry key: {}, " + - "key: {}, value: {}", - segmentIndex, searchKeyFromKey, e.key(), e.value()) + format("Expected segment index: {}, segment index from the entry key: {}, " + + "key: {}, value: {}", + segmentIndex, searchKeyFromKey, e.key(), e.value()) ); return -1; } else { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/HashQuery.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/HashQuery.java index 86d081760..7b10fa408 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/HashQuery.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/HashQuery.java @@ -35,21 +35,29 @@ import static net.openhft.chronicle.hash.impl.stage.query.KeySearch.SearchState. @Staged public abstract class HashQuery implements SetEntry { - @StageRef public VanillaChronicleHashHolder hh; - @StageRef public SegmentStages s; - @StageRef public HashEntryStages entry; - @StageRef public HashLookupSearch hashLookupSearch; - @StageRef public CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef public HashLookupPos hlp; - @StageRef public KeySearch ks; - + @StageRef + public VanillaChronicleHashHolder hh; final DataAccess innerInputKeyDataAccess = hh.h().keyDataAccess.copy(); - + @StageRef + public SegmentStages s; + @StageRef + public HashEntryStages entry; + @StageRef + public HashLookupSearch hashLookupSearch; + @StageRef + public CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + public HashLookupPos hlp; + @StageRef + public KeySearch ks; /** * This stage exists for hooking {@link #innerInputKeyDataAccess} usage, to trigger {@link * DataAccess#uninit()} on context exit */ - @Stage("InputKeyDataAccess") private boolean inputKeyDataAccessInitialized = false; + @Stage("InputKeyDataAccess") + private boolean inputKeyDataAccessInitialized = false; + @Stage("PresenceOfEntry") + private EntryPresence entryPresence = null; void initInputKeyDataAccess() { inputKeyDataAccessInitialized = true; @@ -64,7 +72,7 @@ public abstract class HashQuery implements SetEntry { initInputKeyDataAccess(); return innerInputKeyDataAccess; } - + public void dropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailed() { if (s.locksInit()) { if (s.nestedContextsLockedOnSameSegment && @@ -83,10 +91,6 @@ public abstract class HashQuery implements SetEntry { return ks.inputKey; } - public enum EntryPresence {PRESENT, ABSENT} - - @Stage("PresenceOfEntry") private EntryPresence entryPresence = null; - private void initPresenceOfEntry() { if (ks.searchStatePresent() || tieredEntryPresent()) { entryPresence = EntryPresence.PRESENT; @@ -141,4 +145,6 @@ public abstract class HashQuery implements SetEntry { hh.h().toIdentityString() + ": Entry is absent when doRemove() is called"); } } + + public enum EntryPresence {PRESENT, ABSENT} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/KeySearch.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/KeySearch.java index 4cd94e5b1..afb317adc 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/KeySearch.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/KeySearch.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.impl.stage.query; import net.openhft.chronicle.bytes.Bytes; -import net.openhft.chronicle.bytes.BytesUtil; import net.openhft.chronicle.hash.Data; import net.openhft.chronicle.hash.impl.stage.entry.HashEntryStages; import net.openhft.chronicle.hash.impl.stage.entry.HashLookupSearch; @@ -34,12 +33,17 @@ import static net.openhft.chronicle.hash.impl.stage.query.KeySearch.SearchState. @Staged public abstract class KeySearch { - @StageRef VanillaChronicleMapHolder mh; - @StageRef public SegmentStages s; - @StageRef public HashLookupSearch hashLookupSearch; - @StageRef public HashEntryStages entry; - + @StageRef + public SegmentStages s; + @StageRef + public HashLookupSearch hashLookupSearch; + @StageRef + public HashEntryStages entry; public Data inputKey = null; + @Stage("KeySearch") + protected SearchState searchState = null; + @StageRef + VanillaChronicleMapHolder mh; public abstract boolean inputKeyInit(); @@ -47,13 +51,6 @@ public abstract class KeySearch { this.inputKey = inputKey; } - public enum SearchState { - PRESENT, - ABSENT - } - - @Stage("KeySearch") protected SearchState searchState = null; - public abstract boolean keySearchInit(); @Stage("KeySearch") @@ -62,7 +59,7 @@ public abstract class KeySearch { } public void initKeySearch() { - for (long pos; (pos = hashLookupSearch.nextPos()) >= 0L;) { + for (long pos; (pos = hashLookupSearch.nextPos()) >= 0L; ) { // otherwise we are inside iteration relocation. // During iteration, key search occurs when doReplaceValue() exhausts space in // the current segment, and insertion into the tiered segment requires to locate @@ -95,4 +92,9 @@ public abstract class KeySearch { public boolean searchStateAbsent() { return searchState == ABSENT; } + + public enum SearchState { + PRESENT, + ABSENT + } } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryAlloc.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryAlloc.java index c42ca3ccd..fe0d610db 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryAlloc.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryAlloc.java @@ -25,7 +25,8 @@ import net.openhft.sg.Staged; @Staged public class QueryAlloc implements Alloc { - @StageRef public SegmentStages s; + @StageRef + public SegmentStages s; @Override public long alloc(int chunks, long prevPos, int prevChunks) { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryHashLookupSearch.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryHashLookupSearch.java index ab6b46d79..f003ce4e6 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryHashLookupSearch.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QueryHashLookupSearch.java @@ -25,7 +25,8 @@ import net.openhft.sg.Staged; @Staged public abstract class QueryHashLookupSearch extends HashLookupSearch { - @StageRef KeyHashCode h; + @StageRef + KeyHashCode h; void initSearchKey() { initSearchKey(hl().maskUnsetKey(hh.h().hashSplitting.segmentHash(h.keyHashCode()))); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QuerySegmentStages.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QuerySegmentStages.java index 935dc14b8..9e1a23a5b 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QuerySegmentStages.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/QuerySegmentStages.java @@ -25,7 +25,8 @@ import net.openhft.sg.Staged; @Staged public abstract class QuerySegmentStages extends SegmentStages { - @StageRef KeyHashCode h; + @StageRef + KeyHashCode h; void initSegmentIndex() { segmentIndex = hh.h().hashSplitting.segmentIndex(h.keyHashCode()); diff --git a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/SearchAllocatedChunks.java b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/SearchAllocatedChunks.java index 578d33518..b0415640f 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/stage/query/SearchAllocatedChunks.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/stage/query/SearchAllocatedChunks.java @@ -21,12 +21,11 @@ import net.openhft.chronicle.hash.impl.stage.entry.AllocatedChunks; import net.openhft.sg.StageRef; import net.openhft.sg.Staged; -import static net.openhft.chronicle.hash.impl.stage.query.KeySearch.SearchState.PRESENT; - @Staged public class SearchAllocatedChunks extends AllocatedChunks { - @StageRef KeySearch ks; + @StageRef + KeySearch ks; /** * @return {@code true} if tier has changed diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/BuildVersion.java b/src/main/java/net/openhft/chronicle/hash/impl/util/BuildVersion.java index 2003ddb81..e903037e8 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/BuildVersion.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/BuildVersion.java @@ -31,6 +31,9 @@ public final class BuildVersion { private static String version = null; + private BuildVersion() { + } + public static void main(String[] args) { System.out.println(version()); } @@ -109,6 +112,4 @@ public final class BuildVersion { return null; } } - - private BuildVersion() {} } \ No newline at end of file diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/CanonicalRandomAccessFiles.java b/src/main/java/net/openhft/chronicle/hash/impl/util/CanonicalRandomAccessFiles.java index 2253bbd3d..9f1b57ab9 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/CanonicalRandomAccessFiles.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/CanonicalRandomAccessFiles.java @@ -27,19 +27,12 @@ import java.util.concurrent.ConcurrentHashMap; public final class CanonicalRandomAccessFiles { - private static class RafReference { - RandomAccessFile raf; - int refCount; - - RafReference(RandomAccessFile raf) { - this.raf = raf; - refCount = 1; - } - } - private static final ConcurrentHashMap canonicalRafs = new ConcurrentHashMap<>(); + private CanonicalRandomAccessFiles() { + } + public static RandomAccessFile acquire(File file) throws FileNotFoundException { return canonicalRafs.compute(file, (f, ref) -> { if (ref == null) { @@ -70,5 +63,13 @@ public final class CanonicalRandomAccessFiles { }); } - private CanonicalRandomAccessFiles() {} + private static class RafReference { + RandomAccessFile raf; + int refCount; + + RafReference(RandomAccessFile raf) { + this.raf = raf; + refCount = 1; + } + } } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/CharSequences.java b/src/main/java/net/openhft/chronicle/hash/impl/util/CharSequences.java index 2bbb58088..4e400f974 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/CharSequences.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/CharSequences.java @@ -21,6 +21,9 @@ import org.jetbrains.annotations.NotNull; public final class CharSequences { + private CharSequences() { + } + public static boolean equivalent(@NotNull CharSequence a, @NotNull CharSequence b) { if (a.equals(b)) return true; @@ -47,6 +50,4 @@ public final class CharSequences { } return h; } - - private CharSequences() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/FileIOUtils.java b/src/main/java/net/openhft/chronicle/hash/impl/util/FileIOUtils.java index bb8b12c74..20ea23d83 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/FileIOUtils.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/FileIOUtils.java @@ -23,7 +23,8 @@ import java.nio.channels.FileChannel; public final class FileIOUtils { - private FileIOUtils() {} + private FileIOUtils() { + } public static void readFully(FileChannel fileChannel, long filePosition, ByteBuffer buffer) throws IOException { diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/Objects.java b/src/main/java/net/openhft/chronicle/hash/impl/util/Objects.java index 3bc321bf0..a458f1e9d 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/Objects.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/Objects.java @@ -26,6 +26,9 @@ import java.util.Arrays; * java.util.Objects since Java 7 */ public final class Objects { + private Objects() { + } + public static int hash(Object... values) { return Arrays.hashCode(values); } @@ -44,6 +47,4 @@ public final class Objects { if (obj == null) throw new NullPointerException(); } - - private Objects() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/Throwables.java b/src/main/java/net/openhft/chronicle/hash/impl/util/Throwables.java index c2c121209..cdead239f 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/Throwables.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/Throwables.java @@ -22,6 +22,9 @@ package net.openhft.chronicle.hash.impl.util; */ public final class Throwables { + private Throwables() { + } + public static RuntimeException propagate(Throwable t) { // Avoid calling Objects.requireNonNull(), StackOverflowError-sensitive if (t == null) @@ -55,6 +58,4 @@ public final class Throwables { return thrown; } } - - private Throwables() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/jna/PosixMsync.java b/src/main/java/net/openhft/chronicle/hash/impl/util/jna/PosixMsync.java index 45a79c476..54f3dae16 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/jna/PosixMsync.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/jna/PosixMsync.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.impl.util.jna; import com.sun.jna.*; -import net.openhft.chronicle.core.OS; import java.io.IOException; @@ -26,6 +25,14 @@ public final class PosixMsync { private static final int MS_SYNC = 4; + static { + NativeLibrary clib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME); + Native.register(PosixMsync.class, clib); + } + + private PosixMsync() { + } + public static void msync(long addr, long length) throws IOException { if (msync(new Pointer(addr), new size_t(length), MS_SYNC) == -1) throw new IOException("msync failed: error code " + Native.getLastError()); @@ -33,13 +40,6 @@ public final class PosixMsync { private static native int msync(Pointer addr, size_t length, int flags); - static { - NativeLibrary clib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME); - Native.register(PosixMsync.class, clib); - } - - private PosixMsync() {} - public static class size_t extends IntegerType { private static final long serialVersionUID = 0L; diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java b/src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java index f771268dc..67e7f66ed 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java @@ -31,6 +31,12 @@ import static com.sun.jna.platform.win32.WinError.ERROR_LOCK_VIOLATION; public final class WindowsMsync { + private static final Kernel32Ex KERNEL_32 = (Kernel32Ex) + Native.loadLibrary("kernel32", Kernel32Ex.class, W32APIOptions.UNICODE_OPTIONS); + + private WindowsMsync() { + } + public static void msync(RandomAccessFile raf, long addr, long length) throws IOException { int retry = 0; @@ -57,9 +63,4 @@ public final class WindowsMsync { public interface Kernel32Ex extends Kernel32 { boolean FlushViewOfFile(Pointer addr, SIZE_T length); } - - private static final Kernel32Ex KERNEL_32 = (Kernel32Ex) - Native.loadLibrary("kernel32", Kernel32Ex.class, W32APIOptions.UNICODE_OPTIONS); - - private WindowsMsync() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/math/ContinuedFraction.java b/src/main/java/net/openhft/chronicle/hash/impl/util/math/ContinuedFraction.java index 2c62ae373..805e20f4d 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/math/ContinuedFraction.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/math/ContinuedFraction.java @@ -21,7 +21,7 @@ package net.openhft.chronicle.hash.impl.util.math; /** * Provides a generic means to evaluate continued fractions. Subclasses simply * provided the a and b coefficients to evaluate the continued fraction. - * + *

    *

    * References: *

      @@ -29,13 +29,13 @@ package net.openhft.chronicle.hash.impl.util.math; * Continued Fraction *
    *

    - * */ abstract class ContinuedFraction { /** * Access the n-th a coefficient of the continued fraction. Since a can be * a function of the evaluation point, x, that is passed in as well. + * * @param n the coefficient index to retrieve. * @param x the evaluation point. * @return the n-th a coefficient. @@ -45,6 +45,7 @@ abstract class ContinuedFraction { /** * Access the n-th b coefficient of the continued fraction. Since b can be * a function of the evaluation point, x, that is passed in as well. + * * @param n the coefficient index to retrieve. * @param x the evaluation point. * @return the n-th b coefficient. @@ -57,18 +58,18 @@ abstract class ContinuedFraction { * The implementation of this method is based on the modified Lentz algorithm as described * on page 18 ff. in: * * Note: the implementation uses the terms ai and bi as defined in * Continued Fraction @ MathWorld. *

    * - * @param x the evaluation point. - * @param epsilon maximum error allowed. + * @param x the evaluation point. + * @param epsilon maximum error allowed. * @param maxIterations maximum number of convergents * @return the value of the continued fraction evaluated at x. * @throws IllegalStateException if the algorithm fails to converge. diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/math/Gamma.java b/src/main/java/net/openhft/chronicle/hash/impl/util/math/Gamma.java index 6228cb76c..69efc1173 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/math/Gamma.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/math/Gamma.java @@ -29,10 +29,10 @@ package net.openhft.chronicle.hash.impl.util.math; *
      *
    • Didonato and Morris * (1986), Computation of the Incomplete Gamma Function Ratios and - * their Inverse, TOMS 12(4), 377-393,
    • + * their Inverse, TOMS 12(4), 377-393, *
    • Didonato and Morris * (1992), Algorithm 708: Significant Digit Computation of the - * Incomplete Beta Function Ratios, TOMS 18(3), 360-373,
    • + * Incomplete Beta Function Ratios, TOMS 18(3), 360-373, *
    * and implemented in the * NSWC Library of Mathematical Functions, @@ -44,18 +44,20 @@ package net.openhft.chronicle.hash.impl.util.math; * this library are license free. Since no such notice appears in the code these * functions can safely be ported to Commons-Math. *

    - * */ class Gamma { /** * The value of the {@code g} constant in the Lanczos approximation, see * {@link #lanczos(double)}. + * * @since 3.1 */ public static final double LANCZOS_G = 607.0 / 128.0; - /** Lanczos coefficients */ + /** + * Lanczos coefficients + */ private static final double[] LANCZOS = { 0.99999999999999709182, 57.156235665862923517, @@ -74,7 +76,9 @@ class Gamma { .36899182659531622704e-5, }; - /** Avoid repeated computation of log of 2 PI in logGamma */ + /** + * Avoid repeated computation of log of 2 PI in logGamma + */ private static final double HALF_LOG_2_PI = 0.5 * Math.log(2.0 * Math.PI); /* @@ -82,118 +86,191 @@ class Gamma { * Copied from DGAM1 in the NSWC library. */ - /** The constant {@code A0} defined in {@code DGAM1}. */ + /** + * The constant {@code A0} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_A0 = .611609510448141581788E-08; - /** The constant {@code A1} defined in {@code DGAM1}. */ + /** + * The constant {@code A1} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_A1 = .624730830116465516210E-08; - /** The constant {@code B1} defined in {@code DGAM1}. */ + /** + * The constant {@code B1} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B1 = .203610414066806987300E+00; - /** The constant {@code B2} defined in {@code DGAM1}. */ + /** + * The constant {@code B2} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B2 = .266205348428949217746E-01; - /** The constant {@code B3} defined in {@code DGAM1}. */ + /** + * The constant {@code B3} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B3 = .493944979382446875238E-03; - /** The constant {@code B4} defined in {@code DGAM1}. */ + /** + * The constant {@code B4} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B4 = -.851419432440314906588E-05; - /** The constant {@code B5} defined in {@code DGAM1}. */ + /** + * The constant {@code B5} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B5 = -.643045481779353022248E-05; - /** The constant {@code B6} defined in {@code DGAM1}. */ + /** + * The constant {@code B6} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B6 = .992641840672773722196E-06; - /** The constant {@code B7} defined in {@code DGAM1}. */ + /** + * The constant {@code B7} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B7 = -.607761895722825260739E-07; - /** The constant {@code B8} defined in {@code DGAM1}. */ + /** + * The constant {@code B8} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_B8 = .195755836614639731882E-09; - /** The constant {@code P0} defined in {@code DGAM1}. */ + /** + * The constant {@code P0} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P0 = .6116095104481415817861E-08; - /** The constant {@code P1} defined in {@code DGAM1}. */ + /** + * The constant {@code P1} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P1 = .6871674113067198736152E-08; - /** The constant {@code P2} defined in {@code DGAM1}. */ + /** + * The constant {@code P2} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P2 = .6820161668496170657918E-09; - /** The constant {@code P3} defined in {@code DGAM1}. */ + /** + * The constant {@code P3} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P3 = .4686843322948848031080E-10; - /** The constant {@code P4} defined in {@code DGAM1}. */ + /** + * The constant {@code P4} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P4 = .1572833027710446286995E-11; - /** The constant {@code P5} defined in {@code DGAM1}. */ + /** + * The constant {@code P5} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P5 = -.1249441572276366213222E-12; - /** The constant {@code P6} defined in {@code DGAM1}. */ + /** + * The constant {@code P6} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_P6 = .4343529937408594255178E-14; - /** The constant {@code Q1} defined in {@code DGAM1}. */ + /** + * The constant {@code Q1} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_Q1 = .3056961078365221025009E+00; - /** The constant {@code Q2} defined in {@code DGAM1}. */ + /** + * The constant {@code Q2} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_Q2 = .5464213086042296536016E-01; - /** The constant {@code Q3} defined in {@code DGAM1}. */ + /** + * The constant {@code Q3} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_Q3 = .4956830093825887312020E-02; - /** The constant {@code Q4} defined in {@code DGAM1}. */ + /** + * The constant {@code Q4} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_Q4 = .2692369466186361192876E-03; - /** The constant {@code C} defined in {@code DGAM1}. */ + /** + * The constant {@code C} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C = -.422784335098467139393487909917598E+00; - /** The constant {@code C0} defined in {@code DGAM1}. */ + /** + * The constant {@code C0} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C0 = .577215664901532860606512090082402E+00; - /** The constant {@code C1} defined in {@code DGAM1}. */ + /** + * The constant {@code C1} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C1 = -.655878071520253881077019515145390E+00; - /** The constant {@code C2} defined in {@code DGAM1}. */ + /** + * The constant {@code C2} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C2 = -.420026350340952355290039348754298E-01; - /** The constant {@code C3} defined in {@code DGAM1}. */ + /** + * The constant {@code C3} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C3 = .166538611382291489501700795102105E+00; - /** The constant {@code C4} defined in {@code DGAM1}. */ + /** + * The constant {@code C4} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C4 = -.421977345555443367482083012891874E-01; - /** The constant {@code C5} defined in {@code DGAM1}. */ + /** + * The constant {@code C5} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C5 = -.962197152787697356211492167234820E-02; - /** The constant {@code C6} defined in {@code DGAM1}. */ + /** + * The constant {@code C6} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C6 = .721894324666309954239501034044657E-02; - /** The constant {@code C7} defined in {@code DGAM1}. */ + /** + * The constant {@code C7} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C7 = -.116516759185906511211397108401839E-02; - /** The constant {@code C8} defined in {@code DGAM1}. */ + /** + * The constant {@code C8} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C8 = -.215241674114950972815729963053648E-03; - /** The constant {@code C9} defined in {@code DGAM1}. */ + /** + * The constant {@code C9} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C9 = .128050282388116186153198626328164E-03; - /** The constant {@code C10} defined in {@code DGAM1}. */ + /** + * The constant {@code C10} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C10 = -.201348547807882386556893914210218E-04; - /** The constant {@code C11} defined in {@code DGAM1}. */ + /** + * The constant {@code C11} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C11 = -.125049348214267065734535947383309E-05; - /** The constant {@code C12} defined in {@code DGAM1}. */ + /** + * The constant {@code C12} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C12 = .113302723198169588237412962033074E-05; - /** The constant {@code C13} defined in {@code DGAM1}. */ + /** + * The constant {@code C13} defined in {@code DGAM1}. + */ private static final double INV_GAMMA1P_M1_C13 = -.205633841697760710345015413002057E-06; /** * Default constructor. Prohibit instantiation. */ - private Gamma() {} + private Gamma() { + } /** *

    @@ -206,12 +283,12 @@ class Gamma { *

    * * * @param x Argument. @@ -246,28 +323,28 @@ class Gamma { /** * Returns the regularized gamma function P(a, x). - * + *

    * The implementation of this method is based on: *

    * - * @param a the a parameter. - * @param x the value. - * @param epsilon When the absolute value of the nth item in the - * series is less than epsilon the approximation ceases to calculate - * further elements in the series. + * @param a the a parameter. + * @param x the value. + * @param epsilon When the absolute value of the nth item in the + * series is less than epsilon the approximation ceases to calculate + * further elements in the series. * @param maxIterations Maximum number of "iterations" to complete. * @return the regularized gamma function P(a, x) * @throws IllegalStateException if the algorithm fails to converge. @@ -291,7 +368,7 @@ class Gamma { double n = 0.0; // current element index double an = 1.0 / a; // n-th element in the series double sum = an; // partial sum - while (Math.abs(an/sum) > epsilon && + while (Math.abs(an / sum) > epsilon && n < maxIterations && sum < Double.POSITIVE_INFINITY) { // compute next element in the series @@ -315,25 +392,25 @@ class Gamma { /** * Returns the regularized gamma function Q(a, x) = 1 - P(a, x). - * + *

    * The implementation of this method is based on: *

    * - * @param a the a parameter. - * @param x the value. - * @param epsilon When the absolute value of the nth item in the - * series is less than epsilon the approximation ceases to calculate - * further elements in the series. + * @param a the a parameter. + * @param x the value. + * @param epsilon When the absolute value of the nth item in the + * series is less than epsilon the approximation ceases to calculate + * further elements in the series. * @param maxIterations Maximum number of "iterations" to complete. * @return the regularized gamma function P(a, x) * @throws IllegalStateException if the algorithm fails to converge. @@ -381,7 +458,7 @@ class Gamma { * following equation *
    * {@code gamma(x) = sqrt(2 * pi) / x * (x + g + 0.5) ^ (x + 0.5) - * * exp(-x - g - 0.5) * lanczos(x)}, + * * exp(-x - g - 0.5) * lanczos(x)}, *
    * where {@code g} is the Lanczos constant. *

    diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/math/PoissonDistribution.java b/src/main/java/net/openhft/chronicle/hash/impl/util/math/PoissonDistribution.java index 08a8b47a6..c9f1ebdb5 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/math/PoissonDistribution.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/math/PoissonDistribution.java @@ -92,13 +92,13 @@ public class PoissonDistribution { * (lower, upper]}. The implementation does simple bisection to find the * smallest {@code p}-quantile inf{x in Z | P(X<=x) >= p}. * - * @param p the cumulative probability + * @param p the cumulative probability * @param lower a value satisfying {@code cumulativeProbability(lower) < p} * @param upper a value satisfying {@code p <= cumulativeProbability(upper)} * @return the smallest {@code p}-quantile of this distribution */ private static long solveInverseCumulativeProbability(double mean, final double p, - long lower, long upper) { + long lower, long upper) { while (lower + 1 < upper) { long xm = (lower + upper) / 2; diff --git a/src/main/java/net/openhft/chronicle/hash/impl/util/math/Precision.java b/src/main/java/net/openhft/chronicle/hash/impl/util/math/Precision.java index 779846fcb..0b0512709 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/util/math/Precision.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/math/Precision.java @@ -20,11 +20,17 @@ package net.openhft.chronicle.hash.impl.util.math; class Precision { - /** Offset to order signed double numbers lexicographically. */ + /** + * Offset to order signed double numbers lexicographically. + */ private static final long SGN_MASK = 0x8000000000000000L; - /** Positive zero bits. */ + /** + * Positive zero bits. + */ private static final long POSITIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(+0.0); - /** Negative zero bits. */ + /** + * Negative zero bits. + */ private static final long NEGATIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(-0.0); /** @@ -32,8 +38,8 @@ class Precision { * arguments or the difference between them is within the range of allowed * error (inclusive). * - * @param x First value. - * @param y Second value. + * @param x First value. + * @param y Second value. * @param eps Amount of allowed absolute error. * @return {@code true} if the values are two adjacent floating point * numbers or they are within range of each other. @@ -56,10 +62,10 @@ class Precision { * Bruce Dawson *

    * - * @param x first value - * @param y second value + * @param x first value + * @param y second value * @param maxUlps {@code (maxUlps - 1)} is the number of floating point - * values between {@code x} and {@code y}. + * values between {@code x} and {@code y}. * @return {@code true} if there are fewer than {@code maxUlps} floating * point values between {@code x} and {@code y}. */ @@ -77,10 +83,10 @@ class Precision { final long deltaPlus; final long deltaMinus; if (xInt < yInt) { - deltaPlus = yInt - POSITIVE_ZERO_DOUBLE_BITS; + deltaPlus = yInt - POSITIVE_ZERO_DOUBLE_BITS; deltaMinus = xInt - NEGATIVE_ZERO_DOUBLE_BITS; } else { - deltaPlus = xInt - POSITIVE_ZERO_DOUBLE_BITS; + deltaPlus = xInt - POSITIVE_ZERO_DOUBLE_BITS; deltaMinus = yInt - NEGATIVE_ZERO_DOUBLE_BITS; } @@ -89,7 +95,7 @@ class Precision { } else { isEqual = deltaMinus <= (maxUlps - deltaPlus); } -} + } return isEqual && !Double.isNaN(x) && !Double.isNaN(y); diff --git a/src/main/java/net/openhft/chronicle/hash/locks/InterProcessDeadLockException.java b/src/main/java/net/openhft/chronicle/hash/locks/InterProcessDeadLockException.java index 65f70e072..8d610289f 100644 --- a/src/main/java/net/openhft/chronicle/hash/locks/InterProcessDeadLockException.java +++ b/src/main/java/net/openhft/chronicle/hash/locks/InterProcessDeadLockException.java @@ -27,7 +27,7 @@ public final class InterProcessDeadLockException extends RuntimeException { * Constructs a new {@code InterProcessDeadLockException} with the specified detail message. * * @param message the detail message. The detail message is saved for later retrieval by the - * {@link #getMessage()} method. + * {@link #getMessage()} method. */ public InterProcessDeadLockException(String message) { super(message); @@ -38,8 +38,8 @@ public final class InterProcessDeadLockException extends RuntimeException { * cause. * * @param message the detail message. The detail message is saved for later retrieval by the - * {@link #getMessage()} method. - * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + * {@link #getMessage()} method. + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public InterProcessDeadLockException(String message, Throwable cause) { super(message, cause); diff --git a/src/main/java/net/openhft/chronicle/hash/locks/InterProcessLock.java b/src/main/java/net/openhft/chronicle/hash/locks/InterProcessLock.java index 7d121447a..ec4062530 100644 --- a/src/main/java/net/openhft/chronicle/hash/locks/InterProcessLock.java +++ b/src/main/java/net/openhft/chronicle/hash/locks/InterProcessLock.java @@ -27,27 +27,26 @@ import java.util.concurrent.locks.Lock; /** * An inter-process lock, used to control access to some shared off-heap resources of {@link * ChronicleHash} instances. - * + *

    *

    This lock is not reentrant, but kind of "saturating": multiple {@link #lock()} calls have * the same effect as a single call. Likewise {@link #unlock()} -- multiple unlocks, or unlocking * when the lock isn't actually held, has no negative effects. - * + *

    *

    Once a lock object obtained, it shouldn't be stored in a field and accessed from multiple * threads, instead of that, lock objects should be obtained in each thread separately, using * the same call chain. This is because since the lock is inter-process, it anyway keeps it's * synchronization state in shared off-heap memory, but restricting on-heap "view" of shared lock * to a single thread is beneficial form performance point-of-view, e. g. fields of the on-heap * {@code InterProcessLock} object shouldn't be {@code volatile}. - * + *

    *

    Lock is inter-process, hence it cannot afford to wait for acquisition infinitely, because * it would be too dead-lock prone. {@link #lock()} throws {@code RuntimeException} after some * implementation-defined time spent in waiting for the lock acquisition. - * + *

    *

    {@code InterProcessLock} supports interruption of lock acquisition (in {@link * #lockInterruptibly()} and {@link #tryLock(long, TimeUnit)} methods). * * @implNote Inter-process lock is unfair. - * * @see InterProcessReadWriteUpdateLock */ public interface InterProcessLock extends Lock { @@ -61,15 +60,15 @@ public interface InterProcessLock extends Lock { * Acquires the lock. If this lock (or a stronger-level lock, in the context of {@link * InterProcessReadWriteUpdateLock}) is already held by the current thread, this call returns * immediately. - * + *

    *

    If the lock is not available then the current thread enters a busy loop. After some * threshold time spent in a busy loop, the thread might be disabled for thread * scheduling purposes and lay dormant until the lock has been acquired. After some * implementation-defined time spent in waiting for the lock acquisition, * {@link InterProcessDeadLockException} is thrown. * - * @throws IllegalMonitorStateException if this method call observes illegal lock state, or some - * lock limitations reached (e. g. maximum read lock holders) + * @throws IllegalMonitorStateException if this method call observes illegal lock state, or some + * lock limitations reached (e. g. maximum read lock holders) * @throws InterProcessDeadLockException if fails to acquire a lock for some finite time */ @Override @@ -80,11 +79,11 @@ public interface InterProcessLock extends Lock { * the current thread is not interrupted, and this lock (or a stronger-level lock, in the * context of {@link InterProcessReadWriteUpdateLock}) is already held by the current thread, * this call returns immediately. - * + *

    *

    If the lock is not available then the current thread enters a busy loop, and after some * threshold time spend in a busy loop, the thread might be disabled for thread * scheduling purposes and lay dormant until one of three things happens: - * + *

    *

      *
    • The lock is acquired by the current thread, then {@code lockInterruptibly()} successfully * returns. @@ -95,9 +94,9 @@ public interface InterProcessLock extends Lock { * {@link InterProcessDeadLockException} is thrown. *
    * - * @throws InterruptedException if the current thread is interrupted while acquiring the lock - * @throws IllegalMonitorStateException if this method call observes illegal lock state, or some - * lock limitations reached (e. g. maximum read lock holders) + * @throws InterruptedException if the current thread is interrupted while acquiring the lock + * @throws IllegalMonitorStateException if this method call observes illegal lock state, or some + * lock limitations reached (e. g. maximum read lock holders) * @throws InterProcessDeadLockException if fails to acquire a lock for some finite time */ @Override @@ -106,12 +105,15 @@ public interface InterProcessLock extends Lock { /** * Acquires the lock only if it is free at the time of invocation, also if the lock is already * held by the current thread, this call immediately returns {@code true}. - * + *

    *

    Acquires the lock if it is available and returns immediately * with the value {@code true}. * If the lock is not available then this method will return * immediately with the value {@code false}. * + * @return {@code true} if the lock was acquired and {@code false} otherwise + * @throws IllegalMonitorStateException if this method call observes illegal lock state, or some + * lock limitations reached (e. g. maximum read lock holders) * @apiNote Example usage:

    {@code
          * try (ExternalMapQueryContext q = map.queryContext(key)) {
          *     if (q.updateLock().tryLock()) {
    @@ -135,10 +137,6 @@ public interface InterProcessLock extends Lock {
          *         }
          *     }
          * }}
    - * - * @return {@code true} if the lock was acquired and {@code false} otherwise - * @throws IllegalMonitorStateException if this method call observes illegal lock state, or some - * lock limitations reached (e. g. maximum read lock holders) */ @Override boolean tryLock(); diff --git a/src/main/java/net/openhft/chronicle/hash/locks/InterProcessReadWriteUpdateLock.java b/src/main/java/net/openhft/chronicle/hash/locks/InterProcessReadWriteUpdateLock.java index bef940988..c7a050a13 100644 --- a/src/main/java/net/openhft/chronicle/hash/locks/InterProcessReadWriteUpdateLock.java +++ b/src/main/java/net/openhft/chronicle/hash/locks/InterProcessReadWriteUpdateLock.java @@ -18,28 +18,26 @@ package net.openhft.chronicle.hash.locks; import net.openhft.chronicle.hash.ExternalHashQueryContext; -import net.openhft.chronicle.hash.HashQueryContext; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; /** * Tri-level lock, for efficient handling of concurrent accesses, that require different privileges. * For grasping multi-level lock concept and basic semantic principles, please read * {@link ReadWriteLock} documentation. - * + *

    *

    {@linkplain #readLock() Read lock} is for "readers". Multiple threads might hold read lock * simultaneously. Read lock held by any thread prevents write lock from being acquired. - * + *

    *

    {@linkplain #updateLock() Update lock} is for writers, who must access the resource * exclusively with each other, but write safely for concurrent readers. Only one thread could hold * update or write lock at the same time, but update lock doesn't prevent concurrent readers * to come. - * + *

    *

    {@linkplain #writeLock() Write lock} is for writers, which need total exclusiveness. When * write lock is held, nobody may access the resource at the same time. - * + *

    *

    Same as {@link InterProcessLock} itself, the {@code InterProcessReadWriteUpdateLock} as a * whole is saturating: when stronger-level lock is acquired, all weaker-level locks * are thought to be acquired as well ("saturated"). Unlocking a weaker-level lock "desaturates" @@ -55,15 +53,15 @@ import java.util.concurrent.locks.ReadWriteLock; * However, if you use {@code InterProcessReadWriteUpdateLock} as a part of {@link * ExternalHashQueryContext} query, you shouldn't keep this peculiarity in mind, because {@link * ExternalHashQueryContext#close()} handles unlocking for you. - * + *

    *

    Any downgrades ("desaturations") are possible, but only update -> write upgrade is allowed. * This is so to prevent dead locks: for example, imagine, that two threads came and acquired read * locks, and then both try to upgrade to write lock, blocking each other indefinitely. - * + *

    *

    This interface is based on this * work, might be useful to read to understand read-write-update lock idea, and how to use * this concept. - * + *

    *

    Same as {@code InterProcessLock}, instances of this interface are for single-thread use * only. Views of the same inter-process lock should be obtained in different threads independently. * See {@link InterProcessLock} documentation for rationalization of this. @@ -87,7 +85,7 @@ public interface InterProcessReadWriteUpdateLock extends ReadWriteLock { * Returns the update-level lock. Calling {@link InterProcessLock#lock() lock()} or other * locking methods ({@code tryLock()}, etc.) on this lock acquires the read lock, as well. * Calling {@link InterProcessLock#unlock() unlock()} on this lock also releases the write lock. - * + *

    *

    Any attempt to acquire this lock (including {@code tryLock()}, if the read lock is already * held by the current thread, but the update lock is not yet, is prevented by throwing {@link * IllegalMonitorStateException}. @@ -101,7 +99,7 @@ public interface InterProcessReadWriteUpdateLock extends ReadWriteLock { * Returns the write-level lock. Calling {@link InterProcessLock#lock() lock()} or other * locking methods ({@code tryLock()}, etc.) on this lock acquires the read and update locks, * as well. - * + *

    *

    Any attempt to acquire this lock (including {@code tryLock()}, if the read lock is already * held by the current thread, but the update and write locks are not yet, is prevented by * throwing {@link IllegalMonitorStateException}. diff --git a/src/main/java/net/openhft/chronicle/hash/replication/DefaultEventualConsistencyStrategy.java b/src/main/java/net/openhft/chronicle/hash/replication/DefaultEventualConsistencyStrategy.java index cf447d6b8..f9d28330d 100644 --- a/src/main/java/net/openhft/chronicle/hash/replication/DefaultEventualConsistencyStrategy.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/DefaultEventualConsistencyStrategy.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.replication; import net.openhft.chronicle.hash.ChronicleHash; -import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.hash.ChronicleHashBuilderPrivateAPI; import net.openhft.chronicle.map.replication.MapRemoteOperations; import net.openhft.chronicle.set.replication.SetRemoteOperations; @@ -31,20 +30,23 @@ import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyS * ChronicleHashBuilderPrivateAPI#replication(byte) replicated} {@link ChronicleHash}es: * last write wins. If two writes to a single entry occurred simultaneously on different * nodes, the write on the node with lower identifier wins. - * + * * @see MapRemoteOperations - * @see SetRemoteOperations + * @see SetRemoteOperations */ public final class DefaultEventualConsistencyStrategy { + private DefaultEventualConsistencyStrategy() { + } + /** * Returns the acceptance decision, should be made about the modification operation in the * given {@code context}, aiming to modify the given {@code entry}. This method doesn't do any * changes to {@code entry} nor {@code context} state. {@link MapRemoteOperations} and * {@link SetRemoteOperations} method implementations should guide the result of calling this * method to do something to actually apply the remote operation. - * - * @param entry the entry to be modified + * + * @param entry the entry to be modified * @param context the remote operation context * @return if the remote operation should be accepted or discarded */ @@ -81,8 +83,6 @@ public final class DefaultEventualConsistencyStrategy { // following condition also plays right (the update is discarded, due to it's redundancy). return originIdentifier == context.currentNodeIdentifier() ? DISCARD : ACCEPT; } - - private DefaultEventualConsistencyStrategy() {} /** * Decision, if {@link MapRemoteOperations remote modification operation} should be accepted diff --git a/src/main/java/net/openhft/chronicle/hash/replication/ReplicableEntry.java b/src/main/java/net/openhft/chronicle/hash/replication/ReplicableEntry.java index 00b89df29..e5d1743c0 100644 --- a/src/main/java/net/openhft/chronicle/hash/replication/ReplicableEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/ReplicableEntry.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.replication; import net.openhft.chronicle.hash.ChronicleHash; -import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.hash.ChronicleHashBuilderPrivateAPI; import net.openhft.chronicle.hash.HashAbsentEntry; import net.openhft.chronicle.hash.HashEntry; @@ -38,12 +37,12 @@ public interface ReplicableEntry { /** * The identifier, associated with this entry. Originally, and by default, this identifier means * the identifier of the {@code ChronicleHash} node on which this entry was updated last. - * + *

    *

    When the entry is replicated, this identifier comes to remote nodes as {@link * RemoteOperationContext#remoteIdentifier()}. - * + *

    *

    On {@code ChronicleHash} local operations with entries, like {@link ChronicleMap#put( - * Object, Object)}, this identifier is overwritten to the own {@code ChronicleHash} {@link + *Object, Object)}, this identifier is overwritten to the own {@code ChronicleHash} {@link * Replica#identifier()}. On remote operations, proxied through {@link MapRemoteOperations} or * {@link SetRemoteOperations}, you are free to overwrite this identifier to any value, using * {@link #updateOrigin(byte, long)} method. @@ -54,7 +53,7 @@ public interface ReplicableEntry { /** * The timestamp of the last update to this entry. - * + *

    *

    When the entry is replicated, this timestamp comes to remote nodes as {@link * RemoteOperationContext#remoteTimestamp()}. * @@ -69,7 +68,7 @@ public interface ReplicableEntry { * returns the given {@code newTimestamp} respectively. * * @param newIdentifier the new identifier for the entry - * @param newTimestamp the new timestamp for the entry + * @param newTimestamp the new timestamp for the entry */ void updateOrigin(byte newIdentifier, long newTimestamp); diff --git a/src/main/java/net/openhft/chronicle/hash/replication/TimeProvider.java b/src/main/java/net/openhft/chronicle/hash/replication/TimeProvider.java index 96aefa0a1..955d74064 100644 --- a/src/main/java/net/openhft/chronicle/hash/replication/TimeProvider.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/TimeProvider.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.replication; import net.openhft.chronicle.hash.ChronicleHash; -import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.hash.ChronicleHashBuilderPrivateAPI; import java.util.concurrent.TimeUnit; @@ -39,18 +38,18 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; */ public final class TimeProvider { - private TimeProvider() {} - private static final AtomicLong lastTimeHolder = new AtomicLong(); private static LongSupplier millisecondSupplier = System::currentTimeMillis; + private TimeProvider() { + } /** * Returns a non-decreasing number, assumed to be used as a "timestamp". - * + *

    *

    Approximate system time interval between two calls of this method is retrievable via * {@link #systemTimeIntervalBetween(long, long, TimeUnit)}, applied to the returned values * from those {@code currentTime()} calls. - * + *

    *

    Safe and scalable for concurrent use from multiple threads. * * @return the current timestamp @@ -70,10 +69,10 @@ public final class TimeProvider { * Returns system time interval (i. e. wall time interval) between two time values, taken using * {@link #currentTime()} method, with the highest possible precision, in the given time units. * - * @param earlierTime {@link #currentTime()} result, taken at some moment in the past (earlier) - * @param laterTime {@link #currentTime()} result, taken at some moment in the past, but later - * than {@code earlierTime} was taken ("later" means there is a happens-before relationship - * between the two subject {@code currentTime()} calls) + * @param earlierTime {@link #currentTime()} result, taken at some moment in the past (earlier) + * @param laterTime {@link #currentTime()} result, taken at some moment in the past, but later + * than {@code earlierTime} was taken ("later" means there is a happens-before relationship + * between the two subject {@code currentTime()} calls) * @param systemTimeIntervalUnit the time units to return system time interval in * @return wall time interval between the specified moments in the given time unit */ diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/BytesReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/BytesReader.java index 211fddba5..3bb59f62c 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/BytesReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/BytesReader.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.serialization; import net.openhft.chronicle.bytes.Bytes; -import net.openhft.chronicle.bytes.ReadBytesMarshallable; import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.map.ChronicleMapBuilder; import net.openhft.chronicle.wire.Marshallable; @@ -28,7 +27,7 @@ import org.jetbrains.annotations.Nullable; /** * Deserializer of objects from bytes, pairing {@link BytesWriter}, without accepting additional * information about serialized objects. - * + *

    *

    Read {@code * BytesWriter} and {@code BytesReader} and * custom @@ -49,11 +48,11 @@ public interface BytesReader extends Marshallable { * returned from this method back. If it is impossible for any reason, a new object should be * created and returned. The given {@code using} object could be {@code null}, in this case this * method, of cause, should create a new object. - * + *

    *

    This method should increment the position in the given {@code Bytes}, i. e. consume the * read bytes. {@code in} bytes shouldn't be written. * - * @param in the {@code Bytes} to read the object from + * @param in the {@code Bytes} to read the object from * @param using the object to read the deserialized data into, could be {@code null} * @return the object read from the bytes, either reused or newly created */ diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/BytesWriter.java b/src/main/java/net/openhft/chronicle/hash/serialization/BytesWriter.java index ece8a0d42..7ce3949dd 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/BytesWriter.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/BytesWriter.java @@ -18,7 +18,6 @@ package net.openhft.chronicle.hash.serialization; import net.openhft.chronicle.bytes.Bytes; -import net.openhft.chronicle.bytes.WriteBytesMarshallable; import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.map.ChronicleMapBuilder; import net.openhft.chronicle.wire.Marshallable; @@ -26,7 +25,7 @@ import org.jetbrains.annotations.NotNull; /** * Serializer of objects to bytes, pairing {@link BytesReader}. - * + *

    *

    Read {@code * BytesWriter} and {@code BytesReader} and * custom @@ -42,14 +41,14 @@ public interface BytesWriter extends Marshallable { /** * Serializes the given object to the given {@code out}. - * + *

    *

    Implementation of this method should increment the {@linkplain Bytes#writePosition() * position} of the given {@code out} by the number of bytes written. The given object should be * written into these range between the initial {@code bytes}' position and the position after * this method call returns. Bytes outside of this range shouldn't be written. Any bytes * shouldn't be read from {@code out}. * - * @param out the {@code Bytes} to write the given object to + * @param out the {@code Bytes} to write the given object to * @param toWrite the object to serialize */ void write(Bytes out, @NotNull T toWrite); diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/DataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/DataAccess.java index 0ee214efb..46a2dbdbb 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/DataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/DataAccess.java @@ -32,7 +32,7 @@ import java.nio.ByteBuffer; * that are already in fact sequences of bytes ({@code byte[]}, {@link ByteBuffer}, etc.) and * shouldn't be serialized, and allows to avoid extra data copying. Accessed bytes should be later * readable by some {@link BytesReader}. - * + *

    *

    Read {@link * DataAccess} and {@code SizedReader} and * custom @@ -59,7 +59,7 @@ public interface DataAccess extends StatefulCopyable>, Marshall * Clear references to the accessed object (provided in {@link #getData(Object)} method) in * caching fields of this {@code DataAccess} or the cached {@link Data} object, returned from * {@link #getData(Object)}. - * + *

    * {@code DataAccess} is cached itself in thread-local variables for {@link ChronicleHash} * instances, this method prevents leaking of accessed objects (they are not eligible for * garbage collection while there are some references). diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/ListMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/ListMarshaller.java index 30d298b2e..384c38782 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/ListMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/ListMarshaller.java @@ -31,11 +31,11 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe /** * Marshaller of {@code List}. Uses {@link ArrayList} as the list implementation to deserialize * into. - * + *

    *

    This marshaller supports multimap emulation on top of Chronicle Map, that is possible but * inefficient. See the * README section. - * + *

    *

    Usage:

    {@code
      * ChronicleMap> regNumbers = ChronicleMap
      *     .of(String.class, (Class>) (Class) List.class)
    @@ -45,7 +45,7 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe
      *     .entries(10_000)
      *     .create();
      * }
    - * + *

    *

    Look for pre-defined element marshallers in {@link * net.openhft.chronicle.hash.serialization.impl} package. This package is not included into * Javadocs, but present in Chronicle Map distribution. If there are no existing marshallers for @@ -58,12 +58,30 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe public final class ListMarshaller implements BytesReader>, BytesWriter>, StatefulCopyable> { + // Config fields + private BytesReader elementReader; + private BytesWriter elementWriter; + + /** + * Constructs a {@code ListMarshaller} with the given list elements' serializers. + *

    + *

    Use static factory {@link #of(BytesReader, BytesWriter)} instead of this constructor + * directly. + * + * @param elementReader list elements' reader + * @param elementWriter list elements' writer + */ + public ListMarshaller(BytesReader elementReader, BytesWriter elementWriter) { + this.elementReader = elementReader; + this.elementWriter = elementWriter; + } + /** * Returns a {@code ListMarshaller} which uses the given list elements' serializers. * * @param elementReader list elements' reader * @param elementWriter list elements' writer - * @param type of list elements + * @param type of list elements * @return a {@code ListMarshaller} which uses the given list elements' serializers */ public static ListMarshaller of( @@ -78,9 +96,10 @@ public final class ListMarshaller * .of(String.class,{@code (Class>)} ((Class) List.class)) * .valueMarshaller(ListMarshaller.of(IntegerMarshaller.INSTANCE)) * ...

  • + * * @param elementMarshaller list elements' marshaller - * @param type of list elements - * @param type of list elements' marshaller + * @param type of list elements + * @param type of list elements' marshaller * @return a {@code ListMarshaller} which uses the given list elements' marshaller */ public static & BytesWriter> ListMarshaller of( @@ -88,24 +107,6 @@ public final class ListMarshaller return of(elementMarshaller, elementMarshaller); } - // Config fields - private BytesReader elementReader; - private BytesWriter elementWriter; - - /** - * Constructs a {@code ListMarshaller} with the given list elements' serializers. - * - *

    Use static factory {@link #of(BytesReader, BytesWriter)} instead of this constructor - * directly. - * - * @param elementReader list elements' reader - * @param elementWriter list elements' writer - */ - public ListMarshaller(BytesReader elementReader, BytesWriter elementWriter) { - this.elementReader = elementReader; - this.elementWriter = elementWriter; - } - @NotNull @Override public List read(Bytes in, @Nullable List using) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/MapMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/MapMarshaller.java index 42c420369..8c38d864b 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/MapMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/MapMarshaller.java @@ -33,11 +33,11 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe /** * Marshaller of {@code Map}. Uses {@link HashMap} (hence default key objects' equality and * {@code hashCode()} as the map implementation to deserialize into. - * + *

    *

    This marshaller supports multimap emulation on top of Chronicle Map, that is possible but * inefficient. See the * README section. - * + *

    *

    Look for pre-defined key and value marshallers in {@link * net.openhft.chronicle.hash.serialization.impl} package. This package is not included into * Javadocs, but present in Chronicle Map distribution. If there are no existing marshallers for @@ -64,8 +64,8 @@ public final class MapMarshaller implements BytesReader>, BytesW /** * Constructs a {@code MapMarshaller} with the given map keys' and values' serializers. * - * @param keyReader map keys' reader - * @param keyWriter map keys' writer + * @param keyReader map keys' reader + * @param keyWriter map keys' writer * @param valueReader map values' reader * @param valueWriter map values' writer */ diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/SetMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/SetMarshaller.java index f08b2de1e..4e83619d5 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/SetMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/SetMarshaller.java @@ -33,11 +33,11 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe /** * Marshaller of {@code Set}. Uses {@link HashSet} (hence default element objects' equality and * {@code hashCode()}) as the set implementation to deserialize into. - * + *

    *

    This marshaller supports multimap emulation on top of Chronicle Map, that is possible but * inefficient. See the * README section. - * + *

    *

    Usage:

    {@code
      * SetMarshaller valueMarshaller = SetMarshaller.of(
      *     new StringBytesReader(), CharSequenceBytesWriter.INSTANCE);
    @@ -49,7 +49,7 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe
      *     .entries(10_000)
      *     .create();
      * }
    - * + *

    *

    Look for pre-defined element marshallers in {@link * net.openhft.chronicle.hash.serialization.impl} package. This package is not included into * Javadocs, but present in Chronicle Map distribution. If there are no existing marshallers for @@ -62,12 +62,34 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe public final class SetMarshaller implements BytesReader>, BytesWriter>, StatefulCopyable> { + // Config fields + private BytesReader elementReader; + private BytesWriter elementWriter; + /** + * Cache field + */ + private transient Deque orderedElements; + /** + * Constructs a {@code SetMarshaller} with the given set elements' serializers. + *

    + *

    Use static factory {@link #of(BytesReader, BytesWriter)} instead of this constructor + * directly. + * + * @param elementReader set elements' reader + * @param elementWriter set elements' writer + */ + public SetMarshaller(BytesReader elementReader, BytesWriter elementWriter) { + this.elementReader = elementReader; + this.elementWriter = elementWriter; + initTransients(); + } + /** * Returns a {@code SetMarshaller} which uses the given set elements' serializers. * * @param elementReader set elements' reader * @param elementWriter set elements' writer - * @param type of set elements + * @param type of set elements * @return a {@code SetMarshaller} which uses the given set elements' serializers */ public static SetMarshaller of( @@ -82,9 +104,10 @@ public final class SetMarshaller * .of(String.class,{@code (Class>)} ((Class) Set.class)) * .valueMarshaller(SetMarshaller.of(IntegerMarshaller.INSTANCE)) * ...

  • + * * @param elementMarshaller set elements' marshaller - * @param type of set elements - * @param type of set elements' marshaller + * @param type of set elements + * @param type of set elements' marshaller * @return a {@code SetMarshaller} which uses the given set elements' marshaller */ public static & BytesWriter> SetMarshaller of( @@ -92,28 +115,6 @@ public final class SetMarshaller return of(elementMarshaller, elementMarshaller); } - // Config fields - private BytesReader elementReader; - private BytesWriter elementWriter; - - /** Cache field */ - private transient Deque orderedElements; - - /** - * Constructs a {@code SetMarshaller} with the given set elements' serializers. - * - *

    Use static factory {@link #of(BytesReader, BytesWriter)} instead of this constructor - * directly. - * - * @param elementReader set elements' reader - * @param elementWriter set elements' writer - */ - public SetMarshaller(BytesReader elementReader, BytesWriter elementWriter) { - this.elementReader = elementReader; - this.elementWriter = elementWriter; - initTransients(); - } - private void initTransients() { orderedElements = new ArrayDeque<>(); } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/SizeMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/SizeMarshaller.java index 614d3910f..dd4e84fd9 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/SizeMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/SizeMarshaller.java @@ -32,7 +32,7 @@ import net.openhft.chronicle.wire.Marshallable; * works). Also, this interface allows to generalize storing constantly-sized and variable-sized * blocks of data. Constantly-sized don't require to store the size actually, the corresponding * {@link #constant} {@code SizeMarshaller} consumes 0 bytes. - * + *

    *

    Some {@code SizeMarshaller} implementations couldn't store the whole {@code long} range, for * example each {@link #constant} {@code SizeMarshaller} is able to "store" only a single specific * value (it's constant size). If the marshaller is fed with the size it is not able store, it could @@ -76,7 +76,7 @@ public interface SizeMarshaller extends Marshallable { * @param size the size to store * @return the number of bytes would be taken to store the given size * @throws IllegalArgumentException might be thrown, if the given size if not storable by this - * {@code SizeMarshaller} + * {@code SizeMarshaller} */ int storingLength(long size); @@ -119,10 +119,10 @@ public interface SizeMarshaller extends Marshallable { /** * Writes the given size into the streaming output. * - * @param out the {@code StreamingDataOutput} to write the size to + * @param out the {@code StreamingDataOutput} to write the size to * @param sizeToWrite the size to write * @throws IllegalArgumentException might be thrown, if the given size if not storable by this - * {@code SizeMarshaller} + * {@code SizeMarshaller} * @see #readSize(Bytes) */ void writeSize(Bytes out, long sizeToWrite); diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/SizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/SizedReader.java index 82e7f8116..044778e3a 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/SizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/SizedReader.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.Nullable; * Deserializer of objects from bytes, pairing {@link SizedWriter}, i. e. assuming the length * of the serialized form isn't written in the beginning of the serialized form itself, but managed * by {@link ChronicleHash} implementation and passed to the reading methods. - * + *

    *

    Read {@code * SizedWriter} and {@code SizedReader}, * {@link DataAccess} @@ -54,12 +54,12 @@ public interface SizedReader extends Marshallable { * is possible, this objects then returned from this method. If it is impossible for any reason, * a new object should be created and returned. The given {@code using} object could be {@code * null}, in this case read() should always create a new object. - * + *

    *

    This method should increment the position in the given {@code Bytes} by the given {@code * size}. * - * @param in the {@code Bytes} to read the object from - * @param size the size of the serialized form of the returned object + * @param in the {@code Bytes} to read the object from + * @param size the size of the serialized form of the returned object * @param using the object to read the deserialized data into, could be {@code null} * @return the object read from the bytes, either reused or newly created */ diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/SizedWriter.java b/src/main/java/net/openhft/chronicle/hash/serialization/SizedWriter.java index 035651983..4d8ab8da8 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/SizedWriter.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/SizedWriter.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull; * form of any object before actual serialization 2) doesn't include that length in the serialized * form itself, assuming it will be passed by the {@link ChronicleHash} into {@link * SizedReader#read} deserialization method. - * + *

    *

    Read {@code * SizedWriter} and {@code SizedReader} and * custom @@ -56,17 +56,17 @@ public interface SizedWriter extends Marshallable { /** * Serializes the given object to the given {@code out}, without writing the length of the * serialized form itself. - * + *

    *

    Implementation of this method should increment the {@linkplain Bytes#writePosition() * position} of the given {@code out} by {@link #size(Object) size(toWrite)}. The given object * should be written into these range between the initial {@code bytes}' position and the * position after this method call returns. * - * @param out the {@code Bytes} to write the given object to - * @param size the size, returned by {@link #size(Object)} for the given {@code toWrite} object. - * it is given, because size might be needed during serialization, and it's computation has - * non-constant complexity, i. e. if serializing a {@code CharSequence} using variable-length - * encoding like UTF-8. + * @param out the {@code Bytes} to write the given object to + * @param size the size, returned by {@link #size(Object)} for the given {@code toWrite} object. + * it is given, because size might be needed during serialization, and it's computation has + * non-constant complexity, i. e. if serializing a {@code CharSequence} using variable-length + * encoding like UTF-8. * @param toWrite the object to serialize * @see SizedReader#read(Bytes, long, Object) */ diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/StatefulCopyable.java b/src/main/java/net/openhft/chronicle/hash/serialization/StatefulCopyable.java index d796d1f11..297fbc151 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/StatefulCopyable.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/StatefulCopyable.java @@ -27,7 +27,7 @@ import net.openhft.chronicle.set.ChronicleSet; * {@link BytesReader}, {@link BytesWriter} or {@link DataAccess}), configured for {@link * ChronicleMap} or {@link ChronicleSet} in builder, should implement the {@code StatefulCopyable} * interface. - * + *

    *

    See * Understanding {@code StatefulCopyable} section in the Chronicle Map tutorial for more info * on how to implement and use this interface properly, and for examples. @@ -36,29 +36,13 @@ import net.openhft.chronicle.set.ChronicleSet; */ public interface StatefulCopyable> { - /** - * Creates a copy of this marshaller, with independent state. The current state itself shouldn't - * be copied (it could be "clear" in the copy), only "configuration" of the instance, on which - * {@code copy()} is called, should be inherited in the copy (e. g. the class of objects - * serialized). So, {@code copy()} should be transitive, i. e. {@code marshaller.copy()} and - * {@code marshaller.copy().copy()} should result to identical instances. - * - *

    The state of the instance on which {@code copy()} is called shouldn't be changed. - * - *

    If some marshaller is ought to implement {@code StatefulCopyable} interface (e. g. - * {@link DataAccess}) but is stateless actually, it could return {@code this} from this method. - * - * @return the copy if this marshaller with the same configuration, but independent state - */ - T copy(); - /** * Checks if {@code possiblyStatefulCopyable} implements {@code StatefulCopyable}, then returns * {@link #copy()} of it, otherwise returns the {@code possiblyStatefulCopyable} itself. * * @param possiblyStatefulCopyable the instance to {@code copy()} if it implements {@code - * StatefulCopyable}, or to return without modification - * @param the type of the passed instance + * StatefulCopyable}, or to return without modification + * @param the type of the passed instance * @return the copy of the passed instance with independent state, of the instance back, if it * doesn't implement {@code StatefulCopyable} */ @@ -69,4 +53,20 @@ public interface StatefulCopyable> { } return possiblyStatefulCopyable; } + + /** + * Creates a copy of this marshaller, with independent state. The current state itself shouldn't + * be copied (it could be "clear" in the copy), only "configuration" of the instance, on which + * {@code copy()} is called, should be inherited in the copy (e. g. the class of objects + * serialized). So, {@code copy()} should be transitive, i. e. {@code marshaller.copy()} and + * {@code marshaller.copy().copy()} should result to identical instances. + *

    + *

    The state of the instance on which {@code copy()} is called shouldn't be changed. + *

    + *

    If some marshaller is ought to implement {@code StatefulCopyable} interface (e. g. + * {@link DataAccess}) but is stateless actually, it could return {@code this} from this method. + * + * @return the copy if this marshaller with the same configuration, but independent state + */ + T copy(); } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java index d35938ef7..ec9c1e650 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java @@ -32,11 +32,14 @@ import static net.openhft.chronicle.hash.serialization.impl.DefaultElasticBytes. abstract class AbstractCharSequenceUtf8DataAccess extends AbstractData implements DataAccess, Data { - /** Cache field */ - private transient Bytes bytes; - - /** State field */ + /** + * State field + */ transient T cs; + /** + * Cache field + */ + private transient Bytes bytes; AbstractCharSequenceUtf8DataAccess(long bytesCapacity) { initTransients(bytesCapacity); diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BooleanMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BooleanMarshaller.java index b87f70c62..6579bfaec 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BooleanMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BooleanMarshaller.java @@ -30,7 +30,8 @@ public final class BooleanMarshaller SizedWriter, BytesWriter, EnumMarshallable { public static final BooleanMarshaller INSTANCE = new BooleanMarshaller(); - private BooleanMarshaller() {} + private BooleanMarshaller() { + } @Override public long size(@NotNull Boolean e) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArrayDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArrayDataAccess.java index 0b4f850f0..d87729325 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArrayDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArrayDataAccess.java @@ -29,10 +29,14 @@ import org.jetbrains.annotations.Nullable; public class ByteArrayDataAccess extends AbstractData implements DataAccess { - /** Cache field */ + /** + * Cache field + */ private transient HeapBytesStore bs; - /** State field */ + /** + * State field + */ private transient byte[] array; public ByteArrayDataAccess() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArraySizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArraySizedReader.java index 5517660c3..e71f81dc1 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArraySizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteArraySizedReader.java @@ -28,7 +28,8 @@ public final class ByteArraySizedReader public static final ByteArraySizedReader INSTANCE = new ByteArraySizedReader(); - private ByteArraySizedReader() {} + private ByteArraySizedReader() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteBufferSizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteBufferSizedReader.java index 57aed92bf..2ae61983b 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteBufferSizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteBufferSizedReader.java @@ -28,7 +28,8 @@ public final class ByteBufferSizedReader implements SizedReader, EnumMarshallable { public static final ByteBufferSizedReader INSTANCE = new ByteBufferSizedReader(); - private ByteBufferSizedReader() {} + private ByteBufferSizedReader() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteableDataAccess.java index 26eef9043..4e6d5f2c1 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ByteableDataAccess.java @@ -27,7 +27,9 @@ import org.jetbrains.annotations.Nullable; public class ByteableDataAccess extends InstanceCreatingMarshaller implements DataAccess, Data { - /** State field */ + /** + * State field + */ private transient T instance; public ByteableDataAccess(Class tClass) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesAsSizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesAsSizedReader.java index ff38b7745..ec1b69dca 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesAsSizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesAsSizedReader.java @@ -29,7 +29,9 @@ import org.jetbrains.annotations.Nullable; public class BytesAsSizedReader implements SizedReader, StatefulCopyable> { - /** Config field */ + /** + * Config field + */ private BytesReader reader; public BytesAsSizedReader(BytesReader reader) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java index e9347c330..40588c330 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java @@ -34,7 +34,9 @@ public class BytesMarshallableDataAccess private transient Bytes bytes; private transient VanillaBytes targetBytes; - /** State field */ + /** + * State field + */ private transient T instance; public BytesMarshallableDataAccess(Class tClass) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesReader.java index a051a91de..5a09bbdf6 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesReader.java @@ -22,14 +22,9 @@ import net.openhft.chronicle.hash.serialization.BytesReader; import net.openhft.chronicle.hash.serialization.ListMarshaller; import net.openhft.chronicle.hash.serialization.SetMarshaller; import net.openhft.chronicle.hash.serialization.StatefulCopyable; -import net.openhft.chronicle.wire.WireIn; -import net.openhft.chronicle.wire.WireOut; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.ObjectInputStream; - /** * {@link BytesReader} implementation for {@code CharSequence}. For the primary ChronicleMap's key * or value type {@link CharSequenceSizedReader} + {@link CharSequenceUtf8DataAccess} are more @@ -42,7 +37,8 @@ public final class CharSequenceBytesReader implements BytesReader, StatefulCopyable, EnumMarshallable { public static final CharSequenceBytesReader INSTANCE = new CharSequenceBytesReader(); - private CharSequenceBytesReader() {} + private CharSequenceBytesReader() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesWriter.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesWriter.java index cfb12d382..5aa94bd15 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesWriter.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceBytesWriter.java @@ -35,7 +35,8 @@ public final class CharSequenceBytesWriter implements BytesWriter, EnumMarshallable { public static final CharSequenceBytesWriter INSTANCE = new CharSequenceBytesWriter(); - private CharSequenceBytesWriter() {} + private CharSequenceBytesWriter() { + } @Override public void write(Bytes out, @NotNull CharSequence toWrite) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedReader.java index d6f8c2b2a..191502b6d 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedReader.java @@ -37,7 +37,8 @@ public class CharSequenceSizedReader implements SizedReader, * stateless */ @Deprecated - public CharSequenceSizedReader() {} + public CharSequenceSizedReader() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedWriter.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedWriter.java index 1cf042f1b..ed864e467 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedWriter.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/CharSequenceSizedWriter.java @@ -34,7 +34,8 @@ public final class CharSequenceSizedWriter implements SizedWriter, EnumMarshallable { public static final CharSequenceSizedWriter INSTANCE = new CharSequenceSizedWriter(); - private CharSequenceSizedWriter() {} + private CharSequenceSizedWriter() { + } @Override public long size(@NotNull CharSequence toWrite) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ConstantSizeMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ConstantSizeMarshaller.java index 0ce1faf8e..a53417829 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ConstantSizeMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ConstantSizeMarshaller.java @@ -25,7 +25,9 @@ import org.jetbrains.annotations.NotNull; public final class ConstantSizeMarshaller implements SizeMarshaller { - /** Config field */ + /** + * Config field + */ private long constantSize; public ConstantSizeMarshaller(long constantSize) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java index dc4e52684..db622c3d4 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java @@ -23,6 +23,9 @@ final class DefaultElasticBytes { static final int DEFAULT_BYTES_CAPACITY = 32; + private DefaultElasticBytes() { + } + static Bytes allocateDefaultElasticBytes(long bytesCapacity) { if (bytesCapacity <= Bytes.MAX_BYTE_BUFFER_CAPACITY) { return Bytes.elasticHeapByteBuffer((int) bytesCapacity); @@ -30,6 +33,4 @@ final class DefaultElasticBytes { return Bytes.allocateElasticDirect(bytesCapacity); } } - - private DefaultElasticBytes() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleDataAccess.java index 870b57117..54bd62ded 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleDataAccess.java @@ -36,7 +36,9 @@ public final class DoubleDataAccess extends AbstractData private transient boolean bsInit; private transient BytesStore bs; - /** State field */ + /** + * State field + */ private transient Double instance; public DoubleDataAccess() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleMarshaller.java index 63206df1c..74375bf0d 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DoubleMarshaller.java @@ -32,7 +32,8 @@ public final class DoubleMarshaller SizedWriter, BytesWriter, EnumMarshallable { public static final DoubleMarshaller INSTANCE = new DoubleMarshaller(); - private DoubleMarshaller() {} + private DoubleMarshaller() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java index 4989277d0..9b8d0ce3a 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java @@ -38,10 +38,14 @@ public class ExternalBytesMarshallableDataAccess extends InstanceCreatingMars private SizedReader reader; private BytesWriter writer; - /** Cache field */ + /** + * Cache field + */ private transient Bytes bytes; - /** State field */ + /** + * State field + */ private transient T instance; public ExternalBytesMarshallableDataAccess( diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalizableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalizableDataAccess.java index b03d14cf2..a3be4b8bc 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalizableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalizableDataAccess.java @@ -33,7 +33,9 @@ import static net.openhft.chronicle.hash.serialization.impl.DefaultElasticBytes. public class ExternalizableDataAccess extends SerializableDataAccess { - /** Config field */ + /** + * Config field + */ private Class tClass; public ExternalizableDataAccess(Class tClass) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess.java index 63bc4b4a9..73043e3c2 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess.java @@ -44,7 +44,9 @@ public final class IntegerDataAccess extends AbstractData private transient boolean bsInit; private transient BytesStore bs; - /** State field */ + /** + * State field + */ private transient Integer instance; public IntegerDataAccess() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess_3_13.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess_3_13.java index bacede19e..8b80af505 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess_3_13.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerDataAccess_3_13.java @@ -35,7 +35,9 @@ public final class IntegerDataAccess_3_13 extends AbstractData private transient boolean bsInit; private transient BytesStore bs; - /** State field */ + /** + * State field + */ private transient Integer instance; public IntegerDataAccess_3_13() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerMarshaller.java index 282720d97..0e972e9b5 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/IntegerMarshaller.java @@ -32,7 +32,8 @@ public final class IntegerMarshaller SizedWriter, BytesWriter, EnumMarshallable { public static final IntegerMarshaller INSTANCE = new IntegerMarshaller(); - private IntegerMarshaller() {} + private IntegerMarshaller() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongDataAccess.java index b81297b35..0c2c2fddb 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongDataAccess.java @@ -36,7 +36,9 @@ public final class LongDataAccess extends AbstractData private transient boolean bsInit; private transient BytesStore bs; - /** State field */ + /** + * State field + */ private transient Long instance; public LongDataAccess() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongMarshaller.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongMarshaller.java index 701be3d32..7f2bdaaa4 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongMarshaller.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/LongMarshaller.java @@ -32,7 +32,8 @@ public final class LongMarshaller SizedWriter, BytesWriter, EnumMarshallable { public static final LongMarshaller INSTANCE = new LongMarshaller(); - private LongMarshaller() {} + private LongMarshaller() { + } @Override public long size(@NotNull Long toWrite) { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java index 7ca2b7763..9173d7ce3 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java @@ -39,7 +39,9 @@ public class SerializableDataAccess extends AbstractData transient OutputStream out; transient InputStream in; - /** State field */ + /** + * State field + */ transient T instance; public SerializableDataAccess() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java index 2dbc88378..f479e5d84 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java @@ -43,7 +43,9 @@ public class SizedMarshallableDataAccess extends InstanceCreatingMarshaller { public static final StopBitSizeMarshaller INSTANCE = new StopBitSizeMarshaller(); - - private StopBitSizeMarshaller() {} - private static final long MIN_ENCODABLE_SIZE = Long.MIN_VALUE; private static final long MAX_ENCODABLE_SIZE = Long.MAX_VALUE; + private StopBitSizeMarshaller() { + } private static void rangeChecks(long minSize, long maxSize) { if (minSize > maxSize) diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBuilderSizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBuilderSizedReader.java index ee1ab8023..b20871e6a 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBuilderSizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBuilderSizedReader.java @@ -27,7 +27,8 @@ public final class StringBuilderSizedReader implements SizedReader, EnumMarshallable { public static final StringBuilderSizedReader INSTANCE = new StringBuilderSizedReader(); - private StringBuilderSizedReader() {} + private StringBuilderSizedReader() { + } @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBytesReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBytesReader.java index 0f1f20357..37f861f17 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBytesReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringBytesReader.java @@ -37,7 +37,9 @@ import org.jetbrains.annotations.Nullable; */ public class StringBytesReader implements BytesReader, StatefulCopyable { - /** Cache field */ + /** + * Cache field + */ private transient StringBuilder sb; public StringBytesReader() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringSizedReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringSizedReader.java index bc6fadf0b..deb969b7d 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringSizedReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/StringSizedReader.java @@ -28,7 +28,9 @@ import org.jetbrains.annotations.Nullable; public class StringSizedReader implements SizedReader, StatefulCopyable { - /** Cache field */ + /** + * Cache field + */ private transient StringBuilder sb; public StringSizedReader() { diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueDataAccess.java index 0e48a76d6..9f4126cbc 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueDataAccess.java @@ -33,7 +33,9 @@ import java.nio.ByteBuffer; public class ValueDataAccess extends AbstractData implements DataAccess { - /** Config field */ + /** + * Config field + */ private Class valueType; // Cache fields @@ -42,7 +44,9 @@ public class ValueDataAccess extends AbstractData implements DataAccess private transient Byteable nativeInstance; private transient Copyable nativeInstanceAsCopyable; - /** State field */ + /** + * State field + */ private transient Byteable instance; public ValueDataAccess(Class valueType) { @@ -50,7 +54,9 @@ public class ValueDataAccess extends AbstractData implements DataAccess initTransients(); } - /** Returns the interface of values serialized. */ + /** + * Returns the interface of values serialized. + */ protected Class valueType() { return valueType; } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueReader.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueReader.java index 8db46cc0e..aed8e6a2f 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueReader.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ValueReader.java @@ -29,13 +29,12 @@ import net.openhft.chronicle.wire.WireOut; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.ObjectInputStream; - public class ValueReader implements SizedReader, BytesReader, StatefulCopyable> { - /** Config field */ + /** + * Config field + */ private Class valueType; // Cache fields @@ -48,7 +47,9 @@ public class ValueReader initTransients(); } - /** Returns the interface of values deserialized. */ + /** + * Returns the interface of values deserialized. + */ protected Class valueType() { return valueType; } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/WrongXxHash.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/WrongXxHash.java index 879844cb0..2f1cfa864 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/WrongXxHash.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/WrongXxHash.java @@ -29,6 +29,9 @@ public final class WrongXxHash { private static final long P3 = 1609587929392839161L; private static final long P5 = 2870177450012600261L; + private WrongXxHash() { + } + public static long hashInt(int input) { long hash = P5 + 4; // Preserve old, wrong behaviour. In the correct version, input is widened to long as @@ -46,6 +49,4 @@ public final class WrongXxHash { hash ^= hash >>> 32; return hash; } - - private WrongXxHash() {} } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/package-info.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/package-info.java index 3b03851da..d28515fb1 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/package-info.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/package-info.java @@ -22,17 +22,17 @@ * net.openhft.chronicle.hash.serialization.impl.SerializationBuilder} and it's use in {@link * net.openhft.chronicle.map.ChronicleMapBuilder}. That is why these classes are put into the * separate package (this package) and excluded from the generated Javadocs, to reduce noise. - * + *

    *

    The remaining 5% of cases when these classes might be useful in the user code -- overriding * with different {@link * net.openhft.chronicle.hash.serialization.impl.InstanceCreatingMarshaller#createInstance()} logic, * when the default strategy (call of the default constructor) doesn't work. - * + *

    *

    Another remaining 5% of cases: configuration of complex marshallers with sub-marshallers, see * {@link net.openhft.chronicle.hash.serialization.ListMarshaller}, {@link * net.openhft.chronicle.hash.serialization.SetMarshaller} and {@link * net.openhft.chronicle.hash.serialization.MapMarshaller} for some examples. - * + *

    *

    Classes in this package are undocumented and not guaranteed to stay compatible between * Chronicle Map versions; refer to the source code and use on your own risk. */ diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/package-info.java b/src/main/java/net/openhft/chronicle/hash/serialization/package-info.java index 5238f7742..3b6a50bb0 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/package-info.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/package-info.java @@ -20,10 +20,10 @@ * net.openhft.chronicle.bytes.Bytes} or {@link net.openhft.chronicle.bytes.BytesStore}, used by * Chronicle Map to store objects off-heap, and read them back from off-heap memory to on-heap * objects. - * + *

    *

    Read Custom serializers * section in the Chronicle Map tutorial for more information. - * + *

    *

    Reading methods in the interfaces in this package could use {@link * net.openhft.chronicle.bytes.StreamingDataInput} as the "input" parameter type and {@link * net.openhft.chronicle.bytes.StreamingDataOutput} as the "output" parameter type, but always use diff --git a/src/main/java/net/openhft/chronicle/map/AbstractChronicleMap.java b/src/main/java/net/openhft/chronicle/map/AbstractChronicleMap.java index b4853092b..9edae7fe7 100644 --- a/src/main/java/net/openhft/chronicle/map/AbstractChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/AbstractChronicleMap.java @@ -33,6 +33,16 @@ import static net.openhft.chronicle.hash.impl.util.Objects.requireNonNull; interface AbstractChronicleMap extends ChronicleMap { + // TODO quick and dirty. Think about how generic guava/koloboke equivalence interface could be + // used. See also BytesInterop.equivalent() and hash(). + static int hashCode(Object obj) { + if (!(obj instanceof CharSequence)) { + return obj.hashCode(); + } else { + return CharSequences.hash((CharSequence) obj); + } + } + @Override default R getMapped(K key, @NotNull SerializableFunction function) { requireNonNull(function); @@ -84,7 +94,7 @@ interface AbstractChronicleMap extends ChronicleMap { @Override public Iterator iterator() { return new Iterator() { - private Iterator> i = entrySet().iterator(); + private Iterator> i = entrySet().iterator(); @Override public boolean hasNext() { @@ -170,7 +180,7 @@ interface AbstractChronicleMap extends ChronicleMap { if (!(o instanceof Map)) return false; - Map m = (Map) o; + Map m = (Map) o; if ((m instanceof ChronicleMap ? ((ChronicleMap) m).longSize() : m.size()) != longSize()) return false; @@ -201,16 +211,6 @@ interface AbstractChronicleMap extends ChronicleMap { return h[0]; } - // TODO quick and dirty. Think about how generic guava/koloboke equivalence interface could be - // used. See also BytesInterop.equivalent() and hash(). - static int hashCode(Object obj) { - if (!(obj instanceof CharSequence)) { - return obj.hashCode(); - } else { - return CharSequences.hash((CharSequence) obj); - } - } - default String mapToString() { if (isEmpty()) return "{}"; diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleHashCorruptionImpl.java b/src/main/java/net/openhft/chronicle/map/ChronicleHashCorruptionImpl.java index ee00c3385..b7b4351df 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleHashCorruptionImpl.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleHashCorruptionImpl.java @@ -24,6 +24,11 @@ import java.util.function.Supplier; public class ChronicleHashCorruptionImpl implements ChronicleHashCorruption { + private int segmentIndex; + private Supplier messageSupplier; + private Throwable exception; + private String message; + public static void report( ChronicleHashCorruption.Listener corruptionListener, ChronicleHashCorruptionImpl corruption, int segmentIndex, @@ -44,11 +49,6 @@ public class ChronicleHashCorruptionImpl implements ChronicleHashCorruption { return MessageFormatter.arrayFormat(message, args).getMessage(); } - private int segmentIndex; - private Supplier messageSupplier; - private Throwable exception; - private String message; - private void set(int segmentIndex, Supplier messageSupplier, Throwable exception) { this.segmentIndex = segmentIndex; this.messageSupplier = messageSupplier; diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ChronicleMap.java index 0967737bd..3c3a2ca83 100755 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMap.java @@ -24,25 +24,28 @@ import net.openhft.chronicle.hash.serialization.SizedReader; import net.openhft.chronicle.hash.serialization.SizedWriter; import org.jetbrains.annotations.NotNull; -import java.io.*; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.Serializable; import java.util.Map; import java.util.concurrent.ConcurrentMap; /** * {@code ChronicleMap} provides concurrent access to a Chronicle Map key-value store from a * JVM process. - * + *

    *

    For information on

    • how to construct a {@code ChronicleMap}
    • {@code * ChronicleMap} flavors and properties
    • available configurations
    see {@link * ChronicleMapBuilder} documentation. - * + *

    *

    Functionally this interface defines some methods supporting garbage-free off-heap programming: * {@link #getUsing(Object, Object)}, {@link #acquireUsing(Object, Object)}. - * + *

    *

    Roughly speaking, {@code ChronicleMap} compares keys and values by their binary serialized * form, that shouldn't necessary be the same equality relation as defined by built-in {@link * Object#equals(Object)} method, which is prescribed by general {@link Map} contract. - * + *

    *

    Note that {@code ChronicleMap} extends {@link Closeable}, don't forget to {@linkplain #close() * close} map when it is no longer needed. * @@ -59,10 +62,10 @@ public interface ChronicleMap extends ConcurrentMap, /** * Delegates to {@link ChronicleMapBuilder#of(Class, Class)} for convenience. * - * @param keyClass class of the key type of the Chronicle Map to create + * @param keyClass class of the key type of the Chronicle Map to create * @param valueClass class of the value type of the Chronicle Map to create - * @param the key type of the Chronicle Map to create - * @param the value type of the Chronicle Map to create + * @param the key type of the Chronicle Map to create + * @param the value type of the Chronicle Map to create * @return a new {@code ChronicleMapBuilder} for the given key and value classes */ static ChronicleMapBuilder of(Class keyClass, Class valueClass) { @@ -72,7 +75,7 @@ public interface ChronicleMap extends ConcurrentMap, /** * Returns the value to which the specified key is mapped, or {@code null} if this map contains * no mapping for the key. - * + *

    *

    If the value class allows reusing, consider {@link #getUsing(Object, Object)} method * instead of this to reduce garbage creation. Read the section about usage @@ -89,13 +92,13 @@ public interface ChronicleMap extends ConcurrentMap, /** * Returns the value to which the specified key is mapped, read to the provided {@code value} * object, if possible, or returns {@code null}, if this map contains no mapping for the key. - * + *

    *

    If the specified key is present in the map, the value data is read to the provided {@code * value} object via value reader's {@link SizedReader#read(net.openhft.chronicle.bytes.Bytes, long, Object) * read(StreamingDataInput, size, value)} method. If the value deserializer is able to reuse the * given {@code value} object, calling this method instead of {@link #get(Object)} could help to * reduce garbage creation. - * + *

    *

    The provided {@code value} object is allowed to be {@code null}, in this case {@code * map.getUsing(key, null)} call is semantically equivalent to simple {@code map.get(key)} * call. @@ -112,17 +115,17 @@ public interface ChronicleMap extends ConcurrentMap, /** * Acquire a value for a key, creating if absent. - * + *

    *

    If the specified key is absent in the map, {@linkplain * ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider) default value provider} is * called. Then this object is put to this map for the specified key. - * + *

    *

    Then, either if the key was initially absent in the map or already present, the value is * deserialized just as during {@link #getUsing(Object, Object) getUsing(key, usingValue)} call, * passed the same {@code key} and {@code usingValue} as into this method call. This means, as * in {@link #getUsing}, {@code usingValue} could safely be {@code null}, in this case a new * value instance is created to deserialize the data. - * + *

    *

    In code, {@code acquireUsing} is specified as : *

    {@code
          * V acquireUsing(K key, V usingValue) {
    @@ -130,11 +133,11 @@ public interface ChronicleMap extends ConcurrentMap,
          *         put(key, defaultValue(key));
          *     return getUsing(key, usingValue);
          * }}
    - * - * + *

    + *

    *

    Where {@code defaultValue(key)} returns {@link * ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider) defaultValueProvider}. - * + *

    *

    If the {@code ChronicleMap} is off-heap updatable, i. e. created via {@link * ChronicleMapBuilder} builder (values are {@link Byteable}), there is one more option of what * to do if the key is absent in the map. By default, value bytes are just zeroed out, no diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index 1f087d2d7..210750dcd 100755 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -86,29 +86,29 @@ import static net.openhft.chronicle.map.VanillaChronicleMap.alignAddr; * .of(Key.class, Value.class) * .entries(..) * // ... other configurations - * + *

    * ChronicleMap map1 = builder.create(); * ChronicleMap map2 = builder.create();} * i. e. created {@code ChronicleMap} instances don't depend on 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 ChronicleMap} implementations with completely different properties. - * + *

    *

    In addition to the key and value types, you must 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. - * + *

    *

    If you key or value type is not constantly sized and known to {@code ChronicleHashBuilder}, i. * e. it is not a boxed primitive, {@linkplain net.openhft.chronicle.values.Values value interface}, * or {@link Byteable}, you must provide the {@code ChronicleHashBuilder} with some * information about you keys or values: if they are constantly-sized, call {@link * #constantKeySizeBySample(Object)}, otherwise {@link #averageKey(Object)} or {@link * #averageKeySize(double)} method, and accordingly for values. - * + *

    *

    * There are some JVM-level configurations, which are not stored in the ChronicleMap's persistence * file (or the other way to say this: they are not parts of - *

  • {@link #name(String)}
  • - *
  • {@link #putReturnsNull(boolean)}
  • - *
  • {@link #removeReturnsNull(boolean)}
  • - *
  • {@link #entryOperations(MapEntryOperations)}
  • - *
  • {@link #mapMethods(MapMethods)}
  • - *
  • {@link #defaultValueProvider(DefaultValueProvider)}
  • + *
  • {@link #name(String)}
  • + *
  • {@link #putReturnsNull(boolean)}
  • + *
  • {@link #removeReturnsNull(boolean)}
  • + *
  • {@link #entryOperations(MapEntryOperations)}
  • + *
  • {@link #mapMethods(MapMethods)}
  • + *
  • {@link #defaultValueProvider(DefaultValueProvider)}
  • *
* * @param key type of the maps, produced by this builder @@ -143,7 +143,7 @@ public final class ChronicleMapBuilder implements * to store all segment indexes -- so it could be current JVM max array size, * not Integer.MAX_VALUE (which is an obvious limitation, as many APIs and internals use int * type for representing segment index). - * + *

* Anyway, unlikely anyone ever need more than 1 billion segments. */ private static final int MAX_SEGMENTS = (1 << 30); @@ -153,7 +153,6 @@ public final class ChronicleMapBuilder implements private static final double UNDEFINED_DOUBLE_CONFIG = Double.NaN; private static final ConcurrentHashMap fileLockingControl = new ConcurrentHashMap<>(128); - private static int MAX_BOOTSTRAPPING_HEADER_SIZE = (int) MemoryUnit.KILOBYTES.toBytes(16); private static final Logger chronicleMapLogger = LoggerFactory.getLogger(ChronicleMap.class); private static final ChronicleHashCorruption.Listener defaultChronicleMapCorruptionListener = corruption -> { @@ -163,8 +162,7 @@ public final class ChronicleMapBuilder implements chronicleMapLogger.error(corruption.message()); } }; - - private String name; + private static int MAX_BOOTSTRAPPING_HEADER_SIZE = (int) MemoryUnit.KILOBYTES.toBytes(16); SerializationBuilder keyBuilder; SerializationBuilder valueBuilder; K averageKey; @@ -178,7 +176,6 @@ public final class ChronicleMapBuilder implements long cleanupTimeout = 1; TimeUnit cleanupTimeoutUnit = TimeUnit.MINUTES; boolean cleanupRemovedEntries = true; - ////////////////////////////// // Configuration fields DefaultValueProvider defaultValueProvider = DefaultSpi.defaultValueProvider(); @@ -186,6 +183,7 @@ public final class ChronicleMapBuilder implements MapMethods methods = DefaultSpi.mapMethods(); MapEntryOperations entryOperations = mapEntryOperations(); MapRemoteOperations remoteOperations = mapRemoteOperations(); + private String name; // not final because of cloning private ChronicleMapBuilderPrivateAPI privateAPI = new ChronicleMapBuilderPrivateAPI<>(this); @@ -422,6 +420,52 @@ public final class ChronicleMapBuilder implements writeFully(fileChannel, SIZE_WORD_OFFSET, headerBuffer); } + /** + * @return ByteBuffer, in [position, limit) range the self bootstrapping header is read + */ + private static ByteBuffer readSelfBootstrappingHeader( + File file, RandomAccessFile raf, int headerSize, boolean recover, + ChronicleHashCorruption.Listener corruptionListener, + ChronicleHashCorruptionImpl corruption) throws IOException { + if (raf.length() < headerSize + SELF_BOOTSTRAPPING_HEADER_OFFSET) { + throw throwRecoveryOrReturnIOException(file, + "The file is shorter than the header size: " + headerSize + + ", file size: " + raf.length(), recover); + } + FileChannel fileChannel = raf.getChannel(); + ByteBuffer headerBuffer = ByteBuffer.allocate( + SELF_BOOTSTRAPPING_HEADER_OFFSET + headerSize); + headerBuffer.order(LITTLE_ENDIAN); + readFully(fileChannel, 0, headerBuffer); + if (headerBuffer.remaining() > 0) { + throw throwRecoveryOrReturnIOException(file, "Unable to read the header fully, " + + headerBuffer.remaining() + " is remaining to read, likely the file was " + + "truncated", recover); + } + int sizeWord = headerBuffer.getInt(SIZE_WORD_OFFSET); + if (!SizePrefixedBlob.isReady(sizeWord)) { + if (recover) { + report(corruptionListener, corruption, -1, () -> + format("file={}: size-prefixed blob readiness bit is set to NOT_COMPLETE", + file) + ); + // the bit will be overwritten to READY in the end of recovery procedure, so nothing + // to fix right here + } else { + throw new IOException("file=" + file + ": sizeWord is not ready: " + sizeWord); + } + } + headerBuffer.position(SELF_BOOTSTRAPPING_HEADER_OFFSET); + return headerBuffer; + } + + private static boolean checkSumSelfBootstrappingHeader( + ByteBuffer headerBuffer, int headerSize) { + long checkSum = headerChecksum(headerBuffer, headerSize); + long storedChecksum = headerBuffer.getLong(HEADER_OFFSET); + return storedChecksum == checkSum; + } + @Override public ChronicleMapBuilder clone() { try { @@ -462,7 +506,7 @@ public final class ChronicleMapBuilder implements /** * {@inheritDoc} - * + *

*

Example: if keys in your map(s) are English words in {@link String} form, average English * word length is 5.1, configure average key size of 6:

{@code
      * ChronicleMap wordFrequencies = ChronicleMapBuilder
@@ -474,7 +518,7 @@ public final class ChronicleMapBuilder implements
      * encoded (and each character takes 2 bytes on-heap), because default off-heap {@link String}
      * encoding is UTF-8 in {@code ChronicleMap}.)
      *
-     * @param averageKeySize  the average size of the key
+     * @param averageKeySize the average size of the key
      * @throws IllegalStateException    {@inheritDoc}
      * @throws IllegalArgumentException {@inheritDoc}
      * @see #averageKey(Object)
@@ -515,7 +559,7 @@ public final class ChronicleMapBuilder implements
 
     /**
      * {@inheritDoc}
-     *
+     * 

*

For example, if your keys are Git commit hashes:

{@code
      * Map gitCommitMessagesByHash =
      *     ChronicleMapBuilder.of(byte[].class, String.class)
@@ -545,17 +589,17 @@ public final class ChronicleMapBuilder implements
      * created by this builder. However, in many cases {@link #averageValue(Object)} might be easier
      * to use and more reliable. If value size is always the same, call {@link
      * #constantValueSizeBySample(Object)} method instead of this one.
-     *
+     * 

*

{@code ChronicleHashBuilder} implementation heuristically chooses {@linkplain * #actualChunkSize(int) the actual chunk size} based on this configuration and the key size, * that, however, might result to quite high internal fragmentation, i. e. losses because only * integral number of chunks could be allocated for the entry. If you want to avoid this, you * should manually configure the actual chunk size in addition to this average value size * configuration, which is anyway needed. - * + *

*

If values are of 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. - * + *

*

Calling this method clears any previous {@link #constantValueSizeBySample(Object)} and * {@link #averageValue(Object)} configurations. * @@ -585,17 +629,17 @@ public final class ChronicleMapBuilder implements * #averageValueSize(double)} might be easier to use, than constructing the "average value". * If value size is always the same, call {@link #constantValueSizeBySample(Object)} method * instead of this one. - * + *

*

{@code ChronicleHashBuilder} implementation heuristically chooses {@linkplain * #actualChunkSize(int) the actual chunk size} based on this configuration and the key size, * that, however, might result to quite high internal fragmentation, i. e. losses because only * integral number of chunks could be allocated for the entry. If you want to avoid this, you * should manually configure the actual chunk size in addition to this average value size * configuration, which is anyway needed. - * + *

*

If values are of 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. - * + *

*

Calling this method clears any previous {@link #constantValueSizeBySample(Object)} * and {@link #averageValueSize(double)} configurations. * @@ -621,13 +665,13 @@ public final class ChronicleMapBuilder implements * 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 value size varies, method {@link #averageValue(Object)} or {@link * #averageValueSize(double)} should be called instead of this one. - * + *

*

Calling this method clears any previous {@link #averageValue(Object)} and * {@link #averageValueSize(double)} configurations. * @@ -666,7 +710,7 @@ public final class ChronicleMapBuilder implements * {@inheritDoc} * * @throws IllegalStateException is sizes of both keys and values of maps created by this - * builder are constant, hence chunk size shouldn't be configured by user + * builder are constant, hence chunk size shouldn't be configured by user * @see #entryAndValueOffsetAlignment(int) * @see #entries(long) * @see #maxChunksPerEntry(int) @@ -849,14 +893,14 @@ public final class ChronicleMapBuilder implements * Configures alignment of address in memory of entries and independently of address in memory * of values within entries ((i. e. final addresses in native memory are multiples of the given * alignment) for 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. - * + *

*

If values couldn't reference off-heap memory (i. e. it is not {@link Byteable} or a value * interface), alignment configuration makes no sense. - * + *

*

Default is {@link ValueModel#recommendedOffsetAlignment()} if the value type is a value * interface, otherwise 1 (that is effectively no alignment) or chosen heuristically (configure * explicitly for being sure and to compare performance in your case). @@ -1155,15 +1199,15 @@ public final class ChronicleMapBuilder implements * Configures if the maps created by this {@code ChronicleMapBuilder} 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 simple in-process, on-heap implementations like * {@link HashMap}. But an off-heap collection has to create a new object and deserialize * the data from off-heap memory. A collection hiding remote queries over the network should * send the value back in addition to that. It's expensive for something you probably don't use. - * + *

*

This is a JVM-level configuration. - * + *

*

By default, {@code ChronicleMap} conforms the general {@code Map} contract and returns the * previous mapped value on {@code put()} calls. * @@ -1186,15 +1230,15 @@ public final class ChronicleMapBuilder implements * Configures if the maps created by this {@code ChronicleMapBuilder} 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 simple in-process, on-heap implementations like {@link * HashMap}. But an off-heap collection has to create a new object and deserialize the data * from off-heap memory. A collection hiding remote queries over the network should send * the value back in addition to that. It's expensive for something you probably don't use. - * + *

*

This is a JVM-level configuration. - * + *

*

By default, {@code ChronicleMap} conforms the general {@code Map} contract and returns the * mapped value on {@code remove()} calls. * @@ -1318,7 +1362,7 @@ public final class ChronicleMapBuilder implements @Override public & SizedWriter> - ChronicleMapBuilder keyMarshaller(@NotNull M sizedMarshaller) { + ChronicleMapBuilder keyMarshaller(@NotNull M sizedMarshaller) { return keyMarshallers(sizedMarshaller, sizedMarshaller); } @@ -1332,7 +1376,7 @@ public final class ChronicleMapBuilder implements @Override public & BytesWriter> - ChronicleMapBuilder keyMarshaller(@NotNull M marshaller) { + ChronicleMapBuilder keyMarshaller(@NotNull M marshaller) { return keyMarshallers(marshaller, marshaller); } @@ -1357,10 +1401,14 @@ public final class ChronicleMapBuilder implements boolean checksumEntries() { switch (checksumEntries) { - case NO: return false; - case YES: return true; - case IF_PERSISTED: return persisted; - default: throw new AssertionError(); + case NO: + return false; + case YES: + return true; + case IF_PERSISTED: + return persisted; + default: + throw new AssertionError(); } } @@ -1372,7 +1420,7 @@ public final class ChronicleMapBuilder implements * Configures the {@code DataAccess} and {@code SizedReader} used to serialize and deserialize * values to and from off-heap memory in maps, created by this builder. * - * @param valueReader the new bytes → value object reader strategy + * @param valueReader the new bytes → value object reader strategy * @param valueDataAccess the new strategy of accessing the values' bytes for writing * @return this builder back * @see #valueMarshallers(SizedReader, SizedWriter) @@ -1442,7 +1490,7 @@ public final class ChronicleMapBuilder implements /** * Configures the marshaller used to serialize actual value sizes to off-heap memory in maps, * created by this builder. - * + *

*

Default value size marshaller is so-called "stop bit encoding" marshalling, unless {@link * #constantValueSizeBySample(Object)} or the builder statically knows the value size is * constant -- special constant size marshalling is used by default in these cases. @@ -1461,7 +1509,7 @@ public final class ChronicleMapBuilder implements /** * Specifies the function to obtain a value for the key during {@link ChronicleMap#acquireUsing * acquireUsing()} calls, if the key is absent in the map, created by this builder. - * + *

*

This is a JVM-level configuration. * * @param defaultValueProvider the strategy to obtain a default value by the absent key @@ -1677,52 +1725,6 @@ public final class ChronicleMapBuilder implements } } - /** - * @return ByteBuffer, in [position, limit) range the self bootstrapping header is read - */ - private static ByteBuffer readSelfBootstrappingHeader( - File file, RandomAccessFile raf, int headerSize, boolean recover, - ChronicleHashCorruption.Listener corruptionListener, - ChronicleHashCorruptionImpl corruption) throws IOException { - if (raf.length() < headerSize + SELF_BOOTSTRAPPING_HEADER_OFFSET) { - throw throwRecoveryOrReturnIOException(file, - "The file is shorter than the header size: " + headerSize + - ", file size: " + raf.length(), recover); - } - FileChannel fileChannel = raf.getChannel(); - ByteBuffer headerBuffer = ByteBuffer.allocate( - SELF_BOOTSTRAPPING_HEADER_OFFSET + headerSize); - headerBuffer.order(LITTLE_ENDIAN); - readFully(fileChannel, 0, headerBuffer); - if (headerBuffer.remaining() > 0) { - throw throwRecoveryOrReturnIOException(file, "Unable to read the header fully, " + - headerBuffer.remaining() + " is remaining to read, likely the file was " + - "truncated", recover); - } - int sizeWord = headerBuffer.getInt(SIZE_WORD_OFFSET); - if (!SizePrefixedBlob.isReady(sizeWord)) { - if (recover) { - report(corruptionListener, corruption, -1, () -> - format("file={}: size-prefixed blob readiness bit is set to NOT_COMPLETE", - file) - ); - // the bit will be overwritten to READY in the end of recovery procedure, so nothing - // to fix right here - } else { - throw new IOException("file=" + file + ": sizeWord is not ready: " + sizeWord); - } - } - headerBuffer.position(SELF_BOOTSTRAPPING_HEADER_OFFSET); - return headerBuffer; - } - - private static boolean checkSumSelfBootstrappingHeader( - ByteBuffer headerBuffer, int headerSize) { - long checkSum = headerChecksum(headerBuffer, headerSize); - long storedChecksum = headerBuffer.getLong(HEADER_OFFSET); - return storedChecksum == checkSum; - } - private VanillaChronicleMap createWithNewFile( VanillaChronicleMap map, File file, RandomAccessFile raf, ChronicleHashResources resources, ByteBuffer headerBuffer, int headerSize) @@ -1890,11 +1892,11 @@ public final class ChronicleMapBuilder implements /** * Inject your SPI code around basic {@code ChronicleMap}'s operations with entries: * removing entries, replacing entries' value and inserting new entries. - * + *

*

This affects behaviour of ordinary map.put(), map.remove(), etc. calls, as well as removes * and replacing values during iterations, remote map calls and * internal replication operations. - * + *

*

This is a JVM-level configuration. * * @return this builder back @@ -1909,9 +1911,9 @@ public final class ChronicleMapBuilder implements * Inject your SPI around logic of all {@code ChronicleMap}'s operations with individual keys: * from {@link ChronicleMap#containsKey} to {@link ChronicleMap#acquireUsing} and * {@link ChronicleMap#merge}. - * + *

*

This affects behaviour of ordinary map calls, as well as remote calls. - * + *

*

This is a JVM-level configuration. * * @return this builder back diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapIterator.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapIterator.java index 97a081c4f..6e8dff4f2 100644 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapIterator.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapIterator.java @@ -32,8 +32,8 @@ abstract class ChronicleMapIterator implements Iterator, Consumer map; private final Thread ownerThread = Thread.currentThread(); private final Queue entryBuffer = new ArrayDeque<>(); - private int segmentIndex; E returned; + private int segmentIndex; ChronicleMapIterator(AbstractChronicleMap map) { this.map = map; diff --git a/src/main/java/net/openhft/chronicle/map/DefaultSpi.java b/src/main/java/net/openhft/chronicle/map/DefaultSpi.java index 2aa50c6a7..3dfbbf217 100644 --- a/src/main/java/net/openhft/chronicle/map/DefaultSpi.java +++ b/src/main/java/net/openhft/chronicle/map/DefaultSpi.java @@ -24,14 +24,15 @@ import org.jetbrains.annotations.NotNull; final class DefaultSpi implements MapMethods, MapEntryOperations, MapRemoteOperations, DefaultValueProvider { static final DefaultSpi DEFAULT_SPI = new DefaultSpi(); + static MapMethods mapMethods() { return DEFAULT_SPI; } - + static MapEntryOperations mapEntryOperations() { return DEFAULT_SPI; } - + static MapRemoteOperations mapRemoteOperations() { return DEFAULT_SPI; } diff --git a/src/main/java/net/openhft/chronicle/map/DefaultValueProvider.java b/src/main/java/net/openhft/chronicle/map/DefaultValueProvider.java index ea9a35808..e8dd4a207 100644 --- a/src/main/java/net/openhft/chronicle/map/DefaultValueProvider.java +++ b/src/main/java/net/openhft/chronicle/map/DefaultValueProvider.java @@ -34,7 +34,7 @@ public interface DefaultValueProvider { * Returns the "nil" value, which should be inserted into the map, in the given * {@code absentEntry} context. This is primarily used in {@link ChronicleMap#acquireUsing} * operation implementation, i. e. {@link MapMethods#acquireUsing}. - * + *

* The default implementation simply delegates to {@link MapAbsentEntry#defaultValue()}. */ Data defaultValue(@NotNull MapAbsentEntry absentEntry); diff --git a/src/main/java/net/openhft/chronicle/map/ExternalMapQueryContext.java b/src/main/java/net/openhft/chronicle/map/ExternalMapQueryContext.java index be136f095..b774113a2 100644 --- a/src/main/java/net/openhft/chronicle/map/ExternalMapQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/ExternalMapQueryContext.java @@ -26,9 +26,9 @@ import net.openhft.chronicle.hash.ExternalHashQueryContext; * @param the map key type * @param the map value type * @param the return type of {@link MapEntryOperations}, {@link - * ChronicleMapBuilder#entryOperations(MapEntryOperations) specified} for the queried {@code - * ChronicleMap} - * @see ChronicleMap#queryContext(Object) + * ChronicleMapBuilder#entryOperations(MapEntryOperations) specified} for the queried {@code + * ChronicleMap} + * @see ChronicleMap#queryContext(Object) */ public interface ExternalMapQueryContext extends MapQueryContext, ExternalHashQueryContext { diff --git a/src/main/java/net/openhft/chronicle/map/JsonSerializer.java b/src/main/java/net/openhft/chronicle/map/JsonSerializer.java index 7bb3782d3..c125e0ce1 100644 --- a/src/main/java/net/openhft/chronicle/map/JsonSerializer.java +++ b/src/main/java/net/openhft/chronicle/map/JsonSerializer.java @@ -34,6 +34,20 @@ import java.util.zip.GZIPOutputStream; */ class JsonSerializer { + static final String logErrorSuggestXStreem = + "map.getAll() and map.putAll() methods require the JSON XStream serializer, " + + "we don't include these artifacts by default as some users don't require this functionality. " + + "Please add the following artifacts to your project\n" + + "\n" + + " xstream\n" + + " xstream\n" + + " 1.2.2\n" + + "\n" + + "\n" + + " org.codehaus.jettison\n" + + " jettison\n" + + " 1.3.6\n" + + "\n"; private static final Logger LOG = LoggerFactory.getLogger(JsonSerializer.class); static synchronized void getAll(File toFile, Map map, List jsonConverters) throws IOException { @@ -78,7 +92,7 @@ class JsonSerializer { " expecting an object of type com.thoughtworks.xstream.converters" + ".Converter"); } -} + } return xstream; } catch (NoClassDefFoundError e) { @@ -86,21 +100,6 @@ class JsonSerializer { } } - static final String logErrorSuggestXStreem = - "map.getAll() and map.putAll() methods require the JSON XStream serializer, " + - "we don't include these artifacts by default as some users don't require this functionality. " + - "Please add the following artifacts to your project\n" + - "\n" + - " xstream\n" + - " xstream\n" + - " 1.2.2\n" + - "\n" + - "\n" + - " org.codehaus.jettison\n" + - " jettison\n" + - " 1.3.6\n" + - "\n"; - private static void registerChronicleMapConverter(Map map, XStream xstream) { xstream.registerConverter(new VanillaChronicleMapConverter<>(map)); } diff --git a/src/main/java/net/openhft/chronicle/map/MapAbsentEntry.java b/src/main/java/net/openhft/chronicle/map/MapAbsentEntry.java index abdb5397b..a9d4acb41 100644 --- a/src/main/java/net/openhft/chronicle/map/MapAbsentEntry.java +++ b/src/main/java/net/openhft/chronicle/map/MapAbsentEntry.java @@ -27,25 +27,25 @@ import org.jetbrains.annotations.NotNull; * * @param type of the key in {@code ChronicleMap} * @param type of the value in {@code ChronicleMap} - * * @see MapEntryOperations * @see MapQueryContext#absentEntry() */ public interface MapAbsentEntry extends HashAbsentEntry { @Override - @NotNull MapContext context(); - + @NotNull + MapContext context(); + /** * Inserts the new entry into the map, of {@linkplain #absentKey() the key} and the given {@code * value}. - * + *

*

This method is the default implementation for {@link MapEntryOperations#insert( - * MapAbsentEntry, Data)}, which might be customized over the default. + *MapAbsentEntry, Data)}, which might be customized over the default. * * @param value the value to insert into the map along with {@link #absentKey() the key} * @throws IllegalStateException if some locking/state conditions required to perform insertion - * operation are not met + * operation are not met * @see MapEntryOperations#insert(MapAbsentEntry, Data) */ void doInsert(Data value); @@ -54,7 +54,7 @@ public interface MapAbsentEntry extends HashAbsentEntry { * Returns the default (or nil) value, that should be inserted into the map in * this context. This is primarily used in {@link ChronicleMap#acquireUsing} operation * implementation, i. e. {@link MapMethods#acquireUsing}. - * + *

*

This method if the default implementation for {@link * DefaultValueProvider#defaultValue(MapAbsentEntry)}, * which might be customized over the default. diff --git a/src/main/java/net/openhft/chronicle/map/MapContext.java b/src/main/java/net/openhft/chronicle/map/MapContext.java index e424b75f1..982111de8 100644 --- a/src/main/java/net/openhft/chronicle/map/MapContext.java +++ b/src/main/java/net/openhft/chronicle/map/MapContext.java @@ -19,8 +19,8 @@ package net.openhft.chronicle.map; import net.openhft.chronicle.bytes.BytesStore; import net.openhft.chronicle.hash.ChronicleHash; -import net.openhft.chronicle.hash.HashContext; import net.openhft.chronicle.hash.Data; +import net.openhft.chronicle.hash.HashContext; /** * Context, in which {@link MapEntry MapEntries} are accessed. {@code MapContext} allows to access @@ -31,7 +31,7 @@ import net.openhft.chronicle.hash.Data; * configured for the accessed {@code ChronicleMap} via {@link * ChronicleMapBuilder#defaultValueProvider(DefaultValueProvider)}, or the default {@code * DefaultValueProvider} implementation. - * + * * @param the map key type * @param the map value type * @param the return type of {@link MapEntryOperations} specified for the queried map @@ -52,8 +52,8 @@ public interface MapContext /** * Wraps the given value as a {@code Data}. Useful when you need to pass a value * to some method accepting {@code Data}, for example, {@link MapEntryOperations#replaceValue( - * MapEntry, Data)}, without allocating new objects (i. e. garbage) and {@code ThreadLocals}. - * + *MapEntry, Data)}, without allocating new objects (i. e. garbage) and {@code ThreadLocals}. + *

*

The returned {@code Data} object shouldn't outlive this {@code MapContext}. * * @param value the value object to wrap @@ -64,13 +64,13 @@ public interface MapContext /** * Wraps the given value bytes as a {@code Data}. Useful when you need to pass a value * to some method accepting {@code Data}, for example, {@link MapEntryOperations#replaceValue( - * MapEntry, Data)}, without allocating manual deserialization and {@code ThreadLocals}. - * + *MapEntry, Data)}, without allocating manual deserialization and {@code ThreadLocals}. + *

*

The returned {@code Data} object shouldn't outlive this {@code MapContext}. * * @param valueBytes the value bytes to wrap - * @param offset offset within the given valueBytes, the actual value bytes start from - * @param size length of the value bytes sequence + * @param offset offset within the given valueBytes, the actual value bytes start from + * @param size length of the value bytes sequence * @return the value bytes as {@code Data} */ Data wrapValueBytesAsData(BytesStore valueBytes, long offset, long size); diff --git a/src/main/java/net/openhft/chronicle/map/MapDiagnostics.java b/src/main/java/net/openhft/chronicle/map/MapDiagnostics.java index 53e57e240..412e5e3e9 100644 --- a/src/main/java/net/openhft/chronicle/map/MapDiagnostics.java +++ b/src/main/java/net/openhft/chronicle/map/MapDiagnostics.java @@ -22,6 +22,9 @@ import java.io.IOException; public final class MapDiagnostics { + private MapDiagnostics() { + } + public static void main(String[] args) throws IOException { String mapFile = args[0]; try (ChronicleMap map = ChronicleMap.of(Object.class, Object.class) @@ -39,6 +42,4 @@ public final class MapDiagnostics { } } } - - private MapDiagnostics() {} } diff --git a/src/main/java/net/openhft/chronicle/map/MapEntry.java b/src/main/java/net/openhft/chronicle/map/MapEntry.java index b10ccc96a..93db0c7e9 100644 --- a/src/main/java/net/openhft/chronicle/map/MapEntry.java +++ b/src/main/java/net/openhft/chronicle/map/MapEntry.java @@ -23,15 +23,16 @@ import org.jetbrains.annotations.NotNull; /** * A context of a present entry in the {@link ChronicleMap}. - * + * * @param the map key type * @param the map value type * @see MapEntryOperations - * @see MapQueryContext#entry() + * @see MapQueryContext#entry() */ public interface MapEntry extends HashEntry { @Override - @NotNull MapContext context(); + @NotNull + MapContext context(); /** * Returns the entry value. @@ -41,22 +42,22 @@ public interface MapEntry extends HashEntry { /** * Replaces the entry's value with the given {@code newValue}. - * + *

*

This method is the default implementation for {@link MapEntryOperations#replaceValue( - * MapEntry, Data)}, which might be customized over the default. + *MapEntry, Data)}, which might be customized over the default. * * @param newValue the value to be put into the map instead of the {@linkplain #value() current - * value} + * value} * @throws IllegalStateException if some locking/state conditions required to perform replace - * operation are not met + * operation are not met */ void doReplaceValue(Data newValue); /** * Removes the entry from the map. - * + *

*

This method is the default implementation for {@link MapEntryOperations#remove(MapEntry)}, - * which might be customized over the default. + * which might be customized over the default. */ @Override void doRemove(); diff --git a/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java b/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java index 1904477e3..ed3143ff5 100644 --- a/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java +++ b/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java @@ -25,14 +25,14 @@ import org.jetbrains.annotations.NotNull; * SPI interface for customizing "low-level" modification operations on {@link ChronicleMap} * entries. All {@code ChronicleMap} modifications operate via an instance of this interface: *

    - *
  • Ordinary query operations: {@code map.put()}, {@code map.compute()}, {@code map.remove()} - *
  • - *
  • Operations with entry during iterations on the map, or the key/value/entry views, - * like {@code iterator.remove()}.
  • - *
  • Remote map operation calls and Replicated {@code ChronicleMap} reconciliation operations: - * see {@link MapRemoteOperations}.
  • + *
  • Ordinary query operations: {@code map.put()}, {@code map.compute()}, {@code map.remove()} + *
  • + *
  • Operations with entry during iterations on the map, or the key/value/entry views, + * like {@code iterator.remove()}.
  • + *
  • Remote map operation calls and Replicated {@code ChronicleMap} reconciliation operations: + * see {@link MapRemoteOperations}.
  • *
- * + *

*

By default {@link #remove}, {@link #insert} and {@link #replaceValue} return {@code null}, * but subclasses could return something more sensible, to be used in higher-level SPI interfaces, * namely {@link MapMethods} and {@link MapRemoteOperations}. For example, in bidirectional map @@ -41,15 +41,15 @@ import org.jetbrains.annotations.NotNull; * type could be used to indicate if we were successful to lock both maps before performing * the update:


  * enum DualLockSuccess {SUCCESS, FAIL}
- *
+ * 

* class{@code BiMapEntryOperations} * implements{@code MapEntryOperations} { * {@code ChronicleMap} reverse; - * + *

* public void{@code setReverse(ChronicleMap} reverse) { * this.reverse = reverse; * } - * + *

* {@literal @}Override * public DualLockSuccess{@literal remove(@}NotNull{@code MapEntry} entry) { * try{@code (ExternalMapQueryContext} rq = reverse.queryContext(entry.value())) { @@ -70,10 +70,10 @@ import org.jetbrains.annotations.NotNull; * } * } * } - * + *

* // ... other methods * } - * + *

* class{@code BiMapMethods} implements{@code MapMethods} { * {@literal @}Override * public void{@code remove(MapQueryContext} q, @@ -92,48 +92,46 @@ import org.jetbrains.annotations.NotNull; * } * } * } - * + *

* // ... other methods * }

* * @param the map key type * @param the map value type * @param methods return type, used for communication between lower- and higher-level SPI - * @see ChronicleMapBuilder#entryOperations(MapEntryOperations) + * @see ChronicleMapBuilder#entryOperations(MapEntryOperations) */ public interface MapEntryOperations { - + /** * Removes the given entry from the map. - * - * @implNote default implementation calls {@link MapEntry#doRemove()} on the given entry - * and returns {@code null}. * * @param entry the entry to remove * @return result of operation, understandable by higher-level SPIs, e. g. custom * {@link MapMethods} implementation * @throws IllegalStateException if some locking/state conditions required to perform remove - * operation are not met - * @throws RuntimeException if removal was unconditionally unsuccessful due to any reason + * operation are not met + * @throws RuntimeException if removal was unconditionally unsuccessful due to any reason + * @implNote default implementation calls {@link MapEntry#doRemove()} on the given entry + * and returns {@code null}. */ default R remove(@NotNull MapEntry entry) { entry.doRemove(); return null; } - + /** * Replaces the given entry's value with the new one. * - * @implNote default implementation calls {@link MapEntry#doReplaceValue(Data) - * entry.doReplaceValue(newValue)} and returns {@code null}. - * * @param entry the entry to replace the value in * @return result of operation, understandable by higher-level SPIs, e. g. custom * {@link MapMethods} implementation * @throws IllegalStateException if some locking/state conditions required to perform replace - * operation are not met - * @throws RuntimeException if value replacement was unconditionally unsuccessful due - * to any reason + * operation are not met + * @throws RuntimeException if value replacement was unconditionally unsuccessful due + * to any reason + * @implNote default implementation calls {@link MapEntry#doReplaceValue(Data) + * entry.doReplaceValue(newValue)} and returns {@code null}. */ default R replaceValue(@NotNull MapEntry entry, Data newValue) { entry.doReplaceValue(newValue); @@ -144,14 +142,13 @@ public interface MapEntryOperations { * Inserts the new entry into the map, of {@link MapAbsentEntry#absentKey() the key} from * the given insertion context (absentEntry) and the given {@code value}. * - * @implNote default implementation calls {@link MapAbsentEntry#doInsert(Data) - * absentEntry.doInsert(value)} and returns {@code null}. - * * @return result of operation, understandable by higher-level SPIs, e. g. custom * {@link MapMethods} implementation * @throws IllegalStateException if some locking/state conditions required to perform insertion - * operation are not met - * @throws RuntimeException if insertion was unconditionally unsuccessful due to any reason + * operation are not met + * @throws RuntimeException if insertion was unconditionally unsuccessful due to any reason + * @implNote default implementation calls {@link MapAbsentEntry#doInsert(Data) + * absentEntry.doInsert(value)} and returns {@code null}. */ default R insert(@NotNull MapAbsentEntry absentEntry, Data value) { absentEntry.doInsert(value); diff --git a/src/main/java/net/openhft/chronicle/map/MapMethods.java b/src/main/java/net/openhft/chronicle/map/MapMethods.java index 14153b297..e9f53518c 100644 --- a/src/main/java/net/openhft/chronicle/map/MapMethods.java +++ b/src/main/java/net/openhft/chronicle/map/MapMethods.java @@ -225,6 +225,7 @@ public interface MapMethods { /** * Backing {@link ChronicleMap#remove(Object, Object)} method. * + * @return if the entry was removed * @implNote the default implementation is equivalent to
{@code
      * // remove(key, value) should find the entry & remove most of the time,
      * // so don't try to check key presence and value equivalence under read lock first,
@@ -237,8 +238,6 @@ public interface MapMethods {
      * } else {
      *     return false;
      * }}
- * - * @return if the entry was removed */ default boolean remove(MapQueryContext q, Data value) { // remove(key, value) should find the entry & remove most of the time, @@ -284,6 +283,7 @@ public interface MapMethods { /** * Backing {@link ChronicleMap#replace(Object, Object, Object)} method. * + * @return if the entry was replaced * @implNote the default implementation is equivalent to
{@code
      * // replace(key, old, new) should find the entry & put new value most of the time,
      * // so don't try to check key presence and value equivalence under read lock first,
@@ -296,8 +296,6 @@ public interface MapMethods {
      * } else {
      *     return false;
      * }}
- * - * @return if the entry was replaced */ default boolean replace(MapQueryContext q, Data oldValue, Data newValue) { @@ -382,7 +380,7 @@ public interface MapMethods { if (entry != null) { V oldValue = entry.value().get(); V newValue = remappingFunction.apply(q.queriedKey().get(), oldValue); - if (newValue != null ) { + if (newValue != null) { q.replaceValue(entry, q.wrapValueAsData(newValue)); returnValue.returnValue(q.entry().value()); } else { diff --git a/src/main/java/net/openhft/chronicle/map/MapMethodsSupport.java b/src/main/java/net/openhft/chronicle/map/MapMethodsSupport.java index 3347e040f..f56c58824 100644 --- a/src/main/java/net/openhft/chronicle/map/MapMethodsSupport.java +++ b/src/main/java/net/openhft/chronicle/map/MapMethodsSupport.java @@ -19,6 +19,9 @@ package net.openhft.chronicle.map; final class MapMethodsSupport { + private MapMethodsSupport() { + } + static void returnCurrentValueIfPresent( MapQueryContext q, ReturnValue returnValue) { MapEntry entry = q.entry(); @@ -45,6 +48,4 @@ final class MapMethodsSupport { } return false; } - - private MapMethodsSupport() {} } diff --git a/src/main/java/net/openhft/chronicle/map/MapQueryContext.java b/src/main/java/net/openhft/chronicle/map/MapQueryContext.java index 35123f614..e14dd23db 100644 --- a/src/main/java/net/openhft/chronicle/map/MapQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/MapQueryContext.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.Nullable; * @param the map key type * @param the map value type * @param the return type of {@link MapEntryOperations} specialized for the queried map - * @see ChronicleMap#queryContext(Object) + * @see ChronicleMap#queryContext(Object) */ public interface MapQueryContext extends HashQueryContext, MapContext { diff --git a/src/main/java/net/openhft/chronicle/map/OldDeletedEntriesCleanupThread.java b/src/main/java/net/openhft/chronicle/map/OldDeletedEntriesCleanupThread.java index 47efdd2d8..086838e2f 100644 --- a/src/main/java/net/openhft/chronicle/map/OldDeletedEntriesCleanupThread.java +++ b/src/main/java/net/openhft/chronicle/map/OldDeletedEntriesCleanupThread.java @@ -86,6 +86,35 @@ class OldDeletedEntriesCleanupThread extends Thread inverseSegmentsPermutation = inversePermutation(segmentsPermutation); } + private static int[] randomPermutation(int n) { + int[] a = new int[n]; + for (int i = 0; i < n; i++) { + a[i] = i; + } + shuffle(a); + return a; + } + + // Implementing Fisher–Yates shuffle + private static void shuffle(int[] a) { + Random rnd = ThreadLocalRandom.current(); + for (int i = a.length - 1; i > 0; i--) { + int index = rnd.nextInt(i + 1); + int e = a[index]; + a[index] = a[i]; + a[i] = e; + } + } + + private static int[] inversePermutation(int[] permutation) { + int n = permutation.length; + int[] inverse = new int[n]; + for (int i = 0; i < n; i++) { + inverse[permutation[i]] = i; + } + return inverse; + } + @Override public void run() { while (!shutdown) { @@ -177,33 +206,4 @@ class OldDeletedEntriesCleanupThread extends Thread int nextPermutationIndex = (permutationIndex + 1) % segments; return segmentsPermutation[nextPermutationIndex]; } - - private static int[] randomPermutation(int n) { - int[] a = new int[n]; - for (int i = 0; i < n; i++) { - a[i] = i; - } - shuffle(a); - return a; - } - - // Implementing Fisher–Yates shuffle - private static void shuffle(int[] a) { - Random rnd = ThreadLocalRandom.current(); - for (int i = a.length - 1; i > 0; i--) { - int index = rnd.nextInt(i + 1); - int e = a[index]; - a[index] = a[i]; - a[i] = e; - } - } - - private static int[] inversePermutation(int[] permutation) { - int n = permutation.length; - int[] inverse = new int[n]; - for (int i = 0; i < n; i++) { - inverse[permutation[i]] = i; - } - return inverse; - } } diff --git a/src/main/java/net/openhft/chronicle/map/Replica.java b/src/main/java/net/openhft/chronicle/map/Replica.java index 604d7f6d2..2a1aa933d 100644 --- a/src/main/java/net/openhft/chronicle/map/Replica.java +++ b/src/main/java/net/openhft/chronicle/map/Replica.java @@ -29,29 +29,6 @@ import java.io.Closeable; */ public interface Replica extends Closeable { - interface QueryContext { - - /** - * @param newValue the value of the replicated entry - * @param remoteEntryIdentifier origin identifier of the replicated entry - * @param remoteEntryTimestamp timestamp of the replicated entry - * @param remoteNodeIdentifier identifier of the remote node this replication came from, - * or -1 if unknown/not applicable - */ - void remotePut( - Data newValue, - byte remoteEntryIdentifier, long remoteEntryTimestamp, byte remoteNodeIdentifier); - - /** - * @param remoteEntryIdentifier origin identifier of the replicated entry - * @param remoteEntryTimestamp timestamp of the replicated entry - * @param remoteNodeIdentifier identifier of the remote node this replication came from, - * or -1 if unknown/not applicable - */ - void remoteRemove( - byte remoteEntryIdentifier, long remoteEntryTimestamp, byte remoteNodeIdentifier); - } - /** * Provides the unique Identifier associated with this map instance.

An identifier is used * to determine which replicating node made the change.

If two nodes update their map at the @@ -73,7 +50,7 @@ public interface Replica extends Closeable { * Gets (if it does not exist, creates) an instance of ModificationIterator associated with a * remote node, this weak associated is bound using the {@code identifier}. * - * @param remoteIdentifier the identifier of the remote node + * @param remoteIdentifier the identifier of the remote node * @return the ModificationIterator dedicated for replication to the remote node with the given * identifier * @see #identifier() @@ -95,6 +72,29 @@ public interface Replica extends Closeable { void setRemoteNodeCouldBootstrapFrom( byte remoteIdentifier, long bootstrapTimestamp); + interface QueryContext { + + /** + * @param newValue the value of the replicated entry + * @param remoteEntryIdentifier origin identifier of the replicated entry + * @param remoteEntryTimestamp timestamp of the replicated entry + * @param remoteNodeIdentifier identifier of the remote node this replication came from, + * or -1 if unknown/not applicable + */ + void remotePut( + Data newValue, + byte remoteEntryIdentifier, long remoteEntryTimestamp, byte remoteNodeIdentifier); + + /** + * @param remoteEntryIdentifier origin identifier of the replicated entry + * @param remoteEntryTimestamp timestamp of the replicated entry + * @param remoteNodeIdentifier identifier of the remote node this replication came from, + * or -1 if unknown/not applicable + */ + void remoteRemove( + byte remoteEntryIdentifier, long remoteEntryTimestamp, byte remoteNodeIdentifier); + } + /** * notifies when there is a changed to the modification iterator */ @@ -156,7 +156,8 @@ public interface Replica extends Closeable { /** * 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 + * + * @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 */ @@ -182,7 +183,8 @@ public interface Replica extends Closeable { /** * The map implements this method to save its contents. - * @param entry the byte location of the entry to be stored + * + * @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 @@ -196,8 +198,9 @@ public interface Replica extends Closeable { * in the same sequence and with the same types as were written by {@code * writeExternalEntry()}. This method is typically called when we receive a remote * replication event, this event could originate from either a remote {@code put(K key, V - *value)} or {@code remove(Object key)} - * @param source bytes to read an entry from + * value)} or {@code remove(Object key)} + * + * @param source bytes to read an entry from * @param remoteNodeIdentifier the identifier of the remove node, from which this event came * (NOT origin id of the entry) */ diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java index a10a3d58d..265c62d73 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java @@ -92,23 +92,23 @@ import static net.openhft.chronicle.hash.replication.TimeProvider.currentTime; public class ReplicatedChronicleMap extends VanillaChronicleMap implements Replica, Replica.EntryExternalizable { - private static final Logger LOG = LoggerFactory.getLogger(ReplicatedChronicleMap.class); - public static final int ADDITIONAL_ENTRY_BYTES = 10; - static final byte ENTRY_HUNK = 1; static final byte BOOTSTRAP_TIME_HUNK = 2; - + private static final Logger LOG = LoggerFactory.getLogger(ReplicatedChronicleMap.class); + public transient boolean cleanupRemovedEntries; + public transient long cleanupTimeout; + public transient TimeUnit cleanupTimeoutUnit; + public transient MapRemoteOperations remoteOperations; + transient BitSetFrame tierModIterFrame; private long tierModIterBitSetSizeInBits; private long tierModIterBitSetOuterSize; private long segmentModIterBitSetsForIdentifierOuterSize; private long tierBulkModIterBitSetsForIdentifierOuterSize; - /** * Default value is 0, that corresponds to "unset" identifier value (valid ids are positive) */ private transient byte localIdentifier; - /** * Idiomatically {@code assignedModificationIterators} should be a {@link CopyOnWriteArraySet}, * but we should frequently iterate over this array without creating any garbage, @@ -117,15 +117,6 @@ public class ReplicatedChronicleMap extends VanillaChronicleMap modificationIterators; private transient long startOfModificationIterators; - - public transient boolean cleanupRemovedEntries; - public transient long cleanupTimeout; - public transient TimeUnit cleanupTimeoutUnit; - - public transient MapRemoteOperations remoteOperations; - - transient BitSetFrame tierModIterFrame; - private transient long[] remoteNodeCouldBootstrapFrom; public ReplicatedChronicleMap(@NotNull ChronicleMapBuilder builder) throws IOException { @@ -587,6 +578,16 @@ public class ReplicatedChronicleMap extends VanillaChronicleMap new CompiledReplicatedMapIterationContext(c, m), this); } + @Override + public final V get(Object key) { + return defaultGet(key); + } + + @Override + public final V getUsing(K key, V usingValue) { + return defaultGetUsing(key, usingValue); + } + /** *

Once a change occurs to a map, map replication requires that these changes are picked up * by another thread, this class provides an iterator like interface to poll for such changes. @@ -923,14 +924,4 @@ public class ReplicatedChronicleMap extends VanillaChronicleMap { * Calling this method on a {@code ReturnValue} object, provided as an argument in a method from * {@link MapMethods}, designates that the {@code ChronicleMap}'s method (backed by this * {@code MapMethods}'s method) should return the given {@code value}. - * + *

*

It is not allowed to call {@code returnValue()} twice during a single {@code MapMethods}'s * method call. - * + *

*

Not calling {@code returnValue()} during {@code MapMethods}'s method call will make the * backed {@code ChronicleMap}'s method to return {@code null}. * diff --git a/src/main/java/net/openhft/chronicle/map/SelectedSelectionKeySet.java b/src/main/java/net/openhft/chronicle/map/SelectedSelectionKeySet.java index 70fb44ff9..50fa7e643 100644 --- a/src/main/java/net/openhft/chronicle/map/SelectedSelectionKeySet.java +++ b/src/main/java/net/openhft/chronicle/map/SelectedSelectionKeySet.java @@ -42,14 +42,14 @@ final class SelectedSelectionKeySet extends AbstractSet { if (isA) { int size = keysASize; - keysA[size ++] = o; + keysA[size++] = o; keysASize = size; if (size == keysA.length) { doubleCapacityA(); } } else { int size = keysBSize; - keysB[size ++] = o; + keysB[size++] = o; keysBSize = size; if (size == keysB.length) { doubleCapacityB(); diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index 1f734900d..4fccacc6a 100755 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -56,20 +56,31 @@ public class VanillaChronicleMap ExternalMapQueryContext> implements AbstractChronicleMap { - ///////////////////////////////////////////////// - // Value Data model - Class valueClass; public SizeMarshaller valueSizeMarshaller; public SizedReader valueReader; public DataAccess valueDataAccess; - public boolean constantlySizedEntry; - ///////////////////////////////////////////////// // Memory management and dependent fields public int alignment; public int worstAlignment; - + public transient boolean couldNotDetermineAlignmentBeforeAllocation; + /** + * @see net.openhft.chronicle.set.SetFromMap + */ + public transient ChronicleSet chronicleSet; + public transient MapEntryOperations entryOperations; + public transient MapMethods methods; + public transient DefaultValueProvider defaultValueProvider; + ///////////////////////////////////////////////// + // Value Data model + Class valueClass; + ///////////////////////////////////////////////// + // Behavior + transient boolean putReturnsNull; + transient boolean removeReturnsNull; + transient Set> entrySet; + transient ThreadLocal cxt; ///////////////////////////////////////////////// private transient String name; /** @@ -78,25 +89,7 @@ public class VanillaChronicleMap * initOwnTransients(). */ private transient String identityString; - - public transient boolean couldNotDetermineAlignmentBeforeAllocation; - - ///////////////////////////////////////////////// - // Behavior - transient boolean putReturnsNull; - transient boolean removeReturnsNull; - - transient Set> entrySet; - - /** @see net.openhft.chronicle.set.SetFromMap */ - public transient ChronicleSet chronicleSet; - - public transient MapEntryOperations entryOperations; - public transient MapMethods methods; private transient boolean defaultEntryOperationsAndMethods; - public transient DefaultValueProvider defaultValueProvider; - - transient ThreadLocal cxt; public VanillaChronicleMap(ChronicleMapBuilder builder) throws IOException { super(builder); @@ -116,6 +109,10 @@ public class VanillaChronicleMap initTransients(); } + public static long alignAddr(long addr, long alignment) { + return (addr + alignment - 1) & ~(alignment - 1L); + } + @Override protected void readMarshallableFields(@NotNull WireIn wireIn) { super.readMarshallableFields(wireIn); @@ -287,7 +284,7 @@ public class VanillaChronicleMap ", identityHashCode=" + System.identityHashCode(this) + "}"; } - + @Override public void clear() { forEachEntry(c -> c.context().remove(c)); @@ -306,10 +303,6 @@ public class VanillaChronicleMap entry.readSkip(skip); } - public static long alignAddr(long addr, long alignment) { - return (addr + alignment - 1) & ~(alignment - 1L); - } - final ChainingInterface q() { ThreadLocal cxt = this.cxt; if (cxt == null) @@ -601,7 +594,8 @@ public class VanillaChronicleMap searchLoop: while (true) { long entryPos; - nextPos: { + nextPos: + { while (true) { long entry = hl.readEntryVolatile(tierBaseAddr, hlPos); if (hl.empty(entry)) { diff --git a/src/main/java/net/openhft/chronicle/map/impl/IterationContext.java b/src/main/java/net/openhft/chronicle/map/impl/IterationContext.java index 67fc4acec..653569db8 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/IterationContext.java +++ b/src/main/java/net/openhft/chronicle/map/impl/IterationContext.java @@ -22,12 +22,9 @@ import net.openhft.chronicle.map.ChronicleHashCorruptionImpl; import net.openhft.chronicle.map.MapEntry; import net.openhft.chronicle.map.MapSegmentContext; -import java.util.List; -import java.util.Set; - public interface IterationContext extends MapEntry, MapSegmentContext { long pos(); - + void initSegmentIndex(int segmentIndex); void recoverSegments( diff --git a/src/main/java/net/openhft/chronicle/map/impl/MapQueryContext.java b/src/main/java/net/openhft/chronicle/map/impl/MapQueryContext.java index 52548d61d..a0a35b709 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/MapQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/impl/MapQueryContext.java @@ -69,25 +69,25 @@ import net.openhft.sg.Staged; QueryAlloc.class, }, -nested = { - ReadLock.class, - UpdateLock.class, - WriteLock.class, + nested = { + ReadLock.class, + UpdateLock.class, + WriteLock.class, - EntryKeyBytesData.class, - EntryValueBytesData.class, + EntryKeyBytesData.class, + EntryValueBytesData.class, - InputKeyBytesData.class, + InputKeyBytesData.class, - WrappedValueInstanceDataHolder.class, - WrappedValueBytesData.class, - AcquireHandle.class, - DefaultReturnValue.class, - UsingReturnValue.class, + WrappedValueInstanceDataHolder.class, + WrappedValueBytesData.class, + AcquireHandle.class, + DefaultReturnValue.class, + UsingReturnValue.class, - HashEntryChecksumStrategy.class, + HashEntryChecksumStrategy.class, - DummyValueZeroData.class, -}) + DummyValueZeroData.class, + }) public class MapQueryContext { } diff --git a/src/main/java/net/openhft/chronicle/map/impl/NullReturnValue.java b/src/main/java/net/openhft/chronicle/map/impl/NullReturnValue.java index c7a4abc58..ddb2500eb 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/NullReturnValue.java +++ b/src/main/java/net/openhft/chronicle/map/impl/NullReturnValue.java @@ -23,12 +23,13 @@ import org.jetbrains.annotations.NotNull; public final class NullReturnValue implements InstanceReturnValue { private static final NullReturnValue NULL_RETURN_VALUE = new NullReturnValue(); - + + private NullReturnValue() { + } + public static InstanceReturnValue get() { return NULL_RETURN_VALUE; } - - private NullReturnValue() {} @Override public Object returnValue() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/QueryContextInterface.java b/src/main/java/net/openhft/chronicle/map/impl/QueryContextInterface.java index 8a8acaff9..e11fca02e 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/QueryContextInterface.java +++ b/src/main/java/net/openhft/chronicle/map/impl/QueryContextInterface.java @@ -26,22 +26,22 @@ import net.openhft.chronicle.map.impl.ret.InstanceReturnValue; import net.openhft.chronicle.map.impl.ret.UsableReturnValue; public interface QueryContextInterface extends ExternalMapQueryContext { - + void initInputKey(Data inputKey); Data getInputKeyBytesAsData(BytesStore bytesStore, long offset, long size); - + DataAccess inputKeyDataAccess(); - + InstanceReturnValue defaultReturnValue(); - + UsableReturnValue usingReturnValue(); - + DataAccess inputValueDataAccess(); - + Closeable acquireHandle(); - + void initSegmentIndex(int segmentIndex); - + boolean segmentIndexInit(); } diff --git a/src/main/java/net/openhft/chronicle/map/impl/ReplicatedMapQueryContext.java b/src/main/java/net/openhft/chronicle/map/impl/ReplicatedMapQueryContext.java index 540f8683e..f66c8f747 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/ReplicatedMapQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/impl/ReplicatedMapQueryContext.java @@ -74,27 +74,27 @@ import net.openhft.sg.Staged; ReplicatedQueryAlloc.class, }, -nested = { - ReadLock.class, - UpdateLock.class, - WriteLock.class, + nested = { + ReadLock.class, + UpdateLock.class, + WriteLock.class, - EntryKeyBytesData.class, - EntryValueBytesData.class, + EntryKeyBytesData.class, + EntryValueBytesData.class, - InputKeyBytesData.class, + InputKeyBytesData.class, - WrappedValueInstanceDataHolder.class, - WrappedValueBytesData.class, - AcquireHandle.class, - DefaultReturnValue.class, - UsingReturnValue.class, + WrappedValueInstanceDataHolder.class, + WrappedValueBytesData.class, + AcquireHandle.class, + DefaultReturnValue.class, + UsingReturnValue.class, - ReplicatedMapAbsentDelegating.class, + ReplicatedMapAbsentDelegating.class, - DummyValueZeroData.class, + DummyValueZeroData.class, - HashEntryChecksumStrategy.class, -}) + HashEntryChecksumStrategy.class, + }) public class ReplicatedMapQueryContext { } diff --git a/src/main/java/net/openhft/chronicle/map/impl/VanillaChronicleMapHolder.java b/src/main/java/net/openhft/chronicle/map/impl/VanillaChronicleMapHolder.java index 969ac4220..c4eff95cb 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/VanillaChronicleMapHolder.java +++ b/src/main/java/net/openhft/chronicle/map/impl/VanillaChronicleMapHolder.java @@ -26,7 +26,7 @@ import net.openhft.sg.Staged; @Staged public interface VanillaChronicleMapHolder extends VanillaChronicleHashHolder { - + VanillaChronicleMap m(); @Override diff --git a/src/main/java/net/openhft/chronicle/map/impl/ret/UsableReturnValue.java b/src/main/java/net/openhft/chronicle/map/impl/ret/UsableReturnValue.java index a77b4c70c..aee808e6a 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/ret/UsableReturnValue.java +++ b/src/main/java/net/openhft/chronicle/map/impl/ret/UsableReturnValue.java @@ -18,7 +18,7 @@ package net.openhft.chronicle.map.impl.ret; public interface UsableReturnValue extends InstanceReturnValue { - Object USING_RETURN_VALUE_UNINIT = new Object(); - + Object USING_RETURN_VALUE_UNINIT = new Object(); + void initUsingReturnValue(V usingValue); } diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/data/DummyValueZeroData.java b/src/main/java/net/openhft/chronicle/map/impl/stage/data/DummyValueZeroData.java index 8e5673044..68b41c213 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/data/DummyValueZeroData.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/data/DummyValueZeroData.java @@ -29,11 +29,13 @@ import net.openhft.sg.Staged; @Staged public class DummyValueZeroData extends AbstractData { - @StageRef VanillaChronicleMapHolder mh; - @StageRef ValueBytesInterop vi; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - private final Bytes zeroBytes = ZeroBytesStore.INSTANCE.bytesForRead(); + @StageRef + VanillaChronicleMapHolder mh; + @StageRef + ValueBytesInterop vi; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; @Override public RandomDataInput bytes() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/data/ZeroBytesStore.java b/src/main/java/net/openhft/chronicle/map/impl/stage/data/ZeroBytesStore.java index b96cb5610..f0f4ec140 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/data/ZeroBytesStore.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/data/ZeroBytesStore.java @@ -132,7 +132,6 @@ public enum ZeroBytesStore implements BytesStore { return offset; } - @Override public boolean compareAndSwapInt(long offset, int expected, int value) throws BufferOverflowException, IllegalArgumentException { @@ -238,5 +237,4 @@ public enum ZeroBytesStore implements BytesStore { throw new UnsupportedOperationException(); } - } \ No newline at end of file diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/EntryValueBytesData.java b/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/EntryValueBytesData.java index b943a020b..747c39962 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/EntryValueBytesData.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/EntryValueBytesData.java @@ -22,7 +22,6 @@ import net.openhft.chronicle.bytes.RandomDataInput; import net.openhft.chronicle.hash.AbstractData; import net.openhft.chronicle.hash.impl.stage.entry.SegmentStages; import net.openhft.chronicle.hash.impl.stage.hash.CheckOnEachPublicOperation; -import net.openhft.chronicle.hash.impl.util.CharSequences; import net.openhft.chronicle.map.impl.VanillaChronicleMapHolder; import net.openhft.chronicle.map.impl.stage.entry.MapEntryStages; import net.openhft.chronicle.map.impl.stage.map.ValueBytesInterop; @@ -33,15 +32,22 @@ import net.openhft.sg.Staged; @Staged public class EntryValueBytesData extends AbstractData { - @StageRef VanillaChronicleMapHolder mh; - @StageRef ValueBytesInterop vi; - @StageRef SegmentStages s; - @StageRef MapEntryStages entry; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + VanillaChronicleMapHolder mh; + @StageRef + ValueBytesInterop vi; + @StageRef + SegmentStages s; + @StageRef + MapEntryStages entry; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; - @Stage("CachedEntryValue") private V cachedEntryValue = + @Stage("CachedEntryValue") + private V cachedEntryValue = mh.m().valueClass() == CharSequence.class ? (V) new StringBuilder() : null; - @Stage("CachedEntryValue") private boolean cachedEntryValueRead = false; + @Stage("CachedEntryValue") + private boolean cachedEntryValueRead = false; private void initCachedEntryValue() { cachedEntryValue = innerGetUsing(cachedEntryValue); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/WrappedValueBytesData.java b/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/WrappedValueBytesData.java index 9c8233905..8d758bb61 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/WrappedValueBytesData.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/data/bytes/WrappedValueBytesData.java @@ -32,19 +32,35 @@ import static net.openhft.chronicle.bytes.NoBytesStore.NO_BYTES_STORE; @Staged public class WrappedValueBytesData extends AbstractData { - @StageRef ValueBytesInterop vi; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - + @Stage("WrappedValueBytes") + private final VanillaBytes wrappedValueBytes = + new VanillaBytes(NO_BYTES_STORE); + @StageRef + ValueBytesInterop vi; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; private WrappedValueBytesData next; - + @Stage("WrappedValueBytesStore") + private BytesStore wrappedValueBytesStore; + @Stage("WrappedValueBytesStore") + private long wrappedValueBytesOffset; + @Stage("WrappedValueBytesStore") + private long wrappedValueBytesSize; + @Stage("WrappedValueBytes") + private boolean wrappedValueBytesUsed = false; + @Stage("CachedWrappedValue") + private V cachedWrappedValue; + @Stage("CachedWrappedValue") + private boolean cachedWrappedValueRead = false; + boolean nextInit() { return true; } - + void closeNext() { // do nothing } - + @Stage("Next") public WrappedValueBytesData getUnusedWrappedValueBytesData() { if (!wrappedValueBytesStoreInit()) @@ -54,10 +70,6 @@ public class WrappedValueBytesData extends AbstractData { return next.getUnusedWrappedValueBytesData(); } - @Stage("WrappedValueBytesStore") private BytesStore wrappedValueBytesStore; - @Stage("WrappedValueBytesStore") private long wrappedValueBytesOffset; - @Stage("WrappedValueBytesStore") private long wrappedValueBytesSize; - boolean wrappedValueBytesStoreInit() { return wrappedValueBytesStore != null; } @@ -74,10 +86,6 @@ public class WrappedValueBytesData extends AbstractData { next.closeWrappedValueBytesStore(); } - @Stage("WrappedValueBytes") private final VanillaBytes wrappedValueBytes = - new VanillaBytes(NO_BYTES_STORE); - @Stage("WrappedValueBytes") private boolean wrappedValueBytesUsed = false; - boolean wrappedValueBytesInit() { return wrappedValueBytesUsed; } @@ -93,9 +101,6 @@ public class WrappedValueBytesData extends AbstractData { wrappedValueBytesUsed = false; } - @Stage("CachedWrappedValue") private V cachedWrappedValue; - @Stage("CachedWrappedValue") private boolean cachedWrappedValueRead = false; - private void initCachedWrappedValue() { cachedWrappedValue = innerGetUsing(cachedWrappedValue); cachedWrappedValueRead = true; diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/data/instance/WrappedValueInstanceDataHolder.java b/src/main/java/net/openhft/chronicle/map/impl/stage/data/instance/WrappedValueInstanceDataHolder.java index 170f9cf34..a048ec8e0 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/data/instance/WrappedValueInstanceDataHolder.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/data/instance/WrappedValueInstanceDataHolder.java @@ -26,21 +26,22 @@ import net.openhft.sg.Staged; @Staged public class WrappedValueInstanceDataHolder { - - @StageRef VanillaChronicleMapHolder mh; + public Data wrappedData = null; + @StageRef + VanillaChronicleMapHolder mh; private final DataAccess wrappedValueDataAccess = mh.m().valueDataAccess.copy(); - private WrappedValueInstanceDataHolder next; - + private V value; + boolean nextInit() { return true; } - + void closeNext() { // do nothing } - + @Stage("Next") public WrappedValueInstanceDataHolder getUnusedWrappedValueHolder() { if (!valueInit()) @@ -49,26 +50,22 @@ public class WrappedValueInstanceDataHolder { next = new WrappedValueInstanceDataHolder<>(); return next.getUnusedWrappedValueHolder(); } - - private V value; - + public boolean valueInit() { return value != null; } - + public void initValue(V value) { mh.m().checkValue(value); this.value = value; } - + public void closeValue() { value = null; if (next != null) next.closeValue(); } - public Data wrappedData = null; - private void initWrappedData() { wrappedData = wrappedValueDataAccess.getData(value); } diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/entry/MapEntryStages.java b/src/main/java/net/openhft/chronicle/map/impl/stage/entry/MapEntryStages.java index e9ee2db42..7cf378b91 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/entry/MapEntryStages.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/entry/MapEntryStages.java @@ -38,24 +38,29 @@ import static net.openhft.chronicle.map.VanillaChronicleMap.alignAddr; public abstract class MapEntryStages extends HashEntryStages implements MapEntry { - @StageRef public VanillaChronicleMapHolder mh; - @StageRef public AllocatedChunks allocatedChunks; - @StageRef KeySearch ks; + @StageRef + public VanillaChronicleMapHolder mh; + @StageRef + public AllocatedChunks allocatedChunks; + public long valueSizeOffset = -1; + @Stage("ValueSize") + public long valueSize = -1; + @Stage("ValueSize") + public long valueOffset; + @StageRef + public EntryValueBytesData entryValue; + @StageRef + KeySearch ks; long countValueSizeOffset() { return keyEnd(); } - - public long valueSizeOffset = -1; @SuppressWarnings("unused") void initValueSizeOffset() { valueSizeOffset = countValueSizeOffset(); } - @Stage("ValueSize") public long valueSize = -1; - @Stage("ValueSize") public long valueOffset; - void initValueSize(long valueSize) { this.valueSize = valueSize; Bytes segmentBytes = s.segmentBytesForWrite(); @@ -106,8 +111,6 @@ public abstract class MapEntryStages extends HashEntryStages public long entryEnd() { return valueOffset + valueSize; } - - @StageRef public EntryValueBytesData entryValue; @NotNull @Override @@ -120,7 +123,7 @@ public abstract class MapEntryStages extends HashEntryStages return valueSizeOffset + mh.m().valueSizeMarshaller.storingLength(newValue.size()) - keySizeOffset; } - + public void innerDefaultReplaceValue(Data newValue) { assert s.innerUpdateLock.isHeldByCurrentThread(); @@ -242,7 +245,7 @@ public abstract class MapEntryStages extends HashEntryStages public final void freeExtraAllocatedChunks() { // fast path if (!mh.m().constantlySizedEntry && mh.m().couldNotDetermineAlignmentBeforeAllocation && - entrySizeInChunks < allocatedChunks.allocatedChunks) { + entrySizeInChunks < allocatedChunks.allocatedChunks) { s.freeExtra(pos, allocatedChunks.allocatedChunks, entrySizeInChunks); } else { initEntrySizeInChunks(allocatedChunks.allocatedChunks); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/entry/ReplicatedMapEntryStages.java b/src/main/java/net/openhft/chronicle/map/impl/stage/entry/ReplicatedMapEntryStages.java index 9c8144708..6e67840ab 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/entry/ReplicatedMapEntryStages.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/entry/ReplicatedMapEntryStages.java @@ -32,11 +32,14 @@ import static net.openhft.chronicle.map.ReplicatedChronicleMap.ADDITIONAL_ENTRY_ @Staged public abstract class ReplicatedMapEntryStages extends MapEntryStages implements MapReplicableEntry { - - @StageRef ReplicatedChronicleMapHolder mh; - @StageRef ReplicationUpdate ru; - @Stage("ReplicationState") long replicationBytesOffset = -1; + @StageRef + ReplicatedChronicleMapHolder mh; + @StageRef + ReplicationUpdate ru; + + @Stage("ReplicationState") + long replicationBytesOffset = -1; void initReplicationState() { replicationBytesOffset = keyEnd(); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/input/ReplicatedInput.java b/src/main/java/net/openhft/chronicle/map/impl/stage/input/ReplicatedInput.java index e5b1dbb7b..01f53fff5 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/input/ReplicatedInput.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/input/ReplicatedInput.java @@ -35,12 +35,18 @@ import net.openhft.sg.Staged; public abstract class ReplicatedInput implements RemoteOperationContext, MapRemoteQueryContext, Replica.QueryContext { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef ReplicatedChronicleMapHolder mh; - @StageRef ReplicationUpdate ru; - @StageRef ReplicatedMapQuery q; - @StageRef SegmentStages s; - @StageRef DummyValueZeroData dummyValue; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + ReplicatedChronicleMapHolder mh; + @StageRef + ReplicationUpdate ru; + @StageRef + ReplicatedMapQuery q; + @StageRef + SegmentStages s; + @StageRef + DummyValueZeroData dummyValue; @Override public Data dummyZeroValue() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/IterationCheckOnEachPublicOperation.java b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/IterationCheckOnEachPublicOperation.java index 98ef2afc5..7a6d7eedc 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/IterationCheckOnEachPublicOperation.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/IterationCheckOnEachPublicOperation.java @@ -23,8 +23,9 @@ import net.openhft.sg.Staged; @Staged public class IterationCheckOnEachPublicOperation extends CheckOnEachPublicOperation { - - @StageRef MapSegmentIteration iteration; + + @StageRef + MapSegmentIteration iteration; @Override public void checkOnEachPublicOperation() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/MapSegmentIteration.java b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/MapSegmentIteration.java index dfa8391a5..6bbef36a5 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/MapSegmentIteration.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/MapSegmentIteration.java @@ -31,10 +31,13 @@ import org.jetbrains.annotations.NotNull; @Staged public abstract class MapSegmentIteration extends HashSegmentIteration> implements MapEntry, IterationContext { - - @StageRef MapEntryStages entry; - @StageRef WrappedValueInstanceDataHolder wrappedValueInstanceDataHolder; - @StageRef WrappedValueInstanceDataHolderAccess wrappedValueInstanceDataHolderAccess; + + @StageRef + MapEntryStages entry; + @StageRef + WrappedValueInstanceDataHolder wrappedValueInstanceDataHolder; + @StageRef + WrappedValueInstanceDataHolderAccess wrappedValueInstanceDataHolderAccess; @Override public void hookAfterEachIteration() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapAbsentDelegatingForIteration.java b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapAbsentDelegatingForIteration.java index 8e367ce60..914945812 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapAbsentDelegatingForIteration.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapAbsentDelegatingForIteration.java @@ -34,10 +34,14 @@ import org.jetbrains.annotations.NotNull; public class ReplicatedMapAbsentDelegatingForIteration implements MapAbsentEntry, SetAbsentEntry, ReplicableEntryDelegating { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef ReplicatedMapSegmentIteration delegate; - @StageRef ReplicatedMapEntryStages e; - @StageRef DefaultValue defaultValue; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + ReplicatedMapSegmentIteration delegate; + @StageRef + ReplicatedMapEntryStages e; + @StageRef + DefaultValue defaultValue; @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapEntryDelegating.java b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapEntryDelegating.java index 8a89e20b4..0ab90d2be 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapEntryDelegating.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapEntryDelegating.java @@ -28,11 +28,13 @@ import net.openhft.sg.Staged; import org.jetbrains.annotations.NotNull; @Staged -public class ReplicatedMapEntryDelegating +public class ReplicatedMapEntryDelegating implements MapEntry, ReplicableEntryDelegating { - @StageRef ReplicatedMapSegmentIteration delegate; - @StageRef ReplicatedMapEntryStages e; + @StageRef + ReplicatedMapSegmentIteration delegate; + @StageRef + ReplicatedMapEntryStages e; @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapSegmentIteration.java b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapSegmentIteration.java index 7d61115f0..20ece5282 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapSegmentIteration.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedMapSegmentIteration.java @@ -41,14 +41,18 @@ public abstract class ReplicatedMapSegmentIteration extends MapSegmentI implements ReplicatedIterationContext, ReplicableEntry, ReplicatedHashSegmentContext> { - @StageRef VanillaChronicleMapHolder mh; - @StageRef ReplicatedMapEntryStages e; - @StageRef ReplicationUpdate ru; - @StageRef DummyValueZeroData dummyValue; - @StageRef ReplicatedMapAbsentDelegatingForIteration absentEntryDelegating; - @StageRef ReplicatedMapEntryDelegating entryDelegating; - - enum EntriesToTest {PRESENT, ALL} + @StageRef + VanillaChronicleMapHolder mh; + @StageRef + ReplicatedMapEntryStages e; + @StageRef + ReplicationUpdate ru; + @StageRef + DummyValueZeroData dummyValue; + @StageRef + ReplicatedMapAbsentDelegatingForIteration absentEntryDelegating; + @StageRef + ReplicatedMapEntryDelegating entryDelegating; EntriesToTest entriesToTest = null; void initEntriesToTest(EntriesToTest entriesToTest) { @@ -157,4 +161,6 @@ public abstract class ReplicatedMapSegmentIteration extends MapSegmentI ": Called SetAbsentEntry.doInsert() from Map context"); doInsert((Data) DummyValueData.INSTANCE); } + + enum EntriesToTest {PRESENT, ALL} } diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedTierRecovery.java b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedTierRecovery.java index b45d7bef1..266231357 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedTierRecovery.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/iter/ReplicatedTierRecovery.java @@ -36,9 +36,12 @@ import static net.openhft.chronicle.map.ChronicleHashCorruptionImpl.report; @Staged public class ReplicatedTierRecovery extends TierRecovery { - @StageRef ReplicatedChronicleMapHolder rh; - @StageRef SegmentStages s; - @StageRef ReplicatedMapEntryStages e; + @StageRef + ReplicatedChronicleMapHolder rh; + @StageRef + SegmentStages s; + @StageRef + ReplicatedMapEntryStages e; @Override public void removeDuplicatesInSegment( @@ -72,7 +75,7 @@ public class ReplicatedTierRecovery extends TierRecovery { long finalDeleted = deleted; report(corruptionListener, corruption, s.segmentIndex, () -> format("wrong deleted counter for tier with index {}, stored: {}, should be: {}", - s.tierIndex, s.tierDeleted(), finalDeleted) + s.tierIndex, s.tierDeleted(), finalDeleted) ); s.tierDeleted(deleted); } @@ -83,7 +86,7 @@ public class ReplicatedTierRecovery extends TierRecovery { ReplicatedChronicleMap.ModificationIterator[] its = m.acquireAllModificationIterators(); ReusableBitSet freeList = s.freeList; - for (long pos = 0; pos < m.actualChunksPerSegmentTier;) { + for (long pos = 0; pos < m.actualChunksPerSegmentTier; ) { long nextPos = freeList.nextSetBit(pos); if (nextPos > pos) { for (ReplicatedChronicleMap.ModificationIterator it : its) { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/DefaultValue.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/DefaultValue.java index 59b70c6ee..b68848cef 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/DefaultValue.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/DefaultValue.java @@ -27,8 +27,10 @@ import org.jetbrains.annotations.NotNull; @Staged public abstract class DefaultValue { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef DummyValueZeroData zeroValueData; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + DummyValueZeroData zeroValueData; @NotNull public Data defaultValue() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/MapEntryOperationsDelegation.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/MapEntryOperationsDelegation.java index dbecb2e70..0b73a23e0 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/MapEntryOperationsDelegation.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/MapEntryOperationsDelegation.java @@ -30,8 +30,10 @@ import org.jetbrains.annotations.NotNull; @Staged public abstract class MapEntryOperationsDelegation implements MapContext { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef VanillaChronicleMapHolder mh; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + VanillaChronicleMapHolder mh; @Override public R replaceValue(@NotNull MapEntry entry, Data newValue) { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/ReplicatedChronicleMapHolderImpl.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/ReplicatedChronicleMapHolderImpl.java index 6a52da9e1..00483c390 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/ReplicatedChronicleMapHolderImpl.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/ReplicatedChronicleMapHolderImpl.java @@ -34,7 +34,8 @@ public abstract class ReplicatedChronicleMapHolderImpl extends Chaining implements ReplicatedChronicleMapHolder { - @Stage("Map") private ReplicatedChronicleMap m = null; + @Stage("Map") + private ReplicatedChronicleMap m = null; public ReplicatedChronicleMapHolderImpl(VanillaChronicleMap map) { super(map); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/ValueBytesInterop.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/ValueBytesInterop.java index dca3a8515..58f7fbfa7 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/ValueBytesInterop.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/ValueBytesInterop.java @@ -27,7 +27,8 @@ import static net.openhft.chronicle.hash.serialization.StatefulCopyable.copyIfNe @Staged public class ValueBytesInterop { - @StageRef VanillaChronicleMapHolder mh; + @StageRef + VanillaChronicleMapHolder mh; public final SizedReader valueReader = copyIfNeeded(mh.m().valueReader); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/VanillaChronicleMapHolderImpl.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/VanillaChronicleMapHolderImpl.java index fb97533d3..e34abcfb4 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/VanillaChronicleMapHolderImpl.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/VanillaChronicleMapHolderImpl.java @@ -33,7 +33,8 @@ public abstract class VanillaChronicleMapHolderImpl extends Chaining implements VanillaChronicleMapHolder { - @Stage("Map") private VanillaChronicleMap m = null; + @Stage("Map") + private VanillaChronicleMap m = null; public VanillaChronicleMapHolderImpl(VanillaChronicleMap map) { super(map); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueBytesDataAccess.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueBytesDataAccess.java index a6c8a89b3..1435bc9c3 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueBytesDataAccess.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueBytesDataAccess.java @@ -29,8 +29,10 @@ import net.openhft.sg.Staged; @Staged public abstract class WrappedValueBytesDataAccess implements MapContext { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef WrappedValueBytesData wrappedValueBytesData; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + WrappedValueBytesData wrappedValueBytesData; @Override public Data wrapValueBytesAsData(BytesStore bytesStore, long offset, long size) { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueInstanceDataHolderAccess.java b/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueInstanceDataHolderAccess.java index 2a813147c..de12fb861 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueInstanceDataHolderAccess.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/map/WrappedValueInstanceDataHolderAccess.java @@ -29,8 +29,10 @@ import net.openhft.sg.Staged; public abstract class WrappedValueInstanceDataHolderAccess implements MapContext, SetContext { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef WrappedValueInstanceDataHolder wrappedValueInstanceDataHolder; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + WrappedValueInstanceDataHolder wrappedValueInstanceDataHolder; @Override public Data wrapValueAsData(V value) { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/AcquireHandle.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/AcquireHandle.java index 2c6cd2560..8e7d0a222 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/AcquireHandle.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/AcquireHandle.java @@ -25,10 +25,13 @@ import net.openhft.sg.Staged; @Staged public class AcquireHandle implements Closeable { - - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef MapQuery q; - @StageRef UsingReturnValue usingReturn; + + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + MapQuery q; + @StageRef + UsingReturnValue usingReturn; @Override public void close() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapAbsent.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapAbsent.java index 6e4fdc58a..726e39a6d 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapAbsent.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapAbsent.java @@ -35,13 +35,20 @@ import static net.openhft.chronicle.hash.impl.stage.query.KeySearch.SearchState. @Staged public abstract class MapAbsent implements Absent { - @StageRef public KeySearch ks; - @StageRef MapQuery q; - @StageRef MapEntryStages e; - @StageRef public HashLookupSearch hashLookupSearch; - @StageRef public CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef public SegmentStages s; - @StageRef VanillaChronicleMapHolder mh; + @StageRef + public KeySearch ks; + @StageRef + public HashLookupSearch hashLookupSearch; + @StageRef + public CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + public SegmentStages s; + @StageRef + MapQuery q; + @StageRef + MapEntryStages e; + @StageRef + VanillaChronicleMapHolder mh; void putEntry(Data value) { assert ks.searchStateAbsent(); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapQuery.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapQuery.java index 15ee373dd..c51ee959a 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapQuery.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/MapQuery.java @@ -45,22 +45,30 @@ public abstract class MapQuery extends HashQuery implements MapEntry, ExternalMapQueryContext, ExternalSetQueryContext, QueryContextInterface, MapAndSetContext { - @StageRef VanillaChronicleMapHolder mh; - @StageRef MapEntryStages e; - @StageRef SearchAllocatedChunks allocatedChunks; - @StageRef KeySearch ks; - @StageRef public AcquireHandle acquireHandle; - @StageRef InputKeyBytesData inputKeyBytesData; - - @StageRef public DefaultReturnValue defaultReturnValue; - @StageRef public UsingReturnValue usingReturnValue; - - @StageRef public MapAbsent absent; - + @StageRef + public AcquireHandle acquireHandle; + @StageRef + public DefaultReturnValue defaultReturnValue; + @StageRef + public UsingReturnValue usingReturnValue; + @StageRef + public MapAbsent absent; + @StageRef + VanillaChronicleMapHolder mh; final DataAccess innerInputValueDataAccess = mh.m().valueDataAccess.copy(); - - /** Same as {@link #inputKeyDataAccessInitialized} */ - @Stage("InputValueDataAccess") private boolean inputValueDataAccessInitialized = false; + @StageRef + MapEntryStages e; + @StageRef + SearchAllocatedChunks allocatedChunks; + @StageRef + KeySearch ks; + @StageRef + InputKeyBytesData inputKeyBytesData; + /** + * Same as {@link #inputKeyDataAccessInitialized} + */ + @Stage("InputValueDataAccess") + private boolean inputValueDataAccessInitialized = false; void initInputValueDataAccess() { inputValueDataAccessInitialized = true; @@ -89,7 +97,7 @@ public abstract class MapQuery extends HashQuery checkOnEachPublicOperation.checkOnEachPublicOperation(); return entryPresent() ? null : absent; } - + protected void putPrefix() { checkOnEachPublicOperation.checkOnEachPublicOperation(); if (!s.innerUpdateLock.isHeldByCurrentThread()) diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/QueryCheckOnEachPublicOperation.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/QueryCheckOnEachPublicOperation.java index 4f806bbdc..a1c806b78 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/QueryCheckOnEachPublicOperation.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/QueryCheckOnEachPublicOperation.java @@ -24,9 +24,10 @@ import net.openhft.sg.Staged; @Staged public class QueryCheckOnEachPublicOperation extends CheckOnEachPublicOperation { - - @StageRef HashQuery q; - + + @StageRef + HashQuery q; + @Override public void checkOnEachPublicOperation() { super.checkOnEachPublicOperation(); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsent.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsent.java index ecb5868e7..ca48b607a 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsent.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsent.java @@ -30,9 +30,12 @@ import static net.openhft.chronicle.hash.impl.stage.query.KeySearch.SearchState. @Staged public abstract class ReplicatedMapAbsent extends MapAbsent { - @StageRef MapQuery q; - @StageRef ReplicatedMapEntryStages e; - @StageRef ReplicationUpdate ru; + @StageRef + MapQuery q; + @StageRef + ReplicatedMapEntryStages e; + @StageRef + ReplicationUpdate ru; @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsentDelegating.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsentDelegating.java index e014515fc..880a55eb9 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsentDelegating.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapAbsentDelegating.java @@ -27,9 +27,12 @@ import org.jetbrains.annotations.NotNull; @Staged public class ReplicatedMapAbsentDelegating implements Absent { - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - @StageRef KeySearch ks; - @StageRef ReplicatedMapAbsent delegate; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; + @StageRef + KeySearch ks; + @StageRef + ReplicatedMapAbsent delegate; @NotNull @Override diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapQuery.java b/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapQuery.java index 54d4b9a16..de20455fe 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapQuery.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/query/ReplicatedMapQuery.java @@ -35,10 +35,15 @@ public abstract class ReplicatedMapQuery extends MapQuery implements MapRemoteQueryContext, SetRemoteQueryContext, ReplicableEntry, MapReplicableEntry, SetReplicableEntry { - @StageRef ReplicatedMapEntryStages e; - @StageRef ReplicationUpdate ru; + @StageRef + ReplicatedMapEntryStages e; + @StageRef + ReplicationUpdate ru; - @StageRef ReplicatedMapAbsentDelegating absentDelegating; + @StageRef + ReplicatedMapAbsentDelegating absentDelegating; + @StageRef + DummyValueZeroData dummyValue; @Nullable @Override @@ -60,8 +65,6 @@ public abstract class ReplicatedMapQuery extends MapQuery public boolean entryPresent() { return super.entryPresent() && !e.entryDeleted(); } - - @StageRef DummyValueZeroData dummyValue; @Override public ReplicatedMapQuery entry() { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicatedQueryAlloc.java b/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicatedQueryAlloc.java index 208285130..4c371293b 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicatedQueryAlloc.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicatedQueryAlloc.java @@ -37,13 +37,15 @@ import static net.openhft.chronicle.hash.replication.TimeProvider.systemTimeInte @Staged public class ReplicatedQueryAlloc extends QueryAlloc { - @StageRef ReplicatedChronicleMapHolder mh; - @StageRef SegmentStages s; - final CleanupAction cleanupAction = new CleanupAction(); + @StageRef + ReplicatedChronicleMapHolder mh; + @StageRef + SegmentStages s; /** * Returns {@code true} if at least one old deleted entry was removed. + * * @param prevPos position to skip during cleanup (because cleaned up separately) */ public boolean forcedOldDeletedEntriesCleanup(long prevPos) { @@ -60,28 +62,6 @@ public class ReplicatedQueryAlloc extends QueryAlloc { } } - private class CleanupAction implements Consumer { - int removedCompletely; - long posToSkip; - IterationContext iterationContext; - - @Override - public void accept(ReplicableEntry e) { - ReplicatedChronicleMap map = mh.m(); - if (!(e instanceof MapAbsentEntry) || iterationContext.pos() == posToSkip) - return; - long currentTime = currentTime(); - if (e.originTimestamp() > currentTime) - return; // presumably unsynchronized clocks - long deleteTimeout = systemTimeIntervalBetween( - e.originTimestamp(), currentTime, map.cleanupTimeoutUnit); - if (deleteTimeout <= map.cleanupTimeout || e.isChanged()) - return; - e.doRemoveCompletely(); - removedCompletely++; - } - } - @Override public long alloc(int chunks, long prevPos, int prevChunks) { long ret = s.allocReturnCode(chunks); @@ -121,4 +101,26 @@ public class ReplicatedQueryAlloc extends QueryAlloc { s.nextTier(); } } + + private class CleanupAction implements Consumer { + int removedCompletely; + long posToSkip; + IterationContext iterationContext; + + @Override + public void accept(ReplicableEntry e) { + ReplicatedChronicleMap map = mh.m(); + if (!(e instanceof MapAbsentEntry) || iterationContext.pos() == posToSkip) + return; + long currentTime = currentTime(); + if (e.originTimestamp() > currentTime) + return; // presumably unsynchronized clocks + long deleteTimeout = systemTimeIntervalBetween( + e.originTimestamp(), currentTime, map.cleanupTimeoutUnit); + if (deleteTimeout <= map.cleanupTimeout || e.isChanged()) + return; + e.doRemoveCompletely(); + removedCompletely++; + } + } } diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicationUpdate.java b/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicationUpdate.java index bbaf1469b..0c6f7aca6 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicationUpdate.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/replication/ReplicationUpdate.java @@ -28,14 +28,20 @@ import net.openhft.sg.Staged; @Staged public abstract class ReplicationUpdate implements RemoteOperationContext { - @StageRef SegmentStages s; - @StageRef ReplicatedMapEntryStages e; - @StageRef ReplicatedChronicleMapHolder mh; - @StageRef CheckOnEachPublicOperation checkOnEachPublicOperation; - - @Stage("ReplicationUpdate") public byte innerRemoteIdentifier = (byte) 0; - @Stage("ReplicationUpdate") public long innerRemoteTimestamp; - @Stage("ReplicationUpdate") public byte innerRemoteNodeIdentifier; + @Stage("ReplicationUpdate") + public byte innerRemoteIdentifier = (byte) 0; + @Stage("ReplicationUpdate") + public long innerRemoteTimestamp; + @Stage("ReplicationUpdate") + public byte innerRemoteNodeIdentifier; + @StageRef + SegmentStages s; + @StageRef + ReplicatedMapEntryStages e; + @StageRef + ReplicatedChronicleMapHolder mh; + @StageRef + CheckOnEachPublicOperation checkOnEachPublicOperation; public abstract boolean replicationUpdateInit(); @@ -50,7 +56,7 @@ public abstract class ReplicationUpdate implements RemoteOperationContext } innerRemoteNodeIdentifier = remoteNodeIdentifier; } - + public void dropChange() { mh.m().dropChange(s.tierIndex, e.pos); } @@ -62,7 +68,7 @@ public abstract class ReplicationUpdate implements RemoteOperationContext public void moveChange(long oldTierIndex, long oldPos, long newPos) { mh.m().moveChange(oldTierIndex, oldPos, s.tierIndex, newPos); } - + public void updateChange() { if (!replicationUpdateInit()) { raiseChange(); diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/ret/DefaultReturnValue.java b/src/main/java/net/openhft/chronicle/map/impl/stage/ret/DefaultReturnValue.java index 9c13eda27..d44ddbf67 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/ret/DefaultReturnValue.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/ret/DefaultReturnValue.java @@ -25,18 +25,18 @@ import org.jetbrains.annotations.NotNull; @Staged public abstract class DefaultReturnValue implements InstanceReturnValue { private V defaultReturnedValue = null; - + abstract boolean defaultReturnedValueInit(); - + private void initDefaultReturnedValue(@NotNull Data value) { defaultReturnedValue = value.getUsing(null); } - + @Override public void returnValue(@NotNull Data value) { initDefaultReturnedValue(value); } - + @Override public V returnValue() { if (defaultReturnedValueInit()) { diff --git a/src/main/java/net/openhft/chronicle/map/impl/stage/ret/UsingReturnValue.java b/src/main/java/net/openhft/chronicle/map/impl/stage/ret/UsingReturnValue.java index 4a4147b97..41f6cde03 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/stage/ret/UsingReturnValue.java +++ b/src/main/java/net/openhft/chronicle/map/impl/stage/ret/UsingReturnValue.java @@ -24,18 +24,17 @@ import org.jetbrains.annotations.NotNull; @Staged public abstract class UsingReturnValue implements UsableReturnValue { - + private V usingReturnValue = (V) USING_RETURN_VALUE_UNINIT; - + private V returnedValue = null; + @Override public void initUsingReturnValue(V usingReturnValue) { this.usingReturnValue = usingReturnValue; } - - private V returnedValue = null; - + abstract boolean returnedValueInit(); - + private void initReturnedValue(@NotNull Data value) { returnedValue = value.getUsing(usingReturnValue); } diff --git a/src/main/java/net/openhft/chronicle/map/replication/MapRemoteOperations.java b/src/main/java/net/openhft/chronicle/map/replication/MapRemoteOperations.java index a7b072bd2..2f91c09b7 100644 --- a/src/main/java/net/openhft/chronicle/map/replication/MapRemoteOperations.java +++ b/src/main/java/net/openhft/chronicle/map/replication/MapRemoteOperations.java @@ -20,7 +20,9 @@ package net.openhft.chronicle.map.replication; import net.openhft.chronicle.hash.Data; import net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy; import net.openhft.chronicle.hash.replication.ReplicableEntry; -import net.openhft.chronicle.map.*; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.MapAbsentEntry; +import net.openhft.chronicle.map.MapEntryOperations; import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.AcceptanceDecision.ACCEPT; import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.AcceptanceDecision.DISCARD; @@ -28,7 +30,7 @@ import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyS /** * SPI strategy of performing remote calls and apply replication events for {@link ChronicleMap}. - * + *

*

Example: Grow-only set values CRDT:


  * class GrowOnlySetValuedMapEntryOperations<K, E>
  *         implements MapEntryOperations<K, Set<E>, Void> {
@@ -38,7 +40,7 @@ import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyS
  *                 "doesn't support map value removals");
  *     }
  * }
- *
+ * 

* class GrowOnlySetValuedMapRemoteOperations<K, E> * implements MapRemoteOperations<K, Set<E>, Void> { * @Override @@ -54,7 +56,7 @@ import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyS * q.entry().updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); * } * } - * + *

* @Override * public void remove(MapRemoteQueryContext<K, Set<E>, Void> q) { * throw new UnsupportedOperationException(); @@ -65,7 +67,7 @@ import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyS * @param the map value type * @param the return type of {@link MapEntryOperations} specified fro the queried map * @see DefaultEventualConsistencyStrategy - * @see ChronicleMapBuilderPrivateAPI#remoteOperations(MapRemoteOperations) + * @see net.openhft.chronicle.map.ChronicleMapBuilderPrivateAPI#remoteOperations(MapRemoteOperations) */ public interface MapRemoteOperations { @@ -133,7 +135,7 @@ public interface MapRemoteOperations { * key ({@code q.queriedKey()}) was changed on some remote {@code ChronicleMap} node, with the * given {@code newValue}. * - * @param q the remote operation context + * @param q the remote operation context * @param newValue the new value to put */ default void put(MapRemoteQueryContext q, Data newValue) { diff --git a/src/main/java/net/openhft/chronicle/map/replication/MapRemoteQueryContext.java b/src/main/java/net/openhft/chronicle/map/replication/MapRemoteQueryContext.java index 7da123902..11febb832 100644 --- a/src/main/java/net/openhft/chronicle/map/replication/MapRemoteQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/replication/MapRemoteQueryContext.java @@ -45,7 +45,7 @@ public interface MapRemoteQueryContext extends MapQueryContext * SizeMarshaller#minStorableSize()} minimum possible size} for {@linkplain * ChronicleMapBuilder#valueSizeMarshaller(SizeMarshaller) the configured value size * marshaller}. - * + *

*

The returned value doesn't have object form (i. e. it's {@link Data#get()} and {@link * Data#getUsing(Object)} methods throw {@code UnsupportedOperationException}), it has only * bytes form, of all zero bytes. diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSet.java b/src/main/java/net/openhft/chronicle/set/ChronicleSet.java index 987334fc7..a7d6e30ec 100644 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSet.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSet.java @@ -36,7 +36,7 @@ public interface ChronicleSet * Delegates to {@link ChronicleSetBuilder#of(Class)} for convenience. * * @param keyClass class of the key type of the {@code ChronicleSet} to create - * @param the key type of the {@code ChronicleSet} to create + * @param the key type of the {@code ChronicleSet} to create * @return a new {@code ChronicleSetBuilder} for the given key class */ static ChronicleSetBuilder of(Class keyClass) { diff --git a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java index 5f8de25c1..a7d5d53d2 100755 --- a/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java +++ b/src/main/java/net/openhft/chronicle/set/ChronicleSetBuilder.java @@ -85,8 +85,7 @@ public final class ChronicleSetBuilder @Override public ChronicleSetBuilder clone() { try { - @SuppressWarnings("unchecked") - final ChronicleSetBuilder result = (ChronicleSetBuilder) super.clone(); + @SuppressWarnings("unchecked") final ChronicleSetBuilder result = (ChronicleSetBuilder) super.clone(); result.chronicleMapBuilder = chronicleMapBuilder.clone(); return result; } catch (CloneNotSupportedException e) { @@ -126,14 +125,14 @@ public final class ChronicleSetBuilder /** * {@inheritDoc} - * + *

*

Example: if keys in your set(s) are English words in {@link String} form, average English * word length is 5.1, configure average key size of 6:

{@code
      * ChronicleSet uniqueWords = ChronicleSetBuilder.of(String.class)
      *     .entries(50000)
      *     .averageKeySize(6)
      *     .create();}
- * + *

*

(Note that 6 is chosen as average 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}.) @@ -282,7 +281,7 @@ public final class ChronicleSetBuilder /** * Inject your SPI code around basic {@code ChronicleSet}'s operations with entries: * removing entries and inserting new entries. - * + *

*

This affects behaviour of ordinary set.add(), set.remove(), calls, as well as removes * during iterations, updates during remote calls and * internal replication operations. diff --git a/src/main/java/net/openhft/chronicle/set/DummyValueData.java b/src/main/java/net/openhft/chronicle/set/DummyValueData.java index 623f6baa3..392a6aa37 100644 --- a/src/main/java/net/openhft/chronicle/set/DummyValueData.java +++ b/src/main/java/net/openhft/chronicle/set/DummyValueData.java @@ -26,7 +26,8 @@ public class DummyValueData extends AbstractData { public static final DummyValueData INSTANCE = new DummyValueData(); - private DummyValueData() {} + private DummyValueData() { + } @Override public RandomDataInput bytes() { diff --git a/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java b/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java index 32a1c1ea9..1077a6bda 100644 --- a/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java +++ b/src/main/java/net/openhft/chronicle/set/DummyValueMarshaller.java @@ -29,7 +29,8 @@ final class DummyValueMarshaller implements DataAccess, SizedReader< EnumMarshallable { public static final DummyValueMarshaller INSTANCE = new DummyValueMarshaller(); - private DummyValueMarshaller() {} + private DummyValueMarshaller() { + } @Override public Data getData(@NotNull DummyValue instance) { diff --git a/src/main/java/net/openhft/chronicle/set/ExternalSetQueryContext.java b/src/main/java/net/openhft/chronicle/set/ExternalSetQueryContext.java index cb8c0e477..23c24aa6d 100644 --- a/src/main/java/net/openhft/chronicle/set/ExternalSetQueryContext.java +++ b/src/main/java/net/openhft/chronicle/set/ExternalSetQueryContext.java @@ -25,7 +25,7 @@ import net.openhft.chronicle.hash.ExternalHashQueryContext; * * @param the set key type * @param the return type of {@link SetEntryOperations}, specified for the queried {@code - * ChronicleSet} + * ChronicleSet} * @see ChronicleSet#queryContext(Object) */ public interface ExternalSetQueryContext diff --git a/src/main/java/net/openhft/chronicle/set/SetAbsentEntry.java b/src/main/java/net/openhft/chronicle/set/SetAbsentEntry.java index 2d3f283fb..99e6c9f80 100644 --- a/src/main/java/net/openhft/chronicle/set/SetAbsentEntry.java +++ b/src/main/java/net/openhft/chronicle/set/SetAbsentEntry.java @@ -25,7 +25,6 @@ import org.jetbrains.annotations.NotNull; * into the {@link ChronicleSet}. * * @param the set key type - * * @see SetEntryOperations * @see SetQueryContext#absentEntry() */ @@ -36,12 +35,12 @@ public interface SetAbsentEntry extends HashAbsentEntry { /** * Inserts {@link #absentKey() the new key} into the set. - * + *

*

This method is the default implementation for {@link SetEntryOperations#insert( - * SetAbsentEntry)}, which might be customized over the default. + *SetAbsentEntry)}, which might be customized over the default. * * @throws IllegalStateException if some locking/state conditions required to perform insertion - * operation are not met + * operation are not met * @see SetEntryOperations#insert(SetAbsentEntry) */ void doInsert(); diff --git a/src/main/java/net/openhft/chronicle/set/SetEntry.java b/src/main/java/net/openhft/chronicle/set/SetEntry.java index aaa999476..e0c148263 100644 --- a/src/main/java/net/openhft/chronicle/set/SetEntry.java +++ b/src/main/java/net/openhft/chronicle/set/SetEntry.java @@ -21,10 +21,10 @@ import net.openhft.chronicle.hash.HashEntry; /** * A context of a present entry in the {@link ChronicleSet}. - * + * * @param the set key type * @see SetEntryOperations - * @see SetQueryContext#entry() + * @see SetQueryContext#entry() */ public interface SetEntry extends HashEntry { @Override @@ -32,7 +32,7 @@ public interface SetEntry extends HashEntry { /** * Removes the entry from the {@code ChronicleSet}. - * + *

*

This method is the default implementation for {@link SetEntryOperations#remove(SetEntry)}, * which might be customized over the default. */ diff --git a/src/main/java/net/openhft/chronicle/set/SetEntryOperations.java b/src/main/java/net/openhft/chronicle/set/SetEntryOperations.java index 6fa51eb51..cd70b99f6 100644 --- a/src/main/java/net/openhft/chronicle/set/SetEntryOperations.java +++ b/src/main/java/net/openhft/chronicle/set/SetEntryOperations.java @@ -32,14 +32,13 @@ public interface SetEntryOperations { /** * Removes the given entry from the set. * - * @implNote default implementation calls {@link SetEntry#doRemove()} on the given entry and - * returns {@code null}. - * * @param entry the entry to remove * @return result of operation, understandable by higher-level SPIs * @throws IllegalStateException if some locking/state conditions required to perform remove - * operation are not met - * @throws RuntimeException if removal was unconditionally unsuccessful due to any reason + * operation are not met + * @throws RuntimeException if removal was unconditionally unsuccessful due to any reason + * @implNote default implementation calls {@link SetEntry#doRemove()} on the given entry and + * returns {@code null}. */ default R remove(@NotNull SetEntry entry) { entry.doRemove(); @@ -50,13 +49,12 @@ public interface SetEntryOperations { * Inserts the new entry into the set, of {@link SetAbsentEntry#absentKey() the key} from * the given insertion context (absentEntry). * - * @implNote default implementation calls {@link SetAbsentEntry#doInsert()} and returns - * {@code null}. - * * @return result of operation, understandable by higher-level SPIs * @throws IllegalStateException if some locking/state conditions required to perform insertion - * operation are not met - * @throws RuntimeException if insertion was unconditionally unsuccessful due to any reason + * operation are not met + * @throws RuntimeException if insertion was unconditionally unsuccessful due to any reason + * @implNote default implementation calls {@link SetAbsentEntry#doInsert()} and returns + * {@code null}. */ default R insert(@NotNull SetAbsentEntry absentEntry) { absentEntry.doInsert(); diff --git a/src/main/java/net/openhft/chronicle/set/replication/SetRemoteOperations.java b/src/main/java/net/openhft/chronicle/set/replication/SetRemoteOperations.java index cd616ff75..fcb7e4b38 100644 --- a/src/main/java/net/openhft/chronicle/set/replication/SetRemoteOperations.java +++ b/src/main/java/net/openhft/chronicle/set/replication/SetRemoteOperations.java @@ -25,7 +25,7 @@ import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyS import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.decideOnRemoteModification; public interface SetRemoteOperations { - + default void remove(SetRemoteQueryContext q) { SetReplicableEntry entry = q.entry(); if (entry != null) { diff --git a/src/main/java/net/openhft/xstream/converters/AbstractChronicleMapConverter.java b/src/main/java/net/openhft/xstream/converters/AbstractChronicleMapConverter.java index 9dba66601..2fb7578ac 100644 --- a/src/main/java/net/openhft/xstream/converters/AbstractChronicleMapConverter.java +++ b/src/main/java/net/openhft/xstream/converters/AbstractChronicleMapConverter.java @@ -22,7 +22,6 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import net.openhft.chronicle.values.ValueModel; import net.openhft.chronicle.values.Values; import org.jetbrains.annotations.NotNull; @@ -45,71 +44,6 @@ class AbstractChronicleMapConverter implements Converter { this.mapClazz = map.getClass(); } - @Override - public boolean canConvert(Class aClass) { - //noinspection unchecked - return mapClazz.isAssignableFrom(aClass); - } - - @Override - public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext - marshallingContext) { - - for (Map.Entry e : (Iterable) ((Map) o).entrySet()) { - - writer.startNode("entry"); - { - final Object key = e.getKey(); - writer.startNode(key.getClass().getName()); - marshallingContext.convertAnother(key); - writer.endNode(); - - Object value = e.getValue(); - writer.startNode(value.getClass().getName()); - marshallingContext.convertAnother(value); - writer.endNode(); - } - writer.endNode(); - } -} - - @Override - public Object unmarshal(HierarchicalStreamReader reader, - UnmarshallingContext context) { - // empty map - if ("[\"\"]".equals(reader.getValue())) - return null; - if (!"cmap".equals(reader.getNodeName())) - throw new ConversionException("should be under 'cmap' node"); - reader.moveDown(); - while (reader.hasMoreChildren()) { - reader.moveDown(); - - final String nodeName0 = reader.getNodeName(); - - if (!nodeName0.equals("entry")) - throw new ConversionException("unable to convert node named=" + nodeName0); - - final K k; - final V v; - - reader.moveDown(); - k = deserialize(context, reader); - reader.moveUp(); - - reader.moveDown(); - v = deserialize(context, reader); - reader.moveUp(); - - if (k != null) - map.put(k, v); - - reader.moveUp(); - } - reader.moveUp(); - return null; - } - private static E deserialize(@NotNull UnmarshallingContext unmarshallingContext, @NotNull HierarchicalStreamReader reader) { @@ -151,7 +85,72 @@ class AbstractChronicleMapConverter implements Converter { } catch (Exception e1) { throw new ConversionException("class=" + clazz, e1); } -} + } + } + + @Override + public boolean canConvert(Class aClass) { + //noinspection unchecked + return mapClazz.isAssignableFrom(aClass); + } + + @Override + public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext + marshallingContext) { + + for (Map.Entry e : (Iterable) ((Map) o).entrySet()) { + + writer.startNode("entry"); + { + final Object key = e.getKey(); + writer.startNode(key.getClass().getName()); + marshallingContext.convertAnother(key); + writer.endNode(); + + Object value = e.getValue(); + writer.startNode(value.getClass().getName()); + marshallingContext.convertAnother(value); + writer.endNode(); + } + writer.endNode(); + } + } + + @Override + public Object unmarshal(HierarchicalStreamReader reader, + UnmarshallingContext context) { + // empty map + if ("[\"\"]".equals(reader.getValue())) + return null; + if (!"cmap".equals(reader.getNodeName())) + throw new ConversionException("should be under 'cmap' node"); + reader.moveDown(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + + final String nodeName0 = reader.getNodeName(); + + if (!nodeName0.equals("entry")) + throw new ConversionException("unable to convert node named=" + nodeName0); + + final K k; + final V v; + + reader.moveDown(); + k = deserialize(context, reader); + reader.moveUp(); + + reader.moveDown(); + v = deserialize(context, reader); + reader.moveUp(); + + if (k != null) + map.put(k, v); + + reader.moveUp(); + } + reader.moveUp(); + return null; } } diff --git a/src/main/java/net/openhft/xstream/converters/CharSequenceConverter.java b/src/main/java/net/openhft/xstream/converters/CharSequenceConverter.java index ac5c22740..61d6f814c 100644 --- a/src/main/java/net/openhft/xstream/converters/CharSequenceConverter.java +++ b/src/main/java/net/openhft/xstream/converters/CharSequenceConverter.java @@ -22,7 +22,6 @@ import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; -import net.openhft.chronicle.hash.impl.util.CharSequences; public class CharSequenceConverter implements Converter { diff --git a/src/test/java/eg/BigData.java b/src/test/java/eg/BigData.java index c62c9c9ca..e52db7810 100644 --- a/src/test/java/eg/BigData.java +++ b/src/test/java/eg/BigData.java @@ -35,11 +35,12 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class BigData { final static long MAXSIZE = 1000 * 1000 * 1000L; + static final ChronicleMapBuilder builder = + ChronicleMapBuilder.of(Long.class, BigDataStuff.class); //run 1st test with no map, and Highwatermark set to 0 //then switch to Highwatermark set to MAXSIZE for subsequent test repeats static AtomicInteger Highwatermark = new AtomicInteger((int) MAXSIZE); - static final ChronicleMapBuilder builder = - ChronicleMapBuilder.of(Long.class, BigDataStuff.class); + static Map theMap; // static AtomicInteger Highwatermark = new AtomicInteger(0); static { @@ -50,15 +51,13 @@ public class BigData { String chmPath = dir + "/testmap-" + Long.toString(System.nanoTime(), 36); new File(chmPath).deleteOnExit(); try { - theMap = builder.createPersistedTo(new File(chmPath)); + theMap = builder.createPersistedTo(new File(chmPath)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } - static Map theMap; - public static void main(String[] args) throws IOException, InterruptedException { long start = System.currentTimeMillis(); initialbuild(); diff --git a/src/test/java/eg/OffHeapByteArrayExampleTest.java b/src/test/java/eg/OffHeapByteArrayExampleTest.java index 3e925b1b9..55613b1f8 100644 --- a/src/test/java/eg/OffHeapByteArrayExampleTest.java +++ b/src/test/java/eg/OffHeapByteArrayExampleTest.java @@ -31,14 +31,6 @@ import org.junit.Test; public class OffHeapByteArrayExampleTest { public static final char EXPECTED = 'b'; - - interface ByteArray { - @Array(length = 7) - void setByteValueAt(int index, ByteValue value); - - ByteValue getByteValueAt(int index); - } - private static ChronicleMap chm; @BeforeClass @@ -84,4 +76,11 @@ public class OffHeapByteArrayExampleTest { Assert.assertEquals(EXPECTED, actual); } + + interface ByteArray { + @Array(length = 7) + void setByteValueAt(int index, ByteValue value); + + ByteValue getByteValueAt(int index); + } } diff --git a/src/test/java/eg/TestInstrumentVOInterface.java b/src/test/java/eg/TestInstrumentVOInterface.java index 60d090bb7..2c5875c88 100644 --- a/src/test/java/eg/TestInstrumentVOInterface.java +++ b/src/test/java/eg/TestInstrumentVOInterface.java @@ -26,6 +26,7 @@ import net.openhft.chronicle.values.MaxUtf8Length; public interface TestInstrumentVOInterface { int getSizeOfInstrumentIDArray(); + void setSizeOfInstrumentIDArray(int sizeOfInstrumentIDArray); String getSymbol(); diff --git a/src/test/java/eg/WordCountTest.java b/src/test/java/eg/WordCountTest.java index 3b7670a97..19da14b0b 100644 --- a/src/test/java/eg/WordCountTest.java +++ b/src/test/java/eg/WordCountTest.java @@ -35,6 +35,7 @@ public class WordCountTest { static String[] words; static int expectedSize; + static { try { // english version of war and peace -> ascii diff --git a/src/test/java/examples/portfolio/PortfolioAssetInterface.java b/src/test/java/examples/portfolio/PortfolioAssetInterface.java index dbc7fd742..0b1200ddf 100644 --- a/src/test/java/examples/portfolio/PortfolioAssetInterface.java +++ b/src/test/java/examples/portfolio/PortfolioAssetInterface.java @@ -1,13 +1,15 @@ package examples.portfolio; -public interface PortfolioAssetInterface -{ - public long getAssetId(); - public void setAssetId(long assetId); +public interface PortfolioAssetInterface { + public long getAssetId(); - public int getShares(); - public void setShares(int shares); + public void setAssetId(long assetId); - public double getPrice(); - public void setPrice(double price); + public int getShares(); + + public void setShares(int shares); + + public double getPrice(); + + public void setPrice(double price); } \ No newline at end of file diff --git a/src/test/java/examples/portfolio/PortfolioValueAccumulator.java b/src/test/java/examples/portfolio/PortfolioValueAccumulator.java index 23f0364f3..59cb12559 100644 --- a/src/test/java/examples/portfolio/PortfolioValueAccumulator.java +++ b/src/test/java/examples/portfolio/PortfolioValueAccumulator.java @@ -1,26 +1,23 @@ package examples.portfolio; -import java.util.function.Consumer; - -import org.apache.commons.lang3.mutable.MutableDouble; - import net.openhft.chronicle.core.values.LongValue; import net.openhft.chronicle.map.MapEntry; +import org.apache.commons.lang3.mutable.MutableDouble; -public final class PortfolioValueAccumulator implements Consumer> -{ - final MutableDouble total; - final PortfolioAssetInterface asset; - public PortfolioValueAccumulator(MutableDouble total, PortfolioAssetInterface asset) - { - this.total = total; - this.asset = asset; - } +import java.util.function.Consumer; - @Override - public void accept(MapEntry e) - { - e.value().getUsing(asset); - total.add(asset.getShares() * asset.getPrice()); - } +public final class PortfolioValueAccumulator implements Consumer> { + final MutableDouble total; + final PortfolioAssetInterface asset; + + public PortfolioValueAccumulator(MutableDouble total, PortfolioAssetInterface asset) { + this.total = total; + this.asset = asset; + } + + @Override + public void accept(MapEntry e) { + e.value().getUsing(asset); + total.add(asset.getShares() * asset.getPrice()); + } } \ No newline at end of file diff --git a/src/test/java/examples/portfolio/PortfolioValueTest.java b/src/test/java/examples/portfolio/PortfolioValueTest.java index 92177d83c..6da0797f8 100644 --- a/src/test/java/examples/portfolio/PortfolioValueTest.java +++ b/src/test/java/examples/portfolio/PortfolioValueTest.java @@ -1,163 +1,140 @@ package examples.portfolio; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.apache.commons.lang3.mutable.MutableDouble; -import org.junit.Test; - import net.openhft.chronicle.core.values.LongValue; import net.openhft.chronicle.map.ChronicleMap; import net.openhft.chronicle.map.ChronicleMapBuilder; import net.openhft.chronicle.map.MapSegmentContext; import net.openhft.chronicle.values.Values; +import org.apache.commons.lang3.mutable.MutableDouble; +import org.junit.Test; -public class PortfolioValueTest -{ - private static final boolean useIterator = true; - private static final long nAssets = 10_000_000; - private static final int nThreads = Runtime.getRuntime().availableProcessors(); - private static final int nRepetitions = 11; // 10 for computing average, throwing away the first one (warmup) +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; - @Test - public void test() throws ExecutionException, InterruptedException - { - ChronicleMapBuilder mapBuilder = ChronicleMapBuilder.of(LongValue.class, PortfolioAssetInterface.class).entries(nAssets); +public class PortfolioValueTest { + private static final boolean useIterator = true; + private static final long nAssets = 10_000_000; + private static final int nThreads = Runtime.getRuntime().availableProcessors(); + private static final int nRepetitions = 11; // 10 for computing average, throwing away the first one (warmup) - try (ChronicleMap cache = mapBuilder.create()) - { - createData(cache); + private static void computeValue(final ChronicleMap cache) throws ExecutionException, InterruptedException { + computeValueUsingIterator(cache); + } - // Compute multiple times to get an reasonable average compute time - for (int i = 0; i < nRepetitions; i++) - { - computeValue(cache); - } - } - } + private static void computeValueUsingIterator(final ChronicleMap cache) throws ExecutionException, InterruptedException { + long startTime = System.currentTimeMillis(); - private void createData(final ChronicleMap cache) throws ExecutionException, InterruptedException - { - long startTime = System.currentTimeMillis(); + ExecutorService executor = Executors.newFixedThreadPool(nThreads); + @SuppressWarnings("unchecked") + Future[] futures = new Future[nThreads]; + long batchSize = (useIterator ? cache.segments() : nAssets) / nThreads; - ExecutorService executor = Executors.newFixedThreadPool(nThreads); - Future[] futures = new Future[nThreads]; - long batchSize = nAssets / nThreads; + // Map + for (int t = 0; t < nThreads; t++) { + final int batch = t; - for (int t = 0; t < nThreads; t++) - { - final long batch = t; - futures[t] = executor.submit(() -> { - final LongValue key = Values.newHeapInstance(LongValue.class); - final PortfolioAssetInterface value = Values.newHeapInstance(PortfolioAssetInterface.class); + futures[t] = executor.submit(() -> { + if (useIterator) { + int start = (int) (batch * batchSize); + int end = (int) Math.min(cache.segments(), (batch + 1) * batchSize); + return computeTotalUsingIterator(cache, start, end); + } else { + long start = batch * batchSize; + long end = Math.min(nAssets, (batch + 1) * batchSize); + return computeTotalUsingKeys(cache, start, end); + } + }); + } - long start = batch * batchSize; - long end = Math.min(nAssets, (batch + 1) * batchSize); - long n = (end - start); + // Reduce + double total = 0; + for (Future future : futures) { + total += future.get(); + } - if (end > start) - { - System.out.println("Inserting batch " + (batch + 1) + "/" + nThreads + " of " + n + " records"); + long elapsedTime = (System.currentTimeMillis() - startTime); + System.out.println("Total Portfolio Value: " + total + " for " + cache.longSize() + ", computed in " + elapsedTime + " ms, using " + (useIterator ? "Iterator" : "Keys")); + } - for (long k = start; k < end; k++) - { - key.setValue(k); - value.setAssetId(k); - value.setShares(1); - value.setPrice(2.0); - cache.put(key, value); - } - } - }); - } + protected static double computeTotalUsingIterator(final ChronicleMap cache, int start, int end) { + if (end > start) { + final PortfolioAssetInterface asset = Values.newHeapInstance(PortfolioAssetInterface.class); + PortfolioValueAccumulator accumulator = new PortfolioValueAccumulator(new MutableDouble(), asset); + for (int s = start; s < end; s++) { + try (MapSegmentContext context = cache.segmentContext(s)) { + context.forEachSegmentEntry(accumulator); + } + } + return accumulator.total.doubleValue(); + } + return 0; + } - for (Future future : futures) - { - future.get(); - } + protected static double computeTotalUsingKeys(final ChronicleMap cache, long start, long end) { + final LongValue key = Values.newHeapInstance(LongValue.class); + PortfolioAssetInterface asset = Values.newHeapInstance(PortfolioAssetInterface.class); - long elapsedTime = (System.currentTimeMillis() - startTime); - System.out.println("Data inserted in " + elapsedTime + " ms"); - } + double total = 0; + for (long k = start; k < end; k++) { + key.setValue(k); + asset = cache.getUsing(key, asset); + total += asset.getShares() * asset.getPrice(); + } + return total; + } - private static void computeValue(final ChronicleMap cache) throws ExecutionException, InterruptedException - { - computeValueUsingIterator(cache); - } + @Test + public void test() throws ExecutionException, InterruptedException { + ChronicleMapBuilder mapBuilder = ChronicleMapBuilder.of(LongValue.class, PortfolioAssetInterface.class).entries(nAssets); - private static void computeValueUsingIterator(final ChronicleMap cache) throws ExecutionException, InterruptedException - { - long startTime = System.currentTimeMillis(); + try (ChronicleMap cache = mapBuilder.create()) { + createData(cache); - ExecutorService executor = Executors.newFixedThreadPool(nThreads); - @SuppressWarnings("unchecked") - Future[] futures = new Future[nThreads]; - long batchSize = (useIterator ? cache.segments() : nAssets) / nThreads; + // Compute multiple times to get an reasonable average compute time + for (int i = 0; i < nRepetitions; i++) { + computeValue(cache); + } + } + } - // Map - for (int t = 0; t < nThreads; t++) - { - final int batch = t; + private void createData(final ChronicleMap cache) throws ExecutionException, InterruptedException { + long startTime = System.currentTimeMillis(); - futures[t] = executor.submit(() -> { - if (useIterator) - { - int start = (int) (batch * batchSize); - int end = (int) Math.min(cache.segments(), (batch + 1) * batchSize); - return computeTotalUsingIterator(cache, start, end); - } - else - { - long start = batch * batchSize; - long end = Math.min(nAssets, (batch + 1) * batchSize); - return computeTotalUsingKeys(cache, start, end); - } - }); - } + ExecutorService executor = Executors.newFixedThreadPool(nThreads); + Future[] futures = new Future[nThreads]; + long batchSize = nAssets / nThreads; - // Reduce - double total = 0; - for (Future future : futures) - { - total += future.get(); - } + for (int t = 0; t < nThreads; t++) { + final long batch = t; + futures[t] = executor.submit(() -> { + final LongValue key = Values.newHeapInstance(LongValue.class); + final PortfolioAssetInterface value = Values.newHeapInstance(PortfolioAssetInterface.class); - long elapsedTime = (System.currentTimeMillis() - startTime); - System.out.println("Total Portfolio Value: " + total + " for " + cache.longSize() + ", computed in " + elapsedTime + " ms, using " + (useIterator ? "Iterator" : "Keys")); - } + long start = batch * batchSize; + long end = Math.min(nAssets, (batch + 1) * batchSize); + long n = (end - start); - protected static double computeTotalUsingIterator(final ChronicleMap cache, int start, int end) - { - if (end > start) - { - final PortfolioAssetInterface asset = Values.newHeapInstance(PortfolioAssetInterface.class); - PortfolioValueAccumulator accumulator = new PortfolioValueAccumulator(new MutableDouble(), asset); - for (int s = start; s < end; s++) - { - try (MapSegmentContext context = cache.segmentContext(s)) - { - context.forEachSegmentEntry(accumulator); - } - } - return accumulator.total.doubleValue(); - } - return 0; - } + if (end > start) { + System.out.println("Inserting batch " + (batch + 1) + "/" + nThreads + " of " + n + " records"); - protected static double computeTotalUsingKeys(final ChronicleMap cache, long start, long end) - { - final LongValue key = Values.newHeapInstance(LongValue.class); - PortfolioAssetInterface asset = Values.newHeapInstance(PortfolioAssetInterface.class); + for (long k = start; k < end; k++) { + key.setValue(k); + value.setAssetId(k); + value.setShares(1); + value.setPrice(2.0); + cache.put(key, value); + } + } + }); + } - double total = 0; - for (long k = start; k < end; k++) - { - key.setValue(k); - asset = cache.getUsing(key, asset); - total += asset.getShares() * asset.getPrice(); - } - return total; - } + for (Future future : futures) { + future.get(); + } + + long elapsedTime = (System.currentTimeMillis() - startTime); + System.out.println("Data inserted in " + elapsedTime + " ms"); + } } diff --git a/src/test/java/net/openhft/chronicle/map/BasicReplicationTest.java b/src/test/java/net/openhft/chronicle/map/BasicReplicationTest.java index 667dc8245..28f398830 100644 --- a/src/test/java/net/openhft/chronicle/map/BasicReplicationTest.java +++ b/src/test/java/net/openhft/chronicle/map/BasicReplicationTest.java @@ -6,11 +6,7 @@ import org.hamcrest.CoreMatchers; import org.junit.Test; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; +import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -24,6 +20,10 @@ import static org.junit.Assert.assertThat; public class BasicReplicationTest { + private static byte asByte(final int i) { + return (byte) i; + } + @Test public void shouldReplicate() throws Exception { final ChronicleMapBuilder builder = ChronicleMap.of(String.class, String.class) @@ -54,7 +54,7 @@ public class BasicReplicationTest { executorService.submit(processorTwo::processPendingChangesLoop); executorService.submit(processorThree::processPendingChangesLoop); - final Map[] maps = new Map[] {mapOne, mapTwo, mapThree}; + final Map[] maps = new Map[]{mapOne, mapTwo, mapThree}; final Random random = new Random(0xBAD5EED); for (int i = 0; i < 5000; i++) { final int mapIndex = random.nextInt(maps.length); @@ -77,7 +77,7 @@ public class BasicReplicationTest { assertThat(mapOne.size(), is(equalTo(mapTwo.size()))); assertThat(mapOne.size(), is(equalTo(mapThree.size()))); - for(String key : mapOne.keySet()) { + for (String key : mapOne.keySet()) { final String mapOneValue = mapOne.get(key); final String mapTwoValue = mapTwo.get(key); final String mapThreeValue = mapThree.get(key); @@ -102,8 +102,10 @@ public class BasicReplicationTest { } } - private static byte asByte(final int i) { - return (byte) i; + private ReplicatedChronicleMap + createReplicatedMap(final ChronicleMapBuilder builder, final byte replicaId) { + final ChronicleMap map = builder.replication(replicaId).create(); + return (ReplicatedChronicleMap) map; } private static final class ReplicationEventProcessor { @@ -131,7 +133,7 @@ public class BasicReplicationTest { try { - while(!Thread.currentThread().isInterrupted()) { + while (!Thread.currentThread().isInterrupted()) { while (queueEmpty.get() && !Thread.currentThread().isInterrupted()) { LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(7)); } @@ -170,7 +172,7 @@ public class BasicReplicationTest { @Override public void onEntry(final ReplicableEntry entry, final int chronicleId) { - try { + try { buffer.clear(); sourceMap.writeExternalEntry(entry, null, buffer, chronicleId); @@ -203,10 +205,4 @@ public class BasicReplicationTest { destinationMap.setRemoteNodeCouldBootstrapFrom((byte) chronicleId, bootstrapTime); } } - - private ReplicatedChronicleMap - createReplicatedMap(final ChronicleMapBuilder builder, final byte replicaId) { - final ChronicleMap map = builder.replication(replicaId).create(); - return (ReplicatedChronicleMap) map; - } } \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/map/BiMapTest.java b/src/test/java/net/openhft/chronicle/map/BiMapTest.java index c47236479..ef8573057 100644 --- a/src/test/java/net/openhft/chronicle/map/BiMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/BiMapTest.java @@ -35,7 +35,101 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class BiMapTest { - + + private static void verifyBiMapConsistent(Map m1, Map m2) { + assertEquals(m1.size(), m2.size()); + for (Entry e : m1.entrySet()) { + assertEquals(e.getKey(), m2.get(e.getValue())); + } + } + + @Test + public void biMapTest() throws InterruptedException, ExecutionException { + BiMapEntryOperations biMapOps1 = new BiMapEntryOperations<>(); + ChronicleMap map1 = ChronicleMapBuilder + .of(Integer.class, CharSequence.class) + .entries(100) + .actualSegments(1) + .averageValueSize(10) + .entryOperations(biMapOps1) + .mapMethods(new BiMapMethods<>()) + .create(); + + BiMapEntryOperations biMapOps2 = new BiMapEntryOperations<>(); + ChronicleMap map2 = ChronicleMapBuilder + .of(CharSequence.class, Integer.class) + .entries(100) + .actualSegments(1) + .averageKeySize(10) + .entryOperations(biMapOps2) + .mapMethods(new BiMapMethods<>()) + .create(); + + biMapOps1.setReverse(map2); + biMapOps2.setReverse(map1); + + map1.put(1, "1"); + verifyBiMapConsistent(map1, map2); + + map2.remove("1"); + assertTrue(map2.isEmpty()); + verifyBiMapConsistent(map1, map2); + + map1.put(3, "4"); + map2.put("5", 6); + verifyBiMapConsistent(map1, map2); + + try (ExternalMapQueryContext q = map2.queryContext("4")) { + q.updateLock().lock(); + q.entry().doRemove(); + } + + try { + map1.remove(3); + throw new AssertionError("expected IllegalStateException"); + } catch (IllegalStateException e) { + // expected + } + + try { + map2.put("4", 6); + throw new AssertionError("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + map2.put("4", 3); // recover + verifyBiMapConsistent(map1, map2); + + map1.clear(); + verifyBiMapConsistent(map1, map2); + + ForkJoinPool pool = new ForkJoinPool(8); + try { + pool.submit(() -> { + ThreadLocalRandom.current().ints().limit(10_000).parallel().forEach(i -> { + int v = Math.abs(i % 10); + if ((i & 1) == 0) { + if ((i & 2) == 0) { + map1.putIfAbsent(v, "" + v); + } else { + map1.remove(v, "" + v); + } + } else { + if ((i & 2) == 0) { + map2.putIfAbsent("" + v, v); + } else { + map2.remove("" + v, v); + } + } + }); + }).get(); + verifyBiMapConsistent(map1, map2); + } finally { + pool.shutdownNow(); + } + } + enum DualLockSuccess {SUCCESS, FAIL} static class BiMapMethods implements MapMethods { @@ -217,98 +311,4 @@ public class BiMapTest { } } } - - @Test - public void biMapTest() throws InterruptedException, ExecutionException { - BiMapEntryOperations biMapOps1 = new BiMapEntryOperations<>(); - ChronicleMap map1 = ChronicleMapBuilder - .of(Integer.class, CharSequence.class) - .entries(100) - .actualSegments(1) - .averageValueSize(10) - .entryOperations(biMapOps1) - .mapMethods(new BiMapMethods<>()) - .create(); - - BiMapEntryOperations biMapOps2 = new BiMapEntryOperations<>(); - ChronicleMap map2 = ChronicleMapBuilder - .of(CharSequence.class, Integer.class) - .entries(100) - .actualSegments(1) - .averageKeySize(10) - .entryOperations(biMapOps2) - .mapMethods(new BiMapMethods<>()) - .create(); - - biMapOps1.setReverse(map2); - biMapOps2.setReverse(map1); - - map1.put(1, "1"); - verifyBiMapConsistent(map1, map2); - - map2.remove("1"); - assertTrue(map2.isEmpty()); - verifyBiMapConsistent(map1, map2); - - map1.put(3, "4"); - map2.put("5", 6); - verifyBiMapConsistent(map1, map2); - - try (ExternalMapQueryContext q = map2.queryContext("4")) { - q.updateLock().lock(); - q.entry().doRemove(); - } - - try { - map1.remove(3); - throw new AssertionError("expected IllegalStateException"); - } catch (IllegalStateException e) { - // expected - } - - try { - map2.put("4", 6); - throw new AssertionError("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - - map2.put("4", 3); // recover - verifyBiMapConsistent(map1, map2); - - map1.clear(); - verifyBiMapConsistent(map1, map2); - - ForkJoinPool pool = new ForkJoinPool(8); - try { - pool.submit(() -> { - ThreadLocalRandom.current().ints().limit(10_000).parallel().forEach(i -> { - int v = Math.abs(i % 10); - if ((i & 1) == 0) { - if ((i & 2) == 0) { - map1.putIfAbsent(v, "" + v); - } else { - map1.remove(v, "" + v); - } - } else { - if ((i & 2) == 0) { - map2.putIfAbsent("" + v, v); - } else { - map2.remove("" + v, v); - } - } - }); - }).get(); - verifyBiMapConsistent(map1, map2); - } finally { - pool.shutdownNow(); - } - } - - private static void verifyBiMapConsistent(Map m1, Map m2) { - assertEquals(m1.size(), m2.size()); - for (Entry e : m1.entrySet()) { - assertEquals(e.getKey(), m2.get(e.getValue())); - } - } } diff --git a/src/test/java/net/openhft/chronicle/map/BytesMarshallableValueTest.java b/src/test/java/net/openhft/chronicle/map/BytesMarshallableValueTest.java index dce02eb2b..cd1e6b390 100644 --- a/src/test/java/net/openhft/chronicle/map/BytesMarshallableValueTest.java +++ b/src/test/java/net/openhft/chronicle/map/BytesMarshallableValueTest.java @@ -44,5 +44,5 @@ public class BytesMarshallableValueTest { this.x = x; this.foo = foo; } -} + } } diff --git a/src/test/java/net/openhft/chronicle/map/CHMTest5.java b/src/test/java/net/openhft/chronicle/map/CHMTest5.java index f94f3d11a..3d99ee741 100644 --- a/src/test/java/net/openhft/chronicle/map/CHMTest5.java +++ b/src/test/java/net/openhft/chronicle/map/CHMTest5.java @@ -237,26 +237,30 @@ public class CHMTest5 { @Group(0) long getEntryLockState(); + void setEntryLockState(long entryLockState); @Group(1) int getMaxNumberOfProcessesAllowed(); + void setMaxNumberOfProcessesAllowed(int max); + boolean compareAndSwapMaxNumberOfProcessesAllowed(int expected, int value); @Group(1) @Array(length = 4) void setTimeAt(int index, long time); + long getTimeAt(int index); @Deprecated() default boolean tryLockNanosEntry(long nanos) { return AcquisitionStrategies .spinLoop(nanos, TimeUnit.NANOSECONDS).acquire( - TryAcquireOperations.writeLock(), - VanillaReadWriteWithWaitsLockingStrategy.instance(), - checkedBytesStoreAccess(), ((Byteable) this).bytesStore(), - ((Byteable) this).offset()); + TryAcquireOperations.writeLock(), + VanillaReadWriteWithWaitsLockingStrategy.instance(), + checkedBytesStoreAccess(), ((Byteable) this).bytesStore(), + ((Byteable) this).offset()); } @Deprecated() diff --git a/src/test/java/net/openhft/chronicle/map/CHMUseCasesTest.java b/src/test/java/net/openhft/chronicle/map/CHMUseCasesTest.java index 45e2cf654..4f4e82320 100644 --- a/src/test/java/net/openhft/chronicle/map/CHMUseCasesTest.java +++ b/src/test/java/net/openhft/chronicle/map/CHMUseCasesTest.java @@ -225,7 +225,7 @@ public class CHMUseCasesTest { for (; t < timeOutMs; t++) { if (map1.equals(map2)) break; - Jvm.pause(1); + Jvm.pause(1); } } @@ -445,7 +445,7 @@ public class CHMUseCasesTest { mpx1030.setAskPx(109.7); mpx1030.setBidPx(107.6); } -} + } } @@ -1022,7 +1022,7 @@ public class CHMUseCasesTest { } catch (Exception todoMoreSpecificException) { } -} + } } @Test diff --git a/src/test/java/net/openhft/chronicle/map/ChronicleMapImportExportTest.java b/src/test/java/net/openhft/chronicle/map/ChronicleMapImportExportTest.java index 2ecc5a549..9d5ecd7b9 100644 --- a/src/test/java/net/openhft/chronicle/map/ChronicleMapImportExportTest.java +++ b/src/test/java/net/openhft/chronicle/map/ChronicleMapImportExportTest.java @@ -157,8 +157,8 @@ public class ChronicleMapImportExportTest { System.out.println(file.getAbsolutePath()); ChronicleMapBuilder builder = ChronicleMapBuilder.of(CharSequence.class, CharSequence.class) - .averageKeySize("hello".length()).averageValueSize("world".length()) - .entries(1000); + .averageKeySize("hello".length()).averageValueSize("world".length()) + .entries(1000); try (ChronicleMap expected = builder .create()) { expected.put("hello", "world"); diff --git a/src/test/java/net/openhft/chronicle/map/ChronicleMapSanityCheckTest.java b/src/test/java/net/openhft/chronicle/map/ChronicleMapSanityCheckTest.java index d3f4d4e38..d57333f85 100644 --- a/src/test/java/net/openhft/chronicle/map/ChronicleMapSanityCheckTest.java +++ b/src/test/java/net/openhft/chronicle/map/ChronicleMapSanityCheckTest.java @@ -36,8 +36,7 @@ import java.util.concurrent.locks.LockSupport; public class ChronicleMapSanityCheckTest { @Test - public void testSanity1() throws IOException, InterruptedException - { + public void testSanity1() throws IOException, InterruptedException { String tmp = System.getProperty("java.io.tmpdir"); @@ -120,7 +119,7 @@ public class ChronicleMapSanityCheckTest { throw new RuntimeException(e); } } -} + } enum DummyValue { DUMMY_VALUE diff --git a/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java b/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java index 99a8902e3..a2fa122f9 100755 --- a/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/ChronicleMapTest.java @@ -34,7 +34,6 @@ import java.io.IOException; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; import static java.util.stream.Collectors.toSet; import static org.junit.Assert.*; @@ -42,7 +41,13 @@ import static org.junit.Assert.*; @SuppressWarnings({"unchecked", "ResultOfMethodCallIgnored"}) public class ChronicleMapTest { + static final LongValue ONE = Values.newHeapInstance(LongValue.class); static long count = 0; + + static { + ONE.setValue(1); + } + private StringBuilder sb = new StringBuilder(); static void assertKeySet(Set keySet, int[] expectedKeys) { @@ -107,6 +112,20 @@ public class ChronicleMapTest { return file; } + private static void printStatus() { + if (!new File("/proc/self/status").exists()) return; + try { + BufferedReader br = new BufferedReader(new FileReader("/proc/self/status")); + for (String line; (line = br.readLine()) != null; ) + if (line.startsWith("Vm")) + System.out.print(line.replaceAll(" +", " ") + ", "); + + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + private ChronicleMap getViewTestMap(int noOfElements) throws IOException { ChronicleMap map = ChronicleMapBuilder.of(Integer.class, CharSequence.class) @@ -128,20 +147,6 @@ public class ChronicleMapTest { } - private static void printStatus() { - if (!new File("/proc/self/status").exists()) return; - try { - BufferedReader br = new BufferedReader(new FileReader("/proc/self/status")); - for (String line; (line = br.readLine()) != null; ) - if (line.startsWith("Vm")) - System.out.print(line.replaceAll(" +", " ") + ", "); - - br.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - @Test public void testRemoveWithKey() { @@ -226,7 +231,7 @@ public class ChronicleMapTest { assertEquals(map1, map2); } -} + } } @Test @@ -249,7 +254,7 @@ public class ChronicleMapTest { assertEquals(map1, map2); } -} + } } @Test @@ -272,7 +277,7 @@ public class ChronicleMapTest { assertEquals(map1, map2); } -} + } } @Test @@ -482,6 +487,37 @@ public class ChronicleMapTest { } } + // i7-3970X CPU @ 3.50GHz, hex core: -verbose:gc -Xmx64m + // to tmpfs file system + // 10M users, updated 12 times. Throughput 19.3 M ops/sec, no GC! + // 50M users, updated 12 times. Throughput 19.8 M ops/sec, no GC! + // 100M users, updated 12 times. Throughput 19.0M ops/sec, no GC! + // 200M users, updated 12 times. Throughput 18.4 M ops/sec, no GC! + // 400M users, updated 12 times. Throughput 18.4 M ops/sec, no GC! + + // to ext4 file system. + // 10M users, updated 12 times. Throughput 17.7 M ops/sec, no GC! + // 50M users, updated 12 times. Throughput 16.5 M ops/sec, no GC! + // 100M users, updated 12 times. Throughput 15.9 M ops/sec, no GC! + // 200M users, updated 12 times. Throughput 15.4 M ops/sec, no GC! + // 400M users, updated 12 times. Throughput 7.8 M ops/sec, no GC! + // 600M users, updated 12 times. Throughput 5.8 M ops/sec, no GC! + + // dual E5-2650v2 @ 2.6 GHz, 128 GB: -verbose:gc -Xmx32m + // to tmpfs + // TODO small GC on startup should be tidied up, [GC 9216K->1886K(31744K), 0.0036750 secs] + // 10M users, updated 16 times. Throughput 33.0M ops/sec, VmPeak: 5373848 kB, VmRSS: 544252 kB + // 50M users, updated 16 times. Throughput 31.2 M ops/sec, VmPeak: 9091804 kB, VmRSS: 3324732 kB + // 250M users, updated 16 times. Throughput 30.0 M ops/sec, VmPeak: 24807836 kB, VmRSS: 14329112 kB + // 1000M users, updated 16 times, Throughput 24.1 M ops/sec, VmPeak: 85312732 kB, VmRSS: 57165952 kB + // 2500M users, updated 16 times, Throughput 23.5 M ops/sec, VmPeak: 189545308 kB, VmRSS: 126055868 kB + + // to ext4 + // 10M users, updated 16 times. Throughput 28.4 M ops/sec, VmPeak: 5438652 kB, VmRSS: 544624 kB + // 50M users, updated 16 times. Throughput 28.2 M ops/sec, VmPeak: 9091804 kB, VmRSS: 9091804 kB + // 250M users, updated 16 times. Throughput 26.1 M ops/sec, VmPeak: 24807836 kB, VmRSS: 24807836 kB + // 1000M users, updated 16 times, Throughput 1.3 M ops/sec, TODO FIX this + @Test public void testRemoveWithKeyAndValue() { @@ -534,36 +570,17 @@ public class ChronicleMapTest { } } - // i7-3970X CPU @ 3.50GHz, hex core: -verbose:gc -Xmx64m - // to tmpfs file system - // 10M users, updated 12 times. Throughput 19.3 M ops/sec, no GC! - // 50M users, updated 12 times. Throughput 19.8 M ops/sec, no GC! - // 100M users, updated 12 times. Throughput 19.0M ops/sec, no GC! - // 200M users, updated 12 times. Throughput 18.4 M ops/sec, no GC! - // 400M users, updated 12 times. Throughput 18.4 M ops/sec, no GC! + // i7-3970X CPU @ 3.50GHz, hex core: -Xmx30g -verbose:gc + // 10M users, updated 12 times. Throughput 16.2 M ops/sec, longest [Full GC 853669K->852546K(3239936K), 0.8255960 secs] + // 50M users, updated 12 times. Throughput 13.3 M ops/sec, longest [Full GC 5516214K->5511353K(13084544K), 3.5752970 secs] + // 100M users, updated 12 times. Throughput 11.8 M ops/sec, longest [Full GC 11240703K->11233711K(19170432K), 5.8783010 secs] + // 200M users, updated 12 times. Throughput 4.2 M ops/sec, longest [Full GC 25974721K->22897189K(27962048K), 21.7962600 secs] - // to ext4 file system. - // 10M users, updated 12 times. Throughput 17.7 M ops/sec, no GC! - // 50M users, updated 12 times. Throughput 16.5 M ops/sec, no GC! - // 100M users, updated 12 times. Throughput 15.9 M ops/sec, no GC! - // 200M users, updated 12 times. Throughput 15.4 M ops/sec, no GC! - // 400M users, updated 12 times. Throughput 7.8 M ops/sec, no GC! - // 600M users, updated 12 times. Throughput 5.8 M ops/sec, no GC! - - // dual E5-2650v2 @ 2.6 GHz, 128 GB: -verbose:gc -Xmx32m - // to tmpfs - // TODO small GC on startup should be tidied up, [GC 9216K->1886K(31744K), 0.0036750 secs] - // 10M users, updated 16 times. Throughput 33.0M ops/sec, VmPeak: 5373848 kB, VmRSS: 544252 kB - // 50M users, updated 16 times. Throughput 31.2 M ops/sec, VmPeak: 9091804 kB, VmRSS: 3324732 kB - // 250M users, updated 16 times. Throughput 30.0 M ops/sec, VmPeak: 24807836 kB, VmRSS: 14329112 kB - // 1000M users, updated 16 times, Throughput 24.1 M ops/sec, VmPeak: 85312732 kB, VmRSS: 57165952 kB - // 2500M users, updated 16 times, Throughput 23.5 M ops/sec, VmPeak: 189545308 kB, VmRSS: 126055868 kB - - // to ext4 - // 10M users, updated 16 times. Throughput 28.4 M ops/sec, VmPeak: 5438652 kB, VmRSS: 544624 kB - // 50M users, updated 16 times. Throughput 28.2 M ops/sec, VmPeak: 9091804 kB, VmRSS: 9091804 kB - // 250M users, updated 16 times. Throughput 26.1 M ops/sec, VmPeak: 24807836 kB, VmRSS: 24807836 kB - // 1000M users, updated 16 times, Throughput 1.3 M ops/sec, TODO FIX this + // dual E5-2650v2 @ 2.6 GHz, 128 GB: -verbose:gc -Xmx100g + // 10M users, updated 16 times. Throughput 155.3 M ops/sec, VmPeak: 113291428 kB, VmRSS: 9272176 kB, [Full GC 1624336K->1616457K(7299072K), 2.5381610 secs] + // 50M users, updated 16 times. Throughput 120.4 M ops/sec, VmPeak: 113291428 kB, VmRSS: 28436248 kB [Full GC 6545332K->6529639K(18179584K), 6.9053810 secs] + // 250M users, updated 16 times. Throughput 114.1 M ops/sec, VmPeak: 113291428 kB, VmRSS: 76441464 kB [Full GC 41349527K->41304543K(75585024K), 17.3217490 secs] + // 1000M users, OutOfMemoryError. @Test public void testGetWithNullContainer() { @@ -592,18 +609,6 @@ public class ChronicleMapTest { } } - // i7-3970X CPU @ 3.50GHz, hex core: -Xmx30g -verbose:gc - // 10M users, updated 12 times. Throughput 16.2 M ops/sec, longest [Full GC 853669K->852546K(3239936K), 0.8255960 secs] - // 50M users, updated 12 times. Throughput 13.3 M ops/sec, longest [Full GC 5516214K->5511353K(13084544K), 3.5752970 secs] - // 100M users, updated 12 times. Throughput 11.8 M ops/sec, longest [Full GC 11240703K->11233711K(19170432K), 5.8783010 secs] - // 200M users, updated 12 times. Throughput 4.2 M ops/sec, longest [Full GC 25974721K->22897189K(27962048K), 21.7962600 secs] - - // dual E5-2650v2 @ 2.6 GHz, 128 GB: -verbose:gc -Xmx100g - // 10M users, updated 16 times. Throughput 155.3 M ops/sec, VmPeak: 113291428 kB, VmRSS: 9272176 kB, [Full GC 1624336K->1616457K(7299072K), 2.5381610 secs] - // 50M users, updated 16 times. Throughput 120.4 M ops/sec, VmPeak: 113291428 kB, VmRSS: 28436248 kB [Full GC 6545332K->6529639K(18179584K), 6.9053810 secs] - // 250M users, updated 16 times. Throughput 114.1 M ops/sec, VmPeak: 113291428 kB, VmRSS: 76441464 kB [Full GC 41349527K->41304543K(75585024K), 17.3217490 secs] - // 1000M users, OutOfMemoryError. - @Test public void testAcquireAndGet() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException { @@ -709,7 +714,7 @@ public class ChronicleMapTest { assertEquals(j, value3.getValue()); } } -} + } } } @@ -800,7 +805,7 @@ public class ChronicleMapTest { } } } -} + } @Test public void testLargerEntries() { @@ -996,12 +1001,6 @@ public class ChronicleMapTest { es.awaitTermination(1, TimeUnit.MINUTES); } - static final LongValue ONE = Values.newHeapInstance(LongValue.class); - - static { - ONE.setValue(1); - } - @Test @Ignore("Performance test") public void testAcquireLockedPerf() @@ -1263,7 +1262,7 @@ public class ChronicleMapTest { assertNull(map.getUsing(key, value)); } } -} + } } @Test @@ -1282,7 +1281,7 @@ public class ChronicleMapTest { assertValues(values, new CharSequence[]{"1", "3"}); assertValues(map.values(), new CharSequence[]{"1", "3"}); } -} + } @Test public void mapPutReflectedInViews() throws IOException { @@ -1332,7 +1331,7 @@ public class ChronicleMapTest { assertValues(values, new CharSequence[]{"1", "3"}); } -} + } @Test public void valuesRemoveReflectedInMap() throws IOException { @@ -1348,7 +1347,7 @@ public class ChronicleMapTest { assertValues(values, new CharSequence[]{"1", "3"}); } -} + } @Test public void entrySetIteratorRemoveReflectedInMapAndOtherViews() throws IOException { @@ -1391,7 +1390,7 @@ public class ChronicleMapTest { assertValues(values, expectedValues); } -} + } @Test public void valuesIteratorRemoveReflectedInMapAndOtherViews() throws IOException { @@ -1418,7 +1417,7 @@ public class ChronicleMapTest { assertValues(values, expectedValues); } -} + } @Test public void entrySetRemoveAllReflectedInMapAndOtherViews() throws IOException { @@ -1439,7 +1438,7 @@ public class ChronicleMapTest { assertValues(values, new CharSequence[]{"3"}); } -} + } @Test public void keySetRemoveAllReflectedInMapAndOtherViews() throws IOException { @@ -1455,7 +1454,7 @@ public class ChronicleMapTest { assertValues(values, new CharSequence[]{"3"}); } -} + } @Test public void valuesRemoveAllReflectedInMapAndOtherViews() throws IOException { @@ -1505,7 +1504,7 @@ public class ChronicleMapTest { assertValues(values, new CharSequence[]{"2", "1"}); } -} + } @Test public void valuesRetainAllReflectedInMapAndOtherViews() throws IOException { @@ -1537,7 +1536,7 @@ public class ChronicleMapTest { org.junit.Assert.assertTrue(values.isEmpty()); } -} + } @Test public void keySetClearReflectedInMapAndOtherViews() throws IOException { @@ -1569,7 +1568,7 @@ public class ChronicleMapTest { org.junit.Assert.assertTrue(values.isEmpty()); } -} + } @Test public void clearMapViaEntryIteratorRemoves() throws IOException { @@ -1587,7 +1586,7 @@ public class ChronicleMapTest { assertEquals(noOfElements, sum); } -} + } @Test public void clearMapViaKeyIteratorRemoves() throws IOException { @@ -1660,7 +1659,7 @@ public class ChronicleMapTest { assertValues(map.values(), new String[]{"B"}); } -} + } @Test public void equalsTest() throws IOException { @@ -1679,40 +1678,7 @@ public class ChronicleMapTest { assertEquals(map1, map2); } } -} - - private static final class IncrementRunnable implements Runnable { - - private final ChronicleMap map; - - private final CharSequence key; - - private final int iterations; - - private final CyclicBarrier barrier; - - private IncrementRunnable(ChronicleMap map, CharSequence key, - int iterations, CyclicBarrier barrier) { - this.map = map; - this.key = key; - this.iterations = iterations; - this.barrier = barrier; - } - - @Override - public void run() { - try { - LongValue value = Values.newNativeReference(LongValue.class); - barrier.await(); - for (int i = 0; i < iterations; i++) { - map.acquireUsing(key, value); - value.addAtomicValue(1); - } - } catch (Exception e) { - e.printStackTrace(); - } - } -} + } @Test public void testPutLongValue() throws IOException { @@ -1733,7 +1699,7 @@ public class ChronicleMapTest { throw new AssertionError("Should throw either IllegalStateException or " + "NullPointerException, but succeed"); } -} + } @Test public void testOffheapAcquireUsingLocked() throws IOException { @@ -1789,7 +1755,7 @@ public class ChronicleMapTest { assert value == v; assertEquals(1, c.entry().value().get().getValue()); } -} + } } @Test(expected = IllegalArgumentException.class) @@ -1897,5 +1863,38 @@ public class ChronicleMapTest { tmpFile.delete(); } + private static final class IncrementRunnable implements Runnable { + + private final ChronicleMap map; + + private final CharSequence key; + + private final int iterations; + + private final CyclicBarrier barrier; + + private IncrementRunnable(ChronicleMap map, CharSequence key, + int iterations, CyclicBarrier barrier) { + this.map = map; + this.key = key; + this.iterations = iterations; + this.barrier = barrier; + } + + @Override + public void run() { + try { + LongValue value = Values.newNativeReference(LongValue.class); + barrier.await(); + for (int i = 0; i < iterations; i++) { + map.acquireUsing(key, value); + value.addAtomicValue(1); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } diff --git a/src/test/java/net/openhft/chronicle/map/ConstantSizeBySampleTest.java b/src/test/java/net/openhft/chronicle/map/ConstantSizeBySampleTest.java index 8738608c6..08bcf3741 100644 --- a/src/test/java/net/openhft/chronicle/map/ConstantSizeBySampleTest.java +++ b/src/test/java/net/openhft/chronicle/map/ConstantSizeBySampleTest.java @@ -65,6 +65,38 @@ public class ConstantSizeBySampleTest { } } + @Test + public void testUnexpectedlyLongConstantExternalizableValues() throws IOException { + try (ChronicleMap map = + ChronicleMapBuilder.of(Long.class, ExternalizableData.class) + .valueReaderAndDataAccess(new ExternalizableDataReader(), + new ExternalizableDataDataAccess()) + .constantValueSizeBySample(new ExternalizableData()) + .entries(100) + .actualSegments(1) + .create()) { + ExternalizableData value = new ExternalizableData(); + value.data[42] = 1; + map.put(1L, value); + Assert.assertEquals(map.get(1L), value); + } + } + + @Test + public void testUnexpectedlyLongConstantSerializableValues() throws IOException { + try (ChronicleMap map = + ChronicleMapBuilder.of(Long.class, SerializableData.class) + .constantValueSizeBySample(new SerializableData()) + .entries(100) + .actualSegments(1) + .create()) { + SerializableData value = new SerializableData(); + value.data[42] = 1; + map.put(1L, value); + Assert.assertEquals(map.get(1L), value); + } + } + static class ExternalizableData implements Externalizable { byte[] data = new byte[512 * 1024]; @@ -86,23 +118,6 @@ public class ConstantSizeBySampleTest { } } - @Test - public void testUnexpectedlyLongConstantExternalizableValues() throws IOException { - try ( ChronicleMap map = - ChronicleMapBuilder.of(Long.class, ExternalizableData.class) - .valueReaderAndDataAccess(new ExternalizableDataReader(), - new ExternalizableDataDataAccess()) - .constantValueSizeBySample(new ExternalizableData()) - .entries(100) - .actualSegments(1) - .create()) { - ExternalizableData value = new ExternalizableData(); - value.data[42] = 1; - map.put(1L, value); - Assert.assertEquals(map.get(1L), value); - } - } - static class SerializableData implements Serializable { byte[] data = new byte[512 * 1024]; @@ -114,21 +129,6 @@ public class ConstantSizeBySampleTest { } } - @Test - public void testUnexpectedlyLongConstantSerializableValues() throws IOException { - try ( ChronicleMap map = - ChronicleMapBuilder.of(Long.class, SerializableData.class) - .constantValueSizeBySample(new SerializableData()) - .entries(100) - .actualSegments(1) - .create()) { - SerializableData value = new SerializableData(); - value.data[42] = 1; - map.put(1L, value); - Assert.assertEquals(map.get(1L), value); - } - } - private static class ExternalizableDataDataAccess extends ExternalizableDataAccess implements Serializable { public ExternalizableDataDataAccess() { diff --git a/src/test/java/net/openhft/chronicle/map/DatasetTrackerIssue61Test.java b/src/test/java/net/openhft/chronicle/map/DatasetTrackerIssue61Test.java index 129b5ff99..c4b5cbaa0 100644 --- a/src/test/java/net/openhft/chronicle/map/DatasetTrackerIssue61Test.java +++ b/src/test/java/net/openhft/chronicle/map/DatasetTrackerIssue61Test.java @@ -56,7 +56,9 @@ public class DatasetTrackerIssue61Test { this.value = value; } - /** According to Externalizable spec, there should be a public no-arg constructor */ + /** + * According to Externalizable spec, there should be a public no-arg constructor + */ public Value() { } diff --git a/src/test/java/net/openhft/chronicle/map/DeflatorStringMarshaller.java b/src/test/java/net/openhft/chronicle/map/DeflatorStringMarshaller.java index dd619b470..bdc1d2808 100644 --- a/src/test/java/net/openhft/chronicle/map/DeflatorStringMarshaller.java +++ b/src/test/java/net/openhft/chronicle/map/DeflatorStringMarshaller.java @@ -36,13 +36,12 @@ import java.util.zip.InflaterInputStream; public final class DeflatorStringMarshaller implements BytesReader, BytesWriter, EnumMarshallable { public static final DeflatorStringMarshaller INSTANCE = new DeflatorStringMarshaller(); - - private DeflatorStringMarshaller() {} - private static final StringFactory STRING_FACTORY = getStringFactory(); - private static final int NULL_LENGTH = -1; + private DeflatorStringMarshaller() { + } + private static StringFactory getStringFactory() { try { return new StringFactory17(); diff --git a/src/test/java/net/openhft/chronicle/map/DemoChronicleMapTest.java b/src/test/java/net/openhft/chronicle/map/DemoChronicleMapTest.java index 1451c9b94..6fca59a77 100755 --- a/src/test/java/net/openhft/chronicle/map/DemoChronicleMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/DemoChronicleMapTest.java @@ -27,13 +27,28 @@ import java.io.IOException; import java.util.Map; import static net.openhft.chronicle.values.Values.newNativeReference; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +interface DemoOrderVOInterface { + public CharSequence getSymbol(); +// public StringBuilder getUsingSymbol(StringBuilder sb); + + public void setSymbol(@MaxUtf8Length(20) CharSequence symbol); + + public double addAtomicOrderQty(double toAdd); + + public double getOrderQty(); + + public void setOrderQty(double orderQty); + +} public class DemoChronicleMapTest { @Test public void testMap() throws IOException { - File file = File.createTempFile("DummyOrders"+System.currentTimeMillis(), ".test"); + File file = File.createTempFile("DummyOrders" + System.currentTimeMillis(), ".test"); file.deleteOnExit(); int maxEntries = 1000; try (ChronicleMap map = ChronicleMapBuilder @@ -75,7 +90,7 @@ public class DemoChronicleMapTest { @Test public void testMapLocked() throws IOException { - File file = File.createTempFile("DummyOrders-"+System.currentTimeMillis(), ".test"); + File file = File.createTempFile("DummyOrders-" + System.currentTimeMillis(), ".test"); file.deleteOnExit(); int maxEntries = 1000; try (ChronicleMap map = ChronicleMapBuilder @@ -118,17 +133,3 @@ public class DemoChronicleMapTest { file.delete(); } } - -interface DemoOrderVOInterface { - public CharSequence getSymbol(); -// public StringBuilder getUsingSymbol(StringBuilder sb); - - public void setSymbol(@MaxUtf8Length(20) CharSequence symbol); - - public double addAtomicOrderQty(double toAdd); - - public double getOrderQty(); - - public void setOrderQty(double orderQty); - -} diff --git a/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java b/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java index e6d62e447..0ca603594 100644 --- a/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/EntryCountMapTest.java @@ -36,9 +36,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class EntryCountMapTest { + static final String TMP = System.getProperty("java.io.tmpdir"); + static final int ecmTests = Integer.getInteger("ecm.tests", 5); double score = 0; int scoreCount = 0; - static final String TMP = System.getProperty("java.io.tmpdir"); static File getPersistenceFile() throws IOException { File file = File.createTempFile("ecm-chm-test", ".deleteme"); @@ -57,7 +58,9 @@ public class EntryCountMapTest { return mapBuilder.createPersistedTo(getPersistenceFile()); } - static final int ecmTests = Integer.getInteger("ecm.tests", 5); + private static int moreThanMaxSize(int maxSize) { + return maxSize * 14 / 10 + 300; + } @Ignore("HCOLL-279 fix net.openhft.chronicle.map.EntryCountMapTest#testVerySmall") @Test @@ -256,10 +259,6 @@ public class EntryCountMapTest { ", seg: " + segments + ", min: " + minSize + ", size: " + map.size()); } -} - - private static int moreThanMaxSize(int maxSize) { - return maxSize * 14 / 10 + 300; } private void dumpMapStats(int segments, int minSize, diff --git a/src/test/java/net/openhft/chronicle/map/ExitHookTest.java b/src/test/java/net/openhft/chronicle/map/ExitHookTest.java index 1aad7647e..cc620e8dd 100644 --- a/src/test/java/net/openhft/chronicle/map/ExitHookTest.java +++ b/src/test/java/net/openhft/chronicle/map/ExitHookTest.java @@ -32,6 +32,44 @@ public class ExitHookTest { @Rule public TemporaryFolder folder = new TemporaryFolder(); + public static void main(String[] args) throws IOException, InterruptedException { + System.out.println("Other process started"); + File mapFile = new File(args[0]); + ChronicleMap map = createMap(mapFile); + try (ExternalMapQueryContext c = map.queryContext(KEY)) { + c.writeLock().lock(); + try { + map.close(); + } finally { + Thread.sleep(30_000); + } + } + } + + private static ChronicleMap createMap(File mapFile) throws IOException { + return ChronicleMap + .of(Integer.class, Integer.class) + .entries(1) + .createPersistedTo(mapFile); + } + + // http://stackoverflow.com/a/33171840/648955 + public static long getPidOfProcess(Process p) { + long pid = -1; + + try { + if (p.getClass().getName().equals("java.lang.UNIXProcess")) { + Field f = p.getClass().getDeclaredField("pid"); + f.setAccessible(true); + pid = f.getLong(p); + f.setAccessible(false); + } + } catch (Exception e) { + pid = -1; + } + return pid; + } + @Test public void testExitHook() throws IOException, InterruptedException { if (!OS.isLinux() && !OS.isMacOSX()) @@ -55,27 +93,6 @@ public class ExitHookTest { } } - public static void main(String[] args) throws IOException, InterruptedException { - System.out.println("Other process started"); - File mapFile = new File(args[0]); - ChronicleMap map = createMap(mapFile); - try (ExternalMapQueryContext c = map.queryContext(KEY)) { - c.writeLock().lock(); - try { - map.close(); - } finally { - Thread.sleep(30_000); - } - } - } - - private static ChronicleMap createMap(File mapFile) throws IOException { - return ChronicleMap - .of(Integer.class, Integer.class) - .entries(1) - .createPersistedTo(mapFile); - } - // http://stackoverflow.com/a/7835467/648955 private void interruptProcess(long pidOfProcess) throws IOException { Runtime.getRuntime().exec("kill -SIGINT " + pidOfProcess); @@ -96,21 +113,4 @@ public class ExitHookTest { builder.inheritIO(); return builder.start(); } - - // http://stackoverflow.com/a/33171840/648955 - public static long getPidOfProcess(Process p) { - long pid = -1; - - try { - if (p.getClass().getName().equals("java.lang.UNIXProcess")) { - Field f = p.getClass().getDeclaredField("pid"); - f.setAccessible(true); - pid = f.getLong(p); - f.setAccessible(false); - } - } catch (Exception e) { - pid = -1; - } - return pid; - } } diff --git a/src/test/java/net/openhft/chronicle/map/GuavaTest.java b/src/test/java/net/openhft/chronicle/map/GuavaTest.java index a3614adda..4b4773976 100644 --- a/src/test/java/net/openhft/chronicle/map/GuavaTest.java +++ b/src/test/java/net/openhft/chronicle/map/GuavaTest.java @@ -48,7 +48,7 @@ public class GuavaTest extends TestCase { TestSuite backedTests = backed .named("Guava tests tests of Chronicle Map, backed with HashMap") .createTestSuite(); - + TestSuite tests = new TestSuite(); tests.addTest(chmTests); // TODO @@ -121,9 +121,9 @@ public class GuavaTest extends TestCase { return builder.create(); } } - + static class BackedUpMapGenerator extends CHMTestGenerator { - + @Override Map newMap() { Map m = new HashMap<>(); diff --git a/src/test/java/net/openhft/chronicle/map/Histogram.java b/src/test/java/net/openhft/chronicle/map/Histogram.java index 3d0149fa5..457028c37 100755 --- a/src/test/java/net/openhft/chronicle/map/Histogram.java +++ b/src/test/java/net/openhft/chronicle/map/Histogram.java @@ -24,9 +24,9 @@ public class Histogram { static final String[] FRACTION_STR = "worst,99.99,99.9,99,90,50".split(","); static final int[] FRACTIONS = {Integer.MAX_VALUE, 10000, 1000, 100, 10, 2}; static final int BITS_OF_ACCURACY = 5; - final int[] counters = new int[40 << BITS_OF_ACCURACY]; static final int MANTISSA = 52; static final int BITS_TO_TRUNCATE = MANTISSA - BITS_OF_ACCURACY; + final int[] counters = new int[40 << BITS_OF_ACCURACY]; long count = 0; public void sample(long value) { diff --git a/src/test/java/net/openhft/chronicle/map/Issue110Test.java b/src/test/java/net/openhft/chronicle/map/Issue110Test.java index 7d9afde3f..13a251e9d 100644 --- a/src/test/java/net/openhft/chronicle/map/Issue110Test.java +++ b/src/test/java/net/openhft/chronicle/map/Issue110Test.java @@ -5,12 +5,6 @@ import net.openhft.chronicle.values.Values; import org.junit.Test; public class Issue110Test { - interface IContainer { - @Array(length=10) - double getDoubleArrayAt(int i); - void setDoubleArrayAt(int i, double d); - } - @Test public void testChronicleDoubleArray() { ChronicleMap map = @@ -22,4 +16,11 @@ public class Issue110Test { map.put("0", Values.newHeapInstance(IContainer.class)); assert map.get("0") != null; } + + interface IContainer { + @Array(length = 10) + double getDoubleArrayAt(int i); + + void setDoubleArrayAt(int i, double d); + } } diff --git a/src/test/java/net/openhft/chronicle/map/Issue43Test.java b/src/test/java/net/openhft/chronicle/map/Issue43Test.java index 030e39335..eb62ce6c6 100644 --- a/src/test/java/net/openhft/chronicle/map/Issue43Test.java +++ b/src/test/java/net/openhft/chronicle/map/Issue43Test.java @@ -59,13 +59,14 @@ public class Issue43Test { EnumMarshallable { public static final ArrayMarshaller INSTANCE = new ArrayMarshaller(); - private ArrayMarshaller() {} + private ArrayMarshaller() { + } @Override public void write(Bytes bytes, @NotNull ValueWrapper vw) { bytes.writeInt(vw.values.length); - for (int i = 0; i < vw.values.length; i ++) { + for (int i = 0; i < vw.values.length; i++) { bytes.writeDouble(vw.values[i]); } } diff --git a/src/test/java/net/openhft/chronicle/map/Issue58.java b/src/test/java/net/openhft/chronicle/map/Issue58.java index 2e78ecdac..104ac109e 100644 --- a/src/test/java/net/openhft/chronicle/map/Issue58.java +++ b/src/test/java/net/openhft/chronicle/map/Issue58.java @@ -78,7 +78,7 @@ public class Issue58 { .collect(toMap(k -> data.get(k), k -> k)); reverseMap.putAll(reverse); } -} + } public void test1(Map data) throws IOException { try ( @@ -125,13 +125,14 @@ public class Issue58 { map.entrySet().forEach(e -> System.out.println(e.getKey() + "->" + e.getValue())); reverseMap.forEach((k, v) -> System.out.println(k + " -> " + v)); } -} + } static final class UuidMarshaller implements BytesReader, BytesWriter, EnumMarshallable { public static final UuidMarshaller INSTANCE = new UuidMarshaller(); - private UuidMarshaller() {} + private UuidMarshaller() { + } @Override public void write(Bytes bytes, @NotNull UUID uuid) { diff --git a/src/test/java/net/openhft/chronicle/map/Issue62ChronicleClient.java b/src/test/java/net/openhft/chronicle/map/Issue62ChronicleClient.java index af915d3f9..7734f4125 100644 --- a/src/test/java/net/openhft/chronicle/map/Issue62ChronicleClient.java +++ b/src/test/java/net/openhft/chronicle/map/Issue62ChronicleClient.java @@ -44,7 +44,7 @@ public class Issue62ChronicleClient { .replication((byte) 2); try (ChronicleMap map = - cityPostalCodesMapBuilder.createPersistedTo(MAP_FILE_B)) { + cityPostalCodesMapBuilder.createPersistedTo(MAP_FILE_B)) { LOGGER.info("Starting"); Jvm.pause(3000); diff --git a/src/test/java/net/openhft/chronicle/map/Issue62ChronicleServer.java b/src/test/java/net/openhft/chronicle/map/Issue62ChronicleServer.java index 5b0ea70a7..303bd6286 100644 --- a/src/test/java/net/openhft/chronicle/map/Issue62ChronicleServer.java +++ b/src/test/java/net/openhft/chronicle/map/Issue62ChronicleServer.java @@ -58,7 +58,7 @@ public class Issue62ChronicleServer { ChronicleMap cityPostalCodes = cityPostalCodesMapBuilder.createPersistedTo(MAP_FILE_A); - for(int i = 0; i < 100; i++ ) { + for (int i = 0; i < 100; i++) { cityPostalCodes.put(STR + i, (long) i); } diff --git a/src/test/java/net/openhft/chronicle/map/LataTest.java b/src/test/java/net/openhft/chronicle/map/LataTest.java index 9894609d4..2067ddb85 100644 --- a/src/test/java/net/openhft/chronicle/map/LataTest.java +++ b/src/test/java/net/openhft/chronicle/map/LataTest.java @@ -22,12 +22,6 @@ import net.openhft.chronicle.values.Values; public class LataTest { - public interface IData { - int getData(); - void setData(int data); - int addAtomicData(int addData); - } - private static int max = 6000000; private static int run = 100; private static int currentRun = 0; @@ -69,8 +63,17 @@ public class LataTest { map.close(); } + public interface IData { + int getData(); + + void setData(int data); + + int addAtomicData(int addData); + } + interface StringValue { CharSequence getValue(); + void setValue(@MaxUtf8Length(64) CharSequence value); } } diff --git a/src/test/java/net/openhft/chronicle/map/ListenersTest.java b/src/test/java/net/openhft/chronicle/map/ListenersTest.java index 632f1b55e..1ad3bf8ea 100644 --- a/src/test/java/net/openhft/chronicle/map/ListenersTest.java +++ b/src/test/java/net/openhft/chronicle/map/ListenersTest.java @@ -29,49 +29,27 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; public class ListenersTest { - - static class CountingEntryOperations implements MapEntryOperations { - AtomicInteger removeCount = new AtomicInteger(); - AtomicInteger insertCount = new AtomicInteger(); - AtomicInteger replaceValueCount = new AtomicInteger(); - @Override - public Void remove(@NotNull MapEntry entry) { - removeCount.incrementAndGet(); - return MapEntryOperations.super.remove(entry); - } - @Override - public Void replaceValue(@NotNull MapEntry entry, Data newValue) { - replaceValueCount.incrementAndGet(); - return MapEntryOperations.super.replaceValue(entry, newValue); - } - @Override - public Void insert(@NotNull MapAbsentEntry absentEntry, Data value) { - insertCount.incrementAndGet(); - return MapEntryOperations.super.insert(absentEntry, value); - } - } - @Test public void testAnyRemove() { CountingEntryOperations removeCounting = new CountingEntryOperations<>(); ChronicleMap map = ChronicleMapBuilder.of(Integer.class, Integer.class) - .entries(100) - .entryOperations(removeCounting) - .create(); - + .entries(100) + .entryOperations(removeCounting) + .create(); + map.put(1, 1); map.remove(1); // removeCount 1 - + map.put(1, 1); assertFalse(map.remove(1, 2)); map.remove(1, 1); // removeCount 2 - + map.put(1, 1); map.merge(1, 1, (v1, v2) -> null); // removeCount 3 - + map.put(1, 1); Iterator> it = map.entrySet().iterator(); it.next(); @@ -94,15 +72,15 @@ public class ListenersTest { map.put(1, 2); // replaceValue 1 map.compute(1, (k, v) -> 2); // replaceValue 2 - + map.entrySet().iterator().next().setValue(1); // replaceValue 3 - + map.compute(2, (k, v) -> 1); // insert 2 assertEquals(3, putCounting.replaceValueCount.get()); assertEquals(2, putCounting.insertCount.get()); } - + @Test public void testContainsKey() { AtomicInteger c = new AtomicInteger(); @@ -119,14 +97,14 @@ public class ListenersTest { } }) .create(); - + assertFalse(map.containsKey(1)); // 1 map.put(1, 1); assertTrue(map.containsKey(1)); // 2 - + map.put(2, 2); assertFalse(map.containsKey(2)); - + assertEquals(2, c.get()); } @@ -188,13 +166,37 @@ public class ListenersTest { assertNull(map.put(1, 1)); // 1 assertEquals(1, map.put(1, 2).intValue()); // 2 - + assertNull(map.put(2, 1)); assertNull(map.put(2, 2)); - + assertNull(map.put(3, 1)); assertEquals(2, map.get(3).intValue()); assertEquals(2, c.get()); } + + static class CountingEntryOperations implements MapEntryOperations { + AtomicInteger removeCount = new AtomicInteger(); + AtomicInteger insertCount = new AtomicInteger(); + AtomicInteger replaceValueCount = new AtomicInteger(); + + @Override + public Void remove(@NotNull MapEntry entry) { + removeCount.incrementAndGet(); + return MapEntryOperations.super.remove(entry); + } + + @Override + public Void replaceValue(@NotNull MapEntry entry, Data newValue) { + replaceValueCount.incrementAndGet(); + return MapEntryOperations.super.replaceValue(entry, newValue); + } + + @Override + public Void insert(@NotNull MapAbsentEntry absentEntry, Data value) { + insertCount.incrementAndGet(); + return MapEntryOperations.super.insert(absentEntry, value); + } + } } diff --git a/src/test/java/net/openhft/chronicle/map/LoggingMapEntryOperations.java b/src/test/java/net/openhft/chronicle/map/LoggingMapEntryOperations.java index 741dd9f96..ac71005d6 100644 --- a/src/test/java/net/openhft/chronicle/map/LoggingMapEntryOperations.java +++ b/src/test/java/net/openhft/chronicle/map/LoggingMapEntryOperations.java @@ -25,7 +25,7 @@ import org.slf4j.LoggerFactory; class LoggingMapEntryOperations implements MapEntryOperations { static final Logger LOG = LoggerFactory.getLogger(LoggingMapEntryOperations.class); - + @Override public Void replaceValue(@NotNull MapEntry entry, Data newValue) { LOG.info("replace: old key: {}, old value: {}, new value: {}", diff --git a/src/test/java/net/openhft/chronicle/map/MapCloseTest.java b/src/test/java/net/openhft/chronicle/map/MapCloseTest.java index 56a7ca617..209f5e8b8 100644 --- a/src/test/java/net/openhft/chronicle/map/MapCloseTest.java +++ b/src/test/java/net/openhft/chronicle/map/MapCloseTest.java @@ -55,7 +55,8 @@ public class MapCloseTest { Thread t = new Thread(() -> map.close()); t.start(); t.join(); - map.forEach((k, v) -> {}); + map.forEach((k, v) -> { + }); } @Test(expected = ChronicleHashClosedException.class) diff --git a/src/test/java/net/openhft/chronicle/map/MarkTest.java b/src/test/java/net/openhft/chronicle/map/MarkTest.java index 8d0b4459f..4bcadf053 100644 --- a/src/test/java/net/openhft/chronicle/map/MarkTest.java +++ b/src/test/java/net/openhft/chronicle/map/MarkTest.java @@ -34,6 +34,26 @@ public class MarkTest { static int ENTRIES = 25_000_000; + private static void test( + Function, ChronicleMap> + createMap) { + long ms = System.currentTimeMillis(); + try (ChronicleMap map = createMap.apply(ChronicleMapBuilder + .of(Integer.class, Integer.class) + .entries(ENTRIES) + .entriesPerSegment((1 << 15) / 3) + .checksumEntries(false) + .putReturnsNull(true) + .removeReturnsNull(true))) { + + Random r = ThreadLocalRandom.current(); + for (int i = 0; i < ENTRIES; i++) { + map.put(r.nextInt(), r.nextInt()); + } + } + System.out.println(System.currentTimeMillis() - ms); + } + @Ignore("often out of time, that is a parf issue, not a bug") @Test(timeout = 25000) public void inMemoryTest() { @@ -61,24 +81,4 @@ public class MarkTest { db.delete(); } } - - private static void test( - Function, ChronicleMap> - createMap) { - long ms = System.currentTimeMillis(); - try (ChronicleMap map = createMap.apply(ChronicleMapBuilder - .of(Integer.class, Integer.class) - .entries(ENTRIES) - .entriesPerSegment((1 << 15) / 3) - .checksumEntries(false) - .putReturnsNull(true) - .removeReturnsNull(true))) { - - Random r = ThreadLocalRandom.current(); - for (int i = 0; i < ENTRIES; i++) { - map.put(r.nextInt(), r.nextInt()); - } - } - System.out.println(System.currentTimeMillis() - ms); - } } diff --git a/src/test/java/net/openhft/chronicle/map/MemoryLeaksTest.java b/src/test/java/net/openhft/chronicle/map/MemoryLeaksTest.java index 64ab787c6..f9891d2c7 100644 --- a/src/test/java/net/openhft/chronicle/map/MemoryLeaksTest.java +++ b/src/test/java/net/openhft/chronicle/map/MemoryLeaksTest.java @@ -37,11 +37,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -50,6 +46,30 @@ import static org.junit.Assert.assertEquals; @RunWith(Parameterized.class) public class MemoryLeaksTest { + /** + * Accounting {@link CountedStringReader} creation and finalization. All serializers, + * created since the map creation, should become unreachable after map.close() or collection by + * Cleaner, it means that map contexts (referencing serializers) are collected by the GC + */ + private final AtomicInteger serializerCount = new AtomicInteger(); + private final List> serializers = new ArrayList<>(); + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + private boolean persisted; + private ChronicleMapBuilder builder; + private boolean closeWithinContext; + public MemoryLeaksTest(String testType, boolean replicated, boolean persisted, boolean closeWithinContext) { + this.persisted = persisted; + this.closeWithinContext = closeWithinContext; + builder = ChronicleMap + .of(IntValue.class, String.class) + .valueReaderAndDataAccess(new CountedStringReader(), new StringUtf8DataAccess()); + if (replicated) + builder.replication((byte) 1); + builder.entries(1).averageValueSize(1); + } + @Parameterized.Parameters(name = "{0}") public static Collection data() { List booleans = Arrays.asList(false, true); @@ -68,31 +88,6 @@ public class MemoryLeaksTest { (!flags.get(2) ? "not " : "") + "closed within context"; } - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - - private boolean persisted; - private ChronicleMapBuilder builder; - private boolean closeWithinContext; - /** - * Accounting {@link CountedStringReader} creation and finalization. All serializers, - * created since the map creation, should become unreachable after map.close() or collection by - * Cleaner, it means that map contexts (referencing serializers) are collected by the GC - */ - private final AtomicInteger serializerCount = new AtomicInteger(); - private final List> serializers = new ArrayList<>(); - - public MemoryLeaksTest(String testType, boolean replicated, boolean persisted, boolean closeWithinContext) { - this.persisted = persisted; - this.closeWithinContext = closeWithinContext; - builder = ChronicleMap - .of(IntValue.class, String.class) - .valueReaderAndDataAccess(new CountedStringReader(), new StringUtf8DataAccess()); - if (replicated) - builder.replication((byte) 1); - builder.entries(1).averageValueSize(1); - } - @Before public void initNoBytesStore() { Assert.assertNotEquals(0, NoBytesStore.NO_PAGE); diff --git a/src/test/java/net/openhft/chronicle/map/NestedContextsInIterationContextTest.java b/src/test/java/net/openhft/chronicle/map/NestedContextsInIterationContextTest.java index ea6f09c80..a0c013cbe 100644 --- a/src/test/java/net/openhft/chronicle/map/NestedContextsInIterationContextTest.java +++ b/src/test/java/net/openhft/chronicle/map/NestedContextsInIterationContextTest.java @@ -176,7 +176,8 @@ public class NestedContextsInIterationContextTest { .create()) { map.put(42, 42); try (MapSegmentContext cxt = map.segmentContext(0)) { - cxt.forEachSegmentEntry(e -> map.segmentContext(1).forEachSegmentEntry(e2 -> {})); + cxt.forEachSegmentEntry(e -> map.segmentContext(1).forEachSegmentEntry(e2 -> { + })); } } } diff --git a/src/test/java/net/openhft/chronicle/map/NestedContextsTest.java b/src/test/java/net/openhft/chronicle/map/NestedContextsTest.java index b375235ed..9aacdbc61 100644 --- a/src/test/java/net/openhft/chronicle/map/NestedContextsTest.java +++ b/src/test/java/net/openhft/chronicle/map/NestedContextsTest.java @@ -32,51 +32,6 @@ import static org.junit.Assert.assertTrue; public class NestedContextsTest { - @Test - public void nestedContextsTest() throws ExecutionException, InterruptedException { - HashSet averageValue = new HashSet<>(); - for (int i = 0; i < 5; i++) { - averageValue.add(i); - } - ChronicleMap> graph = ChronicleMap - .of(Integer.class, (Class>) (Class) Set.class) - .entries(10) - .averageValue(averageValue) - .actualSegments(2) - .create(); - - addEdge(graph, 1, 2); - addEdge(graph, 2, 3); - addEdge(graph, 1, 3); - - assertEquals(ImmutableSet.of(2, 3), graph.get(1)); - assertEquals(ImmutableSet.of(1, 3), graph.get(2)); - assertEquals(ImmutableSet.of(1, 2), graph.get(3)); - - verifyGraphConsistent(graph); - - ForkJoinPool pool = new ForkJoinPool(8); - try { - pool.submit(() -> { - ThreadLocalRandom.current().ints().limit(10_000).parallel().forEach(i -> { - int sourceNode = Math.abs(i % 10); - int targetNode; - do { - targetNode = ThreadLocalRandom.current().nextInt(10); - } while (targetNode == sourceNode); - if (i % 2 == 0) { - addEdge(graph, sourceNode, targetNode); - } else { - removeEdge(graph, sourceNode, targetNode); - } - }); - }).get(); - verifyGraphConsistent(graph); - } finally { - pool.shutdownNow(); - } - } - private static void verifyGraphConsistent(ChronicleMap> graph) { graph.forEach((node, neighbours) -> neighbours.forEach(neighbour -> assertTrue(graph.get(neighbour).contains(node)))); @@ -156,7 +111,7 @@ public class NestedContextsTest { } private static void addEdgeBothAbsent(MapQueryContext, ?> sc, int source, - MapQueryContext, ?> tc, int target) { + MapQueryContext, ?> tc, int target) { addEdgeOneSide(sc, target); addEdgeOneSide(tc, source); } @@ -207,4 +162,49 @@ public class NestedContextsTest { } } } + + @Test + public void nestedContextsTest() throws ExecutionException, InterruptedException { + HashSet averageValue = new HashSet<>(); + for (int i = 0; i < 5; i++) { + averageValue.add(i); + } + ChronicleMap> graph = ChronicleMap + .of(Integer.class, (Class>) (Class) Set.class) + .entries(10) + .averageValue(averageValue) + .actualSegments(2) + .create(); + + addEdge(graph, 1, 2); + addEdge(graph, 2, 3); + addEdge(graph, 1, 3); + + assertEquals(ImmutableSet.of(2, 3), graph.get(1)); + assertEquals(ImmutableSet.of(1, 3), graph.get(2)); + assertEquals(ImmutableSet.of(1, 2), graph.get(3)); + + verifyGraphConsistent(graph); + + ForkJoinPool pool = new ForkJoinPool(8); + try { + pool.submit(() -> { + ThreadLocalRandom.current().ints().limit(10_000).parallel().forEach(i -> { + int sourceNode = Math.abs(i % 10); + int targetNode; + do { + targetNode = ThreadLocalRandom.current().nextInt(10); + } while (targetNode == sourceNode); + if (i % 2 == 0) { + addEdge(graph, sourceNode, targetNode); + } else { + removeEdge(graph, sourceNode, targetNode); + } + }); + }).get(); + verifyGraphConsistent(graph); + } finally { + pool.shutdownNow(); + } + } } diff --git a/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java b/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java index aff8b287c..3a09f2c81 100644 --- a/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/ReplicatedChronicleMapTest.java @@ -19,7 +19,6 @@ package net.openhft.chronicle.map; import net.openhft.chronicle.hash.ChronicleHashBuilderPrivateAPI; import net.openhft.chronicle.map.jsr166.JSR166TestCase; -import org.junit.Ignore; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java b/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java index 0099390e2..f36fa2d60 100644 --- a/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java +++ b/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java @@ -93,7 +93,7 @@ public class ReplicationCheckingMap implements ChronicleMap { return r1; if (i > 30) { - Jvm.pause(i); + Jvm.pause(i); } else { Thread.yield(); } diff --git a/src/test/java/net/openhft/chronicle/map/TrickyContextCasesTest.java b/src/test/java/net/openhft/chronicle/map/TrickyContextCasesTest.java index 68e130b56..4f8971031 100644 --- a/src/test/java/net/openhft/chronicle/map/TrickyContextCasesTest.java +++ b/src/test/java/net/openhft/chronicle/map/TrickyContextCasesTest.java @@ -39,7 +39,7 @@ public class TrickyContextCasesTest { .of(Integer.class, IntValue.class) .entries(1).create(); - IntValue v = Values.newHeapInstance(IntValue.class); + IntValue v = Values.newHeapInstance(IntValue.class); v.setValue(2); map.put(1, v); try (ExternalMapQueryContext q = map.queryContext(1)) { @@ -61,8 +61,8 @@ public class TrickyContextCasesTest { .of(Integer.class, byte[].class) .averageValue(new byte[1]) .entries(100).actualSegments(1).create(); - map.put(1, new byte[] {1}); - map.put(2, new byte[] {2}); + map.put(1, new byte[]{1}); + map.put(2, new byte[]{2}); try (ExternalMapQueryContext q = map.queryContext(1)) { MapEntry entry = q.entry(); // acquires read lock implicitly assertNotNull(entry); @@ -70,9 +70,9 @@ public class TrickyContextCasesTest { // this call should try to acquire write lock, that should lead to dead lock // but if not... // relocates the entry for the key 1 after the entry for 2, under update lock - map.put(1, new byte[] {1, 2, 3, 4, 5}); + map.put(1, new byte[]{1, 2, 3, 4, 5}); // puts the entry for 3 at the place of the entry for the key 1, under update lock - map.put(3, new byte[] {3}); + map.put(3, new byte[]{3}); }).get(); // prints [3] System.out.println(Arrays.toString(entry.value().get())); diff --git a/src/test/java/net/openhft/chronicle/map/ValueInterfaceWithEnumTest.java b/src/test/java/net/openhft/chronicle/map/ValueInterfaceWithEnumTest.java index 206459564..ab86d622e 100644 --- a/src/test/java/net/openhft/chronicle/map/ValueInterfaceWithEnumTest.java +++ b/src/test/java/net/openhft/chronicle/map/ValueInterfaceWithEnumTest.java @@ -12,44 +12,48 @@ import java.util.stream.IntStream; */ public class ValueInterfaceWithEnumTest { - /** - * This test will throw an {@link ArrayIndexOutOfBoundsException}. This seems to occur only with Enums having even number of - * values - */ - @Test - public void testValueInterface() { - LongValue longValue = Values.newHeapInstance(LongValue.class); - SimpleValueInterface simpleValueInterface = Values.newHeapInstance(SimpleValueInterface.class); + /** + * This test will throw an {@link ArrayIndexOutOfBoundsException}. This seems to occur only with Enums having even number of + * values + */ + @Test + public void testValueInterface() { + LongValue longValue = Values.newHeapInstance(LongValue.class); + SimpleValueInterface simpleValueInterface = Values.newHeapInstance(SimpleValueInterface.class); - ChronicleMap map = ChronicleMapBuilder.of(LongValue.class, SimpleValueInterface.class).entries(50).create(); + ChronicleMap map = ChronicleMapBuilder.of(LongValue.class, SimpleValueInterface.class).entries(50).create(); - IntStream.range(1, 20).forEach(value -> { - longValue.setValue(value); - simpleValueInterface.setId(value); - simpleValueInterface.setTruth(false); - simpleValueInterface.setSVIEnum(SimpleValueInterface.SVIEnum.SIX); + IntStream.range(1, 20).forEach(value -> { + longValue.setValue(value); + simpleValueInterface.setId(value); + simpleValueInterface.setTruth(false); + simpleValueInterface.setSVIEnum(SimpleValueInterface.SVIEnum.SIX); - map.put(longValue, simpleValueInterface); - }); + map.put(longValue, simpleValueInterface); + }); - IntStream.range(1, 10).forEach(value -> { - longValue.setValue(value); - SimpleValueInterface simpleValueInterface1 = map.get(longValue); - System.out.println(simpleValueInterface1.getId()); - }); - } + IntStream.range(1, 10).forEach(value -> { + longValue.setValue(value); + SimpleValueInterface simpleValueInterface1 = map.get(longValue); + System.out.println(simpleValueInterface1.getId()); + }); + } - public interface SimpleValueInterface { - enum SVIEnum { - ONE, TWO, THREE, FOUR, FIVE, SIX - } + public interface SimpleValueInterface { + int getId(); - int getId(); - void setId(int id); - boolean getTruth(); - void setTruth(boolean truth); + void setId(int id); - SVIEnum getSVIEnum(); - void setSVIEnum(SVIEnum val); - } + boolean getTruth(); + + void setTruth(boolean truth); + + SVIEnum getSVIEnum(); + + void setSVIEnum(SVIEnum val); + + enum SVIEnum { + ONE, TWO, THREE, FOUR, FIVE, SIX + } + } } diff --git a/src/test/java/net/openhft/chronicle/map/WriteThroughputTest.java b/src/test/java/net/openhft/chronicle/map/WriteThroughputTest.java index f3a61da3d..be2318e65 100644 --- a/src/test/java/net/openhft/chronicle/map/WriteThroughputTest.java +++ b/src/test/java/net/openhft/chronicle/map/WriteThroughputTest.java @@ -79,12 +79,12 @@ public class WriteThroughputTest { int count = 2 << 10; int size = 50 << 10; - File file3 = new File("bandwidthTest"+System.nanoTime()+ ".Z.deleteme"); + File file3 = new File("bandwidthTest" + System.nanoTime() + ".Z.deleteme"); file3.deleteOnExit(); try (ChronicleMap map = ChronicleMapBuilder .of(CharSequence.class, CharSequence.class) - .entries(count*3/2) - .averageValueSize(size/4) + .entries(count * 3 / 2) + .averageValueSize(size / 4) .valueMarshaller(DeflatorStringMarshaller.INSTANCE) .putReturnsNull(true) .createPersistedTo(file3)) { @@ -94,7 +94,7 @@ public class WriteThroughputTest { } } - private void doTest(int count, int size,ChronicleMap map) { + private void doTest(int count, int size, ChronicleMap map) { StringBuilder value = new StringBuilder("value"); while (value.length() < size) value.append(value.length()); @@ -118,5 +118,5 @@ public class WriteThroughputTest { long time = System.nanoTime() - start; System.out.printf("Concurrent %,d MB took %.3f seconds%n", size * count >> 20, time / 1e9); } -} + } } diff --git a/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java b/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java index 2251feed0..4215eac01 100644 --- a/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java +++ b/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java @@ -76,16 +76,6 @@ public class HashQueryContextExamples { returnValue.returnValue(q.entry().value()); } - interface Point { - double getX(); - void setX(double x); - double addX(double xAdd); - - double getY(); - void setY(double y); - double addY(double yAdd); - } - Point movePoint(ChronicleMap map, K key, double xMove, double yMove, Point using) { // Moves existing point by [xMove, yMove], if absent - assumes the default point is [0, 0]. @@ -107,4 +97,18 @@ public class HashQueryContextExamples { return offHeapPoint; } } + + interface Point { + double getX(); + + void setX(double x); + + double addX(double xAdd); + + double getY(); + + void setY(double y); + + double addY(double yAdd); + } } diff --git a/src/test/java/net/openhft/chronicle/map/example/LotsOfEntriesMain.java b/src/test/java/net/openhft/chronicle/map/example/LotsOfEntriesMain.java index a9f99e6e3..f5aa884ef 100755 --- a/src/test/java/net/openhft/chronicle/map/example/LotsOfEntriesMain.java +++ b/src/test/java/net/openhft/chronicle/map/example/LotsOfEntriesMain.java @@ -32,6 +32,13 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +interface MyFloats { + @Array(length = 6) + public void setValueAt(int index, float f); + + public float getValueAt(int index); +} + /** * Created by peter.lawrey on 19/12/14. */ @@ -82,7 +89,7 @@ public class LotsOfEntriesMain { else map.getUsing(sb, mf); } catch (Exception e) { - System.out.println("map.size: "+map.size()); + System.out.println("map.size: " + map.size()); throw e; } } @@ -99,10 +106,3 @@ public class LotsOfEntriesMain { map.close(); } } - -interface MyFloats { - @Array(length = 6) - public void setValueAt(int index, float f); - - public float getValueAt(int index); -} diff --git a/src/test/java/net/openhft/chronicle/map/example/PointListSerializationTest.java b/src/test/java/net/openhft/chronicle/map/example/PointListSerializationTest.java index ba9e089f0..53d80f24c 100644 --- a/src/test/java/net/openhft/chronicle/map/example/PointListSerializationTest.java +++ b/src/test/java/net/openhft/chronicle/map/example/PointListSerializationTest.java @@ -58,7 +58,8 @@ public class PointListSerializationTest { EnumMarshallable { public static final AMarshaller INSTANCE = new AMarshaller(); - private AMarshaller() {} + private AMarshaller() { + } @Override public void write(Bytes out, @NotNull A toWrite) { diff --git a/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java b/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java index bec915564..a6dc7c45c 100644 --- a/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java +++ b/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java @@ -29,17 +29,39 @@ import static net.openhft.chronicle.map.example.SimpleMapOperationsListeningTest public class SimpleMapOperationsListeningTest { + @Test + public void simpleLoggingTest() { + ChronicleMap map = ChronicleMapBuilder + .of(Integer.class, IntValue.class) + .entries(100) + .entryOperations(simpleLoggingMapEntryOperations()) + .defaultValueProvider(simpleLoggingDefaultValueProvider()) + .create(); + + IntValue value = Values.newHeapInstance(IntValue.class); + value.setValue(2); + map.put(1, value); + map.remove(1); + map.acquireUsing(3, Values.newNativeReference(IntValue.class)).addAtomicValue(1); + IntValue value2 = Values.newHeapInstance(IntValue.class); + value2.setValue(5); + map.forEachEntry(e -> e.context().replaceValue(e, e.context().wrapValueAsData(value2))); + map.forEachEntry(e -> e.context().remove(e)); + + } + static class SimpleLoggingMapEntryOperations implements MapEntryOperations { private static final SimpleLoggingMapEntryOperations INSTANCE = new SimpleLoggingMapEntryOperations(); + private SimpleLoggingMapEntryOperations() { + } + public static MapEntryOperations simpleLoggingMapEntryOperations() { return SimpleLoggingMapEntryOperations.INSTANCE; } - private SimpleLoggingMapEntryOperations() {} - @Override public Void remove(@NotNull MapEntry entry) { System.out.println("remove " + entry.key() + ": " + entry.value()); @@ -67,12 +89,13 @@ public class SimpleMapOperationsListeningTest { private static final SimpleLoggingDefaultValueProvider INSTANCE = new SimpleLoggingDefaultValueProvider(); + private SimpleLoggingDefaultValueProvider() { + } + public static DefaultValueProvider simpleLoggingDefaultValueProvider() { return INSTANCE; } - private SimpleLoggingDefaultValueProvider() {} - @Override public Data defaultValue(@NotNull MapAbsentEntry absentEntry) { Data defaultValue = absentEntry.defaultValue(); @@ -80,25 +103,4 @@ public class SimpleMapOperationsListeningTest { return defaultValue; } } - - @Test - public void simpleLoggingTest() { - ChronicleMap map = ChronicleMapBuilder - .of(Integer.class, IntValue.class) - .entries(100) - .entryOperations(simpleLoggingMapEntryOperations()) - .defaultValueProvider(simpleLoggingDefaultValueProvider()) - .create(); - - IntValue value = Values.newHeapInstance(IntValue.class); - value.setValue(2); - map.put(1, value); - map.remove(1); - map.acquireUsing(3, Values.newNativeReference(IntValue.class)).addAtomicValue(1); - IntValue value2 = Values.newHeapInstance(IntValue.class); - value2.setValue(5); - map.forEachEntry(e -> e.context().replaceValue(e, e.context().wrapValueAsData(value2))); - map.forEachEntry(e -> e.context().remove(e)); - - } } diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java b/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java index 08ea8031c..8c1986d25 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/BondVOInterface.java @@ -25,25 +25,33 @@ public interface BondVOInterface { @Group(0) long getEntryLockState(); + void setEntryLockState(long entryLockState); @Group(1) long getIssueDate(); + void setIssueDate(long issueDate); /* time in millis */ @Group(1) long getMaturityDate(); + void setMaturityDate(long maturityDate); /* time in millis */ + long addAtomicMaturityDate(long toAdd); @Group(1) boolean compareAndSwapCoupon(double expected, double value); + double getCoupon(); + void setCoupon(double coupon); + double addAtomicCoupon(double toAdd); @Group(1) String getSymbol(); + void setSymbol(@MaxUtf8Length(20) String symbol); // OpenHFT Off-Heap array[ ] processing notice ‘At’ suffix diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArrayBytesMarshaller.java b/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArrayBytesMarshaller.java index 2a8a188bd..863f221de 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArrayBytesMarshaller.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArrayBytesMarshaller.java @@ -35,7 +35,8 @@ public final class CharSequenceArrayBytesMarshaller static final CharSequenceArrayBytesMarshaller INSTANCE = new CharSequenceArrayBytesMarshaller(); - private CharSequenceArrayBytesMarshaller() {} + private CharSequenceArrayBytesMarshaller() { + } @Override public void write(Bytes out, @NotNull CharSequence[] toWrite) { diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArraySerializationTest.java b/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArraySerializationTest.java index 410d04a18..5a47a0612 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArraySerializationTest.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceArraySerializationTest.java @@ -33,7 +33,7 @@ public class CharSequenceArraySerializationTest { .entries(2) .create()) { map.put("fruits", new CharSequence[]{"banana", "pineapple"}); - map.put("vegetables", new CharSequence[] {"carrot", "potato"}); + map.put("vegetables", new CharSequence[]{"carrot", "potato"}); Assert.assertEquals(2, map.get("fruits").length); Assert.assertEquals(2, map.get("vegetables").length); } diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceCustomEncodingBytesWriter.java b/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceCustomEncodingBytesWriter.java index fc5b0ecc8..4697be163 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceCustomEncodingBytesWriter.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/CharSequenceCustomEncodingBytesWriter.java @@ -51,6 +51,15 @@ public final class CharSequenceCustomEncodingBytesWriter initTransients(); } + /** + * Need this method because {@link CharBuffer#append(CharSequence, int, int)} produces garbage + */ + private static void append(CharBuffer charBuffer, CharSequence cs, int start, int end) { + for (int i = start; i < end; i++) { + charBuffer.put(cs.charAt(i)); + } + } + private void initTransients() { charsetEncoder = charset.newEncoder(); inputBuffer = CharBuffer.allocate(inputBufferSize); @@ -120,15 +129,6 @@ public final class CharSequenceCustomEncodingBytesWriter out.writeSkip(remaining); } - /** - * Need this method because {@link CharBuffer#append(CharSequence, int, int)} produces garbage - */ - private static void append(CharBuffer charBuffer, CharSequence cs, int start, int end) { - for (int i = start; i < end; i++) { - charBuffer.put(cs.charAt(i)); - } - } - @Override public void readMarshallable(@NotNull WireIn wireIn) { charset = (Charset) wireIn.read(() -> "charset").object(); diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/CustomCharSequenceEncodingTest.java b/src/test/java/net/openhft/chronicle/map/fromdocs/CustomCharSequenceEncodingTest.java index e9c3e4df7..c6557a018 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/CustomCharSequenceEncodingTest.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/CustomCharSequenceEncodingTest.java @@ -24,8 +24,6 @@ import org.junit.Test; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import static org.junit.Assert.assertNotNull; - public class CustomCharSequenceEncodingTest { @Test diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/Point.java b/src/test/java/net/openhft/chronicle/map/fromdocs/Point.java index cd5bb1057..abedc98ed 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/Point.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/Point.java @@ -19,12 +19,12 @@ package net.openhft.chronicle.map.fromdocs; public final class Point { + double x, y; + public static Point of(double x, double y) { Point p = new Point(); p.x = x; p.y = y; return p; } - - double x, y; } diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/PointListSizedMarshaller.java b/src/test/java/net/openhft/chronicle/map/fromdocs/PointListSizedMarshaller.java index a12fc3090..45c6df975 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/PointListSizedMarshaller.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/PointListSizedMarshaller.java @@ -34,12 +34,14 @@ public final class PointListSizedMarshaller ReadResolvable { static final PointListSizedMarshaller INSTANCE = new PointListSizedMarshaller(); - - private PointListSizedMarshaller() {} - - /** A point takes 16 bytes in serialized form: 8 bytes for both x and y value */ + /** + * A point takes 16 bytes in serialized form: 8 bytes for both x and y value + */ private static final long ELEMENT_SIZE = 16; + private PointListSizedMarshaller() { + } + @Override public long size(@NotNull List toWrite) { return toWrite.size() * ELEMENT_SIZE; diff --git a/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java b/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java index 9163ef6c2..f88b26782 100644 --- a/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java +++ b/src/test/java/net/openhft/chronicle/map/fromdocs/pingpong_latency/PingPongLockLeft.java @@ -17,7 +17,6 @@ package net.openhft.chronicle.map.fromdocs.pingpong_latency; -import net.openhft.chronicle.algo.bytes.Access; import net.openhft.chronicle.algo.locks.AcquisitionStrategies; import net.openhft.chronicle.algo.locks.ReadWriteLockingStrategy; import net.openhft.chronicle.algo.locks.TryAcquireOperations; diff --git a/src/test/java/net/openhft/chronicle/map/jsr166/JSR166TestCase.java b/src/test/java/net/openhft/chronicle/map/jsr166/JSR166TestCase.java index aecbea8f8..95ca2d768 100644 --- a/src/test/java/net/openhft/chronicle/map/jsr166/JSR166TestCase.java +++ b/src/test/java/net/openhft/chronicle/map/jsr166/JSR166TestCase.java @@ -42,9 +42,9 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; * cause the associated test that generated them to itself Assert.fail (which * JUnit does not otherwise arrange). The rules for creating such * tests are: - * + *

*

    - * + *

    *

  1. All assertions in code running in generated threads must use * the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link * #threadAssertEquals}, or {@link #threadAssertNull}, (not @@ -52,12 +52,12 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; * particularly recommended) for other code to use these forms too. * Only the most typically used JUnit assertion methods are defined * this way, but enough to live with.
  2. - * + *

    *

  3. If you override {@link #setUp} or {@link #tearDown}, make sure * to invoke {@code super.setUp} and {@code super.tearDown} within * them. These methods are used to clear and check for thread * assertion Assert.failures.
  4. - * + *

    *

  5. All delays and timeouts must use one of the constants {@code * SHORT_DELAY_MS}, {@code SMALL_DELAY_MS}, {@code MEDIUM_DELAY_MS}, * {@code LONG_DELAY_MS}. The idea here is that a SHORT is always @@ -68,17 +68,17 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; * MEDIUM. And so on. These constants are set to conservative values, * but even so, if there is ever any doubt, they can all be increased * in one spot to rerun tests on slower platforms.
  6. - * + *

    *

  7. All threads generated must be joined inside each test case * method (or {@code Assert.fail} to do so) before returning from the * method. The {@code joinPool} method can be used to do this when * using Executors.
  8. - * + *

    *

- * + *

*

Other notes *

    - * + *

    *

  • Usually, there is one testcase method per JSR166 method * covering "normal" operation, and then as many exception-testing * methods as there are exceptions the method can throw. Sometimes @@ -86,26 +86,26 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; * "normal" behaviors differ significantly. And sometimes testcases * cover multiple methods when they cannot be tested in * isolation.
  • - * + *

    *

  • The documentation style for testcases is to provide as javadoc * a simple sentence or two describing the property that the testcase * method purports to test. The javadocs do not say anything about how * the property is tested. To find out, read the code.
  • - * + *

    *

  • These tests are "conformance tests", and do not attempt to * test throughput, latency, scalability or other performance factors * (see the separate "jtreg" tests for a set intended to check these * for the most central aspects of functionality.) So, most tests use * the smallest sensible numbers of threads, collection sizes, etc * needed to check basic conformance.
  • - * + *

    *

  • The test classes currently do not declare inclusion in * any particular package to simplify things for people integrating * them in TCK test suites.
  • - * + *

    *

  • As a convenience, the {@code main} of this class (JSR166TestCase) * runs all JSR166 unit tests.
  • - * + *

    *

*/ public class JSR166TestCase { @@ -255,11 +255,11 @@ public class JSR166TestCase { /** * Extra checks that get done for all test cases. - * + *

*

Triggers test case Assert.failure if any thread assertions have Assert.failed, * by rethrowing, in the test harness thread, any exception recorded * earlier by threadRecordFailure. - * + *

*

Triggers test case Assert.failure if interrupt status is set in the main thread. */ @After diff --git a/src/test/java/net/openhft/chronicle/set/Builder.java b/src/test/java/net/openhft/chronicle/set/Builder.java index 2ad7b7594..676c00a5c 100644 --- a/src/test/java/net/openhft/chronicle/set/Builder.java +++ b/src/test/java/net/openhft/chronicle/set/Builder.java @@ -67,7 +67,7 @@ public class Builder { System.out.println("same"); break; } -} + } Jvm.pause(1); if (System.currentTimeMillis() - startTime > timeOutMs) break; diff --git a/src/test/java/net/openhft/chronicle/set/Issue24ChronicleSetTest.java b/src/test/java/net/openhft/chronicle/set/Issue24ChronicleSetTest.java index 9ff22efea..1cd4fa0cd 100644 --- a/src/test/java/net/openhft/chronicle/set/Issue24ChronicleSetTest.java +++ b/src/test/java/net/openhft/chronicle/set/Issue24ChronicleSetTest.java @@ -33,7 +33,7 @@ import static com.samskivert.util.CollectionUtil.selectRandomSubset; public class Issue24ChronicleSetTest { - public static , B extends ChronicleHashBuilder> + public static , B extends ChronicleHashBuilder> H init(B builder, int entrySize, int averageKeySize) throws IOException { File file = File.createTempFile("stringSet", ".dat"); @@ -71,20 +71,21 @@ public class Issue24ChronicleSetTest { public static class WorkerThread implements Runnable { private final ChronicleSet set; - public WorkerThread(ChronicleSet set){ + + public WorkerThread(ChronicleSet set) { this.set = set; } @Override public void run() { - System.out.println(Thread.currentThread().getName()+" Start. Command = " + set.size()); + System.out.println(Thread.currentThread().getName() + " Start. Command = " + set.size()); processCommand(); - System.out.println(Thread.currentThread().getName()+" End."); + System.out.println(Thread.currentThread().getName() + " End."); } private void processCommand() { Set nomenclatures = new HashSet<>(); - for(int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) { String nomenclature = "#############################" + i; nomenclatures.add(nomenclature); @@ -119,5 +120,5 @@ public class Issue24ChronicleSetTest { System.out.println(s); } } -} + } } diff --git a/src/test/java/net/openhft/lang/values/MovingAverageCompact.java b/src/test/java/net/openhft/lang/values/MovingAverageCompact.java index 987c4d5ea..4b41b438a 100644 --- a/src/test/java/net/openhft/lang/values/MovingAverageCompact.java +++ b/src/test/java/net/openhft/lang/values/MovingAverageCompact.java @@ -34,7 +34,6 @@ public class MovingAverageCompact extends AbstractBytesMarshallable { out.writeDouble(stdDev); } - public double getMovingAverage() { return movingAverage; }