package com.rayo.storage.lb; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import com.rayo.server.storage.GatewayStorageService; import com.rayo.server.storage.model.RayoNode; import com.voxeo.logging.Loggerf; /** * <p>A default round robin based load balancer.</p> * * @author martin * */ public class RoundRobinLoadBalancer extends BlacklistingLoadBalancer { private Loggerf log = Loggerf.getLogger(RoundRobinLoadBalancer.class); private Map<String,String> lastClients = new ConcurrentHashMap<String,String>(); private Map<String,RayoNode> lastNodes = new ConcurrentHashMap<String,RayoNode>(); private static final long DEFAULT_CLEANING_INTERVAL = 1000 * 60 * 30; // default cleaning interval of 30 minutes public RoundRobinLoadBalancer() { this(DEFAULT_CLEANING_INTERVAL); } public RoundRobinLoadBalancer(long cleaningInterval) { // A cleaning thread checks each 10 minutes if clients and nodes are still active. And if // they are not then the hashmaps are cleaned up TimerTask cleaningTask = new TimerTask() { @Override public void run() { log.debug("Starting cleaning task"); List<String> activeClients = storageService.getClients(); Iterator<Map.Entry<String, String>> it = lastClients.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); if (!activeClients.contains(entry.getKey())) { log.debug("Removing client [%s] from load balancer's clients cache", entry.getKey()); it.remove(); } } } }; log.debug("Creating round robin load balancer's cleaning task"); Date nextExecution = new Date(System.currentTimeMillis() + cleaningInterval); Timer cleaningTimer = new Timer(); cleaningTimer.schedule(cleaningTask, nextExecution, cleaningInterval); } protected String getLastClient(String bareJid) { return lastClients.get(bareJid); } @Override public String pickClientResource(String bareJid) { List<String> resources = storageService.getResourcesForClient(bareJid); if (resources.isEmpty()) { return null; } String client = pickNextResource(resources, bareJid); if (client != null) { lastClients.put(bareJid,client); } return client; } private String pickNextResource(List<String> resources, String bareJid) { String lastClient = lastClients.get(bareJid); String client = lastClient; boolean found = false; do { int i = resources.indexOf(client); if (i == resources.size() -1) { i = -1; } client = resources.get(i+1);// when not found, 0 will be returned if (lastClient == null) { lastClient = client; } if (validClient(bareJid+"/"+client)) { found = true; break; } } while (!client.equals(lastClient)); if (!found) return null; return client; } @Override public RayoNode pickRayoNode(String platformId) { List<RayoNode> nodes = storageService.getRayoNodes(platformId); if (nodes.isEmpty()) { return null; } RayoNode node = pickNextNode(nodes, platformId); if (node != null) { lastNodes.put(platformId,node); } return node; } private RayoNode pickNextNode(List<RayoNode> nodes, String platformId) { RayoNode lastNode = lastNodes.get(platformId); RayoNode node = lastNode; boolean found = false; do { int i = nodes.indexOf(node); if (i == nodes.size() -1) { i = -1; } node = nodes.get(i+1); // when not found, 0 will be returned if (lastNode == null) { lastNode = node; } if (valid(node)) { found = true; break; } } while (!node.equals(lastNode)); if (!found) return null; return node; } public void setStorageService(GatewayStorageService storageService) { this.storageService = storageService; } }