/** * CopyRight by Chinamobile * * ProducerPool.java */ package com.chinamobile.bcbsp.comm; import java.util.ArrayList; import java.util.HashMap; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * ProducerTools Pool * * @author Bai Qiushi * @version 1.0 2012-3-29 */ public class ProducerPool extends ThreadGroup { // For log private static final Log LOG = LogFactory.getLog(ProducerPool.class); private int nextSerialNumber = 0; private int maxProducerNum; @SuppressWarnings("unused") private String jobID; /** HostName:Port--ProducerTool */ private HashMap<String, ProducerTool> producers = null; public ProducerPool(int maxNum, String jobID) { super("ProducerTools Pool"); this.maxProducerNum = maxNum; this.jobID = jobID; this.producers = new HashMap<String, ProducerTool>(); } /** * Tell all producers no more messages to finish them. */ public void finishAll() { Thread[] producers = getAllThread(); for (int i = 0; i < producers.length; i++) { if (!(producers[i] instanceof ProducerTool)) { continue; } ProducerTool p = (ProducerTool) producers[i]; p.setNoMoreMessagesFlag(true); } } public void completeAll() { Thread[] producers = getAllThread(); for (int i = 0; i < producers.length; i++) { if (!(producers[i] instanceof ProducerTool)) { continue; } ProducerTool p = (ProducerTool) producers[i]; p.complete(); } } /** * @param superStepCount * @return The number of ProducerTool that are alive. */ public int getActiveProducerCount(int superStepCount) { Thread[] producers = getAllThread(); int count = 0; for (int i = 0; i < producers.length; i++) { if ((producers[i] instanceof ProducerTool) && ((ProducerTool) producers[i]).getProgress() < superStepCount) { count++; } } return count; } public void setActiveProducerProgress(int superStepCount) { Thread[] producers = getAllThread(); for (int i = 0; i < producers.length; i++) { try { if (producers[i] instanceof ProducerTool) { ((ProducerTool) producers[i]).setProgress(superStepCount); } } catch (Exception e) { // Ingore this. } } } public void cleanFailedProducer() { ArrayList<String> failRecord = new ArrayList<String>(); for (Entry<String, ProducerTool> entry: this.producers.entrySet()) { if (entry.getValue().isFailed()) { failRecord.add(entry.getKey()); } } for (String str: failRecord) { this.producers.remove(str); } } /** * @return The number of ProducerTool. This may include killed Threads that * were not replaced. */ public int getProducerCount() { Thread[] producers = getAllThread(); int count = 0; for (int i = 0; i < producers.length; i++) { if ((producers[i] instanceof ProducerTool)) { count++; } } return count; } /** * Obtain a free ProducerTool to send messages. * Give preference to the ProducerTool for the same destination. * * @param hostNameAndPort * @param superStepCount * @param sender * @return ProducerTool */ public ProducerTool getProducer(String hostNameAndPort, int superStepCount, Sender sender) { ProducerTool pt = null; if (producers.containsKey(hostNameAndPort)) { pt = producers.get(hostNameAndPort); } else { int count = this.getActiveProducerCount(superStepCount-1); if (count < this.maxProducerNum) { pt = startNewProducer(hostNameAndPort, superStepCount, sender); this.producers.put(hostNameAndPort, pt); } else { while ((pt = getAnIdleProducer()) == null) { try { LOG.info("[ProducerPool] is sleeping to wait to get an idle producer..."); Thread.sleep(100); } catch (InterruptedException e) { LOG.error("[ProducerPool] caught: ", e); return null; } } pt.setHostNameAndPort(hostNameAndPort); } } return pt; } /** * get all threads in pool. * * @return */ private Thread[] getAllThread() { Thread[] threads = new Thread[activeCount()]; this.enumerate(threads); return threads; } /** * get an idle producer. * @return ProduerTool or null when no one is idle. */ private ProducerTool getAnIdleProducer() { ProducerTool pt = null; Thread[] producers = getAllThread(); for (int i = 0; i < producers.length; i ++) { if (producers[i] instanceof ProducerTool) { ProducerTool p = (ProducerTool) producers[i]; if (p.isIdle()) { pt = p; return pt; } } } return pt; } /** * Create a new ProducerTool * @param hostNameAndPort * @param superStepCount */ private synchronized ProducerTool startNewProducer(String hostNameAndPort, int superStepCount, Sender sender) { ProducerTool newProducer = new ProducerTool(this, this.nextSerialNumber++, null, hostNameAndPort, "BSP", sender); newProducer.setProgress(superStepCount); newProducer.start(); LOG.info("[ProducerPool] has started a new ProducerTool to: " + hostNameAndPort); return newProducer; } }