Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hazelcast.client.cache.impl.AbstractClientInternalCacheProxy Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, 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.impl.CacheEventData;
import com.hazelcast.cache.impl.CacheEventListenerAdaptor;
import com.hazelcast.cache.impl.CacheProxyUtil;
import com.hazelcast.cache.impl.CacheSyncListenerCompleter;
import com.hazelcast.cache.impl.operation.MutableOperation;
import com.hazelcast.client.impl.ClientMessageDecoder;
import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.CacheAddEntryListenerCodec;
import com.hazelcast.client.impl.protocol.codec.CacheAddInvalidationListenerCodec;
import com.hazelcast.client.impl.protocol.codec.CacheClearCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetAndRemoveCodec;
import com.hazelcast.client.impl.protocol.codec.CacheGetAndReplaceCodec;
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.CacheRemoveEntryListenerCodec;
import com.hazelcast.client.impl.protocol.codec.CacheReplaceCodec;
import com.hazelcast.client.spi.ClientListenerService;
import com.hazelcast.client.spi.EventHandler;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.client.spi.impl.ClientInvocationFuture;
import com.hazelcast.client.spi.impl.ListenerMessageCodec;
import com.hazelcast.client.util.ClientDelegatingFuture;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.HazelcastInstanceNotActiveException;
import com.hazelcast.core.ICompletableFuture;
import com.hazelcast.internal.adapter.ICacheDataStructureAdapter;
import com.hazelcast.internal.nearcache.NearCache;
import com.hazelcast.internal.nearcache.NearCacheManager;
import com.hazelcast.internal.nearcache.impl.invalidation.RepairingHandler;
import com.hazelcast.internal.nearcache.impl.invalidation.RepairingTask;
import com.hazelcast.map.impl.nearcache.InvalidationAwareWrapper;
import com.hazelcast.map.impl.nearcache.KeyStateMarker;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.spi.serialization.SerializationService;
import com.hazelcast.util.ExceptionUtil;
import com.hazelcast.util.executor.CompletedFuture;
import javax.cache.CacheException;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.expiry.ExpiryPolicy;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static com.hazelcast.cache.impl.CacheProxyUtil.validateNotNull;
import static com.hazelcast.cache.impl.ICacheService.SERVICE_NAME;
import static com.hazelcast.cache.impl.operation.MutableOperation.IGNORE_COMPLETION;
import static com.hazelcast.map.impl.nearcache.InvalidationAwareWrapper.asInvalidationAware;
import static com.hazelcast.map.impl.nearcache.KeyStateMarker.TRUE_MARKER;
import static com.hazelcast.util.ExceptionUtil.rethrow;
import static com.hazelcast.util.ExceptionUtil.rethrowAllowedTypeFirst;
/**
* Abstract {@link com.hazelcast.cache.ICache} implementation which provides shared internal implementations
* of cache operations like put, replace, remove and invoke. 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:classdataabstractioncoupling", "checkstyle:classfanoutcomplexity"})
abstract class AbstractClientInternalCacheProxy extends AbstractClientCacheProxyBase
implements CacheSyncListenerCompleter {
private static final long MAX_COMPLETION_LATCH_WAIT_TIME = TimeUnit.MINUTES.toMillis(5);
private static final long COMPLETION_LATCH_WAIT_TIME_STEP = TimeUnit.SECONDS.toMillis(1);
@SuppressWarnings("unchecked")
private static final ClientMessageDecoder GET_AND_REMOVE_RESPONSE_DECODER = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) CacheGetAndRemoveCodec.decodeResponse(clientMessage).response;
}
};
@SuppressWarnings("unchecked")
private static final ClientMessageDecoder REMOVE_RESPONSE_DECODER = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) Boolean.valueOf(CacheRemoveCodec.decodeResponse(clientMessage).response);
}
};
@SuppressWarnings("unchecked")
private static final ClientMessageDecoder REPLACE_RESPONSE_DECODER = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) CacheReplaceCodec.decodeResponse(clientMessage).response;
}
};
@SuppressWarnings("unchecked")
private static final ClientMessageDecoder GET_AND_REPLACE_RESPONSE_DECODER = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) CacheGetAndReplaceCodec.decodeResponse(clientMessage).response;
}
};
@SuppressWarnings("unchecked")
private static final ClientMessageDecoder PUT_RESPONSE_DECODER = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) CachePutCodec.decodeResponse(clientMessage).response;
}
};
@SuppressWarnings("unchecked")
private static final ClientMessageDecoder PUT_IF_ABSENT_RESPONSE_DECODER = new ClientMessageDecoder() {
@Override
public T decodeClientMessage(ClientMessage clientMessage) {
return (T) Boolean.valueOf(CachePutIfAbsentCodec.decodeResponse(clientMessage).response);
}
};
protected HazelcastClientCacheManager cacheManager;
protected RepairingHandler repairingHandler;
protected NearCacheManager nearCacheManager;
// Object => Data or
protected NearCache nearCache;
/**
* used when this cache has no near cache configured
*/
protected KeyStateMarker keyStateMarker = TRUE_MARKER;
protected String nearCacheMembershipRegistrationId;
protected ClientCacheStatisticsImpl statistics;
protected boolean statisticsEnabled;
protected boolean cacheOnUpdate;
private final ConcurrentMap asyncListenerRegistrations;
private final ConcurrentMap syncListenerRegistrations;
private final ConcurrentMap syncLocks;
protected AbstractClientInternalCacheProxy(CacheConfig cacheConfig) {
super(cacheConfig);
this.asyncListenerRegistrations = new ConcurrentHashMap();
this.syncListenerRegistrations = new ConcurrentHashMap();
this.syncLocks = new ConcurrentHashMap();
}
@Override
protected void onInitialize() {
super.onInitialize();
nearCacheManager = clientContext.getNearCacheManager();
initNearCache();
if (nearCache != null) {
statistics = new ClientCacheStatisticsImpl(System.currentTimeMillis(), nearCache.getNearCacheStats());
} else {
statistics = new ClientCacheStatisticsImpl(System.currentTimeMillis());
}
statisticsEnabled = cacheConfig.isStatisticsEnabled();
}
void setCacheManager(HazelcastClientCacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
protected void postDestroy() {
if (cacheManager != null) {
cacheManager.destroyCache(getName());
}
}
private void initNearCache() {
NearCacheConfig nearCacheConfig = clientContext.getClientConfig().getNearCacheConfig(name);
if (nearCacheConfig != null) {
cacheOnUpdate = nearCacheConfig.getLocalUpdatePolicy() == NearCacheConfig.LocalUpdatePolicy.CACHE;
ICacheDataStructureAdapter adapter = new ICacheDataStructureAdapter(this);
nearCache = nearCacheManager.getOrCreateNearCache(nameWithPrefix, nearCacheConfig, adapter);
registerInvalidationListener();
}
}
@Override
public void close() {
if (nearCache != null) {
removeInvalidationListener();
nearCacheManager.clearNearCache(nearCache.getName());
}
if (statisticsEnabled) {
statistics.clear();
}
super.close();
}
@Override
protected void onDestroy() {
if (nearCache != null) {
removeInvalidationListener();
nearCacheManager.destroyNearCache(nearCache.getName());
}
if (statisticsEnabled) {
statistics.clear();
}
}
protected ClientInvocationFuture invoke(ClientMessage req, int partitionId, int completionId) {
boolean completionOperation = completionId != -1;
if (completionOperation) {
registerCompletionLatch(completionId, 1);
}
try {
HazelcastClientInstanceImpl client = (HazelcastClientInstanceImpl) clientContext.getHazelcastInstance();
ClientInvocation clientInvocation = new ClientInvocation(client, req, partitionId);
ClientInvocationFuture f = clientInvocation.invoke();
if (completionOperation) {
waitCompletionLatch(completionId, f);
}
return f;
} catch (Throwable e) {
if (e instanceof IllegalStateException) {
close();
}
if (completionOperation) {
deregisterCompletionLatch(completionId);
}
throw rethrowAllowedTypeFirst(e, CacheException.class);
}
}
protected ClientInvocationFuture invoke(ClientMessage req, Data keyData, int completionId) {
int partitionId = clientContext.getPartitionService().getPartitionId(keyData);
return invoke(req, partitionId, completionId);
}
protected T getSafely(Future future) {
try {
return future.get();
} catch (Throwable throwable) {
throw rethrow(throwable);
}
}
protected ICompletableFuture getAndRemoveAsyncInternal(K key, boolean withCompletionEvent, boolean async) {
final long start = System.nanoTime();
ensureOpen();
validateNotNull(key);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key);
final Data keyData = toData(key);
final int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheGetAndRemoveCodec.encodeRequest(nameWithPrefix, keyData, completionId);
ClientInvocationFuture future;
try {
future = invoke(request, keyData, completionId);
invalidateNearCache(keyData);
} catch (Exception e) {
throw rethrow(e);
}
ClientDelegatingFuture delegatingFuture =
new ClientDelegatingFuture(future, clientContext.getSerializationService(), GET_AND_REMOVE_RESPONSE_DECODER);
if (async && statisticsEnabled) {
delegatingFuture.andThen(new ExecutionCallback() {
public void onResponse(T responseData) {
Object response = clientContext.getSerializationService().toObject(responseData);
handleStatisticsOnRemove(true, start, response);
}
public void onFailure(Throwable t) {
}
});
}
return delegatingFuture;
}
protected ICompletableFuture removeAsyncInternal(K key, V oldValue, boolean hasOldValue, boolean withCompletionEvent,
boolean async) {
final long start = System.nanoTime();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, oldValue);
} else {
validateNotNull(key);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key);
}
Data keyData = toData(key);
Data oldValueData = toData(oldValue);
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheRemoveCodec.encodeRequest(nameWithPrefix, keyData, oldValueData, completionId);
ClientInvocationFuture future;
try {
future = invoke(request, keyData, completionId);
invalidateNearCache(keyData);
} catch (Exception e) {
throw rethrow(e);
}
ClientDelegatingFuture delegatingFuture =
new ClientDelegatingFuture(future, clientContext.getSerializationService(), REMOVE_RESPONSE_DECODER);
if (async && statisticsEnabled) {
delegatingFuture.andThen(new ExecutionCallback() {
public void onResponse(T responseData) {
Object response = clientContext.getSerializationService().toObject(responseData);
handleStatisticsOnRemove(false, start, response);
}
public void onFailure(Throwable t) {
}
});
}
return delegatingFuture;
}
protected void handleStatisticsOnRemove(boolean isGet, long start, Object response) {
if (isGet) {
statistics.addGetTimeNanos(System.nanoTime() - start);
if (response != null) {
statistics.increaseCacheHits();
statistics.increaseCacheRemovals();
statistics.addRemoveTimeNanos(System.nanoTime() - start);
} else {
statistics.increaseCacheMisses();
}
} else {
if (Boolean.TRUE.equals(response)) {
statistics.increaseCacheRemovals();
statistics.addRemoveTimeNanos(System.nanoTime() - start);
}
}
}
protected ICompletableFuture replaceInternal(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy,
boolean hasOldValue, boolean withCompletionEvent, boolean async) {
final long start = System.nanoTime();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue, newValue);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, oldValue, newValue);
} else {
validateNotNull(key, newValue);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, newValue);
}
Data keyData = toData(key);
Data oldValueData = toData(oldValue);
Data newValueData = toData(newValue);
Data expiryPolicyData = toData(expiryPolicy);
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheReplaceCodec.encodeRequest(nameWithPrefix, keyData, oldValueData, newValueData,
expiryPolicyData, completionId);
ClientInvocationFuture future;
try {
future = invoke(request, keyData, completionId);
invalidateNearCache(keyData);
} catch (Exception e) {
throw rethrow(e);
}
ClientDelegatingFuture delegatingFuture =
new ClientDelegatingFuture(future, clientContext.getSerializationService(), REPLACE_RESPONSE_DECODER);
if (async && statisticsEnabled) {
delegatingFuture.andThen(new ExecutionCallback() {
public void onResponse(T responseData) {
Object response = clientContext.getSerializationService().toObject(responseData);
handleStatisticsOnReplace(false, start, response);
}
public void onFailure(Throwable t) {
}
});
}
return delegatingFuture;
}
protected ICompletableFuture replaceAndGetAsyncInternal(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy,
boolean hasOldValue, boolean withCompletionEvent,
boolean async) {
final long start = System.nanoTime();
ensureOpen();
if (hasOldValue) {
validateNotNull(key, oldValue, newValue);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, oldValue, newValue);
} else {
validateNotNull(key, newValue);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, newValue);
}
Data keyData = toData(key);
Data newValueData = toData(newValue);
Data expiryPolicyData = toData(expiryPolicy);
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CacheGetAndReplaceCodec.encodeRequest(nameWithPrefix, keyData, newValueData, expiryPolicyData,
completionId);
ClientInvocationFuture future;
try {
future = invoke(request, keyData, completionId);
invalidateNearCache(keyData);
} catch (Exception e) {
throw rethrow(e);
}
ClientDelegatingFuture delegatingFuture =
new ClientDelegatingFuture(future, clientContext.getSerializationService(), GET_AND_REPLACE_RESPONSE_DECODER);
if (async && statisticsEnabled) {
delegatingFuture.andThen(new ExecutionCallback() {
public void onResponse(T responseData) {
Object response = clientContext.getSerializationService().toObject(responseData);
handleStatisticsOnReplace(true, start, response);
}
public void onFailure(Throwable t) {
}
});
}
return delegatingFuture;
}
protected void handleStatisticsOnReplace(boolean isGet, long start, Object response) {
if (isGet) {
statistics.addGetTimeNanos(System.nanoTime() - start);
if (response != null) {
statistics.increaseCacheHits();
statistics.increaseCachePuts();
statistics.addPutTimeNanos(System.nanoTime() - start);
} else {
statistics.increaseCacheMisses();
}
} else {
if (Boolean.TRUE.equals(response)) {
statistics.increaseCacheHits();
statistics.increaseCachePuts();
statistics.addPutTimeNanos(System.nanoTime() - start);
} else {
statistics.increaseCacheMisses();
}
}
}
protected Object putInternal(K key, V value, ExpiryPolicy expiryPolicy, boolean isGet, boolean withCompletionEvent,
boolean async) {
long start = System.nanoTime();
ensureOpen();
validateNotNull(key, value);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, value);
Data keyData = toData(key);
Data valueData = toData(value);
Data expiryPolicyData = toData(expiryPolicy);
boolean marked = !cacheOnUpdate || keyStateMarker.markIfUnmarked(keyData);
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CachePutCodec.encodeRequest(nameWithPrefix, keyData, valueData, expiryPolicyData, isGet,
completionId);
ClientInvocationFuture future;
try {
future = invoke(request, keyData, completionId);
} catch (Exception e) {
resetToUnmarkedState(keyData);
throw rethrow(e);
}
if (async) {
return putInternalAsync(value, isGet, start, keyData, valueData, future, marked);
}
return putInternalSync(value, isGet, start, keyData, valueData, future, marked);
}
private Object putInternalAsync(final V value, final boolean isGet, final long start, final Data keyData,
final Data valueData, ClientInvocationFuture future, final boolean marked) {
OneShotExecutionCallback oneShotExecutionCallback = null;
if (nearCache != null || statisticsEnabled) {
oneShotExecutionCallback = new OneShotExecutionCallback() {
@Override
protected void onResponseInternal(V responseData) {
if (nearCache != null) {
if (cacheOnUpdate) {
storeInNearCache(keyData, valueData, value, marked);
} else {
invalidateNearCache(keyData);
}
}
if (statisticsEnabled) {
handleStatisticsOnPut(isGet, start, responseData);
}
}
@Override
protected void onFailureInternal(Throwable t) {
if (nearCache != null && cacheOnUpdate) {
resetToUnmarkedState(keyData);
}
}
};
}
SerializationService serializationService = clientContext.getSerializationService();
if (oneShotExecutionCallback == null) {
return new ClientDelegatingFuture(future, serializationService, PUT_RESPONSE_DECODER);
}
ClientDelegatingFuture delegatingFuture = new CallbackAwareClientDelegatingFuture(future,
serializationService, PUT_RESPONSE_DECODER, oneShotExecutionCallback);
delegatingFuture.andThen(oneShotExecutionCallback);
return delegatingFuture;
}
private Object putInternalSync(V value, boolean isGet, long start, Data keyData, Data valueData,
ClientInvocationFuture future, boolean marked) {
try {
ClientDelegatingFuture delegatingFuture = new ClientDelegatingFuture(future,
clientContext.getSerializationService(), PUT_RESPONSE_DECODER);
Object response = delegatingFuture.get();
if (statisticsEnabled) {
handleStatisticsOnPut(isGet, start, response);
}
return response;
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
} finally {
if (nearCache != null) {
if (cacheOnUpdate) {
storeInNearCache(keyData, valueData, value, marked);
} else {
invalidateNearCache(keyData);
}
}
}
}
protected void handleStatisticsOnPut(boolean isGet, long start, Object response) {
statistics.increaseCachePuts();
statistics.addPutTimeNanos(System.nanoTime() - start);
if (isGet) {
Object resp = clientContext.getSerializationService().toObject(response);
statistics.addGetTimeNanos(System.nanoTime() - start);
if (resp == null) {
statistics.increaseCacheMisses();
} else {
statistics.increaseCacheHits();
}
}
}
protected Object putIfAbsentInternal(K key, V value, ExpiryPolicy expiryPolicy, boolean withCompletionEvent,
boolean async) {
long start = System.nanoTime();
ensureOpen();
validateNotNull(key, value);
CacheProxyUtil.validateConfiguredTypes(cacheConfig, key, value);
Data keyData = toData(key);
Data valueData = toData(value);
boolean marked = !cacheOnUpdate || keyStateMarker.markIfUnmarked(keyData);
Data expiryPolicyData = toData(expiryPolicy);
int completionId = withCompletionEvent ? nextCompletionId() : -1;
ClientMessage request = CachePutIfAbsentCodec.encodeRequest(nameWithPrefix, keyData, valueData,
expiryPolicyData, completionId);
ClientInvocationFuture future;
try {
future = invoke(request, keyData, completionId);
} catch (Exception e) {
resetToUnmarkedState(keyData);
throw rethrow(e);
}
ClientDelegatingFuture delegatingFuture = new ClientDelegatingFuture(future,
clientContext.getSerializationService(), PUT_IF_ABSENT_RESPONSE_DECODER);
if (async) {
return putIfAbsentInternalAsync(value, start, keyData, valueData, delegatingFuture, marked);
}
return putIfAbsentInternalSync(value, start, keyData, valueData, delegatingFuture, marked);
}
private Object putIfAbsentInternalAsync(final V value, final long start, final Data keyData, final Data valueData,
ClientDelegatingFuture delegatingFuture, final boolean marked) {
if (nearCache != null || statisticsEnabled) {
delegatingFuture.andThen(new ExecutionCallback() {
@Override
public void onResponse(Boolean responseData) {
if (nearCache != null) {
if (cacheOnUpdate) {
storeInNearCache(keyData, valueData, value, marked);
} else {
invalidateNearCache(keyData);
}
}
if (statisticsEnabled) {
Object response = clientContext.getSerializationService().toObject(responseData);
handleStatisticsOnPutIfAbsent(start, (Boolean) response);
}
}
@Override
public void onFailure(Throwable t) {
if (nearCache != null && cacheOnUpdate) {
resetToUnmarkedState(keyData);
}
}
});
}
return delegatingFuture;
}
private Object putIfAbsentInternalSync(V value, long start, Data keyData, Data valueData,
ClientDelegatingFuture delegatingFuture, boolean marked) {
try {
Object response = delegatingFuture.get();
if (statisticsEnabled) {
handleStatisticsOnPutIfAbsent(start, (Boolean) response);
}
return response;
} catch (Throwable e) {
throw rethrowAllowedTypeFirst(e, CacheException.class);
} finally {
if (nearCache != null) {
if (cacheOnUpdate) {
storeInNearCache(keyData, valueData, value, marked);
} else {
invalidateNearCache(keyData);
}
}
}
}
protected void handleStatisticsOnPutIfAbsent(long start, boolean saved) {
if (saved) {
statistics.increaseCachePuts();
statistics.addPutTimeNanos(System.nanoTime() - start);
}
}
protected void removeAllKeysInternal(Set keys) {
long start = System.nanoTime();
Set keysData;
keysData = new HashSet();
for (K key : keys) {
keysData.add(toData(key));
}
int partitionCount = clientContext.getPartitionService().getPartitionCount();
int completionId = nextCompletionId();
registerCompletionLatch(completionId, partitionCount);
ClientMessage request = CacheRemoveAllKeysCodec.encodeRequest(nameWithPrefix, keysData, completionId);
try {
invoke(request);
waitCompletionLatch(completionId, null);
if (statisticsEnabled) {
// Actually we don't know how many of them are really removed or not.
// We just assume that if there is no exception, all of them are removed.
// Otherwise (if there is an exception), we don't update any cache stats about remove.
statistics.increaseCacheRemovals(keysData.size());
statistics.addRemoveTimeNanos(System.nanoTime() - start);
}
} catch (Throwable t) {
deregisterCompletionLatch(completionId);
throw rethrowAllowedTypeFirst(t, CacheException.class);
}
}
protected void removeAllInternal() {
int partitionCount = clientContext.getPartitionService().getPartitionCount();
int completionId = nextCompletionId();
registerCompletionLatch(completionId, partitionCount);
ClientMessage request = CacheRemoveAllCodec.encodeRequest(nameWithPrefix, completionId);
try {
invoke(request);
waitCompletionLatch(completionId, null);
if (statisticsEnabled) {
statistics.setLastUpdateTime(System.currentTimeMillis());
// We don't support count stats of removing all entries.
}
} catch (Throwable t) {
deregisterCompletionLatch(completionId);
throw rethrowAllowedTypeFirst(t, CacheException.class);
}
}
protected void clearInternal() {
ClientMessage request = CacheClearCodec.encodeRequest(nameWithPrefix);
try {
invoke(request);
if (statisticsEnabled) {
statistics.setLastUpdateTime(System.currentTimeMillis());
// We don't support count stats of removing all entries.
}
} catch (Throwable t) {
throw rethrowAllowedTypeFirst(t, CacheException.class);
}
}
protected void storeInNearCache(Data key, Data valueData, V value, boolean marked) {
if (!marked) {
return;
}
try {
if (nearCache == null || valueData == null) {
return;
}
Object valueToStore = nearCache.selectToSave(value, valueData);
nearCache.put(key, valueToStore);
} finally {
resetToUnmarkedState(key);
}
}
public void resetToUnmarkedState(Data key) {
if (keyStateMarker.unmarkIfMarked(key)) {
return;
}
invalidateNearCache(key);
keyStateMarker.unmarkForcibly(key);
}
protected void invalidateNearCache(Data key) {
if (nearCache != null) {
nearCache.remove(key);
}
}
protected void addListenerLocally(String regId, CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
if (cacheEntryListenerConfiguration.isSynchronous()) {
syncListenerRegistrations.putIfAbsent(cacheEntryListenerConfiguration, regId);
} else {
asyncListenerRegistrations.putIfAbsent(cacheEntryListenerConfiguration, regId);
}
}
protected String removeListenerLocally(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
ConcurrentMap regs;
if (cacheEntryListenerConfiguration.isSynchronous()) {
regs = syncListenerRegistrations;
} else {
regs = asyncListenerRegistrations;
}
return regs.remove(cacheEntryListenerConfiguration);
}
protected String getListenerIdLocal(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
ConcurrentMap regs;
if (cacheEntryListenerConfiguration.isSynchronous()) {
regs = syncListenerRegistrations;
} else {
regs = asyncListenerRegistrations;
}
return regs.get(cacheEntryListenerConfiguration);
}
private void deregisterAllCacheEntryListener(Collection listenerRegistrations) {
ClientListenerService listenerService = clientContext.getListenerService();
for (String regId : listenerRegistrations) {
listenerService.deregisterListener(regId);
}
}
@Override
protected void closeListeners() {
deregisterAllCacheEntryListener(syncListenerRegistrations.values());
deregisterAllCacheEntryListener(asyncListenerRegistrations.values());
syncListenerRegistrations.clear();
asyncListenerRegistrations.clear();
notifyAndClearSyncListenerLatches();
}
private void notifyAndClearSyncListenerLatches() {
// notify waiting sync listeners
Collection latches = syncLocks.values();
Iterator iterator = latches.iterator();
while (iterator.hasNext()) {
CountDownLatch latch = iterator.next();
iterator.remove();
while (latch.getCount() > 0) {
latch.countDown();
}
}
}
@Override
public void countDownCompletionLatch(int countDownLatchId) {
if (countDownLatchId != IGNORE_COMPLETION) {
CountDownLatch countDownLatch = syncLocks.get(countDownLatchId);
if (countDownLatch == null) {
return;
}
countDownLatch.countDown();
if (countDownLatch.getCount() == 0) {
deregisterCompletionLatch(countDownLatchId);
}
}
}
protected Integer registerCompletionLatch(Integer countDownLatchId, int count) {
if (!syncListenerRegistrations.isEmpty()) {
int size = syncListenerRegistrations.size();
CountDownLatch countDownLatch = new CountDownLatch(count * size);
syncLocks.put(countDownLatchId, countDownLatch);
return countDownLatchId;
}
return MutableOperation.IGNORE_COMPLETION;
}
protected void deregisterCompletionLatch(Integer countDownLatchId) {
if (countDownLatchId != IGNORE_COMPLETION) {
syncLocks.remove(countDownLatchId);
}
}
protected void waitCompletionLatch(Integer countDownLatchId, ICompletableFuture future) throws ExecutionException {
if (countDownLatchId != IGNORE_COMPLETION) {
CountDownLatch countDownLatch = syncLocks.get(countDownLatchId);
if (countDownLatch != null) {
awaitLatch(countDownLatch, future);
}
}
}
private void awaitLatch(CountDownLatch countDownLatch, ICompletableFuture future)
throws ExecutionException {
try {
long currentTimeoutMs = MAX_COMPLETION_LATCH_WAIT_TIME;
// Call latch await in small steps to be able to check if node is still active.
// If not active then throw HazelcastInstanceNotActiveException,
// If closed or destroyed then throw IllegalStateException,
// otherwise continue to wait until `MAX_COMPLETION_LATCH_WAIT_TIME` passes.
//
// Warning: Silently ignoring if latch does not countDown in time.
while (currentTimeoutMs > 0
&& !countDownLatch.await(COMPLETION_LATCH_WAIT_TIME_STEP, TimeUnit.MILLISECONDS)) {
if (future != null && future.isDone()) {
Object response = future.get();
if (response instanceof Throwable) {
return;
}
}
currentTimeoutMs -= COMPLETION_LATCH_WAIT_TIME_STEP;
if (!clientContext.isActive()) {
throw new HazelcastInstanceNotActiveException();
} else if (isClosed()) {
throw new IllegalStateException("Cache (" + nameWithPrefix + ") is closed !");
} else if (isDestroyed()) {
throw new IllegalStateException("Cache (" + nameWithPrefix + ") is destroyed !");
}
}
if (countDownLatch.getCount() > 0) {
logger.finest("Countdown latch wait timeout after "
+ MAX_COMPLETION_LATCH_WAIT_TIME + " milliseconds!");
}
} catch (InterruptedException e) {
ExceptionUtil.sneakyThrow(e);
}
}
protected EventHandler createHandler(CacheEventListenerAdaptor adaptor) {
return new CacheEventHandler(adaptor);
}
private final class CacheEventHandler extends CacheAddEntryListenerCodec.AbstractEventHandler
implements EventHandler {
private final CacheEventListenerAdaptor adaptor;
private CacheEventHandler(CacheEventListenerAdaptor adaptor) {
this.adaptor = adaptor;
}
@Override
public void handle(int type, Collection keys, int completionId) {
adaptor.handle(type, keys, completionId);
}
@Override
public void beforeListenerRegister() {
}
@Override
public void onListenerRegister() {
}
}
protected ICompletableFuture createCompletedFuture(Object value) {
return new CompletedFuture(clientContext.getSerializationService(), value,
clientContext.getExecutionService().getAsyncExecutor());
}
private final class NearCacheRepairingHandlerAdapter extends CacheAddInvalidationListenerCodec.AbstractEventHandler
implements EventHandler {
@Override
public void handle(String name, Data key, String sourceUuid, UUID partitionUuid, long sequence) {
repairingHandler.handle(key, sourceUuid, partitionUuid, sequence);
}
@Override
public void handle(String name, Collection keys, Collection sourceUuids,
Collection partitionUuids, Collection sequences) {
repairingHandler.handle(keys, sourceUuids, partitionUuids, sequences);
}
@Override
public void beforeListenerRegister() {
}
@Override
public void onListenerRegister() {
nearCache.clear();
}
}
private void registerInvalidationListener() {
if (nearCache == null || !nearCache.isInvalidatedOnChange()) {
return;
}
int partitionCount = getContext().getPartitionService().getPartitionCount();
nearCache = asInvalidationAware(nearCache, partitionCount);
keyStateMarker = ((InvalidationAwareWrapper) nearCache).getKeyStateMarker();
RepairingTask repairingTask = clientContext.getRepairingTask(SERVICE_NAME);
repairingHandler = repairingTask.registerAndGetHandler(nameWithPrefix, nearCache);
EventHandler handler = new NearCacheRepairingHandlerAdapter();
ListenerMessageCodec listenerCodec = createInvalidationListenerCodec();
ClientListenerService listenerService = clientContext.getListenerService();
nearCacheMembershipRegistrationId = listenerService.registerListener(listenerCodec, handler);
}
private ListenerMessageCodec createInvalidationListenerCodec() {
return new ListenerMessageCodec() {
@Override
public ClientMessage encodeAddRequest(boolean localOnly) {
return CacheAddInvalidationListenerCodec.encodeRequest(nameWithPrefix, localOnly);
}
@Override
public String decodeAddResponse(ClientMessage clientMessage) {
return CacheAddInvalidationListenerCodec.decodeResponse(clientMessage).response;
}
@Override
public ClientMessage encodeRemoveRequest(String realRegistrationId) {
return CacheRemoveEntryListenerCodec.encodeRequest(nameWithPrefix, realRegistrationId);
}
@Override
public boolean decodeRemoveResponse(ClientMessage clientMessage) {
return CacheRemoveEntryListenerCodec.decodeResponse(clientMessage).response;
}
};
}
private void removeInvalidationListener() {
if (nearCache != null && nearCache.isInvalidatedOnChange()) {
String registrationId = nearCacheMembershipRegistrationId;
if (registrationId != null) {
clientContext.getRepairingTask(SERVICE_NAME).deregisterHandler(name);
clientContext.getListenerService().deregisterListener(registrationId);
}
}
}
// public for testing.
public KeyStateMarker getKeyStateMarker() {
return keyStateMarker;
}
}