package org.infinispan.server.hotrod;
import java.util.List;
import java.util.stream.Collectors;
import org.infinispan.Cache;
import org.infinispan.commons.logging.LogFactory;
import org.infinispan.context.Flag;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged;
import org.infinispan.notifications.cachemanagerlistener.event.ViewChangedEvent;
import org.infinispan.remoting.transport.Address;
import org.infinispan.server.hotrod.logging.Log;
/**
* Listener that detects crashed or stopped members and removes them from the address cache.
*
* @author Galder ZamarreƱo
* @since 5.1
*/
@Listener(sync = false)
// Use a separate thread to avoid blocking the view handler thread
class CrashedMemberDetectorListener {
private final Cache<Address, ServerAddress> addressCache;
private final HotRodServer server;
private static final Log log = LogFactory.getLog(CrashedMemberDetectorListener.class, Log.class);
CrashedMemberDetectorListener(Cache<Address, ServerAddress> cache, HotRodServer server) {
// Let all nodes remove the address from their own cache locally.
// This will exclude the address from their topology updates.
this.addressCache = cache.getAdvancedCache().withFlags(Flag.CACHE_MODE_LOCAL);
this.server = server;
}
@ViewChanged
public void handleViewChange(ViewChangedEvent e) {
detectCrashedMember(e);
}
void detectCrashedMember(ViewChangedEvent e) {
try {
if (addressCache.getStatus().allowInvocations()) {
List<Address> goneMembers = e.getOldMembers().stream().filter(o -> !e.getNewMembers().contains(o)).collect(Collectors.toList());
log.tracef("View change received: %s, removing members %s", e, goneMembers);
// Consider doing removeAsync and then waiting for all removals...
goneMembers.forEach(addressCache::remove);
}
} catch (Throwable t) {
log.errorDetectingCrashedMember(t);
}
}
}