/** * CopyRight by Chinamobile * * CombinerTool.java */ package com.chinamobile.bcbsp.comm; import java.util.HashMap; import java.util.Iterator; import java.util.TreeMap; import java.util.Map.Entry; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.chinamobile.bcbsp.api.Combiner; /** * CombinerTool * * CombinerTool is a single thread belongs to a Sender, * to do combination operation for outgoing queues that * is over the sendingCombineThreshold. * * @author * @version */ public class CombinerTool extends Thread { // For log private static final Log LOG = LogFactory.getLog(CombinerTool.class); private MessageQueuesInterface messageQueues = null; private Combiner combiner = null; private int combineThreshold = 1000;//default private Sender sender = null; /** Notes the count since last combination of the queue indexed by String * so that if the new increasing count overs the threshold, we will combine them, * otherwise, do not combine them.*/ private HashMap<String, Integer> combinedCountsMap = new HashMap<String, Integer>(); public CombinerTool(Sender aSender, MessageQueuesInterface msgQueues, Combiner combiner, int threshold) { this.sender = aSender; this.messageQueues = msgQueues; this.combiner = combiner; this.combineThreshold = threshold; } public void run() { LOG.info("[CombinerTool] Start!"); long time = 0; long totalBeforeSize = 0; long totalAfterSize = 0; String outgoingIndex = null; ConcurrentLinkedQueue<BSPMessage> maxQueue = null; int maxSize = 0; int lastCount = 0; while (!this.sender.getNoMoreMessagesFlag()) { outgoingIndex = this.messageQueues.getMaxOutgoingQueueIndex(); if (outgoingIndex != null) { maxSize = this.messageQueues.getOutgoingQueueSize(outgoingIndex); } lastCount = (this.combinedCountsMap.get(outgoingIndex) == null? 0: this.combinedCountsMap.get(outgoingIndex)); // If new updated size is over the threshold if ((maxSize - lastCount) > this.combineThreshold) { // Get the queue out of the map. maxQueue = this.messageQueues.removeOutgoingQueue(outgoingIndex); if (maxQueue == null) continue; long start = System.currentTimeMillis();/**Clock*/ // Combine the messages. maxQueue = combine(maxQueue); long end = System.currentTimeMillis();/**Clock*/ time = time + end - start; int maxSizeBefore = maxSize; totalBeforeSize += maxSizeBefore; maxSize = maxQueue.size(); totalAfterSize += maxSize; // Note the count after combination. this.combinedCountsMap.put(outgoingIndex, maxQueue.size()); // Put the combined messages back to the outgoing queue. Iterator<BSPMessage> iter = maxQueue.iterator(); while (iter.hasNext()) { this.messageQueues.outgoAMessage(outgoingIndex, iter.next()); } maxQueue.clear(); } else { try { Thread.sleep(500); // Wait for 500ms until next check. } catch (Exception e) { LOG.error("[CombinerTool] caught:", e); } } } LOG.info("[CombinerTool] has combined totally (" + totalBeforeSize + ") messages into (" + totalAfterSize + "). Compression rate = " + (float)totalAfterSize*100/totalBeforeSize + "%."); LOG.info("[CombinerTool] has used time: " + time/1000f + " seconds totally!"); LOG.info("[CombinerTool] Die!"); }// end-run private ConcurrentLinkedQueue<BSPMessage> combine(ConcurrentLinkedQueue<BSPMessage> outgoingQueue) { // Map of outgoing queues indexed by destination vertex ID. TreeMap<String, ConcurrentLinkedQueue<BSPMessage>> outgoingQueues = new TreeMap<String, ConcurrentLinkedQueue<BSPMessage>>(); ConcurrentLinkedQueue<BSPMessage> tempQueue = null; BSPMessage tempMessage = null; // Traverse the outgoing queue and put the messages with the same dstVertexID into the same queue in the tree map. Iterator<BSPMessage> iter = outgoingQueue.iterator(); String dstVertexID = null; while (iter.hasNext()) { tempMessage = iter.next(); dstVertexID = tempMessage.getDstVertexID(); tempQueue = outgoingQueues.get(dstVertexID); if (tempQueue == null) { tempQueue = new ConcurrentLinkedQueue<BSPMessage>(); } tempQueue.add(tempMessage); outgoingQueues.put(dstVertexID, tempQueue); } // The result queue for return. ConcurrentLinkedQueue<BSPMessage> resultQueue = new ConcurrentLinkedQueue<BSPMessage>(); // Do combine operation for each of the outgoing queues. for (Entry<String, ConcurrentLinkedQueue<BSPMessage>> entry : outgoingQueues.entrySet()) { tempQueue = entry.getValue(); tempMessage = this.combiner.combine(tempQueue.iterator()); resultQueue.add(tempMessage); } outgoingQueue.clear(); outgoingQueues.clear(); return resultQueue; } }