From 1d7f54635a7a94d16b0c46213b9ce0b4ac1b180f Mon Sep 17 00:00:00 2001 From: leventov Date: Sat, 20 Jun 2015 05:43:34 +0300 Subject: [PATCH] HCOLL-318 added many documentation and examples; Empowerted ReplicableEntry interface, and changed Map/SetRemoteOperations contracts to allow implementing more agile reconciliation strategies --- README.md | 404 +- .../openhft/chronicle/hash/ChronicleHash.java | 28 +- .../chronicle/hash/HashQueryContext.java | 69 +- .../hash/impl/VanillaChronicleHash.java | 1 - .../{ => replication}/AcceptanceDecision.java | 14 +- .../DefaultEventualConsistencyStrategy.java | 5 +- .../hash/replication/HashReplicableEntry.java | 2 +- .../hash/replication/ReplicableEntry.java | 65 + .../openhft/chronicle/map/ChannelFactory.java | 26 - .../chronicle/map/ChronicleMapBuilder.java | 13 +- .../net/openhft/chronicle/map/MapContext.java | 7 +- .../chronicle/map/MapEntryOperations.java | 84 +- .../net/openhft/chronicle/map/MapMethods.java | 273 +- .../chronicle/map/MapQueryContext.java | 6 +- .../chronicle/map/ReplicatedChronicleMap.java | 22 +- .../chronicle/map/VanillaChronicleMap.java | 18 + ...CompiledReplicatedMapIterationContext.java | 1951 +++++----- .../CompiledReplicatedMapQueryContext.java | 3331 ++++++++--------- .../map/replication/MapRemoteOperations.java | 163 +- .../replication/MapRemoteQueryContext.java | 19 +- .../net/openhft/chronicle/set/SetContext.java | 6 +- .../set/replication/SetRemoteOperations.java | 45 +- .../net/openhft/chronicle/map/BiMapTest.java | 6 +- .../map/MaximizingValueRemoteOperations.java | 51 - .../map/TcpReplicationSoakCrdtTest.java | 246 ++ .../chronicle/map/TcpReplicationSoakTest.java | 3 +- .../map/example/HashQueryContextExamples.java | 93 + .../SimpleMapOperationsListeningTest.java | 75 + 28 files changed, 4164 insertions(+), 2862 deletions(-) rename src/main/java/net/openhft/chronicle/hash/{ => replication}/AcceptanceDecision.java (72%) delete mode 100644 src/main/java/net/openhft/chronicle/map/ChannelFactory.java delete mode 100644 src/test/java/net/openhft/chronicle/map/MaximizingValueRemoteOperations.java create mode 100644 src/test/java/net/openhft/chronicle/map/TcpReplicationSoakCrdtTest.java create mode 100644 src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java create mode 100644 src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java diff --git a/README.md b/README.md index 366b82a94..454a7ef6e 100644 --- a/README.md +++ b/README.md @@ -1517,9 +1517,407 @@ a simple off heap set set.add(1); set.remove(1) ``` -and just like map it support shared memory and TCP replication. - - +and just like map it support shared memory and TCP replication. + +# Customizing Chronicle Map behaviour and using listeners + +You could customize Chronicle Map behaviour on several levels: + + - [`ChronicleMapBuilder.entryOperations()`](http://openhft.github.io/Chronicle-Map/apidocs/net/openhft/chronicle/map/ChronicleMapBuilder.html#entryOperations) + define the "inner" listening level, all operations with entries, either during ordinary map + method calls, remote calls, replication or modifications during iteration over the map, operate + via this configured SPI. + + - [`ChronicleMapBuilder.mapMethods()`](http://openhft.github.io/Chronicle-Map/apidocs/net/openhft/chronicle/map/ChronicleMapBuilder.html#mapMethods) + is the higher-level of listening for local calls of Map methods. Methods in `MapMethods` + interface correspond to `Map` interface methods with the same names, and define their + implementations for `ChronicleMap`. + + - [`ChronicleMapBuilder.remoteOperations()`](http://openhft.github.io/Chronicle-Map/apidocs/net/openhft/chronicle/map/ChronicleMapBuilder.html#remoteOperations) + is for listening and customizing behaviour of remote calls, and replication events. + +All executions around `ChronicleMap` go through the three tiers (or the two bottom): + + 1. Query tier: `MapQueryContext` interface + 2. Entry tier: `MapEntry` and `MapAbsentEntry` interfaces + 3. Data tier: `Data` interface + +`MapMethods` and `MapRemoteOperations` methods accept *query context*, i. e. these SPI is above +the Query tier. `MapEntryOperations` methods accept `MapEntry` or `MapAbsentEntry`, i. e. this SPI +is between Query and Entry tiers. + +Combined, listening/customization SPI interfaces and `ChronicleMap.queryContext()` API are powerful +enough to + + - Log all operations of some kind on ChronicleMap (e. g. all remove, insert or update operations) + - Log some specific operations on ChronicleMap (e. g. log only acquireUsing() calls, which + has created a new entry) + - Forbid performing operations of some kind on the ChronicleMap instance + - Backup all changes to ChronicleMap to some durable storage, e. g. SQL database + - Perform multi-ChronicleMap operations correctly in concurrent environment, + by acquiring locks on all ChronicleMaps before updating them. + - Perform multi-key operations on a single ChronicleMap correctly in concurrent environment, + by acquiring locks on all keys before updating the entries SOON + - Define own replication/reconciliation logic for distributed ChronicleMaps + +## Examples + +### Simple logging + +Just log all modification operations on ChronicleMap + +``` +class SimpleLoggingMapEntryOperations implements MapEntryOperations { + + private static final SimpleLoggingMapEntryOperations INSTANCE = + new 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()); + entry.doRemove(); + return null; + } + + @Override + public Void replaceValue(@NotNull MapEntry entry, Data newValue) { + System.out.println("replace " + entry.key() + ": " + entry.value() + " -> " + newValue); + entry.doReplaceValue(newValue); + return null; + } + + @Override + public Void insert(@NotNull MapAbsentEntry absentEntry, Data value) { + System.out.println("insert " + absentEntry.absentKey() + " -> " + value); + absentEntry.doInsert(value); + return null; + } + + @Override + public Data defaultValue(@NotNull MapAbsentEntry absentEntry) { + Data defaultValue = absentEntry.defaultValue(); + System.out.println("default " + absentEntry.absentKey() + " -> " + defaultValue); + return defaultValue; + } +} +``` + +Usage: + +``` +ChronicleMap map = ChronicleMapBuilder + .of(Integer.class, IntValue.class) + .entries(100) + .entryOperations(simpleLoggingMapEntryOperations()) + .create(); + +// do anything with the map +``` + +### BiMap + +Possible bidirectional map (i. e. a map that preserves the uniqueness of its values as well +as that of its keys) implementation over Chronicle Maps. + +``` +enum DualLockSuccess {SUCCESS, FAIL} +``` + +``` +class BiMapMethods implements MapMethods { + @Override + public void remove(MapQueryContext q, ReturnValue returnValue) { + while (true) { + q.updateLock().lock(); + try { + MapEntry entry = q.entry(); + if (entry != null) { + returnValue.returnValue(entry.value()); + if (q.remove(entry) == SUCCESS) + return; + } + } finally { + q.readLock().unlock(); + } + } + } + + @Override + public void put(MapQueryContext q, Data value, + ReturnValue returnValue) { + while (true) { + q.updateLock().lock(); + try { + MapEntry entry = q.entry(); + if (entry != null) { + throw new IllegalStateException(); + } else { + if (q.insert(q.absentEntry(), value) == SUCCESS) + return; + } + } finally { + q.readLock().unlock(); + } + } + } + + @Override + public void putIfAbsent(MapQueryContext q, Data value, + ReturnValue returnValue) { + while (true) { + try { + if (q.readLock().tryLock()) { + MapEntry entry = q.entry(); + if (entry != null) { + returnValue.returnValue(entry.value()); + return; + } + // Key is absent + q.readLock().unlock(); + } + q.updateLock().lock(); + MapEntry entry = q.entry(); + if (entry != null) { + returnValue.returnValue(entry.value()); + return; + } + // Key is absent + if (q.insert(q.absentEntry(), value) == SUCCESS) + return; + } finally { + q.readLock().unlock(); + } + } + } + + @Override + public boolean remove(MapQueryContext q, Data value) { + while (true) { + q.updateLock().lock(); + MapEntry entry = q.entry(); + try { + if (entry != null && bytesEquivalent(entry.value(), value)) { + if (q.remove(entry) == SUCCESS) { + return true; + } else { + //noinspection UnnecessaryContinue + continue; + } + } else { + return false; + } + } finally { + q.readLock().unlock(); + } + } + } + + @Override + public void acquireUsing(MapQueryContext q, + ReturnValue returnValue) { + throw new UnsupportedOperationException(); + } + + @Override + public void replace(MapQueryContext q, Data value, + ReturnValue returnValue) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(MapQueryContext q, Data oldValue, + Data newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public void compute(MapQueryContext q, + BiFunction remappingFunction, + ReturnValue returnValue) { + throw new UnsupportedOperationException(); + } + + @Override + public void merge(MapQueryContext q, Data value, + BiFunction remappingFunction, + ReturnValue returnValue) { + throw new UnsupportedOperationException(); + } +} +``` + +``` +class BiMapEntryOperations implements MapEntryOperations { + ChronicleMap reverse; + + public void setReverse(ChronicleMap reverse) { + this.reverse = reverse; + } + + @Override + public DualLockSuccess remove(@NotNull MapEntry entry) { + try (ExternalMapQueryContext rq = reverse.queryContext(entry.value())) { + if (!rq.updateLock().tryLock()) { + if (entry.context() instanceof MapQueryContext) + return FAIL; + throw new IllegalStateException("Concurrent modifications to reverse map " + + "during remove during iteration"); + } + MapEntry reverseEntry = rq.entry(); + if (reverseEntry != null) { + entry.doRemove(); + reverseEntry.doRemove(); + return SUCCESS; + } else { + throw new IllegalStateException(entry.key() + " maps to " + entry.value() + + ", but in the reverse map this value is absent"); + } + } + } + + @Override + public DualLockSuccess replaceValue(@NotNull MapEntry entry, Data newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public DualLockSuccess insert(@NotNull MapAbsentEntry absentEntry, + Data value) { + try (ExternalMapQueryContext rq = reverse.queryContext(value)) { + if (!rq.updateLock().tryLock()) + return FAIL; + MapAbsentEntry reverseAbsentEntry = rq.absentEntry(); + if (reverseAbsentEntry != null) { + absentEntry.doInsert(value); + reverseAbsentEntry.doInsert(absentEntry.absentKey()); + return SUCCESS; + } else { + Data reverseKey = rq.entry().value(); + if (reverseKey.equals(absentEntry.absentKey())) { + // recover + absentEntry.doInsert(value); + return SUCCESS; + } + throw new IllegalArgumentException("Try to associate " + + absentEntry.absentKey() + " with " + value + ", but in the reverse " + + "map this value already maps to " + reverseKey); + } + } + } +} +``` + +Usage: +``` +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"); +System.out.println(map2.get("1")); +``` + +### CRDT values for replicated Chronicle Maps -- Grow-only set + +`Set` values won't replace each other on replication, but will converge to a single, common set, +the union of all elements added to all sets on all replicated nodes. + +``` +class GrowOnlySetValuedMapEntryOperations + implements MapEntryOperations, Void> { + + private static final GrowOnlySetValuedMapEntryOperations INSTANCE = + new GrowOnlySetValuedMapEntryOperations(); + + public static + MapEntryOperations, Void> growOnlySetValuedMapEntryOperations() { + return GrowOnlySetValuedMapEntryOperations.INSTANCE; + } + + private GrowOnlySetValuedMapEntryOperations() {} + + @Override + public Void remove(@NotNull MapEntry> entry) { + throw new UnsupportedOperationException("Map with grow-only set values " + + "doesn't support map value removals"); + } +} +``` + +``` +class GrowOnlySetValuedMapRemoteOperations + implements MapRemoteOperations, Void> { + + private static final GrowOnlySetValuedMapRemoteOperations INSTANCE = + new GrowOnlySetValuedMapRemoteOperations(); + + public static + MapRemoteOperations, Void> growOnlySetValuedMapRemoteOperations() { + return GrowOnlySetValuedMapRemoteOperations.INSTANCE; + } + + private GrowOnlySetValuedMapRemoteOperations() {} + + @Override + public void put(MapRemoteQueryContext, Void> q, Data, ?> newValue) { + MapReplicableEntry> entry = q.entry(); + if (entry != null) { + Set merged = new HashSet<>(entry.value().get()); + merged.addAll(newValue.get()); + q.replaceValue(entry, q.wrapValueAsValue(merged)); + } else { + q.insert(q.absentEntry(), newValue); + q.entry().updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + } + } + + @Override + public void remove(MapRemoteQueryContext, Void> q) { + throw new UnsupportedOperationException(); + } +} +``` + +Usage: +``` +ChronicleMap> map1 = ChronicleMapBuilder + .of(Integer.class, (Class>) (Class) Set.class) + .entries(100) + .averageValueSize(1000) + .entryOperations(growOnlySetValuedMapEntryOperations()) + .remoteOperations(growOnlySetValuedMapRemoteOperations()) + .replication((byte) 1, /* ... replicated nodes */) + .instance() + .name("map1") + .create(); +``` + + # Performance Topics There are general principles we can give direction on - for specific advise we believe consulting diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java index 95d13b3f6..8b95ade53 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java @@ -19,6 +19,8 @@ package net.openhft.chronicle.hash; import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.MapMethods; +import net.openhft.chronicle.map.MapQueryContext; import net.openhft.chronicle.set.ChronicleSet; import org.jetbrains.annotations.NotNull; @@ -40,7 +42,7 @@ public interface ChronicleHash, EQC extends ExternalH * * @return the file this {@link ChronicleMap} or {@link ChronicleSet} is mapped to, * or {@code null} if it is not mapped to any file - * @see ChronicleHashBuilder#createPersistedTo(java.io.File) + * @see ChronicleHashBuilder#createPersistedTo(File) */ File file(); @@ -57,9 +59,33 @@ public interface ChronicleHash, EQC extends ExternalH */ Class keyClass(); + /** + * Returns the context to perform arbitrary operations with the given key in this map. + * Conventionally, try-with-resources block should wrap the returned context:
{@code
+     * try (ExternalHashQueryContext q = hash.queryContext(key)) {
+     *     // ... do something
+     * }}
+ * See {@link HashQueryContext} and {@link MapMethods} for a lot of inspiration about using this + * functionality. + * + * @param key the queried key + * @return the context to perform operations with the key + * @see HashQueryContext + * @see MapQueryContext + * @see ExternalHashQueryContext + * @see MapMethods + */ @NotNull EQC queryContext(K key); + /** + * Equivalent to {@link #queryContext(Object)}, but accepts {@code Data} instead of key as + * an object. Useful, when you already have {@code Data}, calling this method instead of {@link + * #queryContext(Object)} might help to avoid unnecessary deserialization. + * + * @param key the queried key as {@code Data} + * @return the context to perform operations with the key + */ @NotNull EQC queryContext(Data key); /** diff --git a/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java b/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java index adaa346aa..c3bada023 100644 --- a/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java +++ b/src/main/java/net/openhft/chronicle/hash/HashQueryContext.java @@ -2,7 +2,11 @@ package net.openhft.chronicle.hash; import net.openhft.chronicle.hash.locks.InterProcessLock; import net.openhft.chronicle.hash.locks.InterProcessReadWriteUpdateLock; +import net.openhft.chronicle.map.MapEntryOperations; import net.openhft.chronicle.map.MapMethods; +import net.openhft.chronicle.map.MapQueryContext; +import net.openhft.chronicle.set.SetEntryOperations; +import net.openhft.chronicle.set.SetQueryContext; /** * Context of {@link ChronicleHash} operations with individual keys. @@ -21,10 +25,11 @@ import net.openhft.chronicle.map.MapMethods; * try (ExternalMapQueryContext q = map.queryContext(key)) { * // q.entry(), checks if the entry is present in the map, and acquires * // the read lock for that. - * if (q.entry() != null) { + * MapEntry entry = q.entry(); + * if (entry != null) { * // Tries to acquire the write lock to perform modification, * // but this is an illegal upgrade: read -> write, throws IllegalMonitorStateException - * q.remove(q.entry()); + * q.remove(entry); * } * }} * So, to workaround this, you should acquire the {@linkplain #updateLock() update lock}, @@ -33,9 +38,9 @@ import net.openhft.chronicle.map.MapMethods; * // CORRECT * try (ExternalMapQueryContext q = map.queryContext(key)) { * q.updateLock().lock(); // acquire the update lock before checking the entry presence. - * if (q.entry() != null) { - * q.remove(q.entry()); - * } + * MapEntry entry = q.entry(); + * if (entry != null) + * q.remove(entry); * }} * *
  • You want to try to acquire some lock heuristically, in order to improve total {@code @@ -46,14 +51,14 @@ import net.openhft.chronicle.map.MapMethods; * // 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 * if (q.readLock().tryLock()) { - * MapEntry entry = q.entry(); + * MapEntry entry = q.entry(); * if (entry != null) { * // Entry is present, return * returnValue.returnValue(entry.value()); * return; * } * // Key is absent - * // Need to unlock, to lock to update lock later. Direct updrage is forbidden. + * // Need to unlock, to lock to update lock later. Direct upgrade is forbidden. * q.readLock().unlock(); * } * // We are here, either if we: @@ -63,7 +68,7 @@ import net.openhft.chronicle.map.MapMethods; * // 2) Seen the entry is absent under the read lock. This means we need to insert * // the default value into the map. that requires update-level access as well * q.updateLock().lock(); - * MapEntry entry = q.entry(); + * MapEntry entry = q.entry(); * if (entry != null) { * // Entry is present, return * returnValue.returnValue(entry.value()); @@ -74,7 +79,7 @@ import net.openhft.chronicle.map.MapMethods; * 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 custom timeout: + * 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)) {
    @@ -84,9 +89,53 @@ import net.openhft.chronicle.map.MapMethods;
      *     }
      * }}
  • * + * + *

    {@code HashQueryContext} defines the common pattern for working with {@code ChronicleHash} + * contexts: it has a pair of methods, {@link #entry()} and {@link #absentEntry()}, at any moment + * one of them returns an (absent) entry context object, another - {@code null}, depending on the + * presence of the {@linkplain #queriedKey() queried key} in the {@code ChronicleHash}. Thus, + * block of code that uses {@code HashQueryContext} usually has an if-else statement, + * with "then" branch for dealing with the present entry, {@code else} branch for dealing with + * the absent entry, or vise-versa. For example:

    {@code
    + * 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].
    + *     // Returns the resulting point
    + *     try (ExternalMapQueryContext q = map.queryContext(key)) {
    + *         Point offHeapPoint;
    + *         q.updateLock().lock();
    + *         MapEntry entry = q.entry();
    + *         if (entry != null) {
    + *             // Key is present
    + *             offHeapPoint = entry.value().getUsing(using);
    + *         } else {
    + *             // Key is absent
    + *             q.insert(q.absentEntry(), q.defaultValue(q.absentEntry()));
    + *             offHeapPoint = q.entry().value().getUsing(using);
    + *         }
    + *         offHeapPoint.addX(xMove);
    + *         offHeapPoint.addY(yMove);
    + *         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) + * @see ChronicleHash#queryContext(Object) */ public interface HashQueryContext extends HashContext, InterProcessReadWriteUpdateLock { 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 bdd938afe..e2f488c33 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java @@ -16,7 +16,6 @@ package net.openhft.chronicle.hash.impl; -import net.openhft.chronicle.core.OS; import net.openhft.chronicle.hash.ChronicleHash; import net.openhft.chronicle.hash.ExternalHashQueryContext; import net.openhft.chronicle.hash.KeyContext; diff --git a/src/main/java/net/openhft/chronicle/hash/AcceptanceDecision.java b/src/main/java/net/openhft/chronicle/hash/replication/AcceptanceDecision.java similarity index 72% rename from src/main/java/net/openhft/chronicle/hash/AcceptanceDecision.java rename to src/main/java/net/openhft/chronicle/hash/replication/AcceptanceDecision.java index f3c7a9f37..bc122e550 100644 --- a/src/main/java/net/openhft/chronicle/hash/AcceptanceDecision.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/AcceptanceDecision.java @@ -16,25 +16,21 @@ * limitations under the License. */ -package net.openhft.chronicle.hash; +package net.openhft.chronicle.hash.replication; +import net.openhft.chronicle.hash.ChronicleHash; +import net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy; import net.openhft.chronicle.map.replication.MapRemoteOperations; import net.openhft.chronicle.set.replication.SetRemoteOperations; /** * Decision, if {@link MapRemoteOperations remote modification operation} should be accepted - * or discarded. - * * - * @see MapRemoteOperations - * @see SetRemoteOperations + * or discarded. Used in {@link DefaultEventualConsistencyStrategy}. */ public enum AcceptanceDecision { /** * Acceptance decision -- the remote modification operation is applied to the local - * {@link ChronicleHash} state. This decision should also been returned, when the actual - * state modification is not needed (for example, remote {@code remove entry} operation, while - * the entry is not present in the ChronicleHash locally), but the operation is generally - * considered acceptable. + * {@link ChronicleHash} state. */ ACCEPT, 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 94d3b7747..b33cd0e64 100644 --- a/src/main/java/net/openhft/chronicle/hash/replication/DefaultEventualConsistencyStrategy.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/DefaultEventualConsistencyStrategy.java @@ -18,14 +18,13 @@ package net.openhft.chronicle.hash.replication; -import net.openhft.chronicle.hash.AcceptanceDecision; import net.openhft.chronicle.hash.ChronicleHash; import net.openhft.chronicle.hash.ChronicleHashBuilder; import net.openhft.chronicle.map.replication.MapRemoteOperations; import net.openhft.chronicle.set.replication.SetRemoteOperations; -import static net.openhft.chronicle.hash.AcceptanceDecision.ACCEPT; -import static net.openhft.chronicle.hash.AcceptanceDecision.DISCARD; +import static net.openhft.chronicle.hash.replication.AcceptanceDecision.ACCEPT; +import static net.openhft.chronicle.hash.replication.AcceptanceDecision.DISCARD; /** * Specifies the default eventual consistency strategy for {@link ChronicleHashBuilder#replication( diff --git a/src/main/java/net/openhft/chronicle/hash/replication/HashReplicableEntry.java b/src/main/java/net/openhft/chronicle/hash/replication/HashReplicableEntry.java index b23d8dc5a..f2395eb6b 100644 --- a/src/main/java/net/openhft/chronicle/hash/replication/HashReplicableEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/HashReplicableEntry.java @@ -20,6 +20,6 @@ package net.openhft.chronicle.hash.replication; import net.openhft.chronicle.hash.HashEntry; -public interface HashReplicableEntry extends HashEntry,ReplicableEntry { +public interface HashReplicableEntry extends HashEntry, ReplicableEntry { } 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 43eb977a2..46d795aec 100644 --- a/src/main/java/net/openhft/chronicle/hash/replication/ReplicableEntry.java +++ b/src/main/java/net/openhft/chronicle/hash/replication/ReplicableEntry.java @@ -1,7 +1,72 @@ package net.openhft.chronicle.hash.replication; +import net.openhft.chronicle.hash.ChronicleHash; +import net.openhft.chronicle.hash.ChronicleHashBuilder; +import net.openhft.chronicle.hash.HashAbsentEntry; +import net.openhft.chronicle.hash.HashEntry; +import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.Replica; +import net.openhft.chronicle.map.replication.MapRemoteOperations; +import net.openhft.chronicle.set.replication.SetRemoteOperations; + +/** + * Abstracts an in replicated {@link ChronicleHash}. A {@link HashAbsentEntry} might be a {@code + * ReplicableEntry} as well as {@link HashEntry}. + */ 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 + * HashRemoteQueryContext#remoteIdentifier()}. + * + *

    On {@code ChronicleHash} local operations with entries, like {@link ChronicleMap#put( + * 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. + * + * @return the identifier, associated with this entry + */ byte originIdentifier(); + /** + * The timestamp, associated with this entry. Originally, and by default, this timestamp means + * the time of the last. + * + *

    When the entry is replicated, this timestamp comes to remote nodes as {@link + * HashRemoteQueryContext#remoteTimestamp()}. + * + *

    On {@code ChronicleHash} local operations with entries, like {@link ChronicleMap#put( + * Object, Object)}, this timestamp is overwritten using {@linkplain + * ChronicleHashBuilder#timeProvider(TimeProvider) the configured time provider}. On remote + * operations, proxied through {@link MapRemoteOperations} or {@link SetRemoteOperations}, + * you are free to overwrite this timestamp by any value, using {@link #updateOrigin(byte, long) + * } method. + * + * @return the timestamp, associated with this entry + * @see TimeProvider + */ long originTimestamp(); + + /** + * Overwrite the entry's associated identifier and timestamp. After this call {@link + * #originIdentifier()} returns the given {@code newIdentifier} and {@link #originTimestamp()} + * returns the given {@code newTimestamp} respectively. + * + * @param newIdentifier the new identifier for the entry + * @param newTimestamp the new timestamp for the entry + */ + void updateOrigin(byte newIdentifier, long newTimestamp); + + /** + * Suppress the entry, if it was scheduled to be replicated over to remote Chronicle nodes. + */ + void dropChanged(); + + /** + * Propagate the entry, schedule it to be replicated over to remote Chronicle nodes. + */ + void raiseChanged(); } diff --git a/src/main/java/net/openhft/chronicle/map/ChannelFactory.java b/src/main/java/net/openhft/chronicle/map/ChannelFactory.java deleted file mode 100644 index 5f326f4fd..000000000 --- a/src/main/java/net/openhft/chronicle/map/ChannelFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 Higher Frequency Trading - * - * http://www.higherfrequencytrading.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.openhft.chronicle.map; - -/** - * Created by Rob Austin - */ -public interface ChannelFactory { - void createChannel(short channelID); -} diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java index 65ed0c321..998886298 100755 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMapBuilder.java @@ -28,6 +28,7 @@ import net.openhft.chronicle.hash.replication.*; import net.openhft.chronicle.hash.serialization.*; import net.openhft.chronicle.hash.serialization.internal.MetaBytesWriter; import net.openhft.chronicle.hash.serialization.internal.MetaProvider; +import net.openhft.chronicle.map.replication.MapRemoteOperations; import net.openhft.chronicle.set.ChronicleSetBuilder; import net.openhft.lang.Maths; import net.openhft.lang.io.Bytes; @@ -168,6 +169,7 @@ public final class ChronicleMapBuilder implements MapMethods methods = DefaultSpi.mapMethods(); MapEntryOperations entryOperations = mapEntryOperations(); + MapRemoteOperations remoteOperations = mapRemoteOperations(); ChronicleMapBuilder(Class keyClass, Class valueClass) { keyBuilder = new SerializationBuilder<>(keyClass, SerializationBuilder.Role.KEY); @@ -1495,8 +1497,8 @@ public final class ChronicleMapBuilder implements } /** - * Inject your SPI code around basic {@code ChronicleMap}'s operations with present entries: - * removing entries and replacing the entries' value. + * Inject your SPI code around basic {@code ChronicleMap}'s operations with entries: + * removing entries, replacing the entries' value and inserting the new entry. * * This affects behaviour of ordinary map.put(), map.remove(), etc. calls, as well as removes * and replacing values during iterations, remote map calls and @@ -1520,5 +1522,12 @@ public final class ChronicleMapBuilder implements this.methods = mapMethods; return this; } + + public ChronicleMapBuilder remoteOperations( + MapRemoteOperations remoteOperations) { + Objects.requireNonNull(remoteOperations); + this.remoteOperations = remoteOperations; + return this; + } } diff --git a/src/main/java/net/openhft/chronicle/map/MapContext.java b/src/main/java/net/openhft/chronicle/map/MapContext.java index c59af1c82..da1710fca 100644 --- a/src/main/java/net/openhft/chronicle/map/MapContext.java +++ b/src/main/java/net/openhft/chronicle/map/MapContext.java @@ -22,11 +22,14 @@ import net.openhft.chronicle.hash.HashContext; import net.openhft.chronicle.hash.Data; /** - * Context, in which {@link MapEntry MapEntries} are accessed. + * Context, in which {@link MapEntry MapEntries} are accessed. {@code MapContext} allows to access + * {@link MapEntryOperations}, configured for the accessed {@link ChronicleMap} via {@link + * ChronicleMapBuilder#entryOperations(MapEntryOperations)}. {@code MapContext} implements {@code + * MapEntryOperations} by delegation to the configured {@code entryOperations}. * * @param the map key type * @param the map value type - * @param the return type of {@link MapEntryOperations} specialized for the queried map + * @param the return type of {@link MapEntryOperations} specified for the queried map */ public interface MapContext extends HashContext, MapEntryOperations { /** diff --git a/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java b/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java index 3eeffaba6..cd94e4706 100644 --- a/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java +++ b/src/main/java/net/openhft/chronicle/map/MapEntryOperations.java @@ -19,17 +19,85 @@ package net.openhft.chronicle.map; import net.openhft.chronicle.hash.Data; +import net.openhft.chronicle.map.replication.MapRemoteOperations; import org.jetbrains.annotations.NotNull; /** * SPI interface for customizing "low-level" modification operations on {@link ChronicleMap} - * entries. All {@code ChronicleMap} modifications operate via and instance of this interface: + * entries. All {@code ChronicleMap} modifications operate via an instance of this interface: *

      - *
    • Ordinary query operations: {@code map.put()}, {@code map.compute()}. In fact, the
    • + *
    • 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 + * implementation (i. e. a map that preserves the uniqueness of its values as well as that of + * its keys), that includes two {@code ChronicleMaps}, the {@code MapEntryOperations}' methods return + * type could be used to indicate if we were successful to lock both maps before performing + * the update:

    {@code
    + * enum DualLockSuccess {SUCCESS, FAIL}
    + *
    + * class BiMapEntryOperations implements MapEntryOperations {
    + *     ChronicleMap reverse;
    + *
    + *     public void setReverse(ChronicleMap reverse) {
    + *         this.reverse = reverse;
    + *     }
    + *
    + *     @Override
    + *     public DualLockSuccess remove(@NotNull MapEntry entry) {
    + *         try (ExternalMapQueryContext rq = reverse.queryContext(entry.value())) {
    + *             if (!rq.updateLock().tryLock()) {
    + *                 if (entry.context() instanceof MapQueryContext)
    + *                     return FAIL;
    + *                 throw new IllegalStateException("Concurrent modifications to reverse map " +
    + *                         "during remove during iteration");
    + *             }
    + *             MapEntry reverseEntry = rq.entry();
    + *             if (reverseEntry != null) {
    + *                 entry.doRemove();
    + *                 reverseEntry.doRemove();
    + *                 return SUCCESS;
    + *             } else {
    + *                 throw new IllegalStateException(entry.key() + " maps to " + entry.value() +
    + *                         ", but in the reverse map this value is absent");
    + *             }
    + *         }
    + *     }
    + *
    + *     // ... other methods
    + * }
    + *
    + * class BiMapMethods implements MapMethods {
    + *     @Override
    + *     public void remove(MapQueryContext q, ReturnValue returnValue) {
    + *         while (true) {
    + *             q.updateLock().lock();
    + *             try {
    + *                 MapEntry entry = q.entry();
    + *                 if (entry != null) {
    + *                     returnValue.returnValue(entry.value());
    + *                     if (q.remove(entry) == SUCCESS)
    + *                         return;
    + *                 }
    + *             } finally {
    + *                 q.readLock().unlock();
    + *             }
    + *         }
    + *     }
    + *
    + *     // ... 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) */ public interface MapEntryOperations { @@ -43,6 +111,7 @@ public interface MapEntryOperations { * @param entry the entry to remove * @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 */ default R remove(@NotNull MapEntry entry) { entry.doRemove(); @@ -52,9 +121,14 @@ public interface MapEntryOperations { /** * 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 * @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 */ default R replaceValue(@NotNull MapEntry entry, Data newValue) { entry.doReplaceValue(newValue); @@ -64,11 +138,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}. - * Returns {@code true} if the insertion was successful, {@code false} if it was discarded - * for any reason. + * + * @implNote default implementation calls {@link MapAbsentEntry#doInsert(Data) + * absentEntry.doInsert(value)} and returns {@code null}. * * @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 */ 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 a6ef293d1..85f6bf114 100644 --- a/src/main/java/net/openhft/chronicle/map/MapMethods.java +++ b/src/main/java/net/openhft/chronicle/map/MapMethods.java @@ -21,6 +21,7 @@ package net.openhft.chronicle.map; import net.openhft.chronicle.hash.Data; import java.util.function.BiFunction; +import java.util.function.Function; import static net.openhft.chronicle.hash.Data.bytesEquivalent; import static net.openhft.chronicle.map.MapMethodsSupport.returnCurrentValueIfPresent; @@ -28,6 +29,8 @@ import static net.openhft.chronicle.map.MapMethodsSupport.tryReturnCurrentValueI /** * SPI interface for customizing behaviour of the specific Map's methods with individual keys. + * + * @see ChronicleMapBuilder#mapMethods(MapMethods) */ public interface MapMethods { @@ -38,11 +41,34 @@ public interface MapMethods { /** * Backing {@link ChronicleMap#get}, {@link ChronicleMap#getUsing} and * {@link ChronicleMap#getOrDefault} methods. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * MapEntry entry = q.entry();
    +     * if (entry != null)
    +     *     returnValue.returnValue(entry.value());
    +     * }
    */ default void get(MapQueryContext q, ReturnValue returnValue) { returnCurrentValueIfPresent(q, returnValue); } + /** + * Backing {@link ChronicleMap#put(Object, Object)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * // We cannot read the previous value under read lock, because then we will need
    +     * // to release the read lock -> acquire write lock, the value might be updated in
    +     * // between, that will break ConcurrentMap.put() atomicity guarantee. So, we acquire
    +     * // update lock from the start:
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     returnValue.returnValue(entry.value());
    +     *     q.replaceValue(entry, value);
    +     * } else {
    +     *     q.insert(q.absentEntry(), value);
    +     * }}
    + */ default void put(MapQueryContext q, Data value, ReturnValue returnValue) { // We cannot read the previous value under read lock, because then we will need // to release the read lock -> acquire write lock, the value might be updated in @@ -58,6 +84,29 @@ public interface MapMethods { } } + /** + * Backing {@link ChronicleMap#putIfAbsent(Object, Object)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * if (q.readLock().tryLock()) {
    +     *     MapEntry entry = q.entry();
    +     *     if (entry != null) {
    +     *         returnValue.returnValue(entry.value());
    +     *         return;
    +     *     }
    +     *     // Key is absent
    +     *     q.readLock().unlock();
    +     * }
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     returnValue.returnValue(entry.value());
    +     *     return;
    +     * }
    +     * // Key is absent
    +     * q.insert(q.absentEntry(), value);
    +     * }
    + */ default void putIfAbsent(MapQueryContext q, Data value, ReturnValue returnValue) { if (tryReturnCurrentValueIfPresent(q, returnValue)) @@ -66,6 +115,33 @@ public interface MapMethods { q.insert(q.absentEntry(), value); } + /** + * Backing {@link ChronicleMap#acquireUsing(Object, Object)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * if (q.readLock().tryLock()) {
    +     *     MapEntry entry = q.entry();
    +     *     if (entry != null) {
    +     *         returnValue.returnValue(entry.value());
    +     *         return;
    +     *     }
    +     *     // Key is absent
    +     *     q.readLock().unlock();
    +     * }
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     returnValue.returnValue(entry.value());
    +     *     return;
    +     * }
    +     * // Key is absent
    +     * q.insert(q.absentEntry(), q.defaultValue(q.absentEntry()));
    +     * // Meaningful to return the default as newly-inserted, not the default entry itself.
    +     * // map.acquireUsing() is most useful for data-value generated values, for which it makes
    +     * // big difference -- what bytes to refer. Consider map.acquireUsing(...).incrementValue();
    +     * returnValue.returnValue(q.entry().value());
    +     * }
    + */ default void acquireUsing(MapQueryContext q, ReturnValue returnValue) { if (tryReturnCurrentValueIfPresent(q, returnValue)) return; @@ -73,10 +149,60 @@ public interface MapMethods { q.insert(q.absentEntry(), q.defaultValue(q.absentEntry())); // meaningful to return the default as newly-inserted, not the default entry itself. // map.acquireUsing() is most useful for data-value generated values, for which it makes - // big difference -- what bytes to refer. map.acquireUsing().incrementValue(); + // big difference -- what bytes to refer. consider map.acquireUsing(...).incrementValue(); + // The same reasoning is applied in all same occurrences in this class file returnValue.returnValue(q.entry().value()); } + /** + * Backing {@link ChronicleMap#computeIfAbsent(Object, Function)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * if (q.readLock().tryLock()) {
    +     *     MapEntry entry = q.entry();
    +     *     if (entry != null) {
    +     *         returnValue.returnValue(entry.value());
    +     *         return;
    +     *     }
    +     *     // Key is absent
    +     *     q.readLock().unlock();
    +     * }
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     returnValue.returnValue(entry.value());
    +     *     return;
    +     * }
    +     * // Key is absent
    +     * q.insert(q.absentEntry(), q.wrapValueAsValue(mappingFunction.apply(q.queriedKey().get())));
    +     * returnValue.returnValue(q.entry().value());
    +     * }
    + */ + default void computeIfAbsent(MapQueryContext q, + Function mappingFunction, + ReturnValue returnValue) { + if (tryReturnCurrentValueIfPresent(q, returnValue)) + return; + // Key is absent + q.insert(q.absentEntry(), q.wrapValueAsValue(mappingFunction.apply(q.queriedKey().get()))); + returnValue.returnValue(q.entry().value()); + } + + /** + * Backing {@link ChronicleMap#remove(Object)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * // We cannot read the previous value under read lock, because then we will need
    +     * // to release the read lock -> acquire write lock, the value might be updated in
    +     * // between, that will break ConcurrentMap.remove() atomicity guarantee. So, we acquire
    +     * // update lock from the start:
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     returnValue.returnValue(entry.value());
    +     *     q.remove(entry);
    +     * }}
    + */ default void remove(MapQueryContext q, ReturnValue returnValue) { // We cannot read the previous value under read lock, because then we will need // to release the read lock -> acquire write lock, the value might be updated in @@ -90,6 +216,24 @@ public interface MapMethods { } } + /** + * Backing {@link ChronicleMap#remove(Object, Object)} method. + * + * @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,
    +     * // as in putIfAbsent()/acquireUsing(), start with update lock:
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null && Data.bytesEquivalent(entry.value(), value)) {
    +     *     q.remove(entry);
    +     *     return true;
    +     * } 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, // so don't try to check key presence and value equivalence under read lock first, @@ -104,6 +248,20 @@ public interface MapMethods { } } + /** + * Backing {@link ChronicleMap#replace(Object, Object)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * // replace(key, value) should find the key & put the value most of the time,
    +     * // so don't try to check key presence under read lock first,
    +     * // as in putIfAbsent()/acquireUsing(), start with update lock:
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     returnValue.returnValue(entry.value());
    +     *     q.replaceValue(entry, value);
    +     * }}
    + */ default void replace(MapQueryContext q, Data value, ReturnValue returnValue) { // replace(key, value) should find the key & put the value most of the time, @@ -117,6 +275,24 @@ public interface MapMethods { } } + /** + * Backing {@link ChronicleMap#replace(Object, Object, Object)} method. + * + * @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,
    +     * // as in putIfAbsent()/acquireUsing(), start with update lock:
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null && Data.bytesEquivalent(((MapEntry) entry).value(), oldValue)) {
    +     *     q.replaceValue(entry, newValue);
    +     *     return true;
    +     * } else {
    +     *     return false;
    +     * }}
    + * + * @return if the entry was replaced + */ default boolean replace(MapQueryContext q, Data oldValue, Data newValue) { // replace(key, old, new) should find the entry & put new value most of the time, @@ -132,9 +308,30 @@ public interface MapMethods { } } + /** + * Backing {@link ChronicleMap#compute(Object, BiFunction)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * V oldValue = entry != null ? entry.value().get() : null;
    +     * V newValue = remappingFunction.apply(q.queriedKey().get(), oldValue);
    +     * if (newValue != null) {
    +     *     Data newValueData = q.wrapValueAsValue(newValue);
    +     *     if (entry != null) {
    +     *         q.replaceValue(entry, newValueData);
    +     *     } else {
    +     *         q.insert(q.absentEntry(), newValueData);
    +     *         entry = q.entry();
    +     *     }
    +     *     returnValue.returnValue(entry.value());
    +     * } else if (entry != null) {
    +     *     q.remove(entry);
    +     * }}
    + */ default void compute(MapQueryContext q, - BiFunction remappingFunction, - ReturnValue returnValue) { + BiFunction remappingFunction, + ReturnValue returnValue) { q.updateLock().lock(); MapEntry entry = q.entry(); V oldValue = entry != null ? entry.value().get() : null; @@ -145,16 +342,76 @@ public interface MapMethods { q.replaceValue(entry, newValueData); } else { q.insert(q.absentEntry(), newValueData); + entry = q.entry(); + assert entry != null; } - returnValue.returnValue(newValueData); + returnValue.returnValue(entry.value()); } else if (entry != null) { q.remove(entry); } } + /** + * Backing {@link ChronicleMap#computeIfPresent(Object, BiFunction)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * q.updateLock().lock();
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     V oldValue = entry.value().get();
    +     *     V newValue = remappingFunction.apply(q.queriedKey().get(), oldValue);
    +     *     if (newValue != null ) {
    +     *         q.replaceValue(entry, q.wrapValueAsValue(newValue));
    +     *         returnValue.returnValue(q.entry().value());
    +     *     } else {
    +     *         q.remove(entry);
    +     *     }
    +     * }}
    + */ + default void computeIfPresent(MapQueryContext q, + BiFunction remappingFunction, + ReturnValue returnValue) { + q.updateLock().lock(); + MapEntry entry = q.entry(); + if (entry != null) { + V oldValue = entry.value().get(); + V newValue = remappingFunction.apply(q.queriedKey().get(), oldValue); + if (newValue != null ) { + q.replaceValue(entry, q.wrapValueAsValue(newValue)); + returnValue.returnValue(q.entry().value()); + } else { + q.remove(entry); + } + } + } + + /** + * Backing {@link ChronicleMap#merge(Object, Object, BiFunction)} method. + * + * @implNote the default implementation is equivalent to
    {@code
    +     * q.updateLock().lock();
    +     * Data newValueData;
    +     * MapEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     V oldValue = entry.value().get();
    +     *     V newValue = remappingFunction.apply(oldValue, value.get());
    +     *     if (newValue == null) {
    +     *         q.remove(entry);
    +     *         return;
    +     *     }
    +     *     newValueData = q.wrapValueAsValue(newValue);
    +     *     q.replaceValue(entry, newValueData);
    +     * } else {
    +     *     newValueData = value;
    +     *     q.insert(q.absentEntry(), newValueData);
    +     *     entry = q.entry();
    +     * }
    +     * returnValue.returnValue(entry.value());
    +     * }
    + */ default void merge(MapQueryContext q, Data value, - BiFunction remappingFunction, - ReturnValue returnValue) { + BiFunction remappingFunction, + ReturnValue returnValue) { q.updateLock().lock(); Data newValueData; MapEntry entry = q.entry(); @@ -170,7 +427,9 @@ public interface MapMethods { } else { newValueData = value; q.insert(q.absentEntry(), newValueData); + entry = q.entry(); + assert entry != null; } - returnValue.returnValue(newValueData); + returnValue.returnValue(entry.value()); } } diff --git a/src/main/java/net/openhft/chronicle/map/MapQueryContext.java b/src/main/java/net/openhft/chronicle/map/MapQueryContext.java index 5c8a6bc67..05c534330 100644 --- a/src/main/java/net/openhft/chronicle/map/MapQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/MapQueryContext.java @@ -24,8 +24,10 @@ import org.jetbrains.annotations.Nullable; /** * The context of {@link ChronicleMap} operations with individual keys - * (most: {@code get()}, {@code put()}, etc., opposed to bulk operations). This is the main - * context type of {@link MapMethods} and {@link MapRemoteOperations}. + * (like during {@code get()}, {@code put()}, etc., opposed to bulk operations). + * This is the main context type of {@link MapMethods} and {@link MapRemoteOperations}. + * + * * * @param the map key type * @param the map value type diff --git a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java index 2eeb5dc2d..3f1e76416 100644 --- a/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ReplicatedChronicleMap.java @@ -102,9 +102,7 @@ public class ReplicatedChronicleMap remoteOperations = - DefaultSpi.mapRemoteOperations(); + public transient MapRemoteOperations remoteOperations; transient CompiledReplicatedMapQueryContext remoteOpContext; transient CompiledReplicatedMapIterationContext remoteItContext; @@ -113,6 +111,7 @@ public class ReplicatedChronicleMap) builder.remoteOperations; this.localIdentifier = replication.identifier(); this.bootstrapOnlyLocalEntries = replication.bootstrapOnlyLocalEntries(); @@ -290,6 +289,19 @@ public class ReplicatedChronicleMap 0L; + next = modIterSet.nextSetBit(next + 1L)) { + try { + ModificationIterator modificationIterator = modificationIterators.get((int) next); + if (modificationIterator.dropChange(segmentIndex, oldPos)) + modificationIterator.raiseChange(segmentIndex, newPos); + } catch (Exception e) { + LOG.error("", e); + } + } + } + @Override public boolean identifierCheck(@NotNull ReplicableEntry entry, int chronicleId) { return entry.originIdentifier() == localIdentifier; @@ -515,9 +527,9 @@ public class ReplicatedChronicleMap mappingFunction) { + try (QueryContextInterface q = queryContext(key)) { + methods.computeIfAbsent(q, mappingFunction, q.defaultReturnValue()); + return q.defaultReturnValue().returnValue(); + } + } + + @Override + public V computeIfPresent(K key, + BiFunction remappingFunction) { + try (QueryContextInterface q = queryContext(key)) { + methods.computeIfPresent(q, remappingFunction, q.defaultReturnValue()); + return q.defaultReturnValue().returnValue(); + } + } } diff --git a/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapIterationContext.java b/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapIterationContext.java index 5563c4ca3..9f1415f55 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapIterationContext.java +++ b/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapIterationContext.java @@ -49,22 +49,21 @@ import java.util.function.Predicate; public class CompiledReplicatedMapIterationContext, V, VI, MVI extends MetaBytesInterop, R, T> implements AutoCloseable , HashEntry , InterProcessReadWriteUpdateLock , RemoteOperationContext , ReplicableEntry , MapContext , MapEntry , IterationContextInterface , ReplicatedChronicleMapHolder , ReplicatedIterationContextInterface , MapReplicableEntry { public void close() { + CompiledReplicatedMapIterationContext.this.closePos(); CompiledReplicatedMapIterationContext.this.wrappedValueInstanceValue.closeValue(); CompiledReplicatedMapIterationContext.this.closeReplicationUpdate(); - CompiledReplicatedMapIterationContext.this.closeUsed(); - CompiledReplicatedMapIterationContext.this.closePos(); - CompiledReplicatedMapIterationContext.this.closeKeyOffset(); - CompiledReplicatedMapIterationContext.this.closeAllocatedChunks(); CompiledReplicatedMapIterationContext.this.wrappedValueInstanceValue.closeNext(); + CompiledReplicatedMapIterationContext.this.closeKeyOffset(); CompiledReplicatedMapIterationContext.this.closeEntryRemovedOnThisIteration(); - CompiledReplicatedMapIterationContext.this.closeTheSegmentIndex(); - CompiledReplicatedMapIterationContext.this.closeKeySize(); CompiledReplicatedMapIterationContext.this.closeHashLookupPos(); - CompiledReplicatedMapIterationContext.this.closeReplicatedChronicleMapHolderImplContextAtIndexInChainDependants(); - CompiledReplicatedMapIterationContext.this.innerWriteLock.closeWriteLockForbiddenUpgradeDependants(); + CompiledReplicatedMapIterationContext.this.closeUsed(); + CompiledReplicatedMapIterationContext.this.closeKeySize(); + CompiledReplicatedMapIterationContext.this.closeTheSegmentIndex(); + CompiledReplicatedMapIterationContext.this.closeAllocatedChunks(); CompiledReplicatedMapIterationContext.this.closeReplicatedMapSegmentIterationCheckEntryNotRemovedOnThisIterationDependants(); - CompiledReplicatedMapIterationContext.this.closeValueBytesInteropValueMetaInteropDependants(); CompiledReplicatedMapIterationContext.this.closeOwnerThreadHolderCheckAccessingFromOwnerThreadDependants(); + CompiledReplicatedMapIterationContext.this.closeValueBytesInteropValueMetaInteropDependants(); + CompiledReplicatedMapIterationContext.this.closeReplicatedChronicleMapHolderImplContextAtIndexInChainDependants(); } public void incrementModCountGuarded() { @@ -91,24 +90,24 @@ public class CompiledReplicatedMapIterationContext)(entryBytesAccessor.access(entryBytes))); + this.entryKey = new EntryKeyBytesData(); this.wrappedValueInstanceValue = new WrappedValueInstanceData(); - this.innerReadLock = new ReadLock(); + this.innerWriteLock = new WriteLock(); + this.owner = Thread.currentThread(); this.copies = ThreadLocalCopies.get(); this.valueInterop = CompiledReplicatedMapIterationContext.this.m().valueInteropProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.m().originalValueInterop); this.valueReader = CompiledReplicatedMapIterationContext.this.m().valueReaderProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.m().originalValueReader); this.keyInterop = CompiledReplicatedMapIterationContext.this.h().keyInteropProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.h().originalKeyInterop); this.keyReader = CompiledReplicatedMapIterationContext.this.h().keyReaderProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.h().originalKeyReader); this.innerUpdateLock = new UpdateLock(); - this.owner = Thread.currentThread(); this.deprecatedMapKeyContextOnIteration = new DeprecatedMapKeyContextOnIteration(); - this.entryBytes = CompiledReplicatedMapIterationContext.this.h().ms.bytes(); - this.entryBytesAccessor = JavaLangBytesAccessors.uncheckedBytesAccessor(entryBytes); - this.entryBytesAccessHandle = ((T)(entryBytesAccessor.handle(entryBytes))); - this.entryBytesAccess = ((Access)(entryBytesAccessor.access(entryBytes))); - this.entryKey = new EntryKeyBytesData(); - this.innerWriteLock = new WriteLock(); - this.dummyValue = new DummyValueZeroData(); this.entryValue = new EntryValueBytesData(); + this.dummyValue = new DummyValueZeroData(); + this.innerReadLock = new ReadLock(); } public CompiledReplicatedMapIterationContext(CompiledReplicatedMapIterationContext c) { @@ -116,30 +115,72 @@ public class CompiledReplicatedMapIterationContext)(c.m)); + this.entryBytes = CompiledReplicatedMapIterationContext.this.h().ms.bytes(); + this.entryBytesAccessor = JavaLangBytesAccessors.uncheckedBytesAccessor(entryBytes); + this.entryBytesAccessHandle = ((T)(entryBytesAccessor.handle(entryBytes))); + this.entryBytesAccess = ((Access)(entryBytesAccessor.access(entryBytes))); + this.entryKey = new EntryKeyBytesData(); this.wrappedValueInstanceValue = new WrappedValueInstanceData(); - this.innerReadLock = new ReadLock(); + this.innerWriteLock = new WriteLock(); + this.owner = Thread.currentThread(); this.copies = ThreadLocalCopies.get(); this.valueInterop = CompiledReplicatedMapIterationContext.this.m().valueInteropProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.m().originalValueInterop); this.valueReader = CompiledReplicatedMapIterationContext.this.m().valueReaderProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.m().originalValueReader); this.keyInterop = CompiledReplicatedMapIterationContext.this.h().keyInteropProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.h().originalKeyInterop); this.keyReader = CompiledReplicatedMapIterationContext.this.h().keyReaderProvider.get(CompiledReplicatedMapIterationContext.this.copies, CompiledReplicatedMapIterationContext.this.h().originalKeyReader); this.innerUpdateLock = new UpdateLock(); - this.owner = Thread.currentThread(); this.deprecatedMapKeyContextOnIteration = new DeprecatedMapKeyContextOnIteration(); - this.entryBytes = CompiledReplicatedMapIterationContext.this.h().ms.bytes(); - this.entryBytesAccessor = JavaLangBytesAccessors.uncheckedBytesAccessor(entryBytes); - this.entryBytesAccessHandle = ((T)(entryBytesAccessor.handle(entryBytes))); - this.entryBytesAccess = ((Access)(entryBytesAccessor.access(entryBytes))); - this.entryKey = new EntryKeyBytesData(); - this.innerWriteLock = new WriteLock(); - this.dummyValue = new DummyValueZeroData(); this.entryValue = new EntryValueBytesData(); + this.dummyValue = new DummyValueZeroData(); + this.innerReadLock = new ReadLock(); } public class DeprecatedMapKeyContextOnIteration implements MapKeyContext { + @NotNull + private UnsupportedOperationException unsupportedLocks() { + return new UnsupportedOperationException("Lock operations are not supported (and not needed!) during iteration"); + } + + @NotNull @Override - public void close() { - throw new UnsupportedOperationException("close() is not supported during iteration"); + public InterProcessLock writeLock() { + throw unsupportedLocks(); + } + + @NotNull + @Override + public InterProcessLock updateLock() { + throw unsupportedLocks(); + } + + @NotNull + @Override + public InterProcessLock readLock() { + throw unsupportedLocks(); + } + + @Override + public V get() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.value().get(); + } + + @Override + public boolean valueEqualTo(V value) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return Data.bytesEquivalent(CompiledReplicatedMapIterationContext.this.entryValue, CompiledReplicatedMapIterationContext.this.context().wrapValueAsValue(value)); + } + + @Override + public boolean containsKey() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return true; + } + + @Override + public V getUsing(V usingValue) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.value().getUsing(usingValue); } @NotNull @@ -156,12 +197,6 @@ public class CompiledReplicatedMapIterationContext { @Override - public long size() { - return CompiledReplicatedMapIterationContext.this.m().valueSizeMarshaller.minEncodableSize(); - } - - @Override - public long offset() { - return 0; + public V get() { + throw new UnsupportedOperationException(); } @Override @@ -259,8 +253,8 @@ public class CompiledReplicatedMapIterationContext { - @Override - public T handle() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.entryBytesAccessHandle; - } - @Override public ReadAccess access() { CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); return CompiledReplicatedMapIterationContext.this.entryBytesAccess; } + @Override + public T handle() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.entryBytesAccessHandle; + } + @Override public long size() { CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); @@ -297,12 +296,6 @@ public class CompiledReplicatedMapIterationContext { @@ -709,37 +708,9 @@ public class CompiledReplicatedMapIterationContextT contextAtIndexInChain(int index) { + return ((T)(contextChain.get(index))); } - public void checkAccessingFromOwnerThread() { - if ((owner) != (Thread.currentThread())) { - throw new ConcurrentModificationException("Context shouldn\'t be accessed from multiple threads"); - } - } - - public void closeOwnerThreadHolderCheckAccessingFromOwnerThreadDependants() { - CompiledReplicatedMapIterationContext.this.closeInterationCheckOnEachPublicOperationCheckOnEachPublicOperationDependants(); + public void closeReplicatedChronicleMapHolderImplContextAtIndexInChainDependants() { + CompiledReplicatedMapIterationContext.this.closeSegmentStagesTryFindInitLocksOfThisSegmentDependants(); } public MVI valueMetaInterop(V value) { @@ -1122,109 +1107,16 @@ public class CompiledReplicatedMapIterationContext wrapValueAsValue(V value) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - WrappedValueInstanceData wrapped = CompiledReplicatedMapIterationContext.this.wrappedValueInstanceValue; - wrapped = wrapped.getUnusedWrappedValueGuarded(); - wrapped.initValue(value); - return wrapped; - } - - @Override - public R replaceValue(@NotNull - MapEntry entry, Data newValue) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.m().entryOperations.replaceValue(entry, newValue); - } - - @Override - public R remove(@NotNull - MapEntry entry) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.m().entryOperations.remove(entry); - } - - @NotNull - @Override - public Data value() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.entryValue; - } - - @Override - public Data defaultValue(@NotNull - MapAbsentEntry absentEntry) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.m().entryOperations.defaultValue(absentEntry); - } - - @NotNull - @Override - public Data key() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.entryKey; - } - - @NotNull - @Override - public InterProcessLock updateLock() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.innerUpdateLock; - } - - @NotNull - @Override - public InterProcessLock readLock() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.innerReadLock; - } - - @Override - public R insert(@NotNull - MapAbsentEntry absentEntry, Data value) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapIterationContext.this.m().entryOperations.insert(absentEntry, value); + public MapContext context() { + return CompiledReplicatedMapIterationContext.this; } public long entryBytesAccessOffset(long offset) { return entryBytesAccessor.offset(entryBytes, offset); } - public void incrementSegmentEntriesIfNeeded() { - } - @Override public ReplicatedChronicleMap m() { return m; @@ -1235,22 +1127,6 @@ public class CompiledReplicatedMapIterationContextT contextAtIndexInChain(int index) { - return ((T)(contextChain.get(index))); - } - - public void closeReplicatedChronicleMapHolderImplContextAtIndexInChainDependants() { - CompiledReplicatedMapIterationContext.this.closeSegmentStagesTryFindInitLocksOfThisSegmentDependants(); - } - - private long _MapEntryStages_sizeOfEverythingBeforeValue(long keySize, long valueSize) { - return (((CompiledReplicatedMapIterationContext.this.m().metaDataBytes) + (CompiledReplicatedMapIterationContext.this.m().keySizeMarshaller.sizeEncodingSize(keySize))) + keySize) + (CompiledReplicatedMapIterationContext.this.m().valueSizeMarshaller.sizeEncodingSize(valueSize)); - } - - long sizeOfEverythingBeforeValue(long keySize, long valueSize) { - return (_MapEntryStages_sizeOfEverythingBeforeValue(keySize, valueSize)) + (ReplicatedChronicleMap.ADDITIONAL_ENTRY_BYTES); - } - public long innerEntrySize(long sizeOfEverythingBeforeValue, long valueSize) { if (CompiledReplicatedMapIterationContext.this.m().constantlySizedEntry) { return CompiledReplicatedMapIterationContext.this.m().alignment.alignAddr((sizeOfEverythingBeforeValue + valueSize)); @@ -1261,9 +1137,8 @@ public class CompiledReplicatedMapIterationContext absentEntry, Data value) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.m().entryOperations.insert(absentEntry, value); + } + @NotNull @Override - public MapContext context() { - return CompiledReplicatedMapIterationContext.this; + public InterProcessLock readLock() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.innerReadLock; } - public long hashLookupPos = -1; - - public boolean hashLookupPosInit() { - return (this.hashLookupPos) >= 0; + @Override + public Data defaultValue(@NotNull + MapAbsentEntry absentEntry) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.m().entryOperations.defaultValue(absentEntry); } - public void initHashLookupPos(long hashLookupPos) { - this.hashLookupPos = hashLookupPos; + @NotNull + @Override + public Data key() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.entryKey; } - public long hashLookupPos() { - assert this.hashLookupPosInit() : "HashLookupPos should be init"; - return this.hashLookupPos; + @NotNull + @Override + public InterProcessLock writeLock() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.innerWriteLock; } - public void closeHashLookupPos() { - if (!(this.hashLookupPosInit())) + @Override + public Data wrapValueAsValue(V value) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + WrappedValueInstanceData wrapped = CompiledReplicatedMapIterationContext.this.wrappedValueInstanceValue; + wrapped = wrapped.getUnusedWrappedValueGuarded(); + wrapped.initValue(value); + return wrapped; + } + + @Override + public R remove(@NotNull + MapEntry entry) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.m().entryOperations.remove(entry); + } + + @Override + public R replaceValue(@NotNull + MapEntry entry, Data newValue) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.m().entryOperations.replaceValue(entry, newValue); + } + + @NotNull + @Override + public InterProcessLock updateLock() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.innerUpdateLock; + } + + @NotNull + @Override + public Data value() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapIterationContext.this.entryValue; + } + + public int allocatedChunks = 0; + + public boolean allocatedChunksInit() { + return (this.allocatedChunks) != 0; + } + + public void initAllocatedChunks(int allocatedChunks) { + this.allocatedChunks = allocatedChunks; + } + + public int allocatedChunks() { + assert this.allocatedChunksInit() : "AllocatedChunks should be init"; + return this.allocatedChunks; + } + + public void closeAllocatedChunks() { + if (!(this.allocatedChunksInit())) return ; - this.hashLookupPos = -1; - } - - public long keySize = -1; - - public boolean keySizeInit() { - return (this.keySize) >= 0; - } - - public void initKeySize(long keySize) { - this.keySize = keySize; - this.closeKeySizeDependants(); - } - - public long keySize() { - assert this.keySizeInit() : "KeySize should be init"; - return this.keySize; - } - - public void closeKeySize() { - if (!(this.keySizeInit())) - return ; - - this.closeKeySizeDependants(); - this.keySize = -1; - } - - public void closeKeySizeDependants() { - CompiledReplicatedMapIterationContext.this.entryKey.closeEntryKeyBytesDataSizeDependants(); - CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesKeyEndDependants(); + this.allocatedChunks = 0; } public int segmentIndex = -1; @@ -1369,178 +1331,59 @@ public class CompiledReplicatedMapIterationContext 0; } - private void initSegHeader() { - segmentHeaderAddress = (CompiledReplicatedMapIterationContext.this.h().ms.address()) + (CompiledReplicatedMapIterationContext.this.h().segmentHeaderOffset(segmentIndex())); - segmentHeader = BigSegmentHeader.INSTANCE; - this.closeSegHeaderDependants(); + void initSegment() { + VanillaChronicleHash h = CompiledReplicatedMapIterationContext.this.h(); + long hashLookupOffset = h.segmentOffset(segmentIndex()); + long freeListOffset = hashLookupOffset + (h.segmentHashLookupOuterSize); + freeListBytes.storePositionAndSize(h.ms, freeListOffset, h.segmentFreeListInnerSize); + freeList.reuse(freeListBytes); + entrySpaceOffset = (freeListOffset + (h.segmentFreeListOuterSize)) + (h.segmentEntrySpaceInnerOffset); + this.closeSegmentDependants(); } - public long segmentHeaderAddress() { - if (!(this.segHeaderInit())) - this.initSegHeader(); + public long entrySpaceOffset() { + if (!(this.segmentInit())) + this.initSegment(); - return this.segmentHeaderAddress; + return this.entrySpaceOffset; } - public SegmentHeader segmentHeader() { - if (!(this.segHeaderInit())) - this.initSegHeader(); + public SingleThreadedDirectBitSet freeList() { + if (!(this.segmentInit())) + this.initSegment(); - return this.segmentHeader; + return this.freeList; } - public void closeSegHeader() { - if (!(this.segHeaderInit())) + void closeSegment() { + if (!(this.segmentInit())) return ; - this.closeSegHeaderDependants(); - this.segmentHeader = null; + this.closeSegmentDependants(); + entrySpaceOffset = 0; } - public void closeSegHeaderDependants() { - CompiledReplicatedMapIterationContext.this.closeSegmentStagesTryFindInitLocksOfThisSegmentDependants(); - CompiledReplicatedMapIterationContext.this.closeLocks(); - CompiledReplicatedMapIterationContext.this.innerWriteLock.closeWriteLockLockDependants(); + public void closeSegmentDependants() { + CompiledReplicatedMapIterationContext.this.closeEntryOffset(); } - public void deleted(long deleted) { - segmentHeader().deleted(segmentHeaderAddress(), deleted); - } - - public long deleted() { - return segmentHeader().deleted(segmentHeaderAddress()); - } - - public long entries() { - return segmentHeader().size(segmentHeaderAddress()); - } - - public long size() { - return (entries()) - (deleted()); - } - - boolean tryFindInitLocksOfThisSegment(Object thisContext, int index) { - CompiledReplicatedMapIterationContext c = CompiledReplicatedMapIterationContext.this.contextAtIndexInChain(index); - if ((((c.segmentHeader()) != null) && ((c.segmentHeaderAddress()) == (segmentHeaderAddress()))) && ((c.rootContextOnThisSegment()) != null)) { - throw new IllegalStateException("Nested context not implemented yet"); - } else { - return false; - } - } - - public void closeSegmentStagesTryFindInitLocksOfThisSegmentDependants() { - CompiledReplicatedMapIterationContext.this.closeLocks(); - } - - int totalReadLockCount; - - int totalUpdateLockCount; - - int totalWriteLockCount; - - public int latestSameThreadSegmentModCount; - - public int contextModCount; - - CompiledReplicatedMapIterationContext nextNode; - - public boolean concurrentSameThreadContexts; - - LocalLockState localLockState; - - public CompiledReplicatedMapIterationContext rootContextOnThisSegment = null; - - public boolean locksInit() { - return (this.rootContextOnThisSegment) != null; - } - - void initLocks() { - localLockState = LocalLockState.UNLOCKED; - int indexOfThisContext = CompiledReplicatedMapIterationContext.this.indexInContextChain; - for (int i = indexOfThisContext - 1 ; i >= 0 ; i--) { - if (tryFindInitLocksOfThisSegment(this, i)) - return ; - - } - for (int i = indexOfThisContext + 1, size = CompiledReplicatedMapIterationContext.this.contextChain.size() ; i < size ; i++) { - if (tryFindInitLocksOfThisSegment(this, i)) - return ; - - } - rootContextOnThisSegment = this; - concurrentSameThreadContexts = false; - latestSameThreadSegmentModCount = 0; - contextModCount = 0; - nextNode = null; - totalReadLockCount = 0; - totalUpdateLockCount = 0; - totalWriteLockCount = 0; - this.closeLocksDependants(); - } - - public LocalLockState localLockState() { - if (!(this.locksInit())) - this.initLocks(); - - return this.localLockState; - } - - public CompiledReplicatedMapIterationContext rootContextOnThisSegment() { - if (!(this.locksInit())) - this.initLocks(); - - return this.rootContextOnThisSegment; - } - - void closeLocks() { - if (!(this.locksInit())) - return ; - - this.closeLocksDependants(); - if ((rootContextOnThisSegment) == this) { - closeRootLocks(); - } else { - closeNestedLocks(); - } - localLockState = null; - rootContextOnThisSegment = null; - } - - public void closeLocksDependants() { - CompiledReplicatedMapIterationContext.this.innerWriteLock.closeWriteLockLockDependants(); - } - - public void entries(long size) { - segmentHeader().size(segmentHeaderAddress(), size); - } - - long nextPosToSearchFrom() { - return segmentHeader().nextPosToSearchFrom(segmentHeaderAddress()); - } - - public void nextPosToSearchFrom(long nextPosToSearchFrom) { - segmentHeader().nextPosToSearchFrom(segmentHeaderAddress(), nextPosToSearchFrom); - } - - public void updateNextPosToSearchFrom(long allocated, int chunks) { - long nextPosToSearchFrom = allocated + chunks; - if (nextPosToSearchFrom >= (CompiledReplicatedMapIterationContext.this.h().actualChunksPerSegment)) - nextPosToSearchFrom = 0L; - - nextPosToSearchFrom(nextPosToSearchFrom); + public void moveChange(long oldPos, long newPos) { + CompiledReplicatedMapIterationContext.this.m().moveChange(CompiledReplicatedMapIterationContext.this.segmentIndex(), oldPos, newPos); } int hashLookupEntrySize; @@ -1635,25 +1478,8 @@ public class CompiledReplicatedMapIterationContext>> (keyBits())) & (valueMask()); - } - - public long maskUnsetKey(long key) { - return (key &= keyMask()) != (UNSET_KEY) ? key : keyMask(); + public long step(long pos) { + return (pos += hashLookupEntrySize()) <= (capacityMask2()) ? pos : 0L; } public void clearHashLookup() { @@ -1664,37 +1490,69 @@ public class CompiledReplicatedMapIterationContext= 0 ? pos : capacityMask2(); + } + + public long readEntry(long pos) { + return NativeBytes.UNSAFE.getLong(((address()) + pos)); + } + public void putValueVolatile(long pos, long value) { checkValueForPut(value); long currentEntry = readEntry(pos); writeEntryVolatile(pos, currentEntry, key(currentEntry), value); } + public long value(long entry) { + return (entry >>> (keyBits())) & (valueMask()); + } + + public long maskUnsetKey(long key) { + return (key &= keyMask()) != (UNSET_KEY) ? key : keyMask(); + } + void writeEntry(long pos, long prevEntry, long anotherEntry) { long entry = (prevEntry & (~(entryMask()))) | (anotherEntry & (entryMask())); NativeBytes.UNSAFE.putLong(((address()) + pos), entry); } - public long stepBack(long pos) { - return (pos -= hashLookupEntrySize()) >= 0 ? pos : capacityMask2(); + void clearEntry(long pos, long prevEntry) { + long entry = prevEntry & (~(entryMask())); + NativeBytes.UNSAFE.putLong(((address()) + pos), entry); } - public long step(long pos) { - return (pos += hashLookupEntrySize()) <= (capacityMask2()) ? pos : 0L; + void forEach(EntryConsumer action) { + for (long pos = 0L ; pos <= (capacityMask2()) ; pos += hashLookupEntrySize()) { + long entry = readEntry(pos); + if (!(empty(entry))) + action.accept(key(entry), value(entry)); + + } + } + + String hashLookupToString() { + final StringBuilder sb = new StringBuilder("{"); + forEach((long key,long value) -> sb.append(key).append('=').append(value).append(',')); + sb.append('}'); + return sb.toString(); } long indexToPos(long index) { @@ -1705,10 +1563,6 @@ public class CompiledReplicatedMapIterationContext= (CompiledReplicatedMapIterationContext.this.h().actualChunksPerSegment)) + nextPosToSearchFrom = 0L; + + nextPosToSearchFrom(nextPosToSearchFrom); + } + + public long deleted() { + return segmentHeader().deleted(segmentHeaderAddress()); + } + + public long size() { + return (entries()) - (deleted()); + } + + boolean tryFindInitLocksOfThisSegment(Object thisContext, int index) { + CompiledReplicatedMapIterationContext c = CompiledReplicatedMapIterationContext.this.contextAtIndexInChain(index); + if ((((c.segmentHeader()) != null) && ((c.segmentHeaderAddress()) == (segmentHeaderAddress()))) && ((c.rootContextOnThisSegment()) != null)) { + throw new IllegalStateException("Nested context not implemented yet"); + } else { + return false; } } - String hashLookupToString() { - final StringBuilder sb = new StringBuilder("{"); - forEach((long key,long value) -> sb.append(key).append('=').append(value).append(',')); - sb.append('}'); - return sb.toString(); + public void closeSegmentStagesTryFindInitLocksOfThisSegmentDependants() { + CompiledReplicatedMapIterationContext.this.closeLocks(); } - long entrySpaceOffset = 0; - - MultiStoreBytes freeListBytes = new MultiStoreBytes(); - - public SingleThreadedDirectBitSet freeList = new SingleThreadedDirectBitSet(); - - boolean segmentInit() { - return (entrySpaceOffset) > 0; + public void entries(long size) { + segmentHeader().size(segmentHeaderAddress(), size); } - void initSegment() { - VanillaChronicleHash h = CompiledReplicatedMapIterationContext.this.h(); - long hashLookupOffset = h.segmentOffset(segmentIndex()); - long freeListOffset = hashLookupOffset + (h.segmentHashLookupOuterSize); - freeListBytes.storePositionAndSize(h.ms, freeListOffset, h.segmentFreeListInnerSize); - freeList.reuse(freeListBytes); - entrySpaceOffset = (freeListOffset + (h.segmentFreeListOuterSize)) + (h.segmentEntrySpaceInnerOffset); - this.closeSegmentDependants(); - } - - public long entrySpaceOffset() { - if (!(this.segmentInit())) - this.initSegment(); - - return this.entrySpaceOffset; - } - - public SingleThreadedDirectBitSet freeList() { - if (!(this.segmentInit())) - this.initSegment(); - - return this.freeList; - } - - void closeSegment() { - if (!(this.segmentInit())) - return ; - - this.closeSegmentDependants(); - entrySpaceOffset = 0; - } - - public void closeSegmentDependants() { - CompiledReplicatedMapIterationContext.this.closeEntryOffset(); - } - - public void clearSegment() { - CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); - CompiledReplicatedMapIterationContext.this.clearHashLookup(); - freeList().clear(); - nextPosToSearchFrom(0L); - entries(0L); - } - - public void clear() { - clearSegment(); + long nextPosToSearchFrom() { + return segmentHeader().nextPosToSearchFrom(segmentHeaderAddress()); } public void free(long fromPos, int chunks) { @@ -1842,6 +1713,162 @@ public class CompiledReplicatedMapIterationContext= 0 ; i--) { + if (tryFindInitLocksOfThisSegment(this, i)) + return ; + + } + for (int i = indexOfThisContext + 1, size = CompiledReplicatedMapIterationContext.this.contextChain.size() ; i < size ; i++) { + if (tryFindInitLocksOfThisSegment(this, i)) + return ; + + } + rootContextOnThisSegment = this; + concurrentSameThreadContexts = false; + latestSameThreadSegmentModCount = 0; + contextModCount = 0; + nextNode = null; + totalReadLockCount = 0; + totalUpdateLockCount = 0; + totalWriteLockCount = 0; + } + + public LocalLockState localLockState() { + if (!(this.locksInit())) + this.initLocks(); + + return this.localLockState; + } + + public CompiledReplicatedMapIterationContext rootContextOnThisSegment() { + if (!(this.locksInit())) + this.initLocks(); + + return this.rootContextOnThisSegment; + } + + void closeLocks() { + if (!(this.locksInit())) + return ; + + if ((rootContextOnThisSegment) == this) { + closeRootLocks(); + } else { + closeNestedLocks(); + } + localLockState = null; + rootContextOnThisSegment = null; + } + + public void clearSegment() { + CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); + CompiledReplicatedMapIterationContext.this.clearHashLookup(); + freeList().clear(); + nextPosToSearchFrom(0L); + entries(0L); + } + + public void clear() { + clearSegment(); + } + + public void deleted(long deleted) { + segmentHeader().deleted(segmentHeaderAddress(), deleted); + } + + public long keySize = -1; + + public boolean keySizeInit() { + return (this.keySize) >= 0; + } + + public void initKeySize(long keySize) { + this.keySize = keySize; + this.closeKeySizeDependants(); + } + + public long keySize() { + assert this.keySizeInit() : "KeySize should be init"; + return this.keySize; + } + + public void closeKeySize() { + if (!(this.keySizeInit())) + return ; + + this.closeKeySizeDependants(); + this.keySize = -1; + } + + public void closeKeySizeDependants() { + CompiledReplicatedMapIterationContext.this.entryKey.closeEntryKeyBytesDataSizeDependants(); + CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesKeyEndDependants(); + } + + boolean used; + + public boolean usedInit() { + return used; + } + + public void initUsed(boolean used) { + this.used = used; + } + + void closeUsed() { + if (!(this.usedInit())) + return ; + + used = false; + } + + public long hashLookupPos = -1; + + public boolean hashLookupPosInit() { + return (this.hashLookupPos) >= 0; + } + + public void initHashLookupPos(long hashLookupPos) { + this.hashLookupPos = hashLookupPos; + } + + public long hashLookupPos() { + assert this.hashLookupPosInit() : "HashLookupPos should be init"; + return this.hashLookupPos; + } + + public void closeHashLookupPos() { + if (!(this.hashLookupPosInit())) + return ; + + this.hashLookupPos = -1; + } + public boolean entryRemovedOnThisIteration = false; boolean entryRemovedOnThisIterationInit() { @@ -1859,28 +1886,6 @@ public class CompiledReplicatedMapIterationContext= 0; + } + + void initReplicationState() { + replicationBytesOffset = keyEnd(); + } + + public long replicationBytesOffset() { + if (!(this.replicationStateInit())) + this.initReplicationState(); + + return this.replicationBytesOffset; + } + + public void closeReplicationState() { + if (!(this.replicationStateInit())) + return ; + + this.replicationBytesOffset = -1; + } + + private long identifierOffset() { + return (replicationBytesOffset()) + 8L; + } + + byte identifier() { + return entryBytesAccess.readByte(entryBytesAccessHandle, identifierOffset()); + } + + @Override + public byte originIdentifier() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return identifier(); + } + + private long timestampOffset() { + return replicationBytesOffset(); + } + + public long timestamp() { + return entryBytesAccess.readLong(entryBytesAccessHandle, timestampOffset()); + } + + @Override + public long originTimestamp() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return timestamp(); + } + + void updateReplicationState(long timestamp, byte identifier) { + entryBytes.position(replicationBytesOffset()); + entryBytes.writeLong(timestamp); + entryBytes.writeByte(identifier); + } + + public void updatedReplicationStateOnAbsentEntry() { + if (!(CompiledReplicatedMapIterationContext.this.replicationUpdateInit())) { + CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); + updateReplicationState(CompiledReplicatedMapIterationContext.this.m().timeProvider.currentTime(), CompiledReplicatedMapIterationContext.this.m().identifier()); + } + } + + public void updatedReplicationStateOnPresentEntry() { + if (!(CompiledReplicatedMapIterationContext.this.replicationUpdateInit())) { + CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); + long timestamp; + if ((identifier()) != (CompiledReplicatedMapIterationContext.this.m().identifier())) { + timestamp = Math.max(((timestamp()) + 1), CompiledReplicatedMapIterationContext.this.m().timeProvider.currentTime()); + } else { + timestamp = CompiledReplicatedMapIterationContext.this.m().timeProvider.currentTime(); + } + updateReplicationState(timestamp, CompiledReplicatedMapIterationContext.this.m().identifier()); + } + } + + @Override + public void updateOrigin(byte newIdentifier, long newTimestamp) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); + updateReplicationState(newTimestamp, newIdentifier); + } + + private long entryDeletedOffset() { + return (replicationBytesOffset()) + 9L; + } + + public boolean entryDeleted() { + return entryBytesAccess.readBoolean(entryBytesAccessHandle, entryDeletedOffset()); + } + + private boolean _MapSegmentIteration_entryIsPresent() { + return true; + } + + public boolean entryIsPresent() { + return !(CompiledReplicatedMapIterationContext.this.entryDeleted()); + } + + public void writeEntryDeleted() { + entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), true); + } + + public void writeEntryPresent() { + entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), false); } private long _MapEntryStages_countValueSizeOffset() { @@ -2019,22 +2133,6 @@ public class CompiledReplicatedMapIterationContext value) { - value.writeTo(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(valueOffset())); - } - - public void initValue(Data value) { - entryBytes.position(valueSizeOffset()); - initValSize(value.size()); - writeValue(value); - } - - public void initValueWithoutSize(Data value, long oldValueSizeOffset, long oldValueSize, long oldValueOffset) { - assert oldValueSize == (value.size()); - initValSizeEqualToOld(oldValueSizeOffset, oldValueSize, oldValueOffset); - writeValue(value); - } - private long _HashEntryStages_entryEnd() { return keyEnd(); } @@ -2047,114 +2145,74 @@ public class CompiledReplicatedMapIterationContext= 0; + public void writeValue(Data value) { + value.writeTo(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(valueOffset())); } - void initReplicationState() { - replicationBytesOffset = keyEnd(); - this.closeReplicationStateDependants(); + public void initValueWithoutSize(Data value, long oldValueSizeOffset, long oldValueSize, long oldValueOffset) { + assert oldValueSize == (value.size()); + initValSizeEqualToOld(oldValueSizeOffset, oldValueSize, oldValueOffset); + writeValue(value); } - public long replicationBytesOffset() { - if (!(this.replicationStateInit())) - this.initReplicationState(); - - return this.replicationBytesOffset; + public void initValue(Data value) { + entryBytes.position(valueSizeOffset()); + initValSize(value.size()); + writeValue(value); } - public void closeReplicationState() { - if (!(this.replicationStateInit())) + public long innerRemoteTimestamp; + + public byte innerRemoteIdentifier = ((byte)(0)); + + public boolean replicationUpdateInit() { + return (this.innerRemoteIdentifier) != ((byte)(0)); + } + + public void initReplicationUpdate(long timestamp, byte identifier) { + innerRemoteTimestamp = timestamp; + if (identifier == 0) + throw new IllegalStateException("identifier can\'t be 0"); + + innerRemoteIdentifier = identifier; + } + + public byte innerRemoteIdentifier() { + assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; + return this.innerRemoteIdentifier; + } + + public long innerRemoteTimestamp() { + assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; + return this.innerRemoteTimestamp; + } + + public void closeReplicationUpdate() { + if (!(this.replicationUpdateInit())) return ; - this.closeReplicationStateDependants(); - this.replicationBytesOffset = -1; + this.innerRemoteIdentifier = ((byte)(0)); } - public void closeReplicationStateDependants() { - CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesTimestampOffsetDependants(); - CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesUpdateReplicationStateDependants(); - CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesIdentifierOffsetDependants(); + @Override + public byte remoteIdentifier() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + return innerRemoteIdentifier(); } - private long entryDeletedOffset() { - return (replicationBytesOffset()) + 9L; - } - - public boolean entryDeleted() { - return entryBytesAccess.readBoolean(entryBytesAccessHandle, entryDeletedOffset()); - } - - private boolean _MapSegmentIteration_entryIsPresent() { + private boolean testTimeStampInSensibleRange() { + if ((CompiledReplicatedMapIterationContext.this.m().timeProvider) == (TimeProvider.SYSTEM)) { + long currentTime = TimeProvider.SYSTEM.currentTime(); + assert (Math.abs((currentTime - (timestamp())))) <= 100000000 : "unrealistic timestamp: " + (timestamp()); + assert (Math.abs((currentTime - (CompiledReplicatedMapIterationContext.this.innerRemoteTimestamp())))) <= 100000000 : "unrealistic innerRemoteTimestamp: " + (CompiledReplicatedMapIterationContext.this.innerRemoteTimestamp()); + } return true; } - public boolean entryIsPresent() { - return !(CompiledReplicatedMapIterationContext.this.entryDeleted()); - } - - public void writeEntryDeleted() { - entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), true); - } - - public void writeEntryPresent() { - entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), false); - } - - private long timestampOffset() { - return replicationBytesOffset(); - } - - public void closeReplicatedMapEntryStagesTimestampOffsetDependants() { - CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesTimestampDependants(); - } - - public long timestamp() { - return entryBytesAccess.readLong(entryBytesAccessHandle, timestampOffset()); - } - - public void closeReplicatedMapEntryStagesTimestampDependants() { - CompiledReplicatedMapIterationContext.this.closeUpdatedReplicationState(); - } - @Override - public long originTimestamp() { + public long remoteTimestamp() { CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return timestamp(); - } - - void updateReplicationState(long timestamp, byte identifier) { - entryBytes.position(replicationBytesOffset()); - entryBytes.writeLong(timestamp); - entryBytes.writeByte(identifier); - } - - public void closeReplicatedMapEntryStagesUpdateReplicationStateDependants() { - CompiledReplicatedMapIterationContext.this.closeUpdatedReplicationState(); - } - - private long identifierOffset() { - return (replicationBytesOffset()) + 8L; - } - - public void closeReplicatedMapEntryStagesIdentifierOffsetDependants() { - CompiledReplicatedMapIterationContext.this.closeReplicatedMapEntryStagesIdentifierDependants(); - } - - byte identifier() { - return entryBytesAccess.readByte(entryBytesAccessHandle, identifierOffset()); - } - - public void closeReplicatedMapEntryStagesIdentifierDependants() { - CompiledReplicatedMapIterationContext.this.closeUpdatedReplicationState(); - } - - @Override - public byte originIdentifier() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return identifier(); + return innerRemoteTimestamp(); } public long pos = -1; @@ -2189,16 +2247,11 @@ public class CompiledReplicatedMapIterationContext newValue) { - return ((valueSizeOffset()) + (CompiledReplicatedMapIterationContext.this.m().valueSizeMarshaller.sizeEncodingSize(newValue.size()))) - (keySizeOffset()); - } - - public void copyExistingEntry(long newPos, long bytesToCopy) { - long oldKeySizeOffset = keySizeOffset(); - long oldKeyOffset = keyOffset(); - initPos(newPos); - initKeyOffset(((keySizeOffset()) + (oldKeyOffset - oldKeySizeOffset))); - Access.copy(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(oldKeySizeOffset), entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(keySizeOffset()), bytesToCopy); - } - - public void initEntryAndKeyCopying(long entrySize, long bytesToCopy) { - initAllocatedChunks(CompiledReplicatedMapIterationContext.this.h().inChunks(entrySize)); - CompiledReplicatedMapIterationContext.this.copyExistingEntry(CompiledReplicatedMapIterationContext.this.alloc(allocatedChunks()), bytesToCopy); - incrementSegmentEntriesIfNeeded(); - } - long entrySize() { return (entryEnd()) - (keySizeOffset()); } @@ -2286,33 +2321,28 @@ public class CompiledReplicatedMapIterationContext value) { - initValue(value); - freeExtraAllocatedChunks(); - CompiledReplicatedMapIterationContext.this.putValueVolatile(CompiledReplicatedMapIterationContext.this.hashLookupPos(), pos()); - } - public void innerRemoveEntryExceptHashLookupUpdate() { CompiledReplicatedMapIterationContext.this.free(pos(), entrySizeInChunks()); CompiledReplicatedMapIterationContext.this.entries(((CompiledReplicatedMapIterationContext.this.entries()) - 1L)); CompiledReplicatedMapIterationContext.this.incrementModCountGuarded(); } - public void writeNewEntry(long pos, Data key) { - initPos(pos); - initKeySize(key.size()); - entryBytes.position(keySizeOffset()); - CompiledReplicatedMapIterationContext.this.h().keySizeMarshaller.writeSize(entryBytes, keySize()); - initKeyOffset(entryBytes.position()); - key.writeTo(entryBytesAccessor, entryBytes, keyOffset()); + public void copyExistingEntry(long newPos, long bytesToCopy) { + long oldKeySizeOffset = keySizeOffset(); + long oldKeyOffset = keyOffset(); + initPos(newPos); + initKeyOffset(((keySizeOffset()) + (oldKeyOffset - oldKeySizeOffset))); + Access.copy(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(oldKeySizeOffset), entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(keySizeOffset()), bytesToCopy); + } + + public void initEntryAndKeyCopying(long entrySize, long bytesToCopy) { + initAllocatedChunks(CompiledReplicatedMapIterationContext.this.h().inChunks(entrySize)); + CompiledReplicatedMapIterationContext.this.copyExistingEntry(CompiledReplicatedMapIterationContext.this.alloc(allocatedChunks()), bytesToCopy); + incrementSegmentEntriesIfNeeded(); + } + + public long newSizeOfEverythingBeforeValue(Data newValue) { + return ((valueSizeOffset()) + (CompiledReplicatedMapIterationContext.this.m().valueSizeMarshaller.sizeEncodingSize(newValue.size()))) - (keySizeOffset()); } public void readExistingEntry(long pos) { @@ -2389,101 +2419,20 @@ public class CompiledReplicatedMapIterationContext newValue, long newSizeOfEverythingBeforeValue) { - CompiledReplicatedMapIterationContext.this.free(pos(), entrySizeInChunks()); - long entrySize = innerEntrySize(newSizeOfEverythingBeforeValue, newValue.size()); - CompiledReplicatedMapIterationContext.this.initEntryAndKeyCopying(entrySize, ((valueSizeOffset()) - (keySizeOffset()))); - writeValueAndPutPos(newValue); + public void writeNewEntry(long pos, Data key) { + initPos(pos); + initKeySize(key.size()); + entryBytes.position(keySizeOffset()); + CompiledReplicatedMapIterationContext.this.h().keySizeMarshaller.writeSize(entryBytes, keySize()); + initKeyOffset(entryBytes.position()); + key.writeTo(entryBytesAccessor, entryBytes, keyOffset()); } - protected void relocation(Data newValue, long newSizeOfEverythingBeforeValue) { - CompiledReplicatedMapIterationContext.this.dropChange(); - _MapEntryStages_relocation(newValue, newSizeOfEverythingBeforeValue); - } - - public void innerDefaultReplaceValue(Data newValue) { - assert CompiledReplicatedMapIterationContext.this.innerUpdateLock.isHeldByCurrentThread(); - boolean newValueSizeIsDifferent = (newValue.size()) != (this.valueSize()); - if (newValueSizeIsDifferent) { - long newSizeOfEverythingBeforeValue = newSizeOfEverythingBeforeValue(newValue); - long entryStartOffset = keySizeOffset(); - VanillaChronicleMap m = CompiledReplicatedMapIterationContext.this.m(); - long newValueOffset = m.alignment.alignAddr((entryStartOffset + newSizeOfEverythingBeforeValue)); - long newEntrySize = (newValueOffset + (newValue.size())) - entryStartOffset; - int newSizeInChunks = m.inChunks(newEntrySize); - newValueDoesNotFit : if (newSizeInChunks > (entrySizeInChunks())) { - if (newSizeInChunks > (m.maxChunksPerEntry)) { - throw new IllegalArgumentException(((((("Value too large: " + "entry takes ") + newSizeInChunks) + " chunks, ") + (m.maxChunksPerEntry)) + " is maximum.")); - } - if (CompiledReplicatedMapIterationContext.this.freeList().allClear(((pos()) + (entrySizeInChunks())), ((pos()) + newSizeInChunks))) { - CompiledReplicatedMapIterationContext.this.freeList().set(((pos()) + (entrySizeInChunks())), ((pos()) + newSizeInChunks)); - break newValueDoesNotFit; - } - relocation(newValue, newSizeOfEverythingBeforeValue); - return ; - } else if (newSizeInChunks < (entrySizeInChunks())) { - CompiledReplicatedMapIterationContext.this.freeList().clear(((pos()) + newSizeInChunks), ((pos()) + (entrySizeInChunks()))); - } + public final void freeExtraAllocatedChunks() { + if (((!(CompiledReplicatedMapIterationContext.this.m().constantlySizedEntry)) && (CompiledReplicatedMapIterationContext.this.m().couldNotDetermineAlignmentBeforeAllocation)) && ((entrySizeInChunks()) < (CompiledReplicatedMapIterationContext.this.allocatedChunks()))) { + CompiledReplicatedMapIterationContext.this.free(((pos()) + (entrySizeInChunks())), ((CompiledReplicatedMapIterationContext.this.allocatedChunks()) - (entrySizeInChunks()))); } else { - } - CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); - if (newValueSizeIsDifferent) { - initValue(newValue); - } else { - writeValue(newValue); - } - CompiledReplicatedMapIterationContext.this.putValueVolatile(CompiledReplicatedMapIterationContext.this.hashLookupPos(), pos()); - } - - private void _MapSegmentIteration_doReplaceValue(Data newValue) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - try { - CompiledReplicatedMapIterationContext.this.innerDefaultReplaceValue(newValue); - } finally { - CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); - } - } - - @Override - public void doReplaceValue(Data newValue) { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - try { - CompiledReplicatedMapIterationContext.this.innerDefaultReplaceValue(newValue); - CompiledReplicatedMapIterationContext.this.updateChange(); - CompiledReplicatedMapIterationContext.this.initUpdatedReplicationStateOnPresentEntry(); - } finally { - CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); - } - } - - private void _MapSegmentIteration_doRemove() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - initEntryRemovedOnThisIteration(true); - CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); - try { - if ((CompiledReplicatedMapIterationContext.this.remove(CompiledReplicatedMapIterationContext.this.hashLookupPos())) != (CompiledReplicatedMapIterationContext.this.hashLookupPos())) { - CompiledReplicatedMapIterationContext.this.setHashLookupPosGuarded(CompiledReplicatedMapIterationContext.this.stepBack(CompiledReplicatedMapIterationContext.this.hashLookupPos())); - } - CompiledReplicatedMapIterationContext.this.innerRemoveEntryExceptHashLookupUpdate(); - } finally { - CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); - } - } - - @Override - public void doRemove() { - CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - initEntryRemovedOnThisIteration(true); - try { - if ((CompiledReplicatedMapIterationContext.this.valueSize()) > (CompiledReplicatedMapIterationContext.this.dummyValue.size())) - CompiledReplicatedMapIterationContext.this.innerDefaultReplaceValue(CompiledReplicatedMapIterationContext.this.dummyValue); - - CompiledReplicatedMapIterationContext.this.initUpdatedReplicationStateOnPresentEntry(); - CompiledReplicatedMapIterationContext.this.writeEntryDeleted(); - CompiledReplicatedMapIterationContext.this.updateChange(); - CompiledReplicatedMapIterationContext.this.deleted(((CompiledReplicatedMapIterationContext.this.deleted()) + 1)); - } finally { - CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); + initTheEntrySizeInChunks(CompiledReplicatedMapIterationContext.this.allocatedChunks()); } } @@ -2536,119 +2485,125 @@ public class CompiledReplicatedMapIterationContext value) { + initValue(value); + freeExtraAllocatedChunks(); + CompiledReplicatedMapIterationContext.this.putValueVolatile(CompiledReplicatedMapIterationContext.this.hashLookupPos(), pos()); } - public void initUsed(boolean used) { - this.used = used; + private void _MapEntryStages_relocation(Data newValue, long newSizeOfEverythingBeforeValue) { + CompiledReplicatedMapIterationContext.this.free(pos(), entrySizeInChunks()); + long entrySize = innerEntrySize(newSizeOfEverythingBeforeValue, newValue.size()); + CompiledReplicatedMapIterationContext.this.initEntryAndKeyCopying(entrySize, ((valueSizeOffset()) - (keySizeOffset()))); + writeValueAndPutPos(newValue); } - void closeUsed() { - if (!(this.usedInit())) - return ; - - used = false; + protected void relocation(Data newValue, long newSizeOfEverythingBeforeValue) { + long oldPos = pos(); + _MapEntryStages_relocation(newValue, newSizeOfEverythingBeforeValue); + CompiledReplicatedMapIterationContext.this.moveChange(oldPos, pos()); } - public long innerRemoteTimestamp; - - public byte innerRemoteIdentifier = ((byte)(0)); - - public boolean replicationUpdateInit() { - return (this.innerRemoteIdentifier) != ((byte)(0)); - } - - public void initReplicationUpdate(long timestamp, byte identifier) { - innerRemoteTimestamp = timestamp; - if (identifier == 0) - throw new IllegalStateException("identifier can\'t be 0"); - - innerRemoteIdentifier = identifier; - this.closeReplicationUpdateDependants(); - } - - public byte innerRemoteIdentifier() { - assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; - return this.innerRemoteIdentifier; - } - - public long innerRemoteTimestamp() { - assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; - return this.innerRemoteTimestamp; - } - - public void closeReplicationUpdate() { - if (!(this.replicationUpdateInit())) - return ; - - this.closeReplicationUpdateDependants(); - this.innerRemoteIdentifier = ((byte)(0)); - } - - public void closeReplicationUpdateDependants() { - CompiledReplicatedMapIterationContext.this.closeUpdatedReplicationState(); - } - - private boolean updatedReplicationState = false; - - public boolean updatedReplicationStateInit() { - return (this.updatedReplicationState) != false; - } - - public void initUpdatedReplicationStateOnAbsentEntry() { - CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); - if (CompiledReplicatedMapIterationContext.this.replicationUpdateInit()) { - updateReplicationState(CompiledReplicatedMapIterationContext.this.innerRemoteTimestamp(), CompiledReplicatedMapIterationContext.this.innerRemoteIdentifier()); - } else { - updateReplicationState(CompiledReplicatedMapIterationContext.this.m().timeProvider.currentTime(), CompiledReplicatedMapIterationContext.this.m().identifier()); - } - updatedReplicationState = true; - } - - public void initUpdatedReplicationStateOnPresentEntry() { - CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); - if (CompiledReplicatedMapIterationContext.this.replicationUpdateInit()) { - updateReplicationState(CompiledReplicatedMapIterationContext.this.innerRemoteTimestamp(), CompiledReplicatedMapIterationContext.this.innerRemoteIdentifier()); - } else { - long timestamp; - if ((identifier()) != (CompiledReplicatedMapIterationContext.this.m().identifier())) { - timestamp = Math.max(((timestamp()) + 1), CompiledReplicatedMapIterationContext.this.m().timeProvider.currentTime()); - } else { - timestamp = CompiledReplicatedMapIterationContext.this.m().timeProvider.currentTime(); + public void innerDefaultReplaceValue(Data newValue) { + assert CompiledReplicatedMapIterationContext.this.innerUpdateLock.isHeldByCurrentThread(); + boolean newValueSizeIsDifferent = (newValue.size()) != (this.valueSize()); + if (newValueSizeIsDifferent) { + long newSizeOfEverythingBeforeValue = newSizeOfEverythingBeforeValue(newValue); + long entryStartOffset = keySizeOffset(); + VanillaChronicleMap m = CompiledReplicatedMapIterationContext.this.m(); + long newValueOffset = m.alignment.alignAddr((entryStartOffset + newSizeOfEverythingBeforeValue)); + long newEntrySize = (newValueOffset + (newValue.size())) - entryStartOffset; + int newSizeInChunks = m.inChunks(newEntrySize); + newValueDoesNotFit : if (newSizeInChunks > (entrySizeInChunks())) { + if (newSizeInChunks > (m.maxChunksPerEntry)) { + throw new IllegalArgumentException(((((("Value too large: " + "entry takes ") + newSizeInChunks) + " chunks, ") + (m.maxChunksPerEntry)) + " is maximum.")); + } + if (CompiledReplicatedMapIterationContext.this.freeList().allClear(((pos()) + (entrySizeInChunks())), ((pos()) + newSizeInChunks))) { + CompiledReplicatedMapIterationContext.this.freeList().set(((pos()) + (entrySizeInChunks())), ((pos()) + newSizeInChunks)); + break newValueDoesNotFit; + } + relocation(newValue, newSizeOfEverythingBeforeValue); + return ; + } else if (newSizeInChunks < (entrySizeInChunks())) { + CompiledReplicatedMapIterationContext.this.freeList().clear(((pos()) + newSizeInChunks), ((pos()) + (entrySizeInChunks()))); } - updateReplicationState(timestamp, CompiledReplicatedMapIterationContext.this.m().identifier()); + } else { } - updatedReplicationState = true; + CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); + if (newValueSizeIsDifferent) { + initValue(newValue); + } else { + writeValue(newValue); + } + CompiledReplicatedMapIterationContext.this.putValueVolatile(CompiledReplicatedMapIterationContext.this.hashLookupPos(), pos()); } - public void closeUpdatedReplicationState() { - if (!(this.updatedReplicationStateInit())) - return ; + public void raiseChange() { + CompiledReplicatedMapIterationContext.this.m().raiseChange(CompiledReplicatedMapIterationContext.this.segmentIndex(), CompiledReplicatedMapIterationContext.this.pos()); + } - this.updatedReplicationState = false; + public void updateChange() { + if (!(replicationUpdateInit())) { + raiseChange(); + } + } + + private void _MapSegmentIteration_doRemove() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + initEntryRemovedOnThisIteration(true); + CompiledReplicatedMapIterationContext.this.innerWriteLock.lock(); + try { + if ((CompiledReplicatedMapIterationContext.this.remove(CompiledReplicatedMapIterationContext.this.hashLookupPos())) != (CompiledReplicatedMapIterationContext.this.hashLookupPos())) { + CompiledReplicatedMapIterationContext.this.setHashLookupPosGuarded(CompiledReplicatedMapIterationContext.this.stepBack(CompiledReplicatedMapIterationContext.this.hashLookupPos())); + } + CompiledReplicatedMapIterationContext.this.innerRemoveEntryExceptHashLookupUpdate(); + } finally { + CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); + } } @Override - public long remoteTimestamp() { + public void doRemove() { CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return innerRemoteTimestamp(); + initEntryRemovedOnThisIteration(true); + try { + if ((CompiledReplicatedMapIterationContext.this.valueSize()) > (CompiledReplicatedMapIterationContext.this.dummyValue.size())) + CompiledReplicatedMapIterationContext.this.innerDefaultReplaceValue(CompiledReplicatedMapIterationContext.this.dummyValue); + + CompiledReplicatedMapIterationContext.this.updatedReplicationStateOnPresentEntry(); + CompiledReplicatedMapIterationContext.this.writeEntryDeleted(); + CompiledReplicatedMapIterationContext.this.updateChange(); + CompiledReplicatedMapIterationContext.this.deleted(((CompiledReplicatedMapIterationContext.this.deleted()) + 1)); + } finally { + CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); + } + } + + private void _MapSegmentIteration_doReplaceValue(Data newValue) { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + try { + CompiledReplicatedMapIterationContext.this.innerDefaultReplaceValue(newValue); + } finally { + CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); + } } @Override - public byte remoteIdentifier() { + public void doReplaceValue(Data newValue) { CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); - return innerRemoteIdentifier(); + try { + CompiledReplicatedMapIterationContext.this.innerDefaultReplaceValue(newValue); + CompiledReplicatedMapIterationContext.this.updateChange(); + CompiledReplicatedMapIterationContext.this.updatedReplicationStateOnPresentEntry(); + } finally { + CompiledReplicatedMapIterationContext.this.innerWriteLock.unlock(); + } } - private boolean testTimeStampInSensibleRange() { - if ((CompiledReplicatedMapIterationContext.this.m().timeProvider) == (TimeProvider.SYSTEM)) { - long currentTime = TimeProvider.SYSTEM.currentTime(); - assert (Math.abs((currentTime - (timestamp())))) <= 100000000 : "unrealistic timestamp: " + (timestamp()); - assert (Math.abs((currentTime - (CompiledReplicatedMapIterationContext.this.innerRemoteTimestamp())))) <= 100000000 : "unrealistic innerRemoteTimestamp: " + (CompiledReplicatedMapIterationContext.this.innerRemoteTimestamp()); - } - return true; + @Override + public void raiseChanged() { + CompiledReplicatedMapIterationContext.this.checkOnEachPublicOperation(); + CompiledReplicatedMapIterationContext.this.innerUpdateLock.lock(); + CompiledReplicatedMapIterationContext.this.raiseChange(); } } diff --git a/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapQueryContext.java b/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapQueryContext.java index 08d393fb3..122953d30 100644 --- a/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/impl/CompiledReplicatedMapQueryContext.java @@ -45,29 +45,28 @@ import java.util.concurrent.TimeUnit; public class CompiledReplicatedMapQueryContext, V, VI, MVI extends MetaBytesInterop, R, T> implements AutoCloseable , HashEntry , InterProcessReadWriteUpdateLock , RemoteOperationContext , ExternalMapQueryContext , MapAbsentEntry , MapContext , MapEntry , MapAbsentEntryHolder , QueryContextInterface , ReplicatedChronicleMapHolder , MapRemoteQueryContext , MapReplicableEntry { public void close() { - CompiledReplicatedMapQueryContext.this.inputKeyInstanceValue.closeKey(); - CompiledReplicatedMapQueryContext.this.wrappedValueInstanceValue.closeNext(); - CompiledReplicatedMapQueryContext.this.closeReplicationInput(); - CompiledReplicatedMapQueryContext.this.wrappedValueInstanceValue.closeValue(); - CompiledReplicatedMapQueryContext.this.closePos(); - CompiledReplicatedMapQueryContext.this.bytesReturnValue.closeOutput(); - CompiledReplicatedMapQueryContext.this.closeKeySize(); - CompiledReplicatedMapQueryContext.this.closeInputKey(); - CompiledReplicatedMapQueryContext.this.closeReplicationUpdate(); - CompiledReplicatedMapQueryContext.this.closeInputBytes(); - CompiledReplicatedMapQueryContext.this.closeKeyOffset(); - CompiledReplicatedMapQueryContext.this.defaultReturnValue.closeDefaultReturnedValue(); CompiledReplicatedMapQueryContext.this.closeUsed(); - CompiledReplicatedMapQueryContext.this.inputValueInstanceValue.closeValue(); - CompiledReplicatedMapQueryContext.this.closeAllocatedChunks(); - CompiledReplicatedMapQueryContext.this.usingReturnValue.closeUsingReturnValue(); + CompiledReplicatedMapQueryContext.this.closeReplicationInput(); + CompiledReplicatedMapQueryContext.this.closeKeySize(); + CompiledReplicatedMapQueryContext.this.closeInputBytes(); CompiledReplicatedMapQueryContext.this.closeReplicatedInputBytes(); + CompiledReplicatedMapQueryContext.this.closeReplicationUpdate(); + CompiledReplicatedMapQueryContext.this.closeKeyOffset(); + CompiledReplicatedMapQueryContext.this.closePos(); + CompiledReplicatedMapQueryContext.this.closeAllocatedChunks(); + CompiledReplicatedMapQueryContext.this.inputKeyInstanceValue.closeKey(); + CompiledReplicatedMapQueryContext.this.closeInputKey(); + CompiledReplicatedMapQueryContext.this.wrappedValueInstanceValue.closeValue(); + CompiledReplicatedMapQueryContext.this.inputValueInstanceValue.closeValue(); + CompiledReplicatedMapQueryContext.this.usingReturnValue.closeUsingReturnValue(); + CompiledReplicatedMapQueryContext.this.bytesReturnValue.closeOutput(); + CompiledReplicatedMapQueryContext.this.defaultReturnValue.closeDefaultReturnedValue(); + CompiledReplicatedMapQueryContext.this.wrappedValueInstanceValue.closeNext(); + CompiledReplicatedMapQueryContext.this.closeKeyBytesInteropKeyMetaInteropDependants(); CompiledReplicatedMapQueryContext.this.closeReplicatedChronicleMapHolderImplContextAtIndexInChainDependants(); CompiledReplicatedMapQueryContext.this.closeOwnerThreadHolderCheckAccessingFromOwnerThreadDependants(); - CompiledReplicatedMapQueryContext.this.innerWriteLock.closeWriteLockForbiddenUpgradeDependants(); - CompiledReplicatedMapQueryContext.this.closeValueBytesInteropValueMetaInteropDependants(); - CompiledReplicatedMapQueryContext.this.closeKeyBytesInteropKeyMetaInteropDependants(); CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesEntryBytesAccessOffsetDependants(); + CompiledReplicatedMapQueryContext.this.closeValueBytesInteropValueMetaInteropDependants(); } public void incrementModCountGuarded() { @@ -107,36 +106,36 @@ public class CompiledReplicatedMapQueryContext)(entryBytesAccessor.access(entryBytes))); - this.deprecatedMapAcquireContext = new DeprecatedMapAcquireContextOnQuery(); - this.absentDelegating = new ReplicatedMapAbsentDelegating(); - this.inputKeyBytesValue = new InputKeyBytesData(); - this.entryKey = new EntryKeyBytesData(); - this.inputFirstValueBytesValue = new InputFirstValueBytesData(); - this.inputKeyInstanceValue = new InputKeyInstanceData(); - this.deprecatedMapKeyContext = new DeprecatedMapKeyContextOnQuery(); this.copies = ThreadLocalCopies.get(); this.valueInterop = CompiledReplicatedMapQueryContext.this.m().valueInteropProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.m().originalValueInterop); this.valueReader = CompiledReplicatedMapQueryContext.this.m().valueReaderProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.m().originalValueReader); this.keyInterop = CompiledReplicatedMapQueryContext.this.h().keyInteropProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.h().originalKeyInterop); this.keyReader = CompiledReplicatedMapQueryContext.this.h().keyReaderProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.h().originalKeyReader); - this.dummyValue = new DummyValueZeroData(); - this.inputSecondValueBytesValue = new InputSecondValueBytesData(); - this.entryValue = new EntryValueBytesData(); + this.defaultReturnValue = new DefaultReturnValue(); + this.bytesReturnValue = new BytesReturnValue(); this.innerReadLock = new ReadLock(); - this.innerUpdateLock = new UpdateLock(); + this.innerWriteLock = new WriteLock(); + this.inputKeyBytesValue = new InputKeyBytesData(); + this.inputSecondValueBytesValue = new InputSecondValueBytesData(); this.owner = Thread.currentThread(); + this.entryKey = new EntryKeyBytesData(); this.replicatedInputValueBytesValue = new ReplicatedInputValueBytesData(); + this.inputKeyInstanceValue = new InputKeyInstanceData(); + this.inputValueInstanceValue = new InputValueInstanceData(); + this.usingReturnValue = new UsingReturnValue(); + this.deprecatedMapKeyContext = new DeprecatedMapKeyContextOnQuery(); + this.innerUpdateLock = new UpdateLock(); + this.dummyValue = new DummyValueZeroData(); + this.deprecatedMapAcquireContext = new DeprecatedMapAcquireContextOnQuery(); + this.entryValue = new EntryValueBytesData(); this.replicatedInputKeyBytesValue = new ReplicatedInputKeyBytesData(); + this.inputFirstValueBytesValue = new InputFirstValueBytesData(); + this.absentDelegating = new ReplicatedMapAbsentDelegating(); + this.wrappedValueInstanceValue = new WrappedValueInstanceData(); } public CompiledReplicatedMapQueryContext(CompiledReplicatedMapQueryContext c) { @@ -144,45 +143,39 @@ public class CompiledReplicatedMapQueryContext)(c.m)); - this.usingReturnValue = new UsingReturnValue(); - this.inputValueInstanceValue = new InputValueInstanceData(); - this.defaultReturnValue = new DefaultReturnValue(); - this.innerWriteLock = new WriteLock(); - this.wrappedValueInstanceValue = new WrappedValueInstanceData(); - this.bytesReturnValue = new BytesReturnValue(); this.entryBytes = CompiledReplicatedMapQueryContext.this.h().ms.bytes(); this.entryBytesAccessor = JavaLangBytesAccessors.uncheckedBytesAccessor(entryBytes); this.entryBytesAccessHandle = ((T)(entryBytesAccessor.handle(entryBytes))); this.entryBytesAccess = ((Access)(entryBytesAccessor.access(entryBytes))); - this.deprecatedMapAcquireContext = new DeprecatedMapAcquireContextOnQuery(); - this.absentDelegating = new ReplicatedMapAbsentDelegating(); - this.inputKeyBytesValue = new InputKeyBytesData(); - this.entryKey = new EntryKeyBytesData(); - this.inputFirstValueBytesValue = new InputFirstValueBytesData(); - this.inputKeyInstanceValue = new InputKeyInstanceData(); - this.deprecatedMapKeyContext = new DeprecatedMapKeyContextOnQuery(); this.copies = ThreadLocalCopies.get(); this.valueInterop = CompiledReplicatedMapQueryContext.this.m().valueInteropProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.m().originalValueInterop); this.valueReader = CompiledReplicatedMapQueryContext.this.m().valueReaderProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.m().originalValueReader); this.keyInterop = CompiledReplicatedMapQueryContext.this.h().keyInteropProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.h().originalKeyInterop); this.keyReader = CompiledReplicatedMapQueryContext.this.h().keyReaderProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.h().originalKeyReader); - this.dummyValue = new DummyValueZeroData(); - this.inputSecondValueBytesValue = new InputSecondValueBytesData(); - this.entryValue = new EntryValueBytesData(); + this.defaultReturnValue = new DefaultReturnValue(); + this.bytesReturnValue = new BytesReturnValue(); this.innerReadLock = new ReadLock(); - this.innerUpdateLock = new UpdateLock(); + this.innerWriteLock = new WriteLock(); + this.inputKeyBytesValue = new InputKeyBytesData(); + this.inputSecondValueBytesValue = new InputSecondValueBytesData(); this.owner = Thread.currentThread(); + this.entryKey = new EntryKeyBytesData(); this.replicatedInputValueBytesValue = new ReplicatedInputValueBytesData(); + this.inputKeyInstanceValue = new InputKeyInstanceData(); + this.inputValueInstanceValue = new InputValueInstanceData(); + this.usingReturnValue = new UsingReturnValue(); + this.deprecatedMapKeyContext = new DeprecatedMapKeyContextOnQuery(); + this.innerUpdateLock = new UpdateLock(); + this.dummyValue = new DummyValueZeroData(); + this.deprecatedMapAcquireContext = new DeprecatedMapAcquireContextOnQuery(); + this.entryValue = new EntryValueBytesData(); this.replicatedInputKeyBytesValue = new ReplicatedInputKeyBytesData(); + this.inputFirstValueBytesValue = new InputFirstValueBytesData(); + this.absentDelegating = new ReplicatedMapAbsentDelegating(); + this.wrappedValueInstanceValue = new WrappedValueInstanceData(); } public class DeprecatedMapAcquireContextOnQuery implements MapKeyContext { - @NotNull - @Override - public InterProcessLock updateLock() { - return CompiledReplicatedMapQueryContext.this.updateLock(); - } - @NotNull @Override public InterProcessLock writeLock() { @@ -195,10 +188,10 @@ public class CompiledReplicatedMapQueryContext entry = CompiledReplicatedMapQueryContext.this.entry(); + if (entry != null) { + CompiledReplicatedMapQueryContext.this.remove(entry); + return true; + } else { + return false; + } + } + @Override public boolean put(V newValue) { CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); @@ -252,42 +287,6 @@ public class CompiledReplicatedMapQueryContext entry = CompiledReplicatedMapQueryContext.this.entry(); - if (entry != null) { - CompiledReplicatedMapQueryContext.this.remove(entry); - return true; - } else { - return false; - } - } - - @Override - public long valueOffset() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.valueOffset(); - } - - @Override - public boolean containsKey() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return (CompiledReplicatedMapQueryContext.this.entry()) != null; - } - - @Override - public V getUsing(V usingValue) { - return containsKey() ? CompiledReplicatedMapQueryContext.this.value().getUsing(usingValue) : null; - } - - @Override - public V get() { - assert containsKey(); - return CompiledReplicatedMapQueryContext.this.usingReturnValue.returnValue(); - } } public class DeprecatedMapKeyContextOnQuery implements MapKeyContext { @@ -309,6 +308,25 @@ public class CompiledReplicatedMapQueryContext { @Override - public long size() { - return CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.minEncodableSize(); - } - - @Override - public long offset() { - return 0; - } - - @Override - public Void handle() { - return null; + public ReadAccess access() { + return ReadAccess.zeros(); } @Override @@ -423,14 +412,24 @@ public class CompiledReplicatedMapQueryContext access() { - return ReadAccess.zeros(); + public long offset() { + return 0; } } @@ -447,12 +446,6 @@ public class CompiledReplicatedMapQueryContext access() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.entryBytesAccess; - } - @Override public long size() { CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); @@ -472,12 +465,6 @@ public class CompiledReplicatedMapQueryContext access() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.entryBytesAccess; + } } public class EntryValueBytesData extends AbstractData { + @Override + public ReadAccess access() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.entryBytesAccess; + } + + @Override + public T handle() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.entryBytesAccessHandle; + } + + @Override + public long offset() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.entryBytesAccessOffset(CompiledReplicatedMapQueryContext.this.valueOffset()); + } + @Override public long size() { CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); @@ -532,6 +549,12 @@ public class CompiledReplicatedMapQueryContext access() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.entryBytesAccess; - } - - @Override - public V getUsing(V usingValue) { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return innerGetUsing(usingValue); - } - @Override public V get() { CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); return cachedEntryValue(); } - - @Override - public long offset() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.entryBytesAccessOffset(CompiledReplicatedMapQueryContext.this.valueOffset()); - } - - @Override - public T handle() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.entryBytesAccessHandle; - } } public class InputFirstValueBytesData extends AbstractData { @@ -596,6 +595,11 @@ public class CompiledReplicatedMapQueryContext)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).access(CompiledReplicatedMapQueryContext.this.inputBytes()))); } + @Override + public T handle() { + return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).handle(CompiledReplicatedMapQueryContext.this.inputBytes()))); + } + @Override public long size() { return CompiledReplicatedMapQueryContext.this.firstInputValueSize(); @@ -651,22 +655,12 @@ public class CompiledReplicatedMapQueryContext { @Override - public T handle() { - return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).handle(CompiledReplicatedMapQueryContext.this.inputBytes()))); - } - - @Override - public long offset() { - return JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).offset(CompiledReplicatedMapQueryContext.this.inputBytes(), CompiledReplicatedMapQueryContext.this.inputKeyOffset()); + public ReadAccess access() { + return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).access(CompiledReplicatedMapQueryContext.this.inputBytes()))); } @Override @@ -721,18 +715,6 @@ public class CompiledReplicatedMapQueryContext access() { - return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).access(CompiledReplicatedMapQueryContext.this.inputBytes()))); - } - } - - public class InputSecondValueBytesData extends AbstractData { - @Override - public ReadAccess access() { - return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).access(CompiledReplicatedMapQueryContext.this.inputBytes()))); - } - @Override public T handle() { return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).handle(CompiledReplicatedMapQueryContext.this.inputBytes()))); @@ -740,7 +722,19 @@ public class CompiledReplicatedMapQueryContext { + @Override + public T handle() { + return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).handle(CompiledReplicatedMapQueryContext.this.inputBytes()))); + } + + @Override + public ReadAccess access() { + return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.inputBytes()).access(CompiledReplicatedMapQueryContext.this.inputBytes()))); } @Override @@ -752,6 +746,11 @@ public class CompiledReplicatedMapQueryContext { @Override - public ReadAccess access() { - return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).access(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); + public T handle() { + return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).handle(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); } @Override - public T handle() { - return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).handle(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); + public ReadAccess access() { + return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).access(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); } @Override @@ -940,19 +939,14 @@ public class CompiledReplicatedMapQueryContext { - @Override - public ReadAccess access() { - return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).access(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); - } - @Override public T handle() { return ((T)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).handle(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); } @Override - public long offset() { - return JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).offset(CompiledReplicatedMapQueryContext.this.replicatedInputBytes(), CompiledReplicatedMapQueryContext.this.riValueOffset()); + public ReadAccess access() { + return ((ReadAccess)(JavaLangBytesAccessors.uncheckedBytesAccessor(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()).access(CompiledReplicatedMapQueryContext.this.replicatedInputBytes()))); } @Override @@ -964,6 +958,11 @@ public class CompiledReplicatedMapQueryContext { + @NotNull + @Override + public MapContext context() { + return CompiledReplicatedMapQueryContext.this.context(); + } + @NotNull @Override public Data absentKey() { @@ -1021,12 +1026,6 @@ public class CompiledReplicatedMapQueryContext context() { - return CompiledReplicatedMapQueryContext.this.context(); - } - @Override public void doInsert(Data value) { CompiledReplicatedMapQueryContext.this.doInsert(value); @@ -1054,20 +1053,6 @@ public class CompiledReplicatedMapQueryContext { @@ -1143,6 +1142,18 @@ public class CompiledReplicatedMapQueryContext value) { @@ -1513,14 +1512,6 @@ public class CompiledReplicatedMapQueryContext { @@ -2027,43 +2018,19 @@ public class CompiledReplicatedMapQueryContext m() { + return m; } - public void closeReplicatedMapEntryStagesEntryBytesAccessOffsetDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryKeyEqualsDependants(); + @Override + public ChronicleMap map() { + return m(); } - public MKI keyMetaInterop(K key) { - return CompiledReplicatedMapQueryContext.this.h().metaKeyInteropProvider.get(CompiledReplicatedMapQueryContext.this.copies, CompiledReplicatedMapQueryContext.this.h().originalMetaKeyInterop, keyInterop, key); - } - - public void closeKeyBytesInteropKeyMetaInteropDependants() { - CompiledReplicatedMapQueryContext.this.inputKeyInstanceValue.closeBuffer(); - } - - public long innerEntrySize(long sizeOfEverythingBeforeValue, long valueSize) { - if (CompiledReplicatedMapQueryContext.this.m().constantlySizedEntry) { - return CompiledReplicatedMapQueryContext.this.m().alignment.alignAddr((sizeOfEverythingBeforeValue + valueSize)); - } else if (CompiledReplicatedMapQueryContext.this.m().couldNotDetermineAlignmentBeforeAllocation) { - return (sizeOfEverythingBeforeValue + (CompiledReplicatedMapQueryContext.this.m().worstAlignment)) + valueSize; - } else { - return (CompiledReplicatedMapQueryContext.this.m().alignment.alignAddr(sizeOfEverythingBeforeValue)) + valueSize; - } - } - - private long _MapEntryStages_sizeOfEverythingBeforeValue(long keySize, long valueSize) { - return (((CompiledReplicatedMapQueryContext.this.m().metaDataBytes) + (CompiledReplicatedMapQueryContext.this.m().keySizeMarshaller.sizeEncodingSize(keySize))) + keySize) + (CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.sizeEncodingSize(valueSize)); - } - - long sizeOfEverythingBeforeValue(long keySize, long valueSize) { - return (_MapEntryStages_sizeOfEverythingBeforeValue(keySize, valueSize)) + (ReplicatedChronicleMap.ADDITIONAL_ENTRY_BYTES); - } - - public final long entrySize(long keySize, long valueSize) { - long sizeOfEverythingBeforeValue = sizeOfEverythingBeforeValue(keySize, valueSize); - return innerEntrySize(sizeOfEverythingBeforeValue, valueSize); + @Override + public MapAbsentEntry absent() { + return CompiledReplicatedMapQueryContext.this; } public MVI valueMetaInterop(V value) { @@ -2075,14 +2042,25 @@ public class CompiledReplicatedMapQueryContext m() { - return m; + private long _MapEntryStages_sizeOfEverythingBeforeValue(long keySize, long valueSize) { + return (((CompiledReplicatedMapQueryContext.this.m().metaDataBytes) + (CompiledReplicatedMapQueryContext.this.m().keySizeMarshaller.sizeEncodingSize(keySize))) + keySize) + (CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.sizeEncodingSize(valueSize)); + } + + long sizeOfEverythingBeforeValue(long keySize, long valueSize) { + return (_MapEntryStages_sizeOfEverythingBeforeValue(keySize, valueSize)) + (ReplicatedChronicleMap.ADDITIONAL_ENTRY_BYTES); + } + + public long entryBytesAccessOffset(long offset) { + return entryBytesAccessor.offset(entryBytes, offset); + } + + public void closeReplicatedMapEntryStagesEntryBytesAccessOffsetDependants() { + CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryKeyEqualsDependants(); } @Override - public ChronicleMap map() { - return m(); + public Data dummyZeroValue() { + return CompiledReplicatedMapQueryContext.this.dummyValue; } public void checkAccessingFromOwnerThread() { @@ -2095,11 +2073,6 @@ public class CompiledReplicatedMapQueryContext absent() { - return CompiledReplicatedMapQueryContext.this; - } - public T contextAtIndexInChain(int index) { return ((T)(contextChain.get(index))); } @@ -2129,301 +2102,27 @@ public class CompiledReplicatedMapQueryContext= 0; - } - - public void initKeyOffset(long keyOffset) { - this.keyOffset = keyOffset; - this.closeKeyOffsetDependants(); - } - - public long keyOffset() { - assert this.keyOffsetInit() : "KeyOffset should be init"; - return this.keyOffset; - } - - public void closeKeyOffset() { - if (!(this.keyOffsetInit())) - return ; - - this.closeKeyOffsetDependants(); - this.keyOffset = -1; - } - - public void closeKeyOffsetDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesKeyEndDependants(); - CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryKeyEqualsDependants(); - CompiledReplicatedMapQueryContext.this.entryKey.closeEntryKeyBytesDataInnerGetUsingDependants(); - } - - public Bytes inputBytes = null; - - public boolean inputBytesInit() { - return (this.inputBytes) != null; - } - - public void initInputBytes(Bytes inputBytes) { - this.inputBytes = inputBytes; - this.closeInputBytesDependants(); - } - - public Bytes inputBytes() { - assert this.inputBytesInit() : "InputBytes should be init"; - return this.inputBytes; - } - - public void closeInputBytes() { - if (!(this.inputBytesInit())) - return ; - - this.closeInputBytesDependants(); - this.inputBytes = null; - } - - public void closeInputBytesDependants() { - CompiledReplicatedMapQueryContext.this.closeInputKeyOffsets(); - CompiledReplicatedMapQueryContext.this.closeFirstInputValueOffsets(); - CompiledReplicatedMapQueryContext.this.inputFirstValueBytesValue.closeInputFirstValueBytesDataGetUsingDependants(); - CompiledReplicatedMapQueryContext.this.inputKeyBytesValue.closeInputKeyBytesDataGetUsingDependants(); - CompiledReplicatedMapQueryContext.this.closeSecondInputValueOffsets(); - CompiledReplicatedMapQueryContext.this.inputSecondValueBytesValue.closeInputSecondValueBytesDataGetUsingDependants(); - } - - public long inputKeySize = -1; - - public long inputKeyOffset; - - public boolean inputKeyOffsetsInit() { - return (this.inputKeySize) >= 0; - } - - private void initInputKeyOffsets() { - inputKeySize = CompiledReplicatedMapQueryContext.this.h().keySizeMarshaller.readSize(inputBytes()); - inputKeyOffset = inputBytes().position(); - this.closeInputKeyOffsetsDependants(); - } - - public long inputKeyOffset() { - if (!(this.inputKeyOffsetsInit())) - this.initInputKeyOffsets(); - - return this.inputKeyOffset; - } - - public long inputKeySize() { - if (!(this.inputKeyOffsetsInit())) - this.initInputKeyOffsets(); - - return this.inputKeySize; - } - - public void closeInputKeyOffsets() { - if (!(this.inputKeyOffsetsInit())) - return ; - - this.closeInputKeyOffsetsDependants(); - this.inputKeySize = -1; - } - - public void closeInputKeyOffsetsDependants() { - CompiledReplicatedMapQueryContext.this.closeFirstInputValueOffsets(); - CompiledReplicatedMapQueryContext.this.inputKeyBytesValue.closeInputKeyBytesDataSizeDependants(); - CompiledReplicatedMapQueryContext.this.inputKeyBytesValue.closeInputKeyBytesDataGetUsingDependants(); - } - - public long firstInputValueSize = -1; - - public long firstInputValueOffset; - - public boolean firstInputValueOffsetsInit() { - return (this.firstInputValueSize) >= 0; - } - - private void initFirstInputValueOffsets() { - CompiledReplicatedMapQueryContext.this.inputBytes().position(((CompiledReplicatedMapQueryContext.this.inputKeyOffset()) + (CompiledReplicatedMapQueryContext.this.inputKeySize()))); - firstInputValueSize = CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.readSize(CompiledReplicatedMapQueryContext.this.inputBytes()); - firstInputValueOffset = CompiledReplicatedMapQueryContext.this.inputBytes().position(); - this.closeFirstInputValueOffsetsDependants(); - } - - public long firstInputValueOffset() { - if (!(this.firstInputValueOffsetsInit())) - this.initFirstInputValueOffsets(); - - return this.firstInputValueOffset; - } - - public long firstInputValueSize() { - if (!(this.firstInputValueOffsetsInit())) - this.initFirstInputValueOffsets(); - - return this.firstInputValueSize; - } - - public void closeFirstInputValueOffsets() { - if (!(this.firstInputValueOffsetsInit())) - return ; - - this.closeFirstInputValueOffsetsDependants(); - this.firstInputValueSize = -1; - } - - public void closeFirstInputValueOffsetsDependants() { - CompiledReplicatedMapQueryContext.this.closeSecondInputValueOffsets(); - CompiledReplicatedMapQueryContext.this.inputFirstValueBytesValue.closeInputFirstValueBytesDataSizeDependants(); - CompiledReplicatedMapQueryContext.this.inputFirstValueBytesValue.closeInputFirstValueBytesDataGetUsingDependants(); - } - - public long secondInputValueSize = -1; - - public long secondInputValueOffset; - - public boolean secondInputValueOffsetsInit() { - return (this.secondInputValueSize) >= 0; - } - - private void initSecondInputValueOffsets() { - CompiledReplicatedMapQueryContext.this.inputBytes().position(((firstInputValueOffset()) + (firstInputValueSize()))); - secondInputValueSize = CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.readSize(CompiledReplicatedMapQueryContext.this.inputBytes()); - secondInputValueOffset = CompiledReplicatedMapQueryContext.this.inputBytes().position(); - this.closeSecondInputValueOffsetsDependants(); - } - - public long secondInputValueOffset() { - if (!(this.secondInputValueOffsetsInit())) - this.initSecondInputValueOffsets(); - - return this.secondInputValueOffset; - } - - public long secondInputValueSize() { - if (!(this.secondInputValueOffsetsInit())) - this.initSecondInputValueOffsets(); - - return this.secondInputValueSize; - } - - public void closeSecondInputValueOffsets() { - if (!(this.secondInputValueOffsetsInit())) - return ; - - this.closeSecondInputValueOffsetsDependants(); - this.secondInputValueSize = -1; - } - - public void closeSecondInputValueOffsetsDependants() { - CompiledReplicatedMapQueryContext.this.inputSecondValueBytesValue.closeInputSecondValueBytesDataSizeDependants(); - CompiledReplicatedMapQueryContext.this.inputSecondValueBytesValue.closeInputSecondValueBytesDataGetUsingDependants(); - } - - public long innerRemoteTimestamp; - - public byte innerRemoteIdentifier = ((byte)(0)); - - public boolean replicationUpdateInit() { - return (this.innerRemoteIdentifier) != ((byte)(0)); - } - - public void initReplicationUpdate(long timestamp, byte identifier) { - innerRemoteTimestamp = timestamp; - if (identifier == 0) - throw new IllegalStateException("identifier can\'t be 0"); - - innerRemoteIdentifier = identifier; - this.closeReplicationUpdateDependants(); - } - - public byte innerRemoteIdentifier() { - assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; - return this.innerRemoteIdentifier; - } - - public long innerRemoteTimestamp() { - assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; - return this.innerRemoteTimestamp; - } - - public void closeReplicationUpdate() { - if (!(this.replicationUpdateInit())) - return ; - - this.closeReplicationUpdateDependants(); - this.innerRemoteIdentifier = ((byte)(0)); - } - - public void closeReplicationUpdateDependants() { - CompiledReplicatedMapQueryContext.this.closeUpdatedReplicationState(); + public void closeKeyBytesInteropKeyMetaInteropDependants() { + CompiledReplicatedMapQueryContext.this.inputKeyInstanceValue.closeBuffer(); } public Data inputKey = null; @@ -2451,8 +2150,8 @@ public class CompiledReplicatedMapQueryContext= 0; - } - - public void initSegmentHashLookup() { - long hashLookupOffset = CompiledReplicatedMapQueryContext.this.h().segmentOffset(CompiledReplicatedMapQueryContext.this.segmentIndex()); - innerInitSegmentHashLookup(((CompiledReplicatedMapQueryContext.this.h().ms.address()) + hashLookupOffset), CompiledReplicatedMapQueryContext.this.h().segmentHashLookupCapacity, CompiledReplicatedMapQueryContext.this.h().segmentHashLookupEntrySize, CompiledReplicatedMapQueryContext.this.h().segmentHashLookupKeyBits, CompiledReplicatedMapQueryContext.this.h().segmentHashLookupValueBits); - this.closeSegmentHashLookupDependants(); - } - - public void initSegmentHashLookup(long address, long capacity, int entrySize, int keyBits, int valueBits) { - innerInitSegmentHashLookup(address, capacity, entrySize, keyBits, valueBits); - this.closeSegmentHashLookupDependants(); - } - - public int hashLookupEntrySize() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.hashLookupEntrySize; - } - - public int keyBits() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.keyBits; - } - - public long address() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.address; - } - - public long capacityMask() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.capacityMask; - } - - public long capacityMask2() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.capacityMask2; - } - - public long entryMask() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.entryMask; - } - - public long keyMask() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.keyMask; - } - - public long valueMask() { - if (!(this.segmentHashLookupInit())) - this.initSegmentHashLookup(); - - return this.valueMask; - } - - public void closeSegmentHashLookup() { - if (!(this.segmentHashLookupInit())) - return ; - - this.closeSegmentHashLookupDependants(); - this.address = -1; - } - - public void closeSegmentHashLookupDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupEmptyDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupReadEntryDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupKeyDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupIndexToPosDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupStepBackDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupMaskUnsetKeyDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupValueDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupStepDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupHlPosDependants(); - } - - public void clearHashLookup() { - NativeBytes.UNSAFE.setMemory(address(), ((capacityMask2()) + (hashLookupEntrySize())), ((byte)(0))); - } - - public boolean empty(long entry) { - return (entry & (entryMask())) == (UNSET_ENTRY); - } - - public void closeHashLookupEmptyDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); - } - - public long readEntry(long pos) { - return NativeBytes.UNSAFE.getLong(((address()) + pos)); - } - - public void closeHashLookupReadEntryDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchCheckSlotContainsExpectedKeyAndValueDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); - } - - void clearEntry(long pos, long prevEntry) { - long entry = prevEntry & (~(entryMask())); - NativeBytes.UNSAFE.putLong(((address()) + pos), entry); - } - - public void checkValueForPut(long value) { - assert (value & (~(valueMask()))) == 0L : "Value out of range, was " + value; - } - - public long key(long entry) { - return entry & (keyMask()); - } - - public void closeHashLookupKeyDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchCheckSlotContainsExpectedKeyAndValueDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); - } - - long indexToPos(long index) { - return index * (hashLookupEntrySize()); - } - - public void closeHashLookupIndexToPosDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupHlPosDependants(); - } - - public long stepBack(long pos) { - return (pos -= hashLookupEntrySize()) >= 0 ? pos : capacityMask2(); - } - - public void closeHashLookupStepBackDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchFoundDependants(); - } - - public long maskUnsetKey(long key) { - return (key &= keyMask()) != (UNSET_KEY) ? key : keyMask(); - } - - public void closeHashLookupMaskUnsetKeyDependants() { - CompiledReplicatedMapQueryContext.this.closeSearchKey(); - } - - public long value(long entry) { - return (entry >>> (keyBits())) & (valueMask()); - } - - public void closeHashLookupValueDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchCheckSlotContainsExpectedKeyAndValueDependants(); - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); - } - - void forEach(EntryConsumer action) { - for (long pos = 0L ; pos <= (capacityMask2()) ; pos += hashLookupEntrySize()) { - long entry = readEntry(pos); - if (!(empty(entry))) - action.accept(key(entry), value(entry)); - - } - } - - String hashLookupToString() { - final StringBuilder sb = new StringBuilder("{"); - forEach((long key,long value) -> sb.append(key).append('=').append(value).append(',')); - sb.append('}'); - return sb.toString(); - } - - long entry(long key, long value) { - return key | (value << (keyBits())); - } - - public void writeEntryVolatile(long pos, long prevEntry, long key, long value) { - long entry = (prevEntry & (~(entryMask()))) | (entry(key, value)); - NativeBytes.UNSAFE.putLongVolatile(null, ((address()) + pos), entry); - } - - public void putValueVolatile(long pos, long value) { - checkValueForPut(value); - long currentEntry = readEntry(pos); - writeEntryVolatile(pos, currentEntry, key(currentEntry), value); - } - - public long step(long pos) { - return (pos += hashLookupEntrySize()) <= (capacityMask2()) ? pos : 0L; - } - - public void closeHashLookupStepDependants() { - CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); - } - - void writeEntry(long pos, long prevEntry, long anotherEntry) { - long entry = (prevEntry & (~(entryMask()))) | (anotherEntry & (entryMask())); - NativeBytes.UNSAFE.putLong(((address()) + pos), entry); - } - - public void writeEntry(long pos, long prevEntry, long key, long value) { - long entry = (prevEntry & (~(entryMask()))) | (entry(key, value)); - NativeBytes.UNSAFE.putLong(((address()) + pos), entry); - } - - public long hlPos(long key) { - return indexToPos((key & (capacityMask()))); - } - - public void closeHashLookupHlPosDependants() { - CompiledReplicatedMapQueryContext.this.closeSearchKey(); - } - - public long remove(long posToRemove) { - long entryToRemove = readEntry(posToRemove); - long posToShift = posToRemove; - while (true) { - posToShift = step(posToShift); - long entryToShift = readEntry(posToShift); - if (empty(entryToShift)) - break; - - long insertPos = hlPos(key(entryToShift)); - boolean cond1 = insertPos <= posToRemove; - boolean cond2 = posToRemove <= posToShift; - if ((cond1 && cond2) || ((posToShift < insertPos) && (cond1 || cond2))) { - writeEntry(posToRemove, entryToRemove, entryToShift); - posToRemove = posToShift; - entryToRemove = entryToShift; - } - } - clearEntry(posToRemove, entryToRemove); - return posToRemove; - } - - long entrySpaceOffset = 0; - - MultiStoreBytes freeListBytes = new MultiStoreBytes(); - - public SingleThreadedDirectBitSet freeList = new SingleThreadedDirectBitSet(); - - boolean segmentInit() { - return (entrySpaceOffset) > 0; - } - - void initSegment() { - VanillaChronicleHash h = CompiledReplicatedMapQueryContext.this.h(); - long hashLookupOffset = h.segmentOffset(segmentIndex()); - long freeListOffset = hashLookupOffset + (h.segmentHashLookupOuterSize); - freeListBytes.storePositionAndSize(h.ms, freeListOffset, h.segmentFreeListInnerSize); - freeList.reuse(freeListBytes); - entrySpaceOffset = (freeListOffset + (h.segmentFreeListOuterSize)) + (h.segmentEntrySpaceInnerOffset); - this.closeSegmentDependants(); - } - - public long entrySpaceOffset() { - if (!(this.segmentInit())) - this.initSegment(); - - return this.entrySpaceOffset; - } - - public SingleThreadedDirectBitSet freeList() { - if (!(this.segmentInit())) - this.initSegment(); - - return this.freeList; - } - - void closeSegment() { - if (!(this.segmentInit())) - return ; - - this.closeSegmentDependants(); - entrySpaceOffset = 0; - } - - public void closeSegmentDependants() { - CompiledReplicatedMapQueryContext.this.closeEntryOffset(); + public void moveChange(long oldPos, long newPos) { + CompiledReplicatedMapQueryContext.this.m().moveChange(CompiledReplicatedMapQueryContext.this.segmentIndex(), oldPos, newPos); } long segmentHeaderAddress; @@ -2867,11 +2266,6 @@ public class CompiledReplicatedMapQueryContext= 0; } - long nextPosToSearchFrom() { - return segmentHeader().nextPosToSearchFrom(segmentHeaderAddress()); + public void initSegmentHashLookup() { + long hashLookupOffset = CompiledReplicatedMapQueryContext.this.h().segmentOffset(CompiledReplicatedMapQueryContext.this.segmentIndex()); + innerInitSegmentHashLookup(((CompiledReplicatedMapQueryContext.this.h().ms.address()) + hashLookupOffset), CompiledReplicatedMapQueryContext.this.h().segmentHashLookupCapacity, CompiledReplicatedMapQueryContext.this.h().segmentHashLookupEntrySize, CompiledReplicatedMapQueryContext.this.h().segmentHashLookupKeyBits, CompiledReplicatedMapQueryContext.this.h().segmentHashLookupValueBits); + this.closeSegmentHashLookupDependants(); } - public long alloc(int chunks) { - VanillaChronicleHash h = CompiledReplicatedMapQueryContext.this.h(); - if (chunks > (h.maxChunksPerEntry)) - throw new IllegalArgumentException((((("Entry is too large: requires " + chunks) + " entry size chucks, ") + (h.maxChunksPerEntry)) + " is maximum.")); - - long ret = freeList().setNextNContinuousClearBits(nextPosToSearchFrom(), chunks); - if ((ret == (DirectBitSet.NOT_FOUND)) || ((ret + chunks) > (h.actualChunksPerSegment))) { - if (((ret != (DirectBitSet.NOT_FOUND)) && ((ret + chunks) > (h.actualChunksPerSegment))) && (ret < (h.actualChunksPerSegment))) - freeList().clear(ret, h.actualChunksPerSegment); - - ret = freeList().setNextNContinuousClearBits(0L, chunks); - if ((ret == (DirectBitSet.NOT_FOUND)) || ((ret + chunks) > (h.actualChunksPerSegment))) { - if (((ret != (DirectBitSet.NOT_FOUND)) && ((ret + chunks) > (h.actualChunksPerSegment))) && (ret < (h.actualChunksPerSegment))) - freeList().clear(ret, h.actualChunksPerSegment); - - if (chunks == 1) { - throw new IllegalStateException("Segment is full, no free entries found"); - } else { - throw new IllegalStateException((("Segment is full or has no ranges of " + chunks) + " continuous free chunks")); - } - } - updateNextPosToSearchFrom(ret, chunks); - } else { - if ((chunks == 1) || (freeList().isSet(nextPosToSearchFrom()))) { - updateNextPosToSearchFrom(ret, chunks); - } - } - return ret; + public void initSegmentHashLookup(long address, long capacity, int entrySize, int keyBits, int valueBits) { + innerInitSegmentHashLookup(address, capacity, entrySize, keyBits, valueBits); + this.closeSegmentHashLookupDependants(); } - public void free(long fromPos, int chunks) { - freeList().clear(fromPos, (fromPos + chunks)); - if (fromPos < (nextPosToSearchFrom())) - nextPosToSearchFrom(fromPos); + public int hashLookupEntrySize() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + return this.hashLookupEntrySize; } - public void deleted(long deleted) { - segmentHeader().deleted(segmentHeaderAddress(), deleted); + public int keyBits() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.keyBits; } - public long entries() { - return segmentHeader().size(segmentHeaderAddress()); + public long address() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.address; } - public long size() { - return (entries()) - (deleted()); + public long capacityMask() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.capacityMask; } - public void clearSegment() { - CompiledReplicatedMapQueryContext.this.innerWriteLock.lock(); - CompiledReplicatedMapQueryContext.this.clearHashLookup(); - freeList().clear(); - nextPosToSearchFrom(0L); - entries(0L); + public long capacityMask2() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.capacityMask2; } - public void clear() { - clearSegment(); + public long entryMask() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.entryMask; + } + + public long keyMask() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.keyMask; + } + + public long valueMask() { + if (!(this.segmentHashLookupInit())) + this.initSegmentHashLookup(); + + return this.valueMask; + } + + public void closeSegmentHashLookup() { + if (!(this.segmentHashLookupInit())) + return ; + + this.closeSegmentHashLookupDependants(); + this.address = -1; + } + + public void closeSegmentHashLookupDependants() { + CompiledReplicatedMapQueryContext.this.closeHashLookupReadEntryDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupValueDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupIndexToPosDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupHlPosDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupMaskUnsetKeyDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupStepBackDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupEmptyDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupKeyDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupStepDependants(); + } + + long entry(long key, long value) { + return key | (value << (keyBits())); + } + + public void writeEntryVolatile(long pos, long prevEntry, long key, long value) { + long entry = (prevEntry & (~(entryMask()))) | (entry(key, value)); + NativeBytes.UNSAFE.putLongVolatile(null, ((address()) + pos), entry); + } + + public long readEntry(long pos) { + return NativeBytes.UNSAFE.getLong(((address()) + pos)); + } + + public void closeHashLookupReadEntryDependants() { + CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupSearchCheckSlotContainsExpectedKeyAndValueDependants(); + } + + void writeEntry(long pos, long prevEntry, long anotherEntry) { + long entry = (prevEntry & (~(entryMask()))) | (anotherEntry & (entryMask())); + NativeBytes.UNSAFE.putLong(((address()) + pos), entry); + } + + public long value(long entry) { + return (entry >>> (keyBits())) & (valueMask()); + } + + public void closeHashLookupValueDependants() { + CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); + CompiledReplicatedMapQueryContext.this.closeHashLookupSearchCheckSlotContainsExpectedKeyAndValueDependants(); + } + + void clearEntry(long pos, long prevEntry) { + long entry = prevEntry & (~(entryMask())); + NativeBytes.UNSAFE.putLong(((address()) + pos), entry); + } + + public void checkValueForPut(long value) { + assert (value & (~(valueMask()))) == 0L : "Value out of range, was " + value; + } + + long indexToPos(long index) { + return index * (hashLookupEntrySize()); + } + + public void closeHashLookupIndexToPosDependants() { + CompiledReplicatedMapQueryContext.this.closeHashLookupHlPosDependants(); + } + + public long hlPos(long key) { + return indexToPos((key & (capacityMask()))); + } + + public void closeHashLookupHlPosDependants() { + CompiledReplicatedMapQueryContext.this.closeSearchKey(); + } + + public void clearHashLookup() { + NativeBytes.UNSAFE.setMemory(address(), ((capacityMask2()) + (hashLookupEntrySize())), ((byte)(0))); + } + + public long maskUnsetKey(long key) { + return (key &= keyMask()) != (UNSET_KEY) ? key : keyMask(); + } + + public void closeHashLookupMaskUnsetKeyDependants() { + CompiledReplicatedMapQueryContext.this.closeSearchKey(); } long searchKey = UNSET_KEY; @@ -3107,8 +2631,8 @@ public class CompiledReplicatedMapQueryContext= 0 ? pos : capacityMask2(); + } + + public void closeHashLookupStepBackDependants() { + CompiledReplicatedMapQueryContext.this.closeHashLookupSearchFoundDependants(); + } + + public void found() { + CompiledReplicatedMapQueryContext.this.setHashLookupPosGuarded(CompiledReplicatedMapQueryContext.this.stepBack(CompiledReplicatedMapQueryContext.this.hashLookupPos())); + } + + public void closeHashLookupSearchFoundDependants() { + CompiledReplicatedMapQueryContext.this.closeKeySearch(); + } + + public boolean empty(long entry) { + return (entry & (entryMask())) == (UNSET_ENTRY); + } + + public void closeHashLookupEmptyDependants() { + CompiledReplicatedMapQueryContext.this.closeHashLookupSearchNextPosDependants(); + } + + public boolean checkSlotIsEmpty() { + return CompiledReplicatedMapQueryContext.this.empty(CompiledReplicatedMapQueryContext.this.readEntry(CompiledReplicatedMapQueryContext.this.hashLookupPos())); + } + + public void writeEntry(long pos, long prevEntry, long key, long value) { + long entry = (prevEntry & (~(entryMask()))) | (entry(key, value)); + NativeBytes.UNSAFE.putLong(((address()) + pos), entry); } void put(long value) { @@ -3154,6 +2717,38 @@ public class CompiledReplicatedMapQueryContext sb.append(key).append('=').append(value).append(',')); + sb.append('}'); + return sb.toString(); + } + + public void putVolatile(long value) { + CompiledReplicatedMapQueryContext.this.checkValueForPut(value); + long currentEntry = CompiledReplicatedMapQueryContext.this.readEntry(CompiledReplicatedMapQueryContext.this.hashLookupPos()); + assert (CompiledReplicatedMapQueryContext.this.key(currentEntry)) == (searchKey()); + CompiledReplicatedMapQueryContext.this.writeEntryVolatile(CompiledReplicatedMapQueryContext.this.hashLookupPos(), currentEntry, searchKey(), value); + } + public boolean checkSlotContainsExpectedKeyAndValue(long value) { long entry = CompiledReplicatedMapQueryContext.this.readEntry(CompiledReplicatedMapQueryContext.this.hashLookupPos()); return ((CompiledReplicatedMapQueryContext.this.key(entry)) == (searchKey())) && ((CompiledReplicatedMapQueryContext.this.value(entry)) == value); @@ -3163,33 +2758,18 @@ public class CompiledReplicatedMapQueryContext 0; + } + + void initSegment() { + VanillaChronicleHash h = CompiledReplicatedMapQueryContext.this.h(); + long hashLookupOffset = h.segmentOffset(segmentIndex()); + long freeListOffset = hashLookupOffset + (h.segmentHashLookupOuterSize); + freeListBytes.storePositionAndSize(h.ms, freeListOffset, h.segmentFreeListInnerSize); + freeList.reuse(freeListBytes); + entrySpaceOffset = (freeListOffset + (h.segmentFreeListOuterSize)) + (h.segmentEntrySpaceInnerOffset); + this.closeSegmentDependants(); + } + + public long entrySpaceOffset() { + if (!(this.segmentInit())) + this.initSegment(); + + return this.entrySpaceOffset; + } + + public SingleThreadedDirectBitSet freeList() { + if (!(this.segmentInit())) + this.initSegment(); + + return this.freeList; + } + + void closeSegment() { + if (!(this.segmentInit())) + return ; + + this.closeSegmentDependants(); + entrySpaceOffset = 0; + } + + public void closeSegmentDependants() { + CompiledReplicatedMapQueryContext.this.closeEntryOffset(); + } + + public void free(long fromPos, int chunks) { + freeList().clear(fromPos, (fromPos + chunks)); + if (fromPos < (nextPosToSearchFrom())) + nextPosToSearchFrom(fromPos); + + } + + public void clearSegment() { + CompiledReplicatedMapQueryContext.this.innerWriteLock.lock(); + CompiledReplicatedMapQueryContext.this.clearHashLookup(); + freeList().clear(); + nextPosToSearchFrom(0L); + entries(0L); + } + + public void clear() { + clearSegment(); + } + + public long alloc(int chunks) { + VanillaChronicleHash h = CompiledReplicatedMapQueryContext.this.h(); + if (chunks > (h.maxChunksPerEntry)) + throw new IllegalArgumentException((((("Entry is too large: requires " + chunks) + " entry size chucks, ") + (h.maxChunksPerEntry)) + " is maximum.")); + + long ret = freeList().setNextNContinuousClearBits(nextPosToSearchFrom(), chunks); + if ((ret == (DirectBitSet.NOT_FOUND)) || ((ret + chunks) > (h.actualChunksPerSegment))) { + if (((ret != (DirectBitSet.NOT_FOUND)) && ((ret + chunks) > (h.actualChunksPerSegment))) && (ret < (h.actualChunksPerSegment))) + freeList().clear(ret, h.actualChunksPerSegment); + + ret = freeList().setNextNContinuousClearBits(0L, chunks); + if ((ret == (DirectBitSet.NOT_FOUND)) || ((ret + chunks) > (h.actualChunksPerSegment))) { + if (((ret != (DirectBitSet.NOT_FOUND)) && ((ret + chunks) > (h.actualChunksPerSegment))) && (ret < (h.actualChunksPerSegment))) + freeList().clear(ret, h.actualChunksPerSegment); + + if (chunks == 1) { + throw new IllegalStateException("Segment is full, no free entries found"); + } else { + throw new IllegalStateException((("Segment is full or has no ranges of " + chunks) + " continuous free chunks")); + } + } + updateNextPosToSearchFrom(ret, chunks); + } else { + if ((chunks == 1) || (freeList().isSet(nextPosToSearchFrom()))) { + updateNextPosToSearchFrom(ret, chunks); + } + } + return ret; + } + + public int allocatedChunks = 0; + + public boolean allocatedChunksInit() { + return (this.allocatedChunks) != 0; + } + + public void initAllocatedChunks(int allocatedChunks) { + this.allocatedChunks = allocatedChunks; + } + + public int allocatedChunks() { + assert this.allocatedChunksInit() : "AllocatedChunks should be init"; + return this.allocatedChunks; + } + + public void closeAllocatedChunks() { + if (!(this.allocatedChunksInit())) + return ; + + this.allocatedChunks = 0; + } + + public long pos = -1; + + public boolean posInit() { + return (this.pos) >= 0; + } + + public void initPos(long pos) { + this.pos = pos; + this.closePosDependants(); + } + + public long pos() { + assert this.posInit() : "Pos should be init"; + return this.pos; + } + + public void closePos() { + if (!(this.posInit())) + return ; + + this.closePosDependants(); + this.pos = -1; + } + + public void closePosDependants() { + CompiledReplicatedMapQueryContext.this.closeEntryOffset(); + CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryDropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailedDependants(); + } + + public void raiseChange() { + CompiledReplicatedMapQueryContext.this.m().raiseChange(CompiledReplicatedMapQueryContext.this.segmentIndex(), CompiledReplicatedMapQueryContext.this.pos()); + } + + public void updateChange() { + if (!(replicationUpdateInit())) { + raiseChange(); + } + } + + public long keySizeOffset = -1; + + public boolean entryOffsetInit() { + return (this.keySizeOffset) >= 0; + } + + public void initEntryOffset() { + keySizeOffset = (CompiledReplicatedMapQueryContext.this.entrySpaceOffset()) + ((pos()) * (CompiledReplicatedMapQueryContext.this.h().chunkSize)); + entryBytes.limit(entryBytes.capacity()); + this.closeEntryOffsetDependants(); + } + + public long keySizeOffset() { + if (!(this.entryOffsetInit())) + this.initEntryOffset(); + + return this.keySizeOffset; + } + + public void closeEntryOffset() { + if (!(this.entryOffsetInit())) + return ; + + this.closeEntryOffsetDependants(); + this.keySizeOffset = -1; + } + + public void closeEntryOffsetDependants() { + CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesReadExistingEntryDependants(); + CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesEntrySizeDependants(); + } + + public void readExistingEntry(long pos) { + initPos(pos); + entryBytes.position(keySizeOffset()); + initKeySize(CompiledReplicatedMapQueryContext.this.h().keySizeMarshaller.readSize(entryBytes)); + initKeyOffset(entryBytes.position()); + } + + public void closeReplicatedMapEntryStagesReadExistingEntryDependants() { + CompiledReplicatedMapQueryContext.this.closeKeySearch(); + } + + public void dropChange() { + CompiledReplicatedMapQueryContext.this.m().dropChange(CompiledReplicatedMapQueryContext.this.segmentIndex(), CompiledReplicatedMapQueryContext.this.pos()); + } + + public long keyOffset = -1; + + public boolean keyOffsetInit() { + return (this.keyOffset) >= 0; + } + + public void initKeyOffset(long keyOffset) { + this.keyOffset = keyOffset; + this.closeKeyOffsetDependants(); + } + + public long keyOffset() { + assert this.keyOffsetInit() : "KeyOffset should be init"; + return this.keyOffset; + } + + public void closeKeyOffset() { + if (!(this.keyOffsetInit())) + return ; + + this.closeKeyOffsetDependants(); + this.keyOffset = -1; + } + + public void closeKeyOffsetDependants() { + CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryKeyEqualsDependants(); + CompiledReplicatedMapQueryContext.this.entryKey.closeEntryKeyBytesDataInnerGetUsingDependants(); + CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesKeyEndDependants(); + } + + public void copyExistingEntry(long newPos, long bytesToCopy) { + long oldKeySizeOffset = keySizeOffset(); + long oldKeyOffset = keyOffset(); + initPos(newPos); + initKeyOffset(((keySizeOffset()) + (oldKeyOffset - oldKeySizeOffset))); + Access.copy(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(oldKeySizeOffset), entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(keySizeOffset()), bytesToCopy); + } + + public long innerRemoteTimestamp; + + public byte innerRemoteIdentifier = ((byte)(0)); + + public boolean replicationUpdateInit() { + return (this.innerRemoteIdentifier) != ((byte)(0)); + } + + public void initReplicationUpdate(long timestamp, byte identifier) { + innerRemoteTimestamp = timestamp; + if (identifier == 0) + throw new IllegalStateException("identifier can\'t be 0"); + + innerRemoteIdentifier = identifier; + } + + public byte innerRemoteIdentifier() { + assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; + return this.innerRemoteIdentifier; + } + + public long innerRemoteTimestamp() { + assert this.replicationUpdateInit() : "ReplicationUpdate should be init"; + return this.innerRemoteTimestamp; + } + + public void closeReplicationUpdate() { + if (!(this.replicationUpdateInit())) + return ; + + this.innerRemoteIdentifier = ((byte)(0)); + } + + public Bytes replicatedInputBytes = null; + + public boolean replicatedInputBytesInit() { + return (this.replicatedInputBytes) != null; + } + + public void initReplicatedInputBytes(Bytes replicatedInputBytes) { + this.replicatedInputBytes = replicatedInputBytes; + this.closeReplicatedInputBytesDependants(); + } + + public Bytes replicatedInputBytes() { + assert this.replicatedInputBytesInit() : "ReplicatedInputBytes should be init"; + return this.replicatedInputBytes; + } + + public void closeReplicatedInputBytes() { + if (!(this.replicatedInputBytesInit())) + return ; + + this.closeReplicatedInputBytesDependants(); + this.replicatedInputBytes = null; + } + + public void closeReplicatedInputBytesDependants() { + CompiledReplicatedMapQueryContext.this.replicatedInputKeyBytesValue.closeReplicatedInputKeyBytesDataGetUsingDependants(); + CompiledReplicatedMapQueryContext.this.replicatedInputValueBytesValue.closeReplicatedInputValueBytesDataGetUsingDependants(); + } + + public Bytes inputBytes = null; + + public boolean inputBytesInit() { + return (this.inputBytes) != null; + } + + public void initInputBytes(Bytes inputBytes) { + this.inputBytes = inputBytes; + this.closeInputBytesDependants(); + } + + public Bytes inputBytes() { + assert this.inputBytesInit() : "InputBytes should be init"; + return this.inputBytes; + } + + public void closeInputBytes() { + if (!(this.inputBytesInit())) + return ; + + this.closeInputBytesDependants(); + this.inputBytes = null; + } + + public void closeInputBytesDependants() { + CompiledReplicatedMapQueryContext.this.closeInputKeyOffsets(); + CompiledReplicatedMapQueryContext.this.inputKeyBytesValue.closeInputKeyBytesDataGetUsingDependants(); + CompiledReplicatedMapQueryContext.this.closeFirstInputValueOffsets(); + CompiledReplicatedMapQueryContext.this.inputFirstValueBytesValue.closeInputFirstValueBytesDataGetUsingDependants(); + CompiledReplicatedMapQueryContext.this.closeSecondInputValueOffsets(); + CompiledReplicatedMapQueryContext.this.inputSecondValueBytesValue.closeInputSecondValueBytesDataGetUsingDependants(); + } + + public long inputKeySize = -1; + + public long inputKeyOffset; + + public boolean inputKeyOffsetsInit() { + return (this.inputKeySize) >= 0; + } + + private void initInputKeyOffsets() { + inputKeySize = CompiledReplicatedMapQueryContext.this.h().keySizeMarshaller.readSize(inputBytes()); + inputKeyOffset = inputBytes().position(); + this.closeInputKeyOffsetsDependants(); + } + + public long inputKeyOffset() { + if (!(this.inputKeyOffsetsInit())) + this.initInputKeyOffsets(); + + return this.inputKeyOffset; + } + + public long inputKeySize() { + if (!(this.inputKeyOffsetsInit())) + this.initInputKeyOffsets(); + + return this.inputKeySize; + } + + public void closeInputKeyOffsets() { + if (!(this.inputKeyOffsetsInit())) + return ; + + this.closeInputKeyOffsetsDependants(); + this.inputKeySize = -1; + } + + public void closeInputKeyOffsetsDependants() { + CompiledReplicatedMapQueryContext.this.inputKeyBytesValue.closeInputKeyBytesDataSizeDependants(); + CompiledReplicatedMapQueryContext.this.inputKeyBytesValue.closeInputKeyBytesDataGetUsingDependants(); + CompiledReplicatedMapQueryContext.this.closeFirstInputValueOffsets(); + } + + public long firstInputValueSize = -1; + + public long firstInputValueOffset; + + public boolean firstInputValueOffsetsInit() { + return (this.firstInputValueSize) >= 0; + } + + private void initFirstInputValueOffsets() { + CompiledReplicatedMapQueryContext.this.inputBytes().position(((CompiledReplicatedMapQueryContext.this.inputKeyOffset()) + (CompiledReplicatedMapQueryContext.this.inputKeySize()))); + firstInputValueSize = CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.readSize(CompiledReplicatedMapQueryContext.this.inputBytes()); + firstInputValueOffset = CompiledReplicatedMapQueryContext.this.inputBytes().position(); + this.closeFirstInputValueOffsetsDependants(); + } + + public long firstInputValueOffset() { + if (!(this.firstInputValueOffsetsInit())) + this.initFirstInputValueOffsets(); + + return this.firstInputValueOffset; + } + + public long firstInputValueSize() { + if (!(this.firstInputValueOffsetsInit())) + this.initFirstInputValueOffsets(); + + return this.firstInputValueSize; + } + + public void closeFirstInputValueOffsets() { + if (!(this.firstInputValueOffsetsInit())) + return ; + + this.closeFirstInputValueOffsetsDependants(); + this.firstInputValueSize = -1; + } + + public void closeFirstInputValueOffsetsDependants() { + CompiledReplicatedMapQueryContext.this.closeSecondInputValueOffsets(); + CompiledReplicatedMapQueryContext.this.inputFirstValueBytesValue.closeInputFirstValueBytesDataSizeDependants(); + CompiledReplicatedMapQueryContext.this.inputFirstValueBytesValue.closeInputFirstValueBytesDataGetUsingDependants(); + } + + public long secondInputValueSize = -1; + + public long secondInputValueOffset; + + public boolean secondInputValueOffsetsInit() { + return (this.secondInputValueSize) >= 0; + } + + private void initSecondInputValueOffsets() { + CompiledReplicatedMapQueryContext.this.inputBytes().position(((firstInputValueOffset()) + (firstInputValueSize()))); + secondInputValueSize = CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.readSize(CompiledReplicatedMapQueryContext.this.inputBytes()); + secondInputValueOffset = CompiledReplicatedMapQueryContext.this.inputBytes().position(); + this.closeSecondInputValueOffsetsDependants(); + } + + public long secondInputValueOffset() { + if (!(this.secondInputValueOffsetsInit())) + this.initSecondInputValueOffsets(); + + return this.secondInputValueOffset; + } + + public long secondInputValueSize() { + if (!(this.secondInputValueOffsetsInit())) + this.initSecondInputValueOffsets(); + + return this.secondInputValueSize; + } + + public void closeSecondInputValueOffsets() { + if (!(this.secondInputValueOffsetsInit())) + return ; + + this.closeSecondInputValueOffsetsDependants(); + this.secondInputValueSize = -1; + } + + public void closeSecondInputValueOffsetsDependants() { + CompiledReplicatedMapQueryContext.this.inputSecondValueBytesValue.closeInputSecondValueBytesDataSizeDependants(); + CompiledReplicatedMapQueryContext.this.inputSecondValueBytesValue.closeInputSecondValueBytesDataGetUsingDependants(); + } + public long keySize = -1; public boolean keySizeInit() { @@ -3241,9 +3310,266 @@ public class CompiledReplicatedMapQueryContext key) { + initPos(pos); + initKeySize(key.size()); + entryBytes.position(keySizeOffset()); + CompiledReplicatedMapQueryContext.this.h().keySizeMarshaller.writeSize(entryBytes, keySize()); + initKeyOffset(entryBytes.position()); + key.writeTo(entryBytesAccessor, entryBytes, keyOffset()); + } + + boolean keyEquals() { + return ((inputKey().size()) == (CompiledReplicatedMapQueryContext.this.keySize())) && (inputKey().equivalent(((ReadAccess)(CompiledReplicatedMapQueryContext.this.entryBytesAccess)), CompiledReplicatedMapQueryContext.this.entryBytesAccessHandle, CompiledReplicatedMapQueryContext.this.entryBytesAccessOffset(CompiledReplicatedMapQueryContext.this.keyOffset()))); + } + + public void closeReplicatedMapQueryKeyEqualsDependants() { + CompiledReplicatedMapQueryContext.this.closeKeySearch(); + } + + protected SearchState searchState = null; + + boolean keySearchInit() { + return (this.searchState) != null; + } + + void initKeySearch() { + for (long pos ; (pos = CompiledReplicatedMapQueryContext.this.nextPos()) >= 0L ; ) { + CompiledReplicatedMapQueryContext.this.readExistingEntry(pos); + if (!(keyEquals())) + continue; + + CompiledReplicatedMapQueryContext.this.found(); + keyFound(); + return ; + } + searchState = SearchState.ABSENT; + this.closeKeySearchDependants(); + } + + public SearchState searchState() { + if (!(this.keySearchInit())) + this.initKeySearch(); + + return this.searchState; + } + + void closeKeySearch() { + if (!(this.keySearchInit())) + return ; + + this.closeKeySearchDependants(); + this.searchState = null; + } + + public void closeKeySearchDependants() { + CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryDropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailedDependants(); + } + + private void _AllocatedChunks_incrementSegmentEntriesIfNeeded() { + } + + public void incrementSegmentEntriesIfNeeded() { + if ((CompiledReplicatedMapQueryContext.this.searchState()) != (SearchState.PRESENT)) { + CompiledReplicatedMapQueryContext.this.entries(((CompiledReplicatedMapQueryContext.this.entries()) + 1L)); + } + } + + public void initEntryAndKey(long entrySize) { + initAllocatedChunks(CompiledReplicatedMapQueryContext.this.h().inChunks(entrySize)); + CompiledReplicatedMapQueryContext.this.writeNewEntry(CompiledReplicatedMapQueryContext.this.alloc(allocatedChunks()), CompiledReplicatedMapQueryContext.this.inputKey()); + incrementSegmentEntriesIfNeeded(); + } + + public void initEntryAndKeyCopying(long entrySize, long bytesToCopy) { + initAllocatedChunks(CompiledReplicatedMapQueryContext.this.h().inChunks(entrySize)); + CompiledReplicatedMapQueryContext.this.copyExistingEntry(CompiledReplicatedMapQueryContext.this.alloc(allocatedChunks()), bytesToCopy); + incrementSegmentEntriesIfNeeded(); + } + + public boolean searchStatePresent() { + return (searchState()) == (SearchState.PRESENT); + } + + public void dropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailed() { + if (CompiledReplicatedMapQueryContext.this.locksInit()) { + if ((CompiledReplicatedMapQueryContext.this.concurrentSameThreadContexts()) && ((CompiledReplicatedMapQueryContext.this.rootContextOnThisSegment().latestSameThreadSegmentModCount()) != (CompiledReplicatedMapQueryContext.this.contextModCount()))) { + if (keySearchInit()) { + if ((searchState()) == (SearchState.PRESENT)) { + if (!(CompiledReplicatedMapQueryContext.this.checkSlotContainsExpectedKeyAndValue(CompiledReplicatedMapQueryContext.this.pos()))) + CompiledReplicatedMapQueryContext.this.closeHashLookupPos(); + + } + } + } + } + } + + public void closeReplicatedMapQueryDropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailedDependants() { + CompiledReplicatedMapQueryContext.this.closeQueryCheckOnEachPublicOperationCheckOnEachPublicOperationDependants(); + } + + private void _CheckOnEachPublicOperation_checkOnEachPublicOperation() { + CompiledReplicatedMapQueryContext.this.checkAccessingFromOwnerThread(); + } + + public void checkOnEachPublicOperation() { + _CheckOnEachPublicOperation_checkOnEachPublicOperation(); + CompiledReplicatedMapQueryContext.this.dropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailed(); + } + + public void closeQueryCheckOnEachPublicOperationCheckOnEachPublicOperationDependants() { + CompiledReplicatedMapQueryContext.this.entryValue.closeEntryValueBytesDataSizeDependants(); + CompiledReplicatedMapQueryContext.this.entryKey.closeEntryKeyBytesDataSizeDependants(); + } + + @NotNull + @Override + public MapContext context() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return this; + } + + public Data queriedKey() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return inputKey(); + } + + @NotNull + @Override + public InterProcessLock writeLock() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.innerWriteLock; + } + + @Override + public long remoteTimestamp() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return innerRemoteTimestamp(); + } + + @Override + public Data wrapValueAsValue(V value) { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + WrappedValueInstanceData wrapped = CompiledReplicatedMapQueryContext.this.wrappedValueInstanceValue; + wrapped = wrapped.getUnusedWrappedValueGuarded(); + wrapped.initValue(value); + return wrapped; + } + + @Override + public R remove(@NotNull + MapEntry entry) { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.m().entryOperations.remove(entry); + } + + @Override + public R insert(@NotNull + MapAbsentEntry absentEntry, Data value) { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.m().entryOperations.insert(absentEntry, value); + } + + @Override + public void raiseChanged() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + CompiledReplicatedMapQueryContext.this.innerUpdateLock.lock(); + CompiledReplicatedMapQueryContext.this.raiseChange(); + } + + @NotNull + @Override + public Data absentKey() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.inputKey(); + } + + @NotNull + @Override + public Data value() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.entryValue; + } + + @NotNull + @Override + public InterProcessLock updateLock() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.innerUpdateLock; + } + + @NotNull + @Override + public Data defaultValue() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.wrapValueAsValue(CompiledReplicatedMapQueryContext.this.m().defaultValue(CompiledReplicatedMapQueryContext.this.deprecatedMapKeyContext)); + } + + @Override + public R replaceValue(@NotNull + MapEntry entry, Data newValue) { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.m().entryOperations.replaceValue(entry, newValue); + } + + @Override + public Data defaultValue(@NotNull + MapAbsentEntry absentEntry) { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.m().entryOperations.defaultValue(absentEntry); + } + + @Override + public void dropChanged() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + CompiledReplicatedMapQueryContext.this.innerUpdateLock.lock(); + CompiledReplicatedMapQueryContext.this.dropChange(); + } + + @Override + public byte remoteIdentifier() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return innerRemoteIdentifier(); + } + + @NotNull + @Override + public InterProcessLock readLock() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.innerReadLock; + } + + @NotNull + @Override + public Data key() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return CompiledReplicatedMapQueryContext.this.entryKey; + } + + public boolean searchStateDeleted() { + return (((searchState()) == (SearchState.DELETED)) && (!(CompiledReplicatedMapQueryContext.this.concurrentSameThreadContexts()))) && (CompiledReplicatedMapQueryContext.this.innerUpdateLock.isHeldByCurrentThread()); + } + + public boolean searchStateAbsent() { + return (!(searchStatePresent())) && (!(searchStateDeleted())); + } + + protected void putPrefix() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + boolean underUpdatedLockIsHeld = !(CompiledReplicatedMapQueryContext.this.innerUpdateLock.isHeldByCurrentThread()); + if (underUpdatedLockIsHeld) + CompiledReplicatedMapQueryContext.this.innerUpdateLock.lock(); + + boolean searchResultsNotTrusted = underUpdatedLockIsHeld || (CompiledReplicatedMapQueryContext.this.concurrentSameThreadContexts()); + if (((CompiledReplicatedMapQueryContext.this.hashLookupPosInit()) && (searchStateAbsent())) && searchResultsNotTrusted) + CompiledReplicatedMapQueryContext.this.closeHashLookupPos(); + } public long keyEnd() { @@ -3251,147 +3577,9 @@ public class CompiledReplicatedMapQueryContext= 0; - } - - void initReplicationState() { - replicationBytesOffset = keyEnd(); - this.closeReplicationStateDependants(); - } - - public long replicationBytesOffset() { - if (!(this.replicationStateInit())) - this.initReplicationState(); - - return this.replicationBytesOffset; - } - - public void closeReplicationState() { - if (!(this.replicationStateInit())) - return ; - - this.closeReplicationStateDependants(); - this.replicationBytesOffset = -1; - } - - public void closeReplicationStateDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesIdentifierOffsetDependants(); - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesUpdateReplicationStateDependants(); - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesTimestampOffsetDependants(); - } - - private long entryDeletedOffset() { - return (replicationBytesOffset()) + 9L; - } - - public boolean entryDeleted() { - return entryBytesAccess.readBoolean(entryBytesAccessHandle, entryDeletedOffset()); - } - - public void writeEntryPresent() { - entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), false); - } - - public void writeEntryDeleted() { - entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), true); - } - - private long identifierOffset() { - return (replicationBytesOffset()) + 8L; - } - - public void closeReplicatedMapEntryStagesIdentifierOffsetDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesIdentifierDependants(); - } - - byte identifier() { - return entryBytesAccess.readByte(entryBytesAccessHandle, identifierOffset()); - } - - public void closeReplicatedMapEntryStagesIdentifierDependants() { - CompiledReplicatedMapQueryContext.this.closeUpdatedReplicationState(); - } - - void updateReplicationState(long timestamp, byte identifier) { - entryBytes.position(replicationBytesOffset()); - entryBytes.writeLong(timestamp); - entryBytes.writeByte(identifier); - } - - public void closeReplicatedMapEntryStagesUpdateReplicationStateDependants() { - CompiledReplicatedMapQueryContext.this.closeUpdatedReplicationState(); - } - - private long timestampOffset() { - return replicationBytesOffset(); - } - - public void closeReplicatedMapEntryStagesTimestampOffsetDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesTimestampDependants(); - } - - public long timestamp() { - return entryBytesAccess.readLong(entryBytesAccessHandle, timestampOffset()); - } - - public void closeReplicatedMapEntryStagesTimestampDependants() { - CompiledReplicatedMapQueryContext.this.closeUpdatedReplicationState(); - } - - private boolean testTimeStampInSensibleRange() { - if ((CompiledReplicatedMapQueryContext.this.m().timeProvider) == (TimeProvider.SYSTEM)) { - long currentTime = TimeProvider.SYSTEM.currentTime(); - assert (Math.abs((currentTime - (timestamp())))) <= 100000000 : "unrealistic timestamp: " + (timestamp()); - assert (Math.abs((currentTime - (CompiledReplicatedMapQueryContext.this.innerRemoteTimestamp())))) <= 100000000 : "unrealistic innerRemoteTimestamp: " + (CompiledReplicatedMapQueryContext.this.innerRemoteTimestamp()); - } - return true; - } - - private boolean updatedReplicationState = false; - - public boolean updatedReplicationStateInit() { - return (this.updatedReplicationState) != false; - } - - public void initUpdatedReplicationStateOnAbsentEntry() { - CompiledReplicatedMapQueryContext.this.innerWriteLock.lock(); - if (CompiledReplicatedMapQueryContext.this.replicationUpdateInit()) { - updateReplicationState(CompiledReplicatedMapQueryContext.this.innerRemoteTimestamp(), CompiledReplicatedMapQueryContext.this.innerRemoteIdentifier()); - } else { - updateReplicationState(CompiledReplicatedMapQueryContext.this.m().timeProvider.currentTime(), CompiledReplicatedMapQueryContext.this.m().identifier()); - } - updatedReplicationState = true; - } - - public void initUpdatedReplicationStateOnPresentEntry() { - CompiledReplicatedMapQueryContext.this.innerWriteLock.lock(); - if (CompiledReplicatedMapQueryContext.this.replicationUpdateInit()) { - updateReplicationState(CompiledReplicatedMapQueryContext.this.innerRemoteTimestamp(), CompiledReplicatedMapQueryContext.this.innerRemoteIdentifier()); - } else { - long timestamp; - if ((identifier()) != (CompiledReplicatedMapQueryContext.this.m().identifier())) { - timestamp = Math.max(((timestamp()) + 1), CompiledReplicatedMapQueryContext.this.m().timeProvider.currentTime()); - } else { - timestamp = CompiledReplicatedMapQueryContext.this.m().timeProvider.currentTime(); - } - updateReplicationState(timestamp, CompiledReplicatedMapQueryContext.this.m().identifier()); - } - updatedReplicationState = true; - } - - public void closeUpdatedReplicationState() { - if (!(this.updatedReplicationStateInit())) - return ; - - this.updatedReplicationState = false; + CompiledReplicatedMapQueryContext.this.closeReplicationState(); } private long _MapEntryStages_countValueSizeOffset() { @@ -3505,189 +3693,6 @@ public class CompiledReplicatedMapQueryContext value) { - value.writeTo(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(valueOffset())); - } - - public void initValue(Data value) { - entryBytes.position(valueSizeOffset()); - initValSize(value.size()); - writeValue(value); - } - - public void initValueWithoutSize(Data value, long oldValueSizeOffset, long oldValueSize, long oldValueOffset) { - assert oldValueSize == (value.size()); - initValSizeEqualToOld(oldValueSizeOffset, oldValueSize, oldValueOffset); - writeValue(value); - } - - boolean keyEquals() { - return ((inputKey().size()) == (CompiledReplicatedMapQueryContext.this.keySize())) && (inputKey().equivalent(((ReadAccess)(CompiledReplicatedMapQueryContext.this.entryBytesAccess)), CompiledReplicatedMapQueryContext.this.entryBytesAccessHandle, CompiledReplicatedMapQueryContext.this.entryBytesAccessOffset(CompiledReplicatedMapQueryContext.this.keyOffset()))); - } - - public void closeReplicatedMapQueryKeyEqualsDependants() { - CompiledReplicatedMapQueryContext.this.closeKeySearch(); - } - - public long pos = -1; - - public boolean posInit() { - return (this.pos) >= 0; - } - - public void initPos(long pos) { - this.pos = pos; - this.closePosDependants(); - } - - public long pos() { - assert this.posInit() : "Pos should be init"; - return this.pos; - } - - public void closePos() { - if (!(this.posInit())) - return ; - - this.closePosDependants(); - this.pos = -1; - } - - public void closePosDependants() { - CompiledReplicatedMapQueryContext.this.closeEntryOffset(); - CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryDropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailedDependants(); - } - - public void raiseChange() { - CompiledReplicatedMapQueryContext.this.m().raiseChange(CompiledReplicatedMapQueryContext.this.segmentIndex(), CompiledReplicatedMapQueryContext.this.pos()); - } - - public long keySizeOffset = -1; - - public boolean entryOffsetInit() { - return (this.keySizeOffset) >= 0; - } - - public void initEntryOffset() { - keySizeOffset = (CompiledReplicatedMapQueryContext.this.entrySpaceOffset()) + ((pos()) * (CompiledReplicatedMapQueryContext.this.h().chunkSize)); - entryBytes.limit(entryBytes.capacity()); - this.closeEntryOffsetDependants(); - } - - public long keySizeOffset() { - if (!(this.entryOffsetInit())) - this.initEntryOffset(); - - return this.keySizeOffset; - } - - public void closeEntryOffset() { - if (!(this.entryOffsetInit())) - return ; - - this.closeEntryOffsetDependants(); - this.keySizeOffset = -1; - } - - public void closeEntryOffsetDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesReadExistingEntryDependants(); - CompiledReplicatedMapQueryContext.this.closeReplicatedMapEntryStagesEntrySizeDependants(); - } - - public void readExistingEntry(long pos) { - initPos(pos); - entryBytes.position(keySizeOffset()); - initKeySize(CompiledReplicatedMapQueryContext.this.h().keySizeMarshaller.readSize(entryBytes)); - initKeyOffset(entryBytes.position()); - } - - public void closeReplicatedMapEntryStagesReadExistingEntryDependants() { - CompiledReplicatedMapQueryContext.this.closeKeySearch(); - } - - protected SearchState searchState = null; - - boolean keySearchInit() { - return (this.searchState) != null; - } - - void initKeySearch() { - for (long pos ; (pos = CompiledReplicatedMapQueryContext.this.nextPos()) >= 0L ; ) { - CompiledReplicatedMapQueryContext.this.readExistingEntry(pos); - if (!(keyEquals())) - continue; - - CompiledReplicatedMapQueryContext.this.found(); - keyFound(); - return ; - } - searchState = SearchState.ABSENT; - this.closeKeySearchDependants(); - } - - public SearchState searchState() { - if (!(this.keySearchInit())) - this.initKeySearch(); - - return this.searchState; - } - - void closeKeySearch() { - if (!(this.keySearchInit())) - return ; - - this.closeKeySearchDependants(); - this.searchState = null; - } - - public void closeKeySearchDependants() { - CompiledReplicatedMapQueryContext.this.closeReplicatedMapQueryDropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailedDependants(); - } - - public boolean searchStatePresent() { - return (searchState()) == (SearchState.PRESENT); - } - - private boolean _MapQuery_entryPresent() { - return searchStatePresent(); - } - - public boolean entryPresent() { - return (_MapQuery_entryPresent()) && (!(CompiledReplicatedMapQueryContext.this.entryDeleted())); - } - - public boolean searchStateDeleted() { - return (((searchState()) == (SearchState.DELETED)) && (!(CompiledReplicatedMapQueryContext.this.concurrentSameThreadContexts()))) && (CompiledReplicatedMapQueryContext.this.innerUpdateLock.isHeldByCurrentThread()); - } - - public boolean searchStateAbsent() { - return (!(searchStatePresent())) && (!(searchStateDeleted())); - } - - private void _AllocatedChunks_incrementSegmentEntriesIfNeeded() { - } - - public void incrementSegmentEntriesIfNeeded() { - if ((CompiledReplicatedMapQueryContext.this.searchState()) != (SearchState.PRESENT)) { - CompiledReplicatedMapQueryContext.this.entries(((CompiledReplicatedMapQueryContext.this.entries()) + 1L)); - } - } - - public void writeNewEntry(long pos, Data key) { - initPos(pos); - initKeySize(key.size()); - entryBytes.position(keySizeOffset()); - CompiledReplicatedMapQueryContext.this.h().keySizeMarshaller.writeSize(entryBytes, keySize()); - initKeyOffset(entryBytes.position()); - key.writeTo(entryBytesAccessor, entryBytes, keyOffset()); - } - - public void initEntryAndKey(long entrySize) { - initAllocatedChunks(CompiledReplicatedMapQueryContext.this.h().inChunks(entrySize)); - CompiledReplicatedMapQueryContext.this.writeNewEntry(CompiledReplicatedMapQueryContext.this.alloc(allocatedChunks()), CompiledReplicatedMapQueryContext.this.inputKey()); - incrementSegmentEntriesIfNeeded(); - } - long entrySize() { return (entryEnd()) - (keySizeOffset()); } @@ -3732,24 +3737,60 @@ public class CompiledReplicatedMapQueryContext value) { + value.writeTo(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(valueOffset())); + } + + public void initValueWithoutSize(Data value, long oldValueSizeOffset, long oldValueSize, long oldValueOffset) { + assert oldValueSize == (value.size()); + initValSizeEqualToOld(oldValueSizeOffset, oldValueSize, oldValueOffset); + writeValue(value); + } + + public void initValue(Data value) { + entryBytes.position(valueSizeOffset()); + initValSize(value.size()); + writeValue(value); + } + + public void writeValueAndPutPos(Data value) { + initValue(value); + freeExtraAllocatedChunks(); + CompiledReplicatedMapQueryContext.this.putValueVolatile(CompiledReplicatedMapQueryContext.this.hashLookupPos(), pos()); + } + + private void _MapEntryStages_relocation(Data newValue, long newSizeOfEverythingBeforeValue) { + CompiledReplicatedMapQueryContext.this.free(pos(), entrySizeInChunks()); + long entrySize = innerEntrySize(newSizeOfEverythingBeforeValue, newValue.size()); + CompiledReplicatedMapQueryContext.this.initEntryAndKeyCopying(entrySize, ((valueSizeOffset()) - (keySizeOffset()))); + writeValueAndPutPos(newValue); + } + + protected void relocation(Data newValue, long newSizeOfEverythingBeforeValue) { + long oldPos = pos(); + _MapEntryStages_relocation(newValue, newSizeOfEverythingBeforeValue); + CompiledReplicatedMapQueryContext.this.moveChange(oldPos, pos()); + } + + void putEntry(Data value) { + assert CompiledReplicatedMapQueryContext.this.searchStateAbsent(); + long entrySize = CompiledReplicatedMapQueryContext.this.entrySize(CompiledReplicatedMapQueryContext.this.inputKey().size(), value.size()); + CompiledReplicatedMapQueryContext.this.initEntryAndKey(entrySize); + CompiledReplicatedMapQueryContext.this.initValue(value); + CompiledReplicatedMapQueryContext.this.freeExtraAllocatedChunks(); + CompiledReplicatedMapQueryContext.this.putNewVolatile(CompiledReplicatedMapQueryContext.this.pos()); + } + public long newSizeOfEverythingBeforeValue(Data newValue) { return ((valueSizeOffset()) + (CompiledReplicatedMapQueryContext.this.m().valueSizeMarshaller.sizeEncodingSize(newValue.size()))) - (keySizeOffset()); } - public void copyExistingEntry(long newPos, long bytesToCopy) { - long oldKeySizeOffset = keySizeOffset(); - long oldKeyOffset = keyOffset(); - initPos(newPos); - initKeyOffset(((keySizeOffset()) + (oldKeyOffset - oldKeySizeOffset))); - Access.copy(entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(oldKeySizeOffset), entryBytesAccess, entryBytesAccessHandle, entryBytesAccessOffset(keySizeOffset()), bytesToCopy); - } - - public void initEntryAndKeyCopying(long entrySize, long bytesToCopy) { - initAllocatedChunks(CompiledReplicatedMapQueryContext.this.h().inChunks(entrySize)); - CompiledReplicatedMapQueryContext.this.copyExistingEntry(CompiledReplicatedMapQueryContext.this.alloc(allocatedChunks()), bytesToCopy); - incrementSegmentEntriesIfNeeded(); - } - private void _MapEntryStages_putValueDeletedEntry(Data newValue) { assert CompiledReplicatedMapQueryContext.this.innerUpdateLock.isHeldByCurrentThread(); int newSizeInChunks; @@ -3799,241 +3840,6 @@ public class CompiledReplicatedMapQueryContext value) { - assert CompiledReplicatedMapQueryContext.this.searchStateAbsent(); - long entrySize = CompiledReplicatedMapQueryContext.this.entrySize(CompiledReplicatedMapQueryContext.this.inputKey().size(), value.size()); - CompiledReplicatedMapQueryContext.this.initEntryAndKey(entrySize); - CompiledReplicatedMapQueryContext.this.initValue(value); - CompiledReplicatedMapQueryContext.this.freeExtraAllocatedChunks(); - CompiledReplicatedMapQueryContext.this.putNewVolatile(CompiledReplicatedMapQueryContext.this.pos()); - } - - public void writeValueAndPutPos(Data value) { - initValue(value); - freeExtraAllocatedChunks(); - CompiledReplicatedMapQueryContext.this.putValueVolatile(CompiledReplicatedMapQueryContext.this.hashLookupPos(), pos()); - } - - public void innerRemoveEntryExceptHashLookupUpdate() { - CompiledReplicatedMapQueryContext.this.free(pos(), entrySizeInChunks()); - CompiledReplicatedMapQueryContext.this.entries(((CompiledReplicatedMapQueryContext.this.entries()) - 1L)); - CompiledReplicatedMapQueryContext.this.incrementModCountGuarded(); - } - - public void dropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailed() { - if (CompiledReplicatedMapQueryContext.this.locksInit()) { - if ((CompiledReplicatedMapQueryContext.this.concurrentSameThreadContexts()) && ((CompiledReplicatedMapQueryContext.this.rootContextOnThisSegment().latestSameThreadSegmentModCount()) != (CompiledReplicatedMapQueryContext.this.contextModCount()))) { - if (keySearchInit()) { - if ((searchState()) == (SearchState.PRESENT)) { - if (!(CompiledReplicatedMapQueryContext.this.checkSlotContainsExpectedKeyAndValue(CompiledReplicatedMapQueryContext.this.pos()))) - CompiledReplicatedMapQueryContext.this.closeHashLookupPos(); - - } - } - } - } - } - - public void closeReplicatedMapQueryDropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailedDependants() { - CompiledReplicatedMapQueryContext.this.closeQueryCheckOnEachPublicOperationCheckOnEachPublicOperationDependants(); - } - - private void _CheckOnEachPublicOperation_checkOnEachPublicOperation() { - CompiledReplicatedMapQueryContext.this.checkAccessingFromOwnerThread(); - } - - public void checkOnEachPublicOperation() { - _CheckOnEachPublicOperation_checkOnEachPublicOperation(); - CompiledReplicatedMapQueryContext.this.dropSearchIfNestedContextsAndPresentHashLookupSlotCheckFailed(); - } - - public void closeQueryCheckOnEachPublicOperationCheckOnEachPublicOperationDependants() { - CompiledReplicatedMapQueryContext.this.entryValue.closeEntryValueBytesDataSizeDependants(); - CompiledReplicatedMapQueryContext.this.entryKey.closeEntryKeyBytesDataSizeDependants(); - } - - public Data queriedKey() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return inputKey(); - } - - @Override - public byte remoteIdentifier() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return innerRemoteIdentifier(); - } - - @NotNull - @Override - public Data absentKey() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.inputKey(); - } - - @NotNull - @Override - public Data key() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.entryKey; - } - - protected void putPrefix() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - boolean underUpdatedLockIsHeld = !(CompiledReplicatedMapQueryContext.this.innerUpdateLock.isHeldByCurrentThread()); - if (underUpdatedLockIsHeld) - CompiledReplicatedMapQueryContext.this.innerUpdateLock.lock(); - - boolean searchResultsNotTrusted = underUpdatedLockIsHeld || (CompiledReplicatedMapQueryContext.this.concurrentSameThreadContexts()); - if (((CompiledReplicatedMapQueryContext.this.hashLookupPosInit()) && (searchStateAbsent())) && searchResultsNotTrusted) - CompiledReplicatedMapQueryContext.this.closeHashLookupPos(); - - } - - @Override - public R insert(@NotNull - MapAbsentEntry absentEntry, Data value) { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.m().entryOperations.insert(absentEntry, value); - } - - @Override - public long originTimestamp() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return timestamp(); - } - - @Override - public Data wrapValueAsValue(V value) { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - WrappedValueInstanceData wrapped = CompiledReplicatedMapQueryContext.this.wrappedValueInstanceValue; - wrapped = wrapped.getUnusedWrappedValueGuarded(); - wrapped.initValue(value); - return wrapped; - } - - @NotNull - @Override - public Data defaultValue() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.wrapValueAsValue(CompiledReplicatedMapQueryContext.this.m().defaultValue(CompiledReplicatedMapQueryContext.this.deprecatedMapKeyContext)); - } - - @Override - public R remove(@NotNull - MapEntry entry) { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.m().entryOperations.remove(entry); - } - - @NotNull - @Override - public InterProcessLock writeLock() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.innerWriteLock; - } - - @Override - public long remoteTimestamp() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return innerRemoteTimestamp(); - } - - private MapEntry _MapQuery_entry() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return entryPresent() ? this : null; - } - - @Override - public MapReplicableEntry entry() { - return ((MapReplicableEntry)(_MapQuery_entry())); - } - - @NotNull - @Override - public InterProcessLock updateLock() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.innerUpdateLock; - } - - @Nullable - private MapAbsentEntry _MapQuery_absentEntry() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return entryPresent() ? null : CompiledReplicatedMapQueryContext.this.absent(); - } - - @Nullable - @Override - public MapAbsentEntry absentEntry() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - if (entryPresent()) { - return null; - } else { - if (!(searchStatePresent())) { - return CompiledReplicatedMapQueryContext.this.absentDelegating; - } else { - assert CompiledReplicatedMapQueryContext.this.entryDeleted(); - return CompiledReplicatedMapQueryContext.this.absent(); - } - } - } - - @Override - public byte originIdentifier() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return identifier(); - } - - @NotNull - @Override - public MapContext context() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return this; - } - - @NotNull - @Override - public Data value() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.entryValue; - } - - @Override - public R replaceValue(@NotNull - MapEntry entry, Data newValue) { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.m().entryOperations.replaceValue(entry, newValue); - } - - @NotNull - @Override - public InterProcessLock readLock() { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.innerReadLock; - } - - @Override - public Data defaultValue(@NotNull - MapAbsentEntry absentEntry) { - CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); - return CompiledReplicatedMapQueryContext.this.m().entryOperations.defaultValue(absentEntry); - } - - public void dropChange() { - CompiledReplicatedMapQueryContext.this.m().dropChange(CompiledReplicatedMapQueryContext.this.segmentIndex(), CompiledReplicatedMapQueryContext.this.pos()); - } - - private void _MapEntryStages_relocation(Data newValue, long newSizeOfEverythingBeforeValue) { - CompiledReplicatedMapQueryContext.this.free(pos(), entrySizeInChunks()); - long entrySize = innerEntrySize(newSizeOfEverythingBeforeValue, newValue.size()); - CompiledReplicatedMapQueryContext.this.initEntryAndKeyCopying(entrySize, ((valueSizeOffset()) - (keySizeOffset()))); - writeValueAndPutPos(newValue); - } - - protected void relocation(Data newValue, long newSizeOfEverythingBeforeValue) { - CompiledReplicatedMapQueryContext.this.dropChange(); - _MapEntryStages_relocation(newValue, newSizeOfEverythingBeforeValue); - } - public void innerDefaultReplaceValue(Data newValue) { assert CompiledReplicatedMapQueryContext.this.innerUpdateLock.isHeldByCurrentThread(); boolean newValueSizeIsDifferent = (newValue.size()) != (this.valueSize()); @@ -4068,11 +3874,103 @@ public class CompiledReplicatedMapQueryContext= 0; + } + + void initReplicationState() { + replicationBytesOffset = keyEnd(); + } + + public long replicationBytesOffset() { + if (!(this.replicationStateInit())) + this.initReplicationState(); + + return this.replicationBytesOffset; + } + + public void closeReplicationState() { + if (!(this.replicationStateInit())) + return ; + + this.replicationBytesOffset = -1; + } + + private long entryDeletedOffset() { + return (replicationBytesOffset()) + 9L; + } + + public void writeEntryPresent() { + entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), false); + } + + public boolean entryDeleted() { + return entryBytesAccess.readBoolean(entryBytesAccessHandle, entryDeletedOffset()); + } + + private boolean _MapQuery_entryPresent() { + return searchStatePresent(); + } + + public boolean entryPresent() { + return (_MapQuery_entryPresent()) && (!(CompiledReplicatedMapQueryContext.this.entryDeleted())); + } + + private MapEntry _MapQuery_entry() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return entryPresent() ? this : null; + } + + @Override + public MapReplicableEntry entry() { + return ((MapReplicableEntry)(_MapQuery_entry())); + } + + @Nullable + private MapAbsentEntry _MapQuery_absentEntry() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + return entryPresent() ? null : CompiledReplicatedMapQueryContext.this.absent(); + } + + @Nullable + @Override + public MapAbsentEntry absentEntry() { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + if (entryPresent()) { + return null; } else { - raiseChange(); + if (!(searchStatePresent())) { + return CompiledReplicatedMapQueryContext.this.absentDelegating; + } else { + assert CompiledReplicatedMapQueryContext.this.entryDeleted(); + return CompiledReplicatedMapQueryContext.this.absent(); + } + } + } + + public void writeEntryDeleted() { + entryBytesAccess.writeBoolean(entryBytesAccessHandle, entryDeletedOffset(), true); + } + + void updateReplicationState(long timestamp, byte identifier) { + entryBytes.position(replicationBytesOffset()); + entryBytes.writeLong(timestamp); + entryBytes.writeByte(identifier); + } + + @Override + public void updateOrigin(byte newIdentifier, long newTimestamp) { + CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); + CompiledReplicatedMapQueryContext.this.innerWriteLock.lock(); + updateReplicationState(newTimestamp, newIdentifier); + } + + public void updatedReplicationStateOnAbsentEntry() { + if (!(CompiledReplicatedMapQueryContext.this.replicationUpdateInit())) { + CompiledReplicatedMapQueryContext.this.innerWriteLock.lock(); + updateReplicationState(CompiledReplicatedMapQueryContext.this.m().timeProvider.currentTime(), CompiledReplicatedMapQueryContext.this.m().identifier()); } } @@ -4105,12 +4003,80 @@ public class CompiledReplicatedMapQueryContext newValue) { + putPrefix(); + if (searchStatePresent()) { + CompiledReplicatedMapQueryContext.this.innerDefaultReplaceValue(newValue); + CompiledReplicatedMapQueryContext.this.incrementModCountGuarded(); + setSearchStateGuarded(SearchState.PRESENT); + } else { + throw new IllegalStateException("Entry is absent in the map when doReplaceValue() is called"); + } + } + + @Override + public void doReplaceValue(Data newValue) { + _MapQuery_doReplaceValue(newValue); + CompiledReplicatedMapQueryContext.this.updateChange(); + CompiledReplicatedMapQueryContext.this.updatedReplicationStateOnPresentEntry(); + } + private void _MapQuery_doRemove() { CompiledReplicatedMapQueryContext.this.checkOnEachPublicOperation(); CompiledReplicatedMapQueryContext.this.innerUpdateLock.lock(); @@ -4132,7 +4098,7 @@ public class CompiledReplicatedMapQueryContext (CompiledReplicatedMapQueryContext.this.dummyValue.size())) CompiledReplicatedMapQueryContext.this.innerDefaultReplaceValue(CompiledReplicatedMapQueryContext.this.dummyValue); - CompiledReplicatedMapQueryContext.this.initUpdatedReplicationStateOnPresentEntry(); + CompiledReplicatedMapQueryContext.this.updatedReplicationStateOnPresentEntry(); CompiledReplicatedMapQueryContext.this.writeEntryDeleted(); CompiledReplicatedMapQueryContext.this.updateChange(); CompiledReplicatedMapQueryContext.this.deleted(((CompiledReplicatedMapQueryContext.this.deleted()) + 1)); @@ -4141,24 +4107,6 @@ public class CompiledReplicatedMapQueryContext newValue) { - putPrefix(); - if (searchStatePresent()) { - CompiledReplicatedMapQueryContext.this.innerDefaultReplaceValue(newValue); - CompiledReplicatedMapQueryContext.this.incrementModCountGuarded(); - setSearchStateGuarded(SearchState.PRESENT); - } else { - throw new IllegalStateException("Entry is absent in the map when doReplaceValue() is called"); - } - } - - @Override - public void doReplaceValue(Data newValue) { - _MapQuery_doReplaceValue(newValue); - CompiledReplicatedMapQueryContext.this.updateChange(); - CompiledReplicatedMapQueryContext.this.initUpdatedReplicationStateOnPresentEntry(); - } - public long riKeySize = -1; public long riValueSize; @@ -4251,13 +4199,7 @@ public class CompiledReplicatedMapQueryContextExample: Grow-only set values CRDT:
    
    + * class GrowOnlySetValuedMapEntryOperations<K, E>
    + *         implements MapEntryOperations<K, Set<E>, Void> {
    + *     @Override
    + *     public Void remove(@NotNull MapEntry<K, Set<E>> entry) {
    + *         throw new UnsupportedOperationException("Map with grow-only set values " +
    + *                 "doesn't support map value removals");
    + *     }
    + * }
    + *
    + * class GrowOnlySetValuedMapRemoteOperations<K, E>
    + *         implements MapRemoteOperations<K, Set<E>, Void> {
    + *     @Override
    + *     public void put(MapRemoteQueryContext<K, Set<E>, Void> q,
    + *                     Data<Set<E>, ?> newValue) {
    + *         MapReplicableEntry<K, Set<E>> entry = q.entry();
    + *         if (entry != null) {
    + *             Set<E> merged = new HashSet<>(entry.value().get());
    + *             merged.addAll(newValue.get());
    + *             q.replaceValue(entry, q.wrapValueAsValue(merged));
    + *         } else {
    + *             q.insert(q.absentEntry(), newValue);
    + *             q.entry().updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
    + *         }
    + *     }
    + *
    + *     @Override
    + *     public void remove(MapRemoteQueryContext<K, Set<E>, Void> q) {
    + *         throw new UnsupportedOperationException();
    + *     }
    + * }
    + * + * @param the map key type + * @param the map value type + * @param the return type of {@link MapEntryOperations} specified fro the queried map + * @see DefaultEventualConsistencyStrategy + * @see ChronicleMapBuilder#remoteOperations(MapRemoteOperations) + */ public interface MapRemoteOperations { - - default AcceptanceDecision remove(MapRemoteQueryContext q) { + + /** + * Handle remote {@code remove} call and {@code remove} replication event, i. e. when the entry + * with the query key ({@code q.queriedKey()}) was removed on some {@code ChronicleMap} node. + * + * @implNote the default implementation applies the remove event using {@link + * DefaultEventualConsistencyStrategy} "latest wins" strategy:
    {@code
    +     * MapReplicableEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     if (DefaultEventualConsistencyStrategy.decideOnRemoteModification(entry, q) == ACCEPT) {
    +     *         q.remove(entry);
    +     *         ReplicableEntry replicableAbsentEntry = (ReplicableEntry) q.absentEntry();
    +     *         replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
    +     *         replicableAbsentEntry.dropChanged();
    +     *     }
    +     * } else {
    +     *     MapAbsentEntry absentEntry = q.absentEntry();
    +     *     ReplicableEntry replicableAbsentEntry;
    +     *     if (!(absentEntry instanceof ReplicableEntry)) {
    +     *         // Note in the two following lines dummy value is inserted and removed using direct
    +     *         // entry.doXxx calls, not q.xxx(entry). The intention is to avoid calling possibly
    +     *         // overridden MapEntryOperations, because this is technical procedure of making
    +     *         // "truly absent" entry "deleted", not actual insertion and removal.
    +     *         absentEntry.doInsert(q.dummyZeroValue());
    +     *         q.entry().doRemove();
    +     *         replicableAbsentEntry = (ReplicableEntry) q.absentEntry();
    +     *     } else {
    +     *         replicableAbsentEntry = (ReplicableEntry) absentEntry;
    +     *         if (DefaultEventualConsistencyStrategy.decideOnRemoteModification(
    +     *                 replicableAbsentEntry, q) == DISCARD) {
    +     *             return;
    +     *         }
    +     *     }
    +     *     replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
    +     *     replicableAbsentEntry.dropChanged();
    +     * }}
    + * + * @param q the remote operation context + */ + default void remove(MapRemoteQueryContext q) { MapReplicableEntry entry = q.entry(); if (entry != null) { if (decideOnRemoteModification(entry, q) == ACCEPT) { q.remove(entry); - return ACCEPT; - } else { - return DISCARD; + ReplicableEntry replicableAbsentEntry = (ReplicableEntry) q.absentEntry(); + replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + replicableAbsentEntry.dropChanged(); } } else { MapAbsentEntry absentEntry = q.absentEntry(); - assert absentEntry != null; - if (absentEntry instanceof ReplicableEntry) { - AcceptanceDecision decision = - decideOnRemoteModification((ReplicableEntry) absentEntry, q); - return decision; + ReplicableEntry replicableAbsentEntry; + if (!(absentEntry instanceof ReplicableEntry)) { + // Note in the two following lines dummy value is inserted and removed using direct + // entry.doXxx calls, not q.xxx(entry). The intention is to avoid calling possibly + // overridden MapEntryOperations, because this is technical procedure of making + // "truly absent" entry "deleted", not actual insertion and removal. + absentEntry.doInsert(q.dummyZeroValue()); + q.entry().doRemove(); + replicableAbsentEntry = (ReplicableEntry) q.absentEntry(); } else { - return ACCEPT; + replicableAbsentEntry = (ReplicableEntry) absentEntry; + if (decideOnRemoteModification(replicableAbsentEntry, q) == DISCARD) + return; } + replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + replicableAbsentEntry.dropChanged(); } } - - default AcceptanceDecision put(MapRemoteQueryContext q, Data newValue) { + + /** + * Handle remote {@code put} call or replication event, i. e. when the entry with the queried + * key ({@code q.queriedKey()}) was changed on some remote {@code ChronicleMap} node, with the + * given {@code newValue}. + * + * @implNote the default implementation applies the put event using {@link + * DefaultEventualConsistencyStrategy} "latest wins" strategy:
    {@code
    +     * MapReplicableEntry entry = q.entry();
    +     * if (entry != null) {
    +     *     if (DefaultEventualConsistencyStrategy.decideOnRemoteModification(entry, q) == ACCEPT) {
    +     *         q.replaceValue(entry, newValue);
    +     *         entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
    +     *         entry.dropChanged();
    +     *     }
    +     * } else {
    +     *     MapAbsentEntry absentEntry = q.absentEntry();
    +     *     if (!(absentEntry instanceof ReplicableEntry) ||
    +     *             DefaultEventualConsistencyStrategy.decideOnRemoteModification(
    +     *                     (ReplicableEntry) absentEntry, q) == ACCEPT) {
    +     *         q.insert(absentEntry, newValue);
    +     *         entry = q.entry();
    +     *         entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp());
    +     *         entry.dropChanged();
    +     *     }
    +     * }}
    + * + * @param q the remote operation context + * @param newValue the new value to put + */ + default void put(MapRemoteQueryContext q, Data newValue) { MapReplicableEntry entry = q.entry(); if (entry != null) { if (decideOnRemoteModification(entry, q) == ACCEPT) { q.replaceValue(entry, newValue); - return ACCEPT; - } else { - return DISCARD; + entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + entry.dropChanged(); } } else { MapAbsentEntry absentEntry = q.absentEntry(); - assert absentEntry != null; if (!(absentEntry instanceof ReplicableEntry) || decideOnRemoteModification((ReplicableEntry) absentEntry, q) == ACCEPT) { q.insert(absentEntry, newValue); - return ACCEPT; - } else { - return DISCARD; + entry = q.entry(); + entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + entry.dropChanged(); } } } 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 168561eb2..29ee474ee 100644 --- a/src/main/java/net/openhft/chronicle/map/replication/MapRemoteQueryContext.java +++ b/src/main/java/net/openhft/chronicle/map/replication/MapRemoteQueryContext.java @@ -18,9 +18,12 @@ package net.openhft.chronicle.map.replication; +import net.openhft.chronicle.hash.Data; import net.openhft.chronicle.hash.replication.HashRemoteQueryContext; import net.openhft.chronicle.hash.replication.RemoteOperationContext; +import net.openhft.chronicle.hash.serialization.SizeMarshaller; import net.openhft.chronicle.map.ChronicleMap; +import net.openhft.chronicle.map.ChronicleMapBuilder; import net.openhft.chronicle.map.MapEntryOperations; import net.openhft.chronicle.map.MapQueryContext; import org.jetbrains.annotations.Nullable; @@ -30,7 +33,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 + * @param the return type of {@link MapEntryOperations} specified for the queried map * @see MapRemoteOperations */ public interface MapRemoteQueryContext extends MapQueryContext, @@ -38,4 +41,18 @@ public interface MapRemoteQueryContext extends MapQueryContext @Nullable @Override MapReplicableEntry entry(); + + /** + * The value used as a tombstone, for removed entries, to save space. This value has {@linkplain + * SizeMarshaller#minEncodableSize() 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. + * + * @return dummy value of all zeros, of the minimum possible size. + */ + Data dummyZeroValue(); } diff --git a/src/main/java/net/openhft/chronicle/set/SetContext.java b/src/main/java/net/openhft/chronicle/set/SetContext.java index 33783a5b2..1ab75083d 100644 --- a/src/main/java/net/openhft/chronicle/set/SetContext.java +++ b/src/main/java/net/openhft/chronicle/set/SetContext.java @@ -3,10 +3,12 @@ package net.openhft.chronicle.set; import net.openhft.chronicle.hash.HashContext; /** - * Context, in which {@link SetEntry SetEntries} are accessed. + * Context, in which {@link SetEntry SetEntries} are accessed. {@code SetContext} allows to access + * {@link SetEntryOperations}, configured for the accessed {@link ChronicleSet}. {@code SetContext} + * implements {@code SetEntryOperations} by delegation to the configured {@code entryOperations}. * * @param the set key type - * @param the return type of {@link SetEntryOperations} specialized for the queried set + * @param the return type of {@link SetEntryOperations} specified for the queried set */ public interface SetContext extends HashContext, SetEntryOperations { 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 f135f6401..e10792d13 100644 --- a/src/main/java/net/openhft/chronicle/set/replication/SetRemoteOperations.java +++ b/src/main/java/net/openhft/chronicle/set/replication/SetRemoteOperations.java @@ -1,42 +1,50 @@ package net.openhft.chronicle.set.replication; -import net.openhft.chronicle.hash.AcceptanceDecision; import net.openhft.chronicle.hash.replication.ReplicableEntry; import net.openhft.chronicle.set.SetAbsentEntry; -import static net.openhft.chronicle.hash.AcceptanceDecision.ACCEPT; -import static net.openhft.chronicle.hash.AcceptanceDecision.DISCARD; +import static net.openhft.chronicle.hash.replication.AcceptanceDecision.ACCEPT; +import static net.openhft.chronicle.hash.replication.AcceptanceDecision.DISCARD; import static net.openhft.chronicle.hash.replication.DefaultEventualConsistencyStrategy.decideOnRemoteModification; public interface SetRemoteOperations { - default AcceptanceDecision remove(SetRemoteQueryContext q) { + default void remove(SetRemoteQueryContext q) { SetReplicableEntry entry = q.entry(); if (entry != null) { if (decideOnRemoteModification(entry, q) == ACCEPT) { q.remove(entry); - return ACCEPT; - } else { - return DISCARD; + ReplicableEntry replicableAbsentEntry = (ReplicableEntry) q.absentEntry(); + replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + replicableAbsentEntry.dropChanged(); } } else { SetAbsentEntry absentEntry = q.absentEntry(); - assert absentEntry != null; - if (absentEntry instanceof ReplicableEntry) { - return decideOnRemoteModification((ReplicableEntry) absentEntry, q); + ReplicableEntry replicableAbsentEntry; + if (!(absentEntry instanceof ReplicableEntry)) { + // Note in the two following lines dummy entry is inserted and removed using direct + // entry.doXxx calls, not q.xxx(entry). The intention is to avoid calling possibly + // overridden SetEntryOperations, because this is technical procedure of making + // "truly absent" entry "deleted", not actual insertion and removal. + absentEntry.doInsert(); + q.entry().doRemove(); + replicableAbsentEntry = (ReplicableEntry) q.absentEntry(); } else { - return ACCEPT; + replicableAbsentEntry = (ReplicableEntry) absentEntry; + if (decideOnRemoteModification(replicableAbsentEntry, q) == DISCARD) + return; } + replicableAbsentEntry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + replicableAbsentEntry.dropChanged(); } } - default AcceptanceDecision insert(SetRemoteQueryContext q) { + default void insert(SetRemoteQueryContext q) { SetReplicableEntry entry = q.entry(); if (entry != null) { if (decideOnRemoteModification(entry, q) == ACCEPT) { - return ACCEPT; - } else { - return DISCARD; + entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + entry.dropChanged(); } } else { SetAbsentEntry absentEntry = q.absentEntry(); @@ -44,9 +52,10 @@ public interface SetRemoteOperations { if (!(absentEntry instanceof ReplicableEntry) || decideOnRemoteModification((ReplicableEntry) absentEntry, q) == ACCEPT) { q.insert(absentEntry); - return ACCEPT; - } else { - return DISCARD; + entry = q.entry(); // q.entry() is not null after insert + assert entry != null; + entry.updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + entry.dropChanged(); } } } diff --git a/src/test/java/net/openhft/chronicle/map/BiMapTest.java b/src/test/java/net/openhft/chronicle/map/BiMapTest.java index 946af1295..385510833 100644 --- a/src/test/java/net/openhft/chronicle/map/BiMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/BiMapTest.java @@ -20,7 +20,7 @@ import static org.junit.Assert.assertTrue; public class BiMapTest { enum DualLockSuccess {SUCCESS, FAIL} - + static class BiMapMethods implements MapMethods { @Override public void remove(MapQueryContext q, ReturnValue returnValue) { @@ -88,7 +88,7 @@ public class BiMapTest { } @Override - public boolean remove(MapQueryContext q, net.openhft.chronicle.hash.Data value) { + public boolean remove(MapQueryContext q, Data value) { while (true) { q.updateLock().lock(); MapEntry entry = q.entry(); @@ -141,7 +141,7 @@ public class BiMapTest { throw new UnsupportedOperationException(); } } - + static class BiMapEntryOperations implements MapEntryOperations { ChronicleMap reverse; diff --git a/src/test/java/net/openhft/chronicle/map/MaximizingValueRemoteOperations.java b/src/test/java/net/openhft/chronicle/map/MaximizingValueRemoteOperations.java deleted file mode 100644 index de89d846d..000000000 --- a/src/test/java/net/openhft/chronicle/map/MaximizingValueRemoteOperations.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 Higher Frequency Trading - * - * http://www.higherfrequencytrading.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.openhft.chronicle.map; - -import net.openhft.chronicle.hash.AcceptanceDecision; -import net.openhft.chronicle.hash.Data; -import net.openhft.chronicle.map.replication.MapRemoteOperations; -import net.openhft.chronicle.map.replication.MapRemoteQueryContext; -import net.openhft.chronicle.map.replication.MapReplicableEntry; - -import static net.openhft.chronicle.hash.AcceptanceDecision.ACCEPT; -import static net.openhft.chronicle.hash.AcceptanceDecision.DISCARD; - -// TODO verify eventual consistency -public class MaximizingValueRemoteOperations, R> - implements MapRemoteOperations { - - @Override - public AcceptanceDecision put(MapRemoteQueryContext q, Data newValue) { - MapReplicableEntry entry = q.entry(); - if (entry != null) { - int compareResult = newValue.get().compareTo(entry.value().get()); - if (compareResult > 0 || - (compareResult == 0 && q.remoteIdentifier() <= entry.originIdentifier())) { - // replace, if the new value is greater - entry.doReplaceValue(newValue); - return ACCEPT; - } else { - return DISCARD; - } - } else { - return MapRemoteOperations.super.put(q, newValue); - } - } -} diff --git a/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakCrdtTest.java b/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakCrdtTest.java new file mode 100644 index 000000000..4ec99e546 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakCrdtTest.java @@ -0,0 +1,246 @@ +package net.openhft.chronicle.map; + +import net.openhft.chronicle.hash.Data; +import net.openhft.chronicle.hash.replication.SingleChronicleHashReplication; +import net.openhft.chronicle.hash.replication.TcpTransportAndNetworkConfig; +import net.openhft.chronicle.map.replication.MapRemoteOperations; +import net.openhft.chronicle.map.replication.MapRemoteQueryContext; +import net.openhft.chronicle.map.replication.MapReplicableEntry; +import net.openhft.lang.io.ByteBufferBytes; +import net.openhft.lang.model.Byteable; +import net.openhft.lang.model.DataValueClasses; +import net.openhft.lang.values.IntValue; +import org.jetbrains.annotations.NotNull; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.Closeable; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import static net.openhft.chronicle.core.MemoryUnit.MEGABYTES; +import static net.openhft.chronicle.map.TcpReplicationSoakCrdtTest.GrowOnlySetValuedMapEntryOperations.growOnlySetValuedMapEntryOperations; +import static net.openhft.chronicle.map.TcpReplicationSoakCrdtTest.GrowOnlySetValuedMapRemoteOperations.growOnlySetValuedMapRemoteOperations; +import static org.junit.Assert.assertEquals; + +public class TcpReplicationSoakCrdtTest { + + static class GrowOnlySetValuedMapEntryOperations + implements MapEntryOperations, Void> { + + private static final GrowOnlySetValuedMapEntryOperations INSTANCE = + new GrowOnlySetValuedMapEntryOperations(); + + public static + MapEntryOperations, Void> growOnlySetValuedMapEntryOperations() { + return GrowOnlySetValuedMapEntryOperations.INSTANCE; + } + + private GrowOnlySetValuedMapEntryOperations() {} + + @Override + public Void remove(@NotNull MapEntry> entry) { + throw new UnsupportedOperationException("Map with grow-only set values " + + "doesn't support map value removals"); + } + } + + static class GrowOnlySetValuedMapRemoteOperations + implements MapRemoteOperations, Void> { + + private static final GrowOnlySetValuedMapRemoteOperations INSTANCE = + new GrowOnlySetValuedMapRemoteOperations(); + + public static + MapRemoteOperations, Void> growOnlySetValuedMapRemoteOperations() { + return GrowOnlySetValuedMapRemoteOperations.INSTANCE; + } + + private GrowOnlySetValuedMapRemoteOperations() {} + + @Override + public void put(MapRemoteQueryContext, Void> q, Data, ?> newValue) { + MapReplicableEntry> entry = q.entry(); + if (entry != null) { + Set merged = new HashSet<>(entry.value().get()); + merged.addAll(newValue.get()); + q.replaceValue(entry, q.wrapValueAsValue(merged)); + } else { + q.insert(q.absentEntry(), newValue); + q.entry().updateOrigin(q.remoteIdentifier(), q.remoteTimestamp()); + } + } + + @Override + public void remove(MapRemoteQueryContext, Void> q) { + throw new UnsupportedOperationException(); + } + } + + private ChronicleMap> map1; + private ChronicleMap> map2; + static int s_port = 8093; + + @Before + public void setup() throws IOException { + final InetSocketAddress endpoint = new InetSocketAddress("localhost", s_port + 1); + + ChronicleMapBuilder> builder = ChronicleMapBuilder + .of(Integer.class, (Class>) (Class) Set.class) + .entries(Builder.SIZE) + .averageValueSize(3000) // more than HashSet of 10 Integers on average, serialized + .entryOperations(growOnlySetValuedMapEntryOperations()) + .remoteOperations(growOnlySetValuedMapRemoteOperations()); + + { + final TcpTransportAndNetworkConfig tcpConfig1 = TcpTransportAndNetworkConfig.of(s_port, + endpoint).autoReconnectedUponDroppedConnection(true) + .heartBeatInterval(1, TimeUnit.SECONDS) + .tcpBufferSize((int) MEGABYTES.toBytes(64)); + + map1 = builder + .replication(SingleChronicleHashReplication.builder() + .tcpTransportAndNetwork(tcpConfig1) + .name("map1") + .createWithId((byte) 1)) + .instance() + .name("map1") + .create(); + } + { + final TcpTransportAndNetworkConfig tcpConfig2 = TcpTransportAndNetworkConfig.of + (s_port + 1).autoReconnectedUponDroppedConnection(true) + .heartBeatInterval(1, TimeUnit.SECONDS) + .tcpBufferSize((int) MEGABYTES.toBytes(64)); + + map2 = builder + .replication(SingleChronicleHashReplication.builder() + .tcpTransportAndNetwork(tcpConfig2) + .name("map2") + .createWithId((byte) 2)) + .instance() + .name("map2") + .create(); + + } + s_port += 2; + } + + + @After + public void tearDown() throws InterruptedException { + + for (final Closeable closeable : new Closeable[]{map1, map2}) { + try { + closeable.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + System.gc(); + } + + Set threads; + + @Before + public void sampleThreads() { + threads = Thread.getAllStackTraces().keySet(); + } + + @After + public void checkThreadsShutdown() { + StatelessClientTest.checkThreadsShutdown(threads); + } + + + @Test + public void testReplicatedValuesMerged() throws InterruptedException { + HashSet v1 = new HashSet<>(); + v1.add(1); + map1.put(1, v1); + HashSet v2 = new HashSet<>(); + v2.add(2); + map2.put(1, v2); + waitTillEqual(5000); + // Map1 not equal to Map2, because it use byte-to-byte comparison of serialized HashSet + // values, that are different for some reason + assertEquals(map1.entrySet(), map2.entrySet()); + } + + @Test + public void testSoakTestWithRandomData() throws IOException, InterruptedException { + try { + System.out.print("SoakTesting "); + for (int j = 1; j < 2 * Builder.SIZE; j++) { + if (j % 1000 == 0) + System.out.print("."); + Random rnd = new Random(j); + for (int i = 1; i < 10; i++) { + final ChronicleMap> map = rnd.nextBoolean() ? map1 : map2; + int key = rnd.nextInt(Builder.SIZE); + try (ExternalMapQueryContext, ?> q = + map.queryContext(key)) { + q.updateLock().lock(); + MapEntry> entry = q.entry(); + if (entry != null) { + Set value = entry.value().get(); + value.add(rnd.nextInt(20)); + q.replaceValue(entry, q.wrapValueAsValue(value)); + } else { + HashSet value = new HashSet<>(); + q.insert(q.absentEntry(), q.wrapValueAsValue(value)); + } + } + } + } + + System.out.println("\nwaiting till equal"); + + waitTillEqual(15000); + + // not map1.equals(map2), the reason is described above + assertEquals(map1.entrySet(), map2.entrySet()); + } finally { + map1.close(); + map2.close(); + } + + } + + + private void waitTillEqual(final int timeOutMs) throws InterruptedException { + + Map map1UnChanged = new HashMap(); + Map map2UnChanged = new HashMap(); + + int numberOfTimesTheSame = 0; + long startTime = System.currentTimeMillis(); + for (int t = 0; t < timeOutMs + 100; t++) { + // not map1.equals(map2), the reason is described above + if (map1.entrySet().equals(map2.entrySet())) { + if (map1.equals(map1UnChanged) && map2.equals(map2UnChanged)) { + numberOfTimesTheSame++; + } else { + numberOfTimesTheSame = 0; + map1UnChanged = new HashMap(map1); + map2UnChanged = new HashMap(map2); + } + Thread.sleep(1); + if (numberOfTimesTheSame == 10) { + System.out.println("same"); + break; + } + + } + Thread.sleep(1); + if (System.currentTimeMillis() - startTime > timeOutMs) + break; + } + } +} + diff --git a/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakTest.java b/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakTest.java index 768002e8b..18d6ff57e 100644 --- a/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakTest.java +++ b/src/test/java/net/openhft/chronicle/map/TcpReplicationSoakTest.java @@ -26,12 +26,11 @@ public class TcpReplicationSoakTest { private ChronicleMap map1; private ChronicleMap map2; - private IntValue value; static int s_port = 8093; @Before public void setup() throws IOException { - value = DataValueClasses.newDirectReference(IntValue.class); + IntValue value = DataValueClasses.newDirectReference(IntValue.class); ((Byteable) value).bytes(new ByteBufferBytes(ByteBuffer.allocateDirect(4)), 0); final InetSocketAddress endpoint = new InetSocketAddress("localhost", s_port + 1); diff --git a/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java b/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java new file mode 100644 index 000000000..dc7c53d80 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/example/HashQueryContextExamples.java @@ -0,0 +1,93 @@ +package net.openhft.chronicle.map.example; + +import net.openhft.chronicle.map.*; + +public class HashQueryContextExamples { + + public static void incorrectRemovePresentEntry(ChronicleMap map, K key) { + try (ExternalMapQueryContext q = map.queryContext(key)) { + // q.entry(), checks if the entry is present in the map, and acquires + // the read lock for that. + MapEntry entry = q.entry(); + if (entry != null) { + // Tries to acquire the write lock to perform modification, + // but this is an illegal upgrade: read -> write, throws IllegalMonitorStateException + q.remove(entry); + } + } + } + + public static void correctRemovePresentEntry(ChronicleMap map, K key) { + try (ExternalMapQueryContext q = map.queryContext(key)) { + q.updateLock().lock(); // acquire the update lock before checking the entry presence. + MapEntry entry = q.entry(); + if (entry != null) + q.remove(entry); + } + } + + public static void possibleAcquireUsingImplementation( + 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 + if (q.readLock().tryLock()) { + MapEntry entry = q.entry(); + if (entry != null) { + // Entry is present, return + returnValue.returnValue(entry.value()); + return; + } + // Key is absent + // Need to unlock, to lock to update lock later. Direct upgrade is forbidden. + q.readLock().unlock(); + } + // We are here, either if we: + // 1) Failed to acquire the read lock, this means some other thread is holding the write + // lock now, in this case waiting for the update lock acquisition is no longer, than for + // the read + // 2) Seen the entry is absent under the read lock. This means we need to insert + // the default value into the map. that requires update-level access as well + q.updateLock().lock(); + MapEntry entry = q.entry(); + if (entry != null) { + // Entry is present, return + returnValue.returnValue(entry.value()); + return; + } + // Key is absent + q.insert(q.absentEntry(), q.defaultValue(q.absentEntry())); + 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]. + // Returns the resulting point + try (ExternalMapQueryContext q = map.queryContext(key)) { + Point offHeapPoint; + q.updateLock().lock(); + MapEntry entry = q.entry(); + if (entry != null) { + // Key is present + offHeapPoint = entry.value().getUsing(using); + } else { + // Key is absent + q.insert(q.absentEntry(), q.defaultValue(q.absentEntry())); + offHeapPoint = q.entry().value().getUsing(using); + } + offHeapPoint.addX(xMove); + offHeapPoint.addY(yMove); + return offHeapPoint; + } + } +} diff --git a/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java b/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java new file mode 100644 index 000000000..41cce5283 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/example/SimpleMapOperationsListeningTest.java @@ -0,0 +1,75 @@ +package net.openhft.chronicle.map.example; + +import net.openhft.chronicle.hash.Data; +import net.openhft.chronicle.map.*; +import net.openhft.lang.model.DataValueClasses; +import net.openhft.lang.values.IntValue; +import org.jetbrains.annotations.NotNull; +import org.junit.Ignore; +import org.junit.Test; + +import static net.openhft.chronicle.map.example.SimpleMapOperationsListeningTest.SimpleLoggingMapEntryOperations.simpleLoggingMapEntryOperations; + +public class SimpleMapOperationsListeningTest { + + static class SimpleLoggingMapEntryOperations implements MapEntryOperations { + + private static final SimpleLoggingMapEntryOperations INSTANCE = + new 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()); + entry.doRemove(); + return null; + } + + @Override + public Void replaceValue(@NotNull MapEntry entry, Data newValue) { + System.out.println("replace " + entry.key() + ": " + entry.value() + " -> " + newValue); + entry.doReplaceValue(newValue); + return null; + } + + @Override + public Void insert(@NotNull MapAbsentEntry absentEntry, Data value) { + System.out.println("insert " + absentEntry.absentKey() + " -> " + value); + absentEntry.doInsert(value); + return null; + } + + @Override + public Data defaultValue(@NotNull MapAbsentEntry absentEntry) { + Data defaultValue = absentEntry.defaultValue(); + System.out.println("default " + absentEntry.absentKey() + " -> " + defaultValue); + return defaultValue; + } + } + + @Test + @Ignore("Example test, run manually to see the output") + public void simpleLoggingTest() { + ChronicleMap map = ChronicleMapBuilder + .of(Integer.class, IntValue.class) + .entries(100) + .entryOperations(simpleLoggingMapEntryOperations()) + .create(); + + IntValue value = DataValueClasses.newDirectInstance(IntValue.class); + value.setValue(2); + map.put(1, value); + map.remove(1); + map.acquireUsing(3, value).addAtomicValue(1); + IntValue value2 = DataValueClasses.newDirectInstance(IntValue.class); + value2.setValue(5); + map.forEachEntry(c -> c.put(value2)); + map.forEachEntry(c -> c.remove()); + + } +}