
com.hazelcast.client.cache.impl.ClientCacheProxySupport Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.client.cache.impl;
import com.hazelcast.cache.HazelcastCacheManager;
import com.hazelcast.cache.impl.CacheEventListenerAdaptor;
import com.hazelcast.cache.impl.CacheSyncListenerCompleter;
import com.hazelcast.cache.impl.ICacheInternal;
import com.hazelcast.cache.impl.ICacheService;
import com.hazelcast.client.cache.impl.ClientCacheProxySupportUtil.EmptyCompletionListener;
import com.hazelcast.internal.nearcache.impl.RemoteCallHook;
import com.hazelcast.client.impl.ClientDelegatingFuture;
import com.hazelcast.client.impl.clientside.ClientMessageDecoder;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.CacheClearCodec;
import com.hazelcast.client.impl.protocol.codec.CacheContainsKeyCodec;
import com.hazelcast.client.impl.protocol.codec.CacheEntryProcessorCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetAllCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetAndRemoveCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetAndReplaceCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetCodec;
import com.hazelcast.client.impl.protocol.codec.CacheListenerRegistrationCodec;
import com.hazelcast.client.impl.protocol.codec.CacheLoadAllCodec;
import com.hazelcast.client.impl.protocol.codec.CachePutAllCodec;
import com.hazelcast.client.impl.protocol.codec.CachePutCodec;
import com.hazelcast.client.impl.protocol.codec.CachePutIfAbsentCodec;
import com.hazelcast.client.impl.protocol.codec.CacheRemoveAllCodec;
import com.hazelcast.client.impl.protocol.codec.CacheRemoveAllKeysCodec;
import com.hazelcast.client.impl.protocol.codec.CacheRemoveCodec;
import com.hazelcast.client.impl.protocol.codec.CacheReplaceCodec;
import com.hazelcast.client.impl.protocol.codec.CacheSetExpiryPolicyCodec;
import com.hazelcast.client.impl.spi.ClientContext;
import com.hazelcast.client.impl.spi.ClientListenerService;
import com.hazelcast.client.impl.spi.ClientPartitionService;
import com.hazelcast.client.impl.spi.ClientProxy;
import com.hazelcast.client.impl.spi.impl.ClientInvocation;
import com.hazelcast.client.impl.spi.impl.ClientInvocationFuture;
import com.hazelcast.cluster.Member;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.core.ManagedContext;
import com.hazelcast.internal.nio.IOUtil;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.internal.util.ExceptionUtil;
import com.hazelcast.internal.util.FutureUtil;
import com.hazelcast.internal.util.Timer;
import com.hazelcast.logging.ILogger;
import com.hazelcast.spi.impl.InternalCompletableFuture;
import javax.annotation.Nonnull;
import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.event.CacheEntryListener;
import javax.cache.expiry.ExpiryPolicy;
import javax.cache.integration.CompletionListener;
import javax.cache.processor.EntryProcessorException;
import java.io.Closeable;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import static com.hazelcast.cache.impl.CacheProxyUtil.NULL_KEY_IS_NOT_ALLOWED;
import static com.hazelcast.cache.impl.CacheProxyUtil.validateConfiguredTypes;
import static com.hazelcast.cache.impl.CacheProxyUtil.validateNotNull;
import static com.hazelcast.cache.impl.operation.MutableOperation.IGNORE_COMPLETION;
import static com.hazelcast.client.cache.impl.ClientCacheProxySupportUtil.addCallback;
import static com.hazelcast.client.cache.impl.ClientCacheProxySupportUtil.getSafely;
import static com.hazelcast.client.cache.impl.ClientCacheProxySupportUtil.handleFailureOnCompletionListener;
import static com.hazelcast.internal.util.CollectionUtil.objectToDataCollection;
import static com.hazelcast.internal.util.ConcurrencyUtil.getDefaultAsyncExecutor;
import static com.hazelcast.internal.util.ExceptionUtil.rethrow;
import static com.hazelcast.internal.util.ExceptionUtil.rethrowAllowedTypeFirst;
import static com.hazelcast.internal.util.ExceptionUtil.sneakyThrow;
/**
* Abstract {@link com.hazelcast.cache.ICache} implementation which provides shared internal implementations
* of cache operations like put, replace, remove, invoke and open/close operations. These internal implementations are delegated
* by actual cache methods.
*
* Note: this partial implementation is used by client.
*
* @param the type of key
* @param the type of value
*/
@SuppressWarnings({"checkstyle:methodcount", "checkstyle:classfanoutcomplexity"})
abstract class ClientCacheProxySupport extends ClientProxy implements ICacheInternal,
CacheSyncListenerCompleter {
private static final int TIMEOUT = 10;
private static final CompletionListener NULL_COMPLETION_LISTENER = new EmptyCompletionListener();
// this will represent the name from the user perspective
protected final String name;
protected final String nameWithPrefix;
protected final CacheConfig cacheConfig;
protected int partitionCount;
boolean statisticsEnabled;
CacheStatsHandler statsHandler;
private ILogger logger;
private final AtomicReference cacheManagerRef = new AtomicReference<>();
private final ConcurrentMap loadAllCalls = new ConcurrentHashMap<>();
private final AtomicBoolean isClosed = new AtomicBoolean(false);
private final AtomicBoolean isDestroyed = new AtomicBoolean(false);
private final AtomicInteger completionIdCounter = new AtomicInteger();
private final ClientCacheProxySyncListenerCompleter listenerCompleter;
private final ConcurrentMap closeableListeners;
ClientCacheProxySupport(CacheConfig cacheConfig, ClientContext context) {
super(ICacheService.SERVICE_NAME, cacheConfig.getName(), context);
this.name = cacheConfig.getName();
this.nameWithPrefix = cacheConfig.getNameWithPrefix();
this.cacheConfig = cacheConfig;
this.statisticsEnabled = cacheConfig.isStatisticsEnabled();
this.closeableListeners = new ConcurrentHashMap<>();
this.listenerCompleter = new ClientCacheProxySyncListenerCompleter(this);
}
@Override
protected void onInitialize() {
logger = getContext().getLoggingService().getLogger(getClass());
statsHandler = new CacheStatsHandler(getSerializationService());
ClientPartitionService partitionService = getContext().getPartitionService();
partitionCount = partitionService.getPartitionCount();
}
@Override
protected String getDistributedObjectName() {
return cacheConfig.getNameWithPrefix();
}
@Override
public void close() {
if (!isClosed.compareAndSet(false, true)) {
return;
}
if (statisticsEnabled) {
statsHandler.clear();
}
close0(false);
}
@Override
protected boolean preDestroy() {
if (!isDestroyed.compareAndSet(false, true)) {
return false;
}
close0(true);
isClosed.set(true);
return true;
}
@Override
public boolean isClosed() {
return isClosed.get();
}
@Override
public boolean isDestroyed() {
return isDestroyed.get();
}
@Override
public void open() {
if (isDestroyed.get()) {
throw new IllegalStateException("Cache is already destroyed! Cannot be reopened");
}
isClosed.set(false);
}
@Override
public String getPrefixedName() {
return nameWithPrefix;
}
@Override
protected T invoke(ClientMessage clientMessage) {
try {
Future future = new ClientInvocation(getClient(), clientMessage, getName()).invoke();
return (T) future.get();
} catch (Exception e) {
throw rethrow(e);
}
}
@Override
public void countDownCompletionLatch(int countDownLatchId) {
listenerCompleter.countDownCompletionLatch(countDownLatchId);
}
@Override
public CacheManager getCacheManager() {
return cacheManagerRef.get();
}
@Override
public void setCacheManager(HazelcastCacheManager cacheManager) {
assert cacheManager instanceof HazelcastClientCacheManager;
// optimistically assume the CacheManager is already set
if (cacheManagerRef.get() == cacheManager) {
return;
}
if (!cacheManagerRef.compareAndSet(null, (HazelcastClientCacheManager) cacheManager)) {
if (cacheManagerRef.get() == cacheManager) {
// some other thread managed to set the same CacheManager, we are good
return;
}
throw new IllegalStateException("Cannot overwrite a Cache's CacheManager.");
}
}
@Override
public void resetCacheManager() {
cacheManagerRef.set(null);
}
@Override
protected void postDestroy() {
CacheManager cacheManager = cacheManagerRef.get();
if (cacheManager != null) {
cacheManager.destroyCache(getName());
}
resetCacheManager();
}
@Override
protected void onDestroy() {
if (statisticsEnabled) {
statsHandler.clear();
}
super.onDestroy();
}
protected void ensureOpen() {
if (isClosed()) {
throw new IllegalStateException("Cache operations can not be performed. The cache closed");
}
}
@SuppressWarnings("unchecked")
protected T injectDependencies(T obj) {
ManagedContext managedContext = getSerializationService().getManagedContext();
return (T) managedContext.initialize(obj);
}
protected long nowInNanosOrDefault() {
return statisticsEnabled ? Timer.nanos() : -1;
}
protected ClientInvocationFuture invoke(ClientMessage req, int partitionId, int completionId) {
boolean completionOperation = completionId != -1;
if (completionOperation) {
listenerCompleter.registerCompletionLatch(completionId, 1);
}
try {
ClientInvocation clientInvocation = new ClientInvocation(getClient(), req, name, partitionId);
ClientInvocationFuture future = clientInvocation.invoke();
if (completionOperation) {
listenerCompleter.waitCompletionLatch(completionId, future);
}
return future;
} catch (Throwable e) {
if (e instanceof IllegalStateException) {
close();
}
if (completionOperation) {
listenerCompleter.deregisterCompletionLatch(completionId);
}
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected ClientInvocationFuture invoke(ClientMessage req, Data keyData, int completionId) {
int partitionId = getContext().getPartitionService().getPartitionId(keyData);
return invoke(req, partitionId, completionId);
}
protected V getAndRemoveSyncInternal(K key) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
validateNotNull(key);
validateConfiguredTypes(cacheConfig, key);
Data keyData = toData(key);
V response = callGetAndRemoveSync(key, keyData);
if (statisticsEnabled) {
statsHandler.onRemove(true, startNanos, response);
}
return response;
}
@Nonnull
protected V callGetAndRemoveSync(K key, Data keyData) {
try {
return (V) getAndRemoveInternal(keyData, true).get();
} catch (Throwable t) {
throw ExceptionUtil.rethrow(t);
}
}
protected CompletableFuture getAndRemoveAsyncInternal(K key) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
validateNotNull(key);
validateConfiguredTypes(cacheConfig, key);
Data keyData = toData(key);
BiConsumer statsCallback = statisticsEnabled
? statsHandler.newOnRemoveCallback(true, startNanos)
: null;
return callGetAndRemoveAsync(key, keyData, statsCallback);
}
@Nonnull
protected CompletableFuture callGetAndRemoveAsync(K key, Data keyData,
BiConsumer statsCallback) {
ClientDelegatingFuture delegatingFuture = getAndRemoveInternal(keyData, false);
addCallback(delegatingFuture, statsCallback);
return delegatingFuture;
}
private ClientDelegatingFuture getAndRemoveInternal(Data keyData, boolean withCompletionEvent) {
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheGetAndRemoveCodec.encodeRequest(nameWithPrefix, keyData, completionId);
ClientInvocationFuture future = invoke(request, keyData, completionId);
return newDelegatingFuture(future, CacheGetAndRemoveCodec::decodeResponse);
}
protected boolean removeSync(K key, V oldValue,
boolean hasOldValue, boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue);
validateConfiguredTypes(cacheConfig, key, oldValue);
} else {
validateNotNull(key);
validateConfiguredTypes(cacheConfig, key);
}
Data keyData = toData(key);
Data oldValueData = toData(oldValue);
boolean removed = callRemoveSync(key, keyData, oldValueData, withCompletionEvent);
if (statisticsEnabled) {
statsHandler.onRemove(false, startNanos, removed);
}
return removed;
}
protected boolean callRemoveSync(K key, Data keyData, Data oldValueData, boolean withCompletionEvent) {
InternalCompletableFuture delegatingFuture
= doRemoveOnServer(keyData, oldValueData, withCompletionEvent);
try {
return delegatingFuture.get();
} catch (Throwable t) {
throw rethrow(t);
}
}
protected CompletableFuture removeAsync(K key, V oldValue,
boolean hasOldValue, boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue);
validateConfiguredTypes(cacheConfig, key, oldValue);
} else {
validateNotNull(key);
validateConfiguredTypes(cacheConfig, key);
}
Data keyData = toData(key);
Data oldValueData = toData(oldValue);
BiConsumer callback = statisticsEnabled
? statsHandler.newOnRemoveCallback(false, startNanos)
: null;
return callRemoveAsync(key, keyData, oldValueData, withCompletionEvent, callback);
}
protected CompletableFuture callRemoveAsync(K key, Data keyData, Data oldValueData,
boolean withCompletionEvent,
BiConsumer callback) {
return addCallback(doRemoveOnServer(keyData, oldValueData, withCompletionEvent), callback);
}
@Nonnull
private InternalCompletableFuture doRemoveOnServer(Data keyData, Data oldValueData, boolean withCompletionEvent) {
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheRemoveCodec.encodeRequest(nameWithPrefix, keyData, oldValueData, completionId);
ClientInvocationFuture future = invoke(request, keyData, completionId);
return newDelegatingFuture(future, CacheRemoveCodec::decodeResponse);
}
protected boolean replaceSync(K key, V oldValue, V newValue,
ExpiryPolicy expiryPolicy, boolean hasOldValue) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue, newValue);
validateConfiguredTypes(cacheConfig, key, oldValue, newValue);
} else {
validateNotNull(key, newValue);
validateConfiguredTypes(cacheConfig, key, newValue);
}
Data keyData = toData(key);
Data oldValueData = toData(oldValue);
Data newValueData = toData(newValue);
Data expiryPolicyData = toData(expiryPolicy);
boolean replaced = callReplaceSync(key, keyData, newValue, newValueData,
oldValueData, expiryPolicyData);
if (statisticsEnabled) {
statsHandler.onReplace(false, startNanos, replaced);
}
return replaced;
}
protected boolean callReplaceSync(K key, Data keyData, V newValue, Data newValueData,
Data oldValueData, Data expiryPolicyData) {
CompletableFuture future = doReplaceOnServer(keyData, newValueData,
oldValueData, expiryPolicyData, true, null);
try {
return future.get();
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected CompletableFuture replaceAsync(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy,
boolean hasOldValue, boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue, newValue);
validateConfiguredTypes(cacheConfig, key, oldValue, newValue);
} else {
validateNotNull(key, newValue);
validateConfiguredTypes(cacheConfig, key, newValue);
}
Data keyData = toData(key);
Data oldValueData = toData(oldValue);
Data newValueData = toData(newValue);
Data expiryPolicyData = toData(expiryPolicy);
BiConsumer statsCallback = statisticsEnabled
? statsHandler.newOnReplaceCallback(startNanos)
: null;
return callReplaceAsync(key, keyData, newValue, newValueData, oldValueData,
expiryPolicyData, withCompletionEvent, statsCallback);
}
protected CompletableFuture callReplaceAsync(K key, Data keyData, V newValue, Data newValueData,
Data oldValueData, Data expiryPolicyData,
boolean withCompletionEvent,
BiConsumer statsCallback) {
return doReplaceOnServer(keyData, newValueData, oldValueData, expiryPolicyData, withCompletionEvent, statsCallback);
}
private CompletableFuture doReplaceOnServer(Data keyData, Data newValueData,
Data oldValueData, Data expiryPolicyData,
boolean withCompletionEvent,
BiConsumer statsCallback) {
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheReplaceCodec.encodeRequest(nameWithPrefix, keyData, oldValueData, newValueData,
expiryPolicyData, completionId);
ClientDelegatingFuture delegatingFuture
= newDelegatingFuture(invoke(request, keyData, completionId), CacheReplaceCodec::decodeResponse);
return addCallback(delegatingFuture, statsCallback);
}
protected V getAndReplaceSync(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy,
boolean hasOldValue, boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue, newValue);
validateConfiguredTypes(cacheConfig, key, oldValue, newValue);
} else {
validateNotNull(key, newValue);
validateConfiguredTypes(cacheConfig, key, newValue);
}
Data keyData = toData(key);
Data newValueData = toData(newValue);
Data expiryPolicyData = toData(expiryPolicy);
V response = callGetAndReplaceSync(key, keyData, newValue, newValueData,
expiryPolicyData, withCompletionEvent);
if (statisticsEnabled) {
statsHandler.onReplace(true, startNanos, response);
}
return response;
}
protected V callGetAndReplaceSync(K key, Data keyData, V newValue, Data newValueData,
Data expiryPolicyData, boolean withCompletionEvent) {
try {
return (V) doGetAndReplaceOnServer(keyData, newValueData,
expiryPolicyData, withCompletionEvent, null).get();
} catch (Throwable t) {
throw ExceptionUtil.rethrow(t);
}
}
private CompletableFuture doGetAndReplaceOnServer(Data keyData, Data newValueData,
Data expiryPolicyData,
boolean withCompletionEvent,
BiConsumer statsCallback) {
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheGetAndReplaceCodec.encodeRequest(nameWithPrefix, keyData,
newValueData, expiryPolicyData, completionId);
ClientInvocationFuture future = invoke(request, keyData, completionId);
ClientDelegatingFuture delegatingFuture
= newDelegatingFuture(future, CacheGetAndReplaceCodec::decodeResponse);
return addCallback(delegatingFuture, statsCallback);
}
protected CompletableFuture getAndReplaceAsync(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy,
boolean hasOldValue, boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue, newValue);
validateConfiguredTypes(cacheConfig, key, oldValue, newValue);
} else {
validateNotNull(key, newValue);
validateConfiguredTypes(cacheConfig, key, newValue);
}
Data keyData = toData(key);
Data newValueData = toData(newValue);
Data expiryPolicyData = toData(expiryPolicy);
BiConsumer statsCallback
= statisticsEnabled
? statsHandler.newOnReplaceCallback(startNanos) : null;
return callGetAndReplaceAsync(key, keyData, newValue, newValueData,
expiryPolicyData, withCompletionEvent, statsCallback);
}
protected CompletableFuture callGetAndReplaceAsync(K key, Data keyData,
V newValue, Data newValueData,
Data expiryPolicyData,
boolean withCompletionEvent,
BiConsumer statsCallback) {
return doGetAndReplaceOnServer(keyData, newValueData,
expiryPolicyData, withCompletionEvent, statsCallback);
}
protected V putSyncInternal(K key, V value, ExpiryPolicy expiryPolicy, boolean isGet) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
validateNotNull(key, value);
validateConfiguredTypes(cacheConfig, key, value);
Data keyData = toData(key);
Data valueData = toData(value);
Data expiryPolicyData = toData(expiryPolicy);
try {
V response = callPutSync(key, keyData, value, valueData, expiryPolicyData, isGet);
if (statisticsEnabled) {
statsHandler.onPut(isGet, startNanos, response != null);
}
return response;
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected V callPutSync(K key, Data keyData,
V value, Data valueData,
Data expiryPolicyData, boolean isGet) throws InterruptedException, ExecutionException {
ClientInvocationFuture invocationFuture = putInternal(keyData, valueData, expiryPolicyData, isGet, true);
ClientDelegatingFuture delegatingFuture =
newDelegatingFuture(invocationFuture, CachePutCodec::decodeResponse);
return delegatingFuture.get();
}
protected CompletableFuture putAsyncInternal(K key, V value, ExpiryPolicy expiryPolicy,
boolean isGet,
boolean withCompletionEvent) {
ensureOpen();
validateNotNull(key, value);
validateConfiguredTypes(cacheConfig, key, value);
Data keyData = toData(key);
Data valueData = toData(value);
Data expiryPolicyData = toData(expiryPolicy);
BiConsumer statsCallback = newStatsCallbackOrNull(isGet);
return callPutAsync(key, keyData, value, valueData, expiryPolicyData,
isGet, withCompletionEvent, statsCallback);
}
protected CompletableFuture callPutAsync(K key, Data keyData, V value,
Data valueData, Data expiryPolicyData,
boolean isGet, boolean withCompletionEvent,
BiConsumer statsCallback) {
ClientInvocationFuture invocationFuture = putInternal(keyData, valueData, expiryPolicyData, isGet, withCompletionEvent);
InternalCompletableFuture future
= newDelegatingFuture(invocationFuture, CachePutCodec::decodeResponse);
return addCallback(future, statsCallback);
}
protected Boolean putIfAbsentSync(K key, V value, ExpiryPolicy expiryPolicy, boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
validateNotNull(key, value);
validateConfiguredTypes(cacheConfig, key, value);
Data keyData = toData(key);
Data valueData = toData(value);
Data expiryPolicyData = toData(expiryPolicy);
Boolean result = callPutIfAbsentSync(key, keyData, value, valueData, expiryPolicyData, withCompletionEvent);
if (statisticsEnabled) {
statsHandler.onPutIfAbsent(startNanos, result);
}
return result;
}
protected Boolean callPutIfAbsentSync(K key, Data keyData, V value, Data valueData,
Data expiryPolicyData, boolean withCompletionEvent) {
InternalCompletableFuture future = doPutIfAbsentOnServer(keyData, valueData,
expiryPolicyData, withCompletionEvent);
try {
return future.get();
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected CompletableFuture putIfAbsentAsync(K key, V value,
ExpiryPolicy expiryPolicy,
boolean withCompletionEvent) {
long startNanos = nowInNanosOrDefault();
ensureOpen();
validateNotNull(key, value);
validateConfiguredTypes(cacheConfig, key, value);
Data keyData = toData(key);
Data valueData = toData(value);
Data expiryPolicyData = toData(expiryPolicy);
BiConsumer statsCallback = statisticsEnabled
? statsHandler.newOnPutIfAbsentCallback(startNanos)
: null;
return callPutIfAbsentAsync(key, keyData, value, valueData,
expiryPolicyData, withCompletionEvent, statsCallback);
}
@SuppressWarnings("checkstyle:parameternumber")
protected CompletableFuture callPutIfAbsentAsync(K key, Data keyData, V value, Data valueData,
Data expiryPolicyData, boolean withCompletionEvent,
BiConsumer statsCallback) {
InternalCompletableFuture future = doPutIfAbsentOnServer(keyData, valueData,
expiryPolicyData, withCompletionEvent);
return addCallback(future, statsCallback);
}
private InternalCompletableFuture doPutIfAbsentOnServer(Data keyData, Data valueData,
Data expiryPolicyData, boolean withCompletionEvent) {
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CachePutIfAbsentCodec.encodeRequest(nameWithPrefix, keyData,
valueData, expiryPolicyData, completionId);
ClientInvocationFuture future = invoke(request, keyData, completionId);
return newDelegatingFuture(future, CachePutIfAbsentCodec::decodeResponse);
}
protected BiConsumer newStatsCallbackOrNull(boolean isGet) {
if (!statisticsEnabled) {
return null;
}
return statsHandler.newOnPutCallback(isGet, Timer.nanos());
}
protected boolean setExpiryPolicyInternal(K key, ExpiryPolicy expiryPolicy) {
ensureOpen();
validateNotNull(key);
validateNotNull(expiryPolicy);
Data keyData = toData(key);
Data expiryPolicyData = toData(expiryPolicy);
List list = Collections.singletonList(keyData);
ClientMessage request = CacheSetExpiryPolicyCodec.encodeRequest(nameWithPrefix, list, expiryPolicyData);
ClientInvocationFuture future = invoke(request, keyData, IGNORE_COMPLETION);
ClientDelegatingFuture delegatingFuture =
newDelegatingFuture(future, CacheSetExpiryPolicyCodec::decodeResponse);
try {
return delegatingFuture.get();
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected void removeAllKeysInternal(Set extends K> keys, Collection dataKeys, long startNanos) {
int partitionCount = getContext().getPartitionService().getPartitionCount();
int completionId = nextCompletionId();
listenerCompleter.registerCompletionLatch(completionId, partitionCount);
ClientMessage request = CacheRemoveAllKeysCodec.encodeRequest(nameWithPrefix, dataKeys, completionId);
try {
invoke(request);
listenerCompleter.waitCompletionLatch(completionId, null);
if (statisticsEnabled) {
statsHandler.onBatchRemove(startNanos, dataKeys.size());
}
} catch (Throwable t) {
listenerCompleter.deregisterCompletionLatch(completionId);
throw rethrowAllowedTypeFirst(t, CacheException.class);
}
}
protected void removeAllInternal() {
int partitionCount = getContext().getPartitionService().getPartitionCount();
int completionId = nextCompletionId();
listenerCompleter.registerCompletionLatch(completionId, partitionCount);
ClientMessage request = CacheRemoveAllCodec.encodeRequest(nameWithPrefix, completionId);
try {
invoke(request);
listenerCompleter.waitCompletionLatch(completionId, null);
if (statisticsEnabled) {
statsHandler.getStatistics().setLastUpdateTime(System.currentTimeMillis());
// we don't support count stats of removing all entries
}
} catch (Throwable t) {
listenerCompleter.deregisterCompletionLatch(completionId);
throw rethrowAllowedTypeFirst(t, CacheException.class);
}
}
protected void clearInternal() {
ClientMessage request = CacheClearCodec.encodeRequest(nameWithPrefix);
try {
invoke(request);
if (statisticsEnabled) {
statsHandler.getStatistics().setLastUpdateTime(System.currentTimeMillis());
// we don't support count stats of removing all entries
}
} catch (Throwable t) {
throw rethrowAllowedTypeFirst(t, CacheException.class);
}
}
protected void addListenerLocally(UUID regId, CacheEntryListenerConfiguration cacheEntryListenerConfiguration,
CacheEventListenerAdaptor adaptor) {
listenerCompleter.putListenerIfAbsent(cacheEntryListenerConfiguration, regId);
CacheEntryListener entryListener = adaptor.getCacheEntryListener();
if (entryListener instanceof Closeable closeable) {
closeableListeners.putIfAbsent(regId, closeable);
}
}
protected void removeListenerLocally(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
UUID registrationId = listenerCompleter.removeListener(cacheEntryListenerConfiguration);
if (registrationId != null) {
Closeable closeable = closeableListeners.remove(registrationId);
IOUtil.closeResource(closeable);
}
}
protected UUID getListenerIdLocal(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
return listenerCompleter.getListenerId(cacheEntryListenerConfiguration);
}
private void deregisterAllCacheEntryListener(Collection listenerRegistrations) {
ClientListenerService listenerService = getContext().getListenerService();
for (UUID regId : listenerRegistrations) {
listenerService.deregisterListener(regId);
}
}
protected V callGetSync(Object key, ExpiryPolicy expiryPolicy) {
long startNanos = nowInNanosOrDefault();
try {
Data dataKey = toData(key);
V value = getInternal(dataKey, expiryPolicy, false).get();
if (statisticsEnabled) {
statsHandler.onGet(startNanos, value != null);
}
return value;
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected CompletableFuture getAsyncInternal(Object key, ExpiryPolicy expiryPolicy) {
long startNanos = nowInNanosOrDefault();
BiConsumer statsCallback = statisticsEnabled
? statsHandler.newOnGetCallback(startNanos) : null;
return callGetAsync(key, expiryPolicy, statsCallback);
}
@Nonnull
protected CompletableFuture callGetAsync(Object key, ExpiryPolicy expiryPolicy,
BiConsumer statsCallback) {
Data dataKey = toData(key);
ClientDelegatingFuture future = getInternal(dataKey, expiryPolicy, true);
return addCallback(future, statsCallback);
}
protected void getAllInternal(Set extends K> keys, Collection dataKeys,
ExpiryPolicy expiryPolicy, List