com.oracle.coherence.concurrent.atomic.AsyncRemoteAtomicReference Maven / Gradle / Ivy
Show all versions of coherence-concurrent Show documentation
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.oracle.coherence.concurrent.atomic;
import com.tangosol.net.AsyncNamedMap;
import com.tangosol.util.function.Remote;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
/**
* The remote implementation of {@link AsyncAtomicReference}, backed by a
* Coherence {@code NamedMap} entry.
*
* Every method in this class is guaranteed to execute effectively-once, and provides
* cluster-wide atomicity guarantees for the backing atomic value. However,
* keep in mind that this comes at a significant cost -- each method invocation
* results in a network call to a remote owner of the backing atomic value,
* which means that each operation has significantly higher latency than a
* corresponding {@link AsyncLocalAtomicReference local} implementation.
*
* @param the type of object referred to by this reference
*
* @author Aleks Seovic 2020.12.08
* @since 21.12
*/
public class AsyncRemoteAtomicReference
implements AsyncAtomicReference
{
// ----- constructors ---------------------------------------------------
/**
* Constructs a new {@code AsyncRemoteAtomicReference}.
*
* @param mapAtomic the map that holds this atomic value
* @param sName the name of this atomic value
*/
protected AsyncRemoteAtomicReference(AsyncNamedMap> mapAtomic, String sName)
{
f_mapAtomic = mapAtomic;
f_sName = sName;
}
// ----- AsyncAtomicReference interface ------------------------------
@Override
public CompletableFuture get()
{
return invoke(AtomicReference::get, false);
}
@Override
public CompletableFuture set(V newValue)
{
return invoke(value ->
{
value.set(newValue);
return null;
});
}
@Override
public CompletableFuture getAndSet(V newValue)
{
return invoke(value -> value.getAndSet(newValue));
}
@Override
@SuppressWarnings("DuplicatedCode")
public CompletableFuture compareAndSet(V expectedValue, V newValue)
{
return invoke(value ->
{
V v = value.get();
if (Objects.equals(v, expectedValue))
{
value.set(newValue);
return true;
}
return false;
});
}
@Override
public CompletableFuture getAndUpdate(Remote.UnaryOperator updateFunction)
{
return getAndUpdate((UnaryOperator) updateFunction);
}
@Override
public CompletableFuture getAndUpdate(UnaryOperator updateFunction)
{
return invoke(value -> value.getAndUpdate(updateFunction));
}
@Override
public CompletableFuture updateAndGet(Remote.UnaryOperator updateFunction)
{
return updateAndGet((UnaryOperator) updateFunction);
}
@Override
public CompletableFuture updateAndGet(UnaryOperator updateFunction)
{
return invoke(value -> value.updateAndGet(updateFunction));
}
@Override
public CompletableFuture getAndAccumulate(V x, Remote.BinaryOperator accumulatorFunction)
{
return getAndAccumulate(x, (BinaryOperator) accumulatorFunction);
}
@Override
public CompletableFuture getAndAccumulate(V x, BinaryOperator accumulatorFunction)
{
return invoke(value -> value.getAndAccumulate(x, accumulatorFunction));
}
@Override
public CompletableFuture accumulateAndGet(V x, Remote.BinaryOperator accumulatorFunction)
{
return accumulateAndGet(x, (BinaryOperator) accumulatorFunction);
}
@Override
public CompletableFuture accumulateAndGet(V x, BinaryOperator accumulatorFunction)
{
return invoke(value -> value.accumulateAndGet(x, accumulatorFunction));
}
@Override
@SuppressWarnings("DuplicatedCode")
public CompletableFuture compareAndExchange(V expectedValue, V newValue)
{
return invoke(value ->
{
V v = value.get();
if (v == null)
{
if (expectedValue == null)
{
value.set(newValue);
}
}
else
{
if (v.equals(expectedValue))
{
value.set(newValue);
}
}
return v;
});
}
// ----- Object methods -------------------------------------------------
/**
* Returns the String representation of the current value.
*
* @return the String representation of the current value
*/
@Override
public String toString()
{
return String.valueOf(get().join());
}
// ----- helpers methods ------------------------------------------------
/**
* Apply specified function against the remote object and return the result.
*
* Any changes the function makes to the remote object will be preserved.
*
* @param function the function to apply
* @param the type of the result
*
* @return the result of the function applied to a remote object
*/
protected CompletableFuture invoke(Remote.Function, R> function)
{
return invoke(function, true);
}
/**
* Apply specified function against the remote object and return the result.
*
* If the {@code fMutate} argument is {@code true}, any changes to the
* remote object will be preserved.
*
* @param function the function to apply
* @param fMutate flag specifying whether the function mutates the object
* @param the type of the result
*
* @return the result of the function applied to a remote object
*/
protected CompletableFuture invoke(Remote.Function, R> function, boolean fMutate)
{
return f_mapAtomic.invoke(f_sName, entry ->
{
AtomicReference value = entry.getValue();
R result = function.apply(value);
if (fMutate)
{
entry.setValue(value);
}
return result;
});
}
// ----- data members ---------------------------------------------------
/**
* The map that holds this atomic value.
*/
private final AsyncNamedMap> f_mapAtomic;
/**
* The name of this atomic value.
*/
private final String f_sName;
}