package com.rayo.storage.lb; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; import com.rayo.server.storage.GatewayException; import com.rayo.server.storage.GatewayStorageService; import com.rayo.server.storage.model.RayoNode; import com.voxeo.logging.Loggerf; /** * Base class that adds blacklisting capabilities using the callback methods defined at the * {@link GatewayOperationListener} interface. * * @author martin * */ public abstract class BlacklistingLoadBalancer implements GatewayLoadBalancingStrategy, GatewayStorageServiceSupport { private static final Loggerf log = Loggerf.getLogger(BlacklistingLoadBalancer.class); GatewayStorageService storageService; private Map<String,Failure> clientErrors = new ConcurrentHashMap<String,Failure>(); /** * Number of consecutive failures allowed before blacklisting a node or resource */ private int consecutiveFailuresAllowed = 5; private ReentrantLock nodeLock = new ReentrantLock(); private ReentrantLock clientLock = new ReentrantLock(); @Override public void nodeOperationFailed(RayoNode node) { log.debug("Node operation failed. Updating rayo node [%s] error statistics", node); nodeLock.lock(); try { node.setConsecutiveErrors(node.getConsecutiveErrors()+1); valid(node); storageService.updateRayoNode(node); } catch (Exception e) { log.error(e.getMessage(),e); } finally { nodeLock.unlock(); } } @Override public void nodeOperationSuceeded(RayoNode node) { if (node.isBlackListed() || node.getConsecutiveErrors() > 0) { nodeLock.lock(); try { log.debug("Node operation suceeded. Resetting rayo node [%s] error statistics", node); node.setBlackListed(false); node.setConsecutiveErrors(0); storageService.updateRayoNode(node); } catch (GatewayException e) { log.error(e.getMessage(),e); } finally { nodeLock.unlock(); } } } boolean valid(RayoNode node) { if (node.isBlackListed()) { return false; } if (node.getConsecutiveErrors() >= consecutiveFailuresAllowed) { node.setBlackListed(true); return false; } return true; } @Override public void clientOperationFailed(String fullJid) { clientLock.lock(); try { Failure failure = clientErrors.get(fullJid); if (failure == null) { failure = new Failure(); clientErrors.put(fullJid, failure); } failure.consecutiveErrors++; failure.lastError = System.currentTimeMillis(); } finally { clientLock.unlock(); } } @Override public void clientOperationSuceeded(String fullJid) { Failure failure = clientErrors.get(fullJid); if (failure != null) { clientLock.lock(); clientErrors.remove(fullJid); clientLock.unlock(); } } boolean validClient(String fullJid) { Failure failure = clientErrors.get(fullJid); if (failure != null) { if (failure.getConsecutiveErrors() > consecutiveFailuresAllowed) { return false; } } return true; } public void setStorageService(GatewayStorageService storageService) { this.storageService = storageService; } public void setConsecutiveFailuresAllowed(int consecutiveFailuresAllowed) { this.consecutiveFailuresAllowed = consecutiveFailuresAllowed; } class Failure { int consecutiveErrors = 0; long lastError = 0; public int getConsecutiveErrors() { return consecutiveErrors; } public long getLastError() { return lastError; } } }