From 8b9ba7f5f31627b30a67a2fb9d720074ff424878 Mon Sep 17 00:00:00 2001 From: Matko Medenjak Date: Mon, 3 Aug 2020 13:32:42 +0200 Subject: [PATCH] ExtendedMapEntry extends Map.Entry (#17175) ExtendedMapEntry extends Map.Entry Usability enhancement, so that when a user downcasts the entry in EntryProcessor#process(entry) they can use it to access Map.Entry methods. Co-authored-by: Vassilis Bekiaris --- .../com/hazelcast/map/EntryProcessor.java | 38 +++++++++++++++++-- .../com/hazelcast/map/ExtendedMapEntry.java | 4 +- .../com/hazelcast/map/impl/LazyMapEntry.java | 2 +- .../map/impl/operation/EntryOperator.java | 3 +- .../com/hazelcast/map/EntryProcessorTest.java | 2 +- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/hazelcast/src/main/java/com/hazelcast/map/EntryProcessor.java b/hazelcast/src/main/java/com/hazelcast/map/EntryProcessor.java index d39f6001125e..874eb6c214ea 100644 --- a/hazelcast/src/main/java/com/hazelcast/map/EntryProcessor.java +++ b/hazelcast/src/main/java/com/hazelcast/map/EntryProcessor.java @@ -24,15 +24,16 @@ import java.util.Map.Entry; /** - * An EntryProcessor passes you a {@link java.util.Map.Entry}. At the time you receive it - * the entry is locked and not released until the EntryProcessor completes. + * An EntryProcessor processes a {@link java.util.Map.Entry}. + * The {@code EntryProcessor}'s {@link #process(Entry)} method is executed atomically. * This obviates the need to explicitly lock as would be required with a {@link java.util.concurrent.ExecutorService}. *

* Performance can be very high as the data is not moved off the Member partition. This avoids network cost and, if * the storage format is {@link com.hazelcast.config.InMemoryFormat#OBJECT}, then there is no de-serialization or serialization * cost. *

- * EntryProcessors execute on the partition thread in a member. Multiple operations on the same partition are queued. + * EntryProcessors execute on the partition thread in a member. Multiple operations on the same partition are queued + * and executed sequentially. *

* While executing partition migrations are not allowed. Any migrations are queued on the partition thread. *

@@ -56,11 +57,40 @@ * otherwise EntryProcessor does not guarantee that it will modify the entry. *

* EntryProcessor instances can be shared between threads. If an EntryProcessor instance contains mutable state, proper - * concurrency control needs to be provided to coordinate access to mutable state. Another option is to rely on threadlocals. + * concurrency control needs to be provided to coordinate access to mutable state. Another option is to rely + * on {@code ThreadLocal}s. + *

+ * Since Hazelcast 4.0.3, an instance of {@link ExtendedMapEntry} is provided as argument in {@link #process(Entry)} + * method: + *

+ * {@code
+ * class IncrementWithOptionalTtl implements EntryProcessor {
+ *     private final long ttlSeconds;
+ *
+ *     public IncrementWithOptionalTtl(long ttlSeconds) {
+ *         this.ttlSeconds = ttlSeconds;
+ *     }
+ *
+ *     @Override
+ *     public Void process(Map.Entry e) {
+ *         ExtendedMapEntry entry = (ExtendedMapEntry) e;
+ *         int newValue = entry.getValue() + 1;
+ *         if (ttlSeconds > 0) {
+ *             entry.setValue(newValue, ttlSeconds, TimeUnit.SECONDS);
+ *         } else {
+ *             entry.setValue(newValue);
+ *         }
+ *         return null;
+ *     }
+ * }
+ * }
+ * 
* * @param map entry key type * @param map entry value type * @param return type + * + * @see ExtendedMapEntry */ @BinaryInterface @FunctionalInterface diff --git a/hazelcast/src/main/java/com/hazelcast/map/ExtendedMapEntry.java b/hazelcast/src/main/java/com/hazelcast/map/ExtendedMapEntry.java index 3649d2e1ffb1..e3aad07b2115 100644 --- a/hazelcast/src/main/java/com/hazelcast/map/ExtendedMapEntry.java +++ b/hazelcast/src/main/java/com/hazelcast/map/ExtendedMapEntry.java @@ -16,6 +16,7 @@ package com.hazelcast.map; +import java.util.Map.Entry; import java.util.concurrent.TimeUnit; /** @@ -24,9 +25,10 @@ * @see com.hazelcast.map.IMap#set(Object, Object, long, TimeUnit) * @see com.hazelcast.map.IMap#put(Object, Object, long, TimeUnit) * + * @param key type * @param value type */ -public interface ExtendedMapEntry { +public interface ExtendedMapEntry extends Entry { /** Set the value and set the TTL to a non-default value for the IMap */ V setValue(V value, long ttl, TimeUnit ttlUnit); diff --git a/hazelcast/src/main/java/com/hazelcast/map/impl/LazyMapEntry.java b/hazelcast/src/main/java/com/hazelcast/map/impl/LazyMapEntry.java index 861834b651fa..360465107797 100644 --- a/hazelcast/src/main/java/com/hazelcast/map/impl/LazyMapEntry.java +++ b/hazelcast/src/main/java/com/hazelcast/map/impl/LazyMapEntry.java @@ -60,7 +60,7 @@ * @param value */ public class LazyMapEntry extends CachedQueryEntry - implements Serializable, IdentifiedDataSerializable, ExtendedMapEntry { + implements Serializable, IdentifiedDataSerializable, ExtendedMapEntry { private static final long serialVersionUID = 0L; diff --git a/hazelcast/src/main/java/com/hazelcast/map/impl/operation/EntryOperator.java b/hazelcast/src/main/java/com/hazelcast/map/impl/operation/EntryOperator.java index 340631831646..47b7604b8755 100644 --- a/hazelcast/src/main/java/com/hazelcast/map/impl/operation/EntryOperator.java +++ b/hazelcast/src/main/java/com/hazelcast/map/impl/operation/EntryOperator.java @@ -25,6 +25,7 @@ import com.hazelcast.internal.serialization.InternalSerializationService; import com.hazelcast.internal.util.Clock; import com.hazelcast.map.EntryProcessor; +import com.hazelcast.map.ExtendedMapEntry; import com.hazelcast.map.impl.LazyMapEntry; import com.hazelcast.map.impl.LocalMapStatsProvider; import com.hazelcast.map.impl.LockAwareLazyMapEntry; @@ -325,7 +326,7 @@ private static long getLatencyNanos(long beginTimeNanos) { return System.nanoTime() - beginTimeNanos; } - private void process(Entry entry) { + private void process(ExtendedMapEntry entry) { if (backup) { backupProcessor.process(entry); return; diff --git a/hazelcast/src/test/java/com/hazelcast/map/EntryProcessorTest.java b/hazelcast/src/test/java/com/hazelcast/map/EntryProcessorTest.java index f98eee0ee5bc..a4ca0de111ef 100644 --- a/hazelcast/src/test/java/com/hazelcast/map/EntryProcessorTest.java +++ b/hazelcast/src/test/java/com/hazelcast/map/EntryProcessorTest.java @@ -1479,7 +1479,7 @@ private static class TTLChangingEntryProcessor implements EntryProcessor entry) { - return ((ExtendedMapEntry) entry).setValue(newValue, newTtl.toMillis(), TimeUnit.MILLISECONDS); + return ((ExtendedMapEntry) entry).setValue(newValue, newTtl.toMillis(), TimeUnit.MILLISECONDS); } }