All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.client.cache.impl.AbstractClientInternalCacheProxy Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2020, 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.CacheEventData;
import com.hazelcast.cache.impl.CacheEventListenerAdaptor;
import com.hazelcast.cache.impl.CacheSyncListenerCompleter;
import com.hazelcast.cache.impl.operation.MutableOperation;
import com.hazelcast.client.HazelcastClientNotActiveException;
import com.hazelcast.client.impl.clientside.ClientMessageDecoder;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.CacheAddEntryListenerCodec;
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.CacheReplaceCodec;
import com.hazelcast.client.impl.protocol.codec.CacheSetExpiryPolicyCodec;
import com.hazelcast.client.spi.ClientContext;
import com.hazelcast.client.spi.ClientListenerService;
import com.hazelcast.client.spi.ClientPartitionService;
import com.hazelcast.client.spi.EventHandler;
import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.client.spi.impl.ClientInvocationFuture;
import com.hazelcast.client.util.ClientDelegatingFuture;
import com.hazelcast.config.CacheConfig;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.ICompletableFuture;
import com.hazelcast.nio.IOUtil;
import com.hazelcast.nio.serialization.Data;

import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.event.CacheEntryListener;
import javax.cache.expiry.ExpiryPolicy;
import java.io.Closeable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
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 java.util.concurrent.atomic.AtomicReference;

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.util.ExceptionUtil.rethrow;
import static com.hazelcast.util.ExceptionUtil.rethrowAllowedTypeFirst;
import static com.hazelcast.util.ExceptionUtil.sneakyThrow;
import static java.lang.Thread.currentThread;

