/** * CopyRight by Chinamobile * * Communicator.java */ package com.chinamobile.bcbsp.comm; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.Text; import org.apache.hadoop.util.ReflectionUtils; import com.chinamobile.bcbsp.Constants; import com.chinamobile.bcbsp.api.Combiner; import com.chinamobile.bcbsp.api.Partitioner; import com.chinamobile.bcbsp.graph.GraphDataInterface; import com.chinamobile.bcbsp.util.BSPJob; import com.chinamobile.bcbsp.util.BSPJobID; /** * Communicator * * The communication tool for BSP. It manages the outgoing and incoming queues * of each staff. * * @author * @version */ public class Communicator implements CommunicatorInterface { private static final Log LOG = LogFactory.getLog(Communicator.class); private BSPJobID jobID = null; private BSPJob job = null; private int partitionID = 0; private GraphDataInterface graphData = null; private Sender sender = null; private Receiver receiver = null; /** Route Table: HashID---PartitionID */ private HashMap<Integer, Integer> hashBucketToPartition = null; /** Route Table: PartitionID---WorkerManagerNameAndPort(HostName:Port) */ private HashMap<Integer, String> partitionToWorkerManagerNameAndPort = null; /** The message queues manager */ private MessageQueuesInterface messageQueues = null; private Partitioner<Text> partitioner; // Sending message counter for a super step. private long sendMessageCounter; // Outgoing message counter for a super step. private long outgoMessageCounter; /** * Constructor */ public Communicator(BSPJobID jobID, BSPJob job, int partitionID, Partitioner<Text> partitioner) { this.jobID = jobID; this.job = job; this.partitionID = partitionID; this.partitioner = partitioner; this.sendMessageCounter = 0; this.outgoMessageCounter = 0; int version = job.getMessageQueuesVersion(); if (version == job.MEMORY_VERSION) { this.messageQueues = new MessageQueuesForMem(); }else if (version == job.DISK_VERSION) { this.messageQueues = new MessageQueuesForDisk(job, partitionID); }else if (version == job.BDB_VERSION) { this.messageQueues = new MessageQueuesForBDB(job, partitionID); } } /** * Initialize the communicator * * @param ahashBucketToPartition * @param aPartitionToWorkerManagerNameAndPort * @param aGraphData */ @Override public void initialize(HashMap<Integer, Integer> ahashBucketToPartition, HashMap<Integer, String> aPartitionToWorkerManagerNameAndPort, GraphDataInterface aGraphData) { this.hashBucketToPartition = ahashBucketToPartition; this.partitionToWorkerManagerNameAndPort = aPartitionToWorkerManagerNameAndPort; this.graphData = aGraphData; } public void setBSPJobID(BSPJobID jobID) { this.jobID = jobID; } public BSPJobID getBSPJobID() { return this.jobID; } public BSPJob getJob() { return job; } public void setJob(BSPJob job) { this.job = job; } public void setPartitionID(int partitionID) { this.partitionID = partitionID; } public int getPartitionID() { return this.partitionID; } public MessageQueuesInterface getMessageQueues() { return this.messageQueues; } /** * Get the dstPartitionID from the vertexID. * * @param vertexID * @return dstPartitionID */ @SuppressWarnings("unused") private int getDstPartitionID(int vertexID) { int dstPartitionID = 0; for (Entry<Integer, Integer> e : this.hashBucketToPartition.entrySet()) { List<Integer> rangeList = new ArrayList<Integer>(e.getValue()); if ((vertexID <= rangeList.get(1)) && (vertexID >= rangeList.get(0))) { dstPartitionID = e.getKey(); // destination partition id break; } } return dstPartitionID; } /** * Get the dstWorkerManagerName from the dstPartitionID * * @param dstPartitionID * @return dstWorkerManagerName */ private String getDstWorkerManagerNameAndPort(int dstPartitionID) { String dstWorkerManagerNameAndPort = null; dstWorkerManagerNameAndPort = this.partitionToWorkerManagerNameAndPort .get(dstPartitionID); return dstWorkerManagerNameAndPort; } @Override public void setPartitionToWorkerManagerNamePort(HashMap<Integer, String> value) { this.partitionToWorkerManagerNameAndPort = value; } /* * (non-Javadoc) * * @see * com.chinamobile.bcbsp.comm.CommunicatorInterface#GetMessageIterator(java * .lang.String) */ @Override public Iterator<BSPMessage> getMessageIterator(String vertexID) throws IOException { ConcurrentLinkedQueue<BSPMessage> incomedQueue = messageQueues .removeIncomedQueue(vertexID); Iterator<BSPMessage> iterator = incomedQueue.iterator(); return iterator; } /* * (non-Javadoc) * * @see * com.chinamobile.bcbsp.comm.CommunicatorInterface#GetMessageQueue(java * .lang.String) */ @Override public ConcurrentLinkedQueue<BSPMessage> getMessageQueue(String vertexID) throws IOException { return messageQueues.removeIncomedQueue(vertexID); } /* * (non-Javadoc) * * @see * com.chinamobile.bcbsp.comm.CommunicatorInterface#Send(java.lang.String, * com.chinamobile.bcbsp.bsp.BSPMessage) */ @Override public void send(BSPMessage msg) throws IOException { Text vertexID=new Text(msg.getDstVertexID()); int dsthashID = this.partitioner.getPartitionID(vertexID); int dstPartitionID = -1; if (this.hashBucketToPartition != null) dstPartitionID = this.hashBucketToPartition.get(dsthashID); else dstPartitionID = dsthashID; msg.setDstPartition(dstPartitionID); // The destination partition is just in this staff. if (dstPartitionID == this.partitionID) { String dstVertexID = msg.getDstVertexID(); messageQueues.incomeAMessage(dstVertexID, msg); } else { String dstWorkerManagerNameAndPort = this .getDstWorkerManagerNameAndPort(dstPartitionID); String outgoingIndex = dstWorkerManagerNameAndPort; messageQueues.outgoAMessage(outgoingIndex, msg); this.outgoMessageCounter ++; } this.sendMessageCounter ++; } @Override public void sendToAllEdges(BSPMessage msg) throws IOException { } @Override public void clearAllQueues() { messageQueues.clearAllQueues(); } @Override public void clearOutgoingQueues() { messageQueues.clearOutgoingQueues(); } @Override public void clearIncomingQueues() { messageQueues.clearIncomingQueues(); } @Override public void clearIncomedQueues() { messageQueues.clearIncomedQueues(); } @Override public void exchangeIncomeQueues() { messageQueues.showMemoryInfo(); messageQueues.exchangeIncomeQueues(); LOG.info("[Communicator] has sent " + this.sendMessageCounter + " messages totally."); LOG.info("[Communicator] has outgo " + this.outgoMessageCounter + " messages totally."); this.sendMessageCounter = 0; this.outgoMessageCounter = 0; } @Override public int getOutgoingQueuesSize() { return messageQueues.getOutgoingQueuesSize(); } @Override public int getIncomingQueuesSize() { return messageQueues.getIncomingQueuesSize(); } @Override public int getIncomedQueuesSize() { return messageQueues.getIncomedQueuesSize(); } @Override public void start() { int edgeSize = this.graphData.getEdgeSize(); this.sender = new Sender(this); this.sender.setCombineThreshold((int)(edgeSize*0.4/10)); this.sender.setSendThreshold((int)(edgeSize*0.4/10)); this.sender.setMessagePackSize(1000); this.sender.setMaxProducerNum(20); this.sender.start(); } @Override public void noMoreMessagesForSending() { // To notify the sender no more // messages for sending. this.sender.setNoMoreMessagesFlag(true); } @Override public boolean isSendingOver() { boolean result = false; if (this.sender.isOver()) { result = true; } return result; } @Override public void noMoreMessagesForReceiving() { // To notify the receiver no more // messages for receiving. this.receiver.setNoMoreMessagesFlag(true); } @Override public boolean isReceivingOver() { boolean result = false; if (!this.receiver.isAlive()) { // When the receiver is not alive, // return true. result = true; } return result; } public boolean isSendCombineSetFlag() { return this.job.isCombinerSetFlag(); } public boolean isReceiveCombineSetFlag() { return this.job.isReceiveCombinerSetFlag(); } public Combiner getCombiner() { if (this.job != null) { return ( Combiner ) ReflectionUtils.newInstance( job.getConf().getClass( Constants.USER_BC_BSP_JOB_COMBINER_CLASS, Combiner.class), job.getConf()); } else return null; } @Override public void begin(int superStepCount) { String localhostNameAndPort = this.getDstWorkerManagerNameAndPort(this.partitionID); String brokerName = localhostNameAndPort.split(":")[0] + "-" + this.partitionID; this.receiver = new Receiver(this, brokerName); this.receiver.setCombineThreshold(8); this.receiver.start(); this.sender.begin(superStepCount); } @Override public void complete() { this.sender.complete(); } }