Skip to content

Commit

Permalink
ExtendedMapEntry extends Map.Entry (#17175)
Browse files Browse the repository at this point in the history
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 <vbekiaris@gmail.com>
  • Loading branch information
mmedenjak and vbekiaris committed Aug 3, 2020
1 parent d709b90 commit 8b9ba7f
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 8 deletions.
38 changes: 34 additions & 4 deletions hazelcast/src/main/java/com/hazelcast/map/EntryProcessor.java
Expand Up @@ -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}.
* <p>
* 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.
* <p>
* 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.
* <p>
* While executing partition migrations are not allowed. Any migrations are queued on the partition thread.
* <p>
Expand All @@ -56,11 +57,40 @@
* otherwise EntryProcessor does not guarantee that it will modify the entry.
*<p>
* 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.
* <p>
* Since Hazelcast 4.0.3, an instance of {@link ExtendedMapEntry} is provided as argument in {@link #process(Entry)}
* method:
* <pre>
* {@code
* class IncrementWithOptionalTtl implements EntryProcessor<Integer, Integer, Void> {
* private final long ttlSeconds;
*
* public IncrementWithOptionalTtl(long ttlSeconds) {
* this.ttlSeconds = ttlSeconds;
* }
*
* @Override
* public Void process(Map.Entry<Integer, Integer> e) {
* ExtendedMapEntry<Integer, Integer> entry = (ExtendedMapEntry<Integer, Integer>) e;
* int newValue = entry.getValue() + 1;
* if (ttlSeconds > 0) {
* entry.setValue(newValue, ttlSeconds, TimeUnit.SECONDS);
* } else {
* entry.setValue(newValue);
* }
* return null;
* }
* }
* }
* </pre>
*
* @param <K> map entry key type
* @param <V> map entry value type
* @param <R> return type
*
* @see ExtendedMapEntry
*/
@BinaryInterface
@FunctionalInterface
Expand Down
Expand Up @@ -16,6 +16,7 @@

package com.hazelcast.map;

import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

/**
Expand All @@ -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 <K> key type
* @param <V> value type
*/
public interface ExtendedMapEntry<V> {
public interface ExtendedMapEntry<K, V> extends Entry<K, V> {

/** Set the value and set the TTL to a non-default value for the IMap */
V setValue(V value, long ttl, TimeUnit ttlUnit);
Expand Down
Expand Up @@ -60,7 +60,7 @@
* @param <V> value
*/
public class LazyMapEntry<K, V> extends CachedQueryEntry<K, V>
implements Serializable, IdentifiedDataSerializable, ExtendedMapEntry<V> {
implements Serializable, IdentifiedDataSerializable, ExtendedMapEntry<K, V> {

private static final long serialVersionUID = 0L;

Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Expand Up @@ -1479,7 +1479,7 @@ private static class TTLChangingEntryProcessor<K, V> implements EntryProcessor<K

@Override
public V process(Entry<K, V> entry) {
return ((ExtendedMapEntry<V>) entry).setValue(newValue, newTtl.toMillis(), TimeUnit.MILLISECONDS);
return ((ExtendedMapEntry<K, V>) entry).setValue(newValue, newTtl.toMillis(), TimeUnit.MILLISECONDS);
}

}
Expand Down

0 comments on commit 8b9ba7f

Please sign in to comment.