/**
 * 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") 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); } }; private static final ClientMessageDecoder SET_EXPIRY_POLICY_DECODER = new ClientMessageDecoder() { @Override public T decodeClientMessage(ClientMessage clientMessage) { return (T) Boolean.valueOf(CacheSetExpiryPolicyCodec.decodeResponse(clientMessage).response); } }; protected final AtomicReference cacheManagerRef = new AtomicReference(); protected int partitionCount; private final ConcurrentMap asyncListenerRegistrations; private final ConcurrentMap syncListenerRegistrations; private final ConcurrentMap closeableListeners; private final ConcurrentMap syncLocks; AbstractClientInternalCacheProxy(CacheConfig cacheConfig, ClientContext context) { super(cacheConfig, context); this.asyncListenerRegistrations = new ConcurrentHashMap(); this.syncListenerRegistrations = new ConcurrentHashMap(); this.closeableListeners = new ConcurrentHashMap(); this.syncLocks = new ConcurrentHashMap(); } @Override protected void onInitialize() { super.onInitialize(); ClientPartitionService partitionService = getContext().getPartitionService(); partitionCount = partitionService.getPartitionCount(); } @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 public void close() { if (statisticsEnabled) { statsHandler.clear(); } super.close(); } @Override protected void onDestroy() { if (statisticsEnabled) { statsHandler.clear(); } super.onDestroy(); } protected ClientInvocationFuture invoke(ClientMessage req, int partitionId, int completionId) { boolean completionOperation = completionId != -1; if (completionOperation) { registerCompletionLatch(completionId, 1); } try { ClientInvocation clientInvocation = new ClientInvocation(getClient(), req, name, partitionId); ClientInvocationFuture future = clientInvocation.invoke(); if (completionOperation) { waitCompletionLatch(completionId, future); } return future; } 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 = getContext().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) { long startNanos = nowInNanosOrDefault(); ensureOpen(); validateNotNull(key); validateConfiguredTypes(cacheConfig, key); Data keyData = toData(key); ClientDelegatingFuture delegatingFuture = getAndRemoveInternal(keyData, false); ExecutionCallback callback = !statisticsEnabled ? null : statsHandler.newOnRemoveCallback(true, startNanos); onGetAndRemoveAsyncInternal(key, keyData, delegatingFuture, callback); return delegatingFuture; } protected ClientDelegatingFuture getAndRemoveSyncInternal(K key) { ensureOpen(); validateNotNull(key); validateConfiguredTypes(cacheConfig, key); Data keyData = toData(key); ClientDelegatingFuture delegatingFuture = getAndRemoveInternal(keyData, true); onGetAndRemoveAsyncInternal(key, keyData, delegatingFuture, null); 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, GET_AND_REMOVE_RESPONSE_DECODER); } protected void onGetAndRemoveAsyncInternal(K key, Data keyData, ClientDelegatingFuture delegatingFuture, ExecutionCallback callback) { addCallback(delegatingFuture, callback); } protected Object removeAsyncInternal(K key, V oldValue, boolean hasOldValue, boolean withCompletionEvent, boolean async) { 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); int completionId = withCompletionEvent ? nextCompletionId() : -1; ClientMessage request = CacheRemoveCodec.encodeRequest(nameWithPrefix, keyData, oldValueData, completionId); ClientInvocationFuture future = invoke(request, keyData, completionId); ClientDelegatingFuture delegatingFuture = newDelegatingFuture(future, REMOVE_RESPONSE_DECODER); if (async) { ExecutionCallback callback = !statisticsEnabled ? null : statsHandler.newOnRemoveCallback(false, startNanos); onRemoveAsyncInternal(key, keyData, delegatingFuture, callback); return delegatingFuture; } else { try { Object result = delegatingFuture.get(); onRemoveSyncInternal(key, keyData); return result; } catch (Throwable t) { throw rethrow(t); } } } public void onRemoveSyncInternal(Object key, Data keyData) { // NOP } protected void onRemoveAsyncInternal(Object key, Data keyData, ClientDelegatingFuture future, ExecutionCallback callback) { addCallback(future, callback); } protected boolean replaceSyncInternal(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy, boolean hasOldValue) { long startNanos = nowInNanosOrDefault(); Future future = replaceAsyncInternal(key, oldValue, newValue, expiryPolicy, hasOldValue, true, false); try { boolean replaced = future.get(); if (statisticsEnabled) { statsHandler.onReplace(false, startNanos, replaced); } return replaced; } catch (Throwable e) { throw rethrowAllowedTypeFirst(e, CacheException.class); } } protected ICompletableFuture replaceAsyncInternal(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy, boolean hasOldValue, boolean withCompletionEvent, boolean async) { 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); int completionId = withCompletionEvent ? nextCompletionId() : -1; ClientMessage request = CacheReplaceCodec.encodeRequest(nameWithPrefix, keyData, oldValueData, newValueData, expiryPolicyData, completionId); ClientInvocationFuture future = invoke(request, keyData, completionId); ClientDelegatingFuture delegatingFuture = newDelegatingFuture(future, REPLACE_RESPONSE_DECODER); ExecutionCallback callback = async && statisticsEnabled ? statsHandler.newOnReplaceCallback(startNanos) : null; onReplaceInternalAsync(key, newValue, keyData, newValueData, delegatingFuture, callback); return delegatingFuture; } protected void onReplaceInternalAsync(K key, V value, Data keyData, Data valueData, ClientDelegatingFuture delegatingFuture, ExecutionCallback callback) { addCallback(delegatingFuture, callback); } protected ICompletableFuture replaceAndGetAsyncInternal(K key, V oldValue, V newValue, ExpiryPolicy expiryPolicy, boolean hasOldValue, boolean withCompletionEvent, boolean async) { 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); int completionId = withCompletionEvent ? nextCompletionId() : -1; ClientMessage request = CacheGetAndReplaceCodec.encodeRequest(nameWithPrefix, keyData, newValueData, expiryPolicyData, completionId); ClientInvocationFuture future = invoke(request, keyData, completionId); ClientDelegatingFuture delegatingFuture = newDelegatingFuture(future, GET_AND_REPLACE_RESPONSE_DECODER); ExecutionCallback callback = async && statisticsEnabled ? statsHandler.newOnReplaceCallback(startNanos) : null; onReplaceAndGetAsync(key, newValue, keyData, newValueData, delegatingFuture, callback); return delegatingFuture; } protected void onReplaceAndGetAsync(K key, V value, Data keyData, Data valueData, ClientDelegatingFuture delegatingFuture, ExecutionCallback callback) { addCallback(delegatingFuture, callback); } protected static void addCallback(ClientDelegatingFuture delegatingFuture, ExecutionCallback callback) { if (callback == null) { return; } delegatingFuture.andThen(callback); } private ClientInvocationFuture putInternal(Data keyData, Data valueData, Data expiryPolicyData, boolean isGet, boolean withCompletionEvent) { int completionId = withCompletionEvent ? nextCompletionId() : -1; ClientMessage request = CachePutCodec.encodeRequest(nameWithPrefix, keyData, valueData, expiryPolicyData, isGet, completionId); return invoke(request, keyData, completionId); } 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 { ClientInvocationFuture invocationFuture = putInternal(keyData, valueData, expiryPolicyData, isGet, true); ClientDelegatingFuture delegatingFuture = newDelegatingFuture(invocationFuture, PUT_RESPONSE_DECODER); V response = delegatingFuture.get(); if (statisticsEnabled) { statsHandler.onPut(isGet, startNanos, response != null); } return response; } catch (Throwable e) { throw rethrowAllowedTypeFirst(e, CacheException.class); } finally { onPutSyncInternal(key, value, keyData, valueData); } } protected void onPutSyncInternal(K key, V value, Data keyData, Data valueData) { // NOP } protected ClientDelegatingFuture putAsyncInternal(K key, V value, ExpiryPolicy expiryPolicy, boolean isGet, boolean withCompletionEvent, OneShotExecutionCallback callback) { ensureOpen(); validateNotNull(key, value); validateConfiguredTypes(cacheConfig, key, value); Data keyData = toData(key); Data valueData = toData(value); Data expiryPolicyData = toData(expiryPolicy); ClientInvocationFuture invocationFuture = putInternal(keyData, valueData, expiryPolicyData, isGet, withCompletionEvent); return wrapPutAsyncFuture(key, value, keyData, valueData, invocationFuture, callback); } protected ClientDelegatingFuture wrapPutAsyncFuture(K key, V value, Data keyData, Data valueData, ClientInvocationFuture invocationFuture, OneShotExecutionCallback callback) { if (callback == null) { return newDelegatingFuture(invocationFuture, PUT_RESPONSE_DECODER); } CallbackAwareClientDelegatingFuture future = new CallbackAwareClientDelegatingFuture(invocationFuture, getSerializationService(), PUT_RESPONSE_DECODER, callback); future.andThen(callback); return future; } protected OneShotExecutionCallback newStatsCallbackOrNull(boolean isGet) { if (!statisticsEnabled) { return null; } return statsHandler.newOnPutCallback(isGet, System.nanoTime()); } 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, SET_EXPIRY_POLICY_DECODER); try { return delegatingFuture.get(); } catch (Throwable e) { throw rethrowAllowedTypeFirst(e, CacheException.class); } } protected Object putIfAbsentInternal(K key, V value, ExpiryPolicy expiryPolicy, boolean withCompletionEvent, boolean async) { long startNanos = nowInNanosOrDefault(); ensureOpen(); validateNotNull(key, value); validateConfiguredTypes(cacheConfig, key, value); Data keyData = toData(key); Data valueData = toData(value); Data expiryPolicyData = toData(expiryPolicy); int completionId = withCompletionEvent ? nextCompletionId() : -1; ClientMessage request = CachePutIfAbsentCodec.encodeRequest(nameWithPrefix, keyData, valueData, expiryPolicyData, completionId); ClientInvocationFuture future = invoke(request, keyData, completionId); ClientDelegatingFuture delegatingFuture = newDelegatingFuture(future, PUT_IF_ABSENT_RESPONSE_DECODER); if (async) { ExecutionCallback callback = !statisticsEnabled ? null : statsHandler.newOnPutIfAbsentCallback(startNanos); onPutIfAbsentAsyncInternal(key, value, keyData, valueData, delegatingFuture, callback); return delegatingFuture; } else { try { Object response = delegatingFuture.get(); if (statisticsEnabled) { statsHandler.onPutIfAbsent(startNanos, (Boolean) response); } onPutIfAbsentSyncInternal(key, value, keyData, valueData); return response; } catch (Throwable e) { throw rethrowAllowedTypeFirst(e, CacheException.class); } } } protected void onPutIfAbsentAsyncInternal(K key, V value, Data keyData, Data valueData, ClientDelegatingFuture delegatingFuture, ExecutionCallback callback) { addCallback(delegatingFuture, callback); } protected void onPutIfAbsentSyncInternal(K key, V value, Data keyData, Data valueData) { // NOP } protected void removeAllKeysInternal(Set keys, Collection dataKeys, long startNanos) { int partitionCount = getContext().getPartitionService().getPartitionCount(); int completionId = nextCompletionId(); registerCompletionLatch(completionId, partitionCount); ClientMessage request = CacheRemoveAllKeysCodec.encodeRequest(nameWithPrefix, dataKeys, completionId); try { invoke(request); waitCompletionLatch(completionId, null); if (statisticsEnabled) { statsHandler.onBatchRemove(startNanos, dataKeys.size()); } } catch (Throwable t) { deregisterCompletionLatch(completionId); throw rethrowAllowedTypeFirst(t, CacheException.class); } } protected void removeAllInternal() { int partitionCount = getContext().getPartitionService().getPartitionCount(); int completionId = nextCompletionId(); registerCompletionLatch(completionId, partitionCount); ClientMessage request = CacheRemoveAllCodec.encodeRequest(nameWithPrefix, completionId); try { invoke(request); waitCompletionLatch(completionId, null); if (statisticsEnabled) { statsHandler.getStatistics().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) { 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(String regId, CacheEntryListenerConfiguration cacheEntryListenerConfiguration, CacheEventListenerAdaptor adaptor) { if (cacheEntryListenerConfiguration.isSynchronous()) { syncListenerRegistrations.putIfAbsent(cacheEntryListenerConfiguration, regId); } else { asyncListenerRegistrations.putIfAbsent(cacheEntryListenerConfiguration, regId); } CacheEntryListener entryListener = adaptor.getCacheEntryListener(); if (entryListener instanceof Closeable) { closeableListeners.putIfAbsent(regId, (Closeable) entryListener); } } protected String removeListenerLocally(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { ConcurrentMap regs; if (cacheEntryListenerConfiguration.isSynchronous()) { regs = syncListenerRegistrations; } else { regs = asyncListenerRegistrations; } String registrationId = regs.remove(cacheEntryListenerConfiguration); if (registrationId != null) { Closeable closeable = closeableListeners.remove(registrationId); IOUtil.closeResource(closeable); } return registrationId; } 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 = getContext().getListenerService(); for (String regId : listenerRegistrations) { listenerService.deregisterListener(regId); } } @Override protected void closeListeners() { deregisterAllCacheEntryListener(syncListenerRegistrations.values()); deregisterAllCacheEntryListener(asyncListenerRegistrations.values()); syncListenerRegistrations.clear(); asyncListenerRegistrations.clear(); notifyAndClearSyncListenerLatches(); for (Closeable closeable : closeableListeners.values()) { IOUtil.closeResource(closeable); } } 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 (!getContext().isActive()) { throw new HazelcastClientNotActiveException("Client is not active."); } 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) { currentThread().interrupt(); 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 handleCacheEventV10(int type, Collection keys, int completionId) { adaptor.handle(type, keys, completionId); } @Override public void beforeListenerRegister() { } @Override public void onListenerRegister() { } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy