com.chinamobile.bcbsp.comm.RPCSender.java Source code

Java tutorial

Introduction

Here is the source code for com.chinamobile.bcbsp.comm.RPCSender.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.chinamobile.bcbsp.comm;

import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.chinamobile.bcbsp.api.Combiner;
import com.chinamobile.bcbsp.util.BSPJobID;

/**
 * A sender belongs to a communicator, for sending messages from the outgoing
 * queues. This is the real thread for controlling of the message. Itself has
 * some control signal, the control sends instances of specific state.
 */
public class RPCSender extends Thread implements CombineSenderInterface {
    /** class logger. */
    private static final Log LOG = LogFactory.getLog(RPCSender.class);
    /** time change. */
    private static final float TIME_CHANGE = 1000f;
    /** the time of send messages connection. */
    private Long connectTime = 0L;
    /** Clock of send time. */
    private Long sendTime = 0L;
    /** flag of RPC sender condition controller. */
    private boolean condition = false;
    /** BSP Job ID. */
    private BSPJobID jobID = null;
    /** message counter. */
    private int messageCount = 0;
    /** message byte counter. */
    private long messageBytesCount = 0;
    /** the communication tool for BSP. */
    private RPCCommunicator communicator = null;
    /** message Queues. */
    private MessageQueuesInterface messageQueues = null;
    /** thread pool of sender. */
    private RPCSendSlavePool rpcSlavePool = null;
    /** the flag of combine. */
    private boolean combinerFlag = false;
    /** combiner of sender. */
    private Combiner combiner = null;
    /** the combine tool of sender to combine for outgoing queues. */
    private CombinerTool combinerTool = null;
    // some controll params
    /** the threshold of combine. */
    private int combineThreshold;
    /** the threshold of sender. */
    private int sendThreshold;
    /** message package size. */
    private int packSize;
    /** max number of job producer. */
    private int maxSlaveNum;
    /** the flag of no more message, if true thread sleep. */
    private boolean noMoreMessagesFlag = false;
    /** the flag of send complete. */
    private volatile boolean completed = false;
    /** the flag for a super step. */
    private volatile boolean over = false;
    /** The superstep counter current progress. */
    private volatile int superStepCounter = 0;
    /** staff ID for test. */
    private String staffId;

    /**
     * Constructor of RPC Sender.
     * @param comm
     */
    public RPCSender(RPCCommunicator comm) {
        this.communicator = comm;
        this.sendThreshold = this.communicator.getJob().getSendThreshold();
        this.packSize = this.communicator.getJob().getMessagePackSize();
        this.jobID = this.communicator.getBSPJobID();
        this.messageQueues = this.communicator.getMessageQueues();
        this.combinerFlag = this.communicator.isSendCombineSetFlag();
        // Get the combiner from the communicator.
        if (combinerFlag) {
            this.combiner = this.communicator.getCombiner();
            this.combineThreshold = this.communicator.getJob().getSendCombineThreshold();
        }
        this.maxSlaveNum = this.communicator.getJob().getMaxProducerNum();
        this.superStepCounter = 0;
    }

    /**
     * To tell the consumer tool that there are no more messages for it.
     * @param flag
     */
    public void setNoMoreMessagesFlag(boolean flag) {
        this.noMoreMessagesFlag = flag;
    }

    /**
     * Get the flag of noMoreMessagesFlag.
     * @return boolean
     */
    public boolean getNoMoreMessagesFlag() {
        return this.noMoreMessagesFlag;
    }

    /**
     * Set the sendThreshold.
     * @param aSendThreshold
     */
    public void setSendThreshold(int aSendThreshold) {
        if (this.sendThreshold == 0) {
            this.sendThreshold = aSendThreshold;
        }
    }

    /**
     * Set the sendThreshold.
     * @param aSendThreshold
     */
    public void setCombineThreshold(int aCombineThreshold) {
        if (this.combineThreshold == 0) {
            this.combineThreshold = aCombineThreshold;
        }
    }

    /**
     * Set the packSize of message.
     * @param size
     */
    public void setMessagePackSize(int size) {
        if (this.packSize == 0) {
            this.packSize = size;
        }
    }

    /**
     * Set the packSize of message.
     * @param size
     */
    public void setMaxProducerNum(int num) {
        if (this.maxSlaveNum == 0) {
            this.maxSlaveNum = num;
        }
    }

    /**
     * Add the time of connectTime.
     * @param size
     */
    public void addConnectTime(long time) {
        synchronized (this.connectTime) {
            this.connectTime += time;
        }
    }

    /**
     * Add the time of sendTime.
     * @param size
     */
    public void addSendTime(long time) {
        synchronized (this.sendTime) {
            this.sendTime += time;
        }
    }

    /**
     * Show the initialization information of sender. initialize the rpcSlavePool.
     */
    private void initialize() {
        LOG.info("========== Initialize Sender ==========");
        LOG.info("[Send Threshold] = " + this.sendThreshold);
        LOG.info("[Message Pack Size] = " + this.packSize);
        if (this.combinerFlag) {
            LOG.info("[Combine Threshold for sending] = " + this.combineThreshold);
        }
        LOG.info("[Max Slave Number] = " + this.maxSlaveNum);
        LOG.info("=======================================");
        this.rpcSlavePool = new RPCSendSlavePool(this.maxSlaveNum, this.jobID.toString());
    }

    /**
     * Begin the sender's task for a super step. ???sender
     * @param superStepCount
     */
    public void begin(int superStepCount) {
        this.superStepCounter = superStepCount;
        if (this.rpcSlavePool == null) {
            this.rpcSlavePool = new RPCSendSlavePool(this.maxSlaveNum, this.jobID.toString());
            LOG.error("Test Null this.producePool is null and it is re-initialized");
        }
        this.rpcSlavePool.setActiveSlaveProgress(superStepCount);
        this.rpcSlavePool.cleanFailedSlave();
        this.noMoreMessagesFlag = false;
        this.over = false;
        this.messageCount = 0;
        this.messageBytesCount = 0L;
        // sender ?
        synchronized (this) {
            this.condition = true;
            notify();
        }
    }

    /**
     * Justify if the sender has finished the task for the current super step.
     * @return over
     */
    public boolean isOver() {
        return this.over;
    }

    /**
     * To notice the sender to complete and return.
     */
    public void complete() {
        this.rpcSlavePool.completeAll();
        this.completed = true;
        synchronized (this) {
            this.condition = true;
            notify();
        }
    }

    /** Run method of Sender Thread. */
    public void run() {
        try {
            LOG.info("[RPCSender] starts successfully!");
            this.initialize();
            synchronized (this) {
                try {
                    while (!this.condition) {
                        wait();
                    }
                    this.condition = false;
                } catch (InterruptedException e) {
                    LOG.error("[RPCSender] caught: ", e);
                }
            }
            do {
                LOG.info("[RPCSender] begins to work for super step <" + this.superStepCounter + ">!");
                LOG.info("this.messageQueues.getNextOutgoingQueueIndex(); "
                        + this.messageQueues.getNextOutgoingQueueIndex());
                this.connectTime = 0L;
                /** Clock */
                this.sendTime = 0L;
                /** Clock */
                RPCSingleSendSlave slave = null;
                if (combinerFlag && !this.noMoreMessagesFlag) {
                    this.combinerTool = new CombinerTool(this, messageQueues, combiner, combineThreshold);
                    this.combinerTool.start();
                }
                String outgoingIndex = null;
                ConcurrentLinkedQueue<IMessage> maxQueue = null;
                int maxSize = 0;
                while (true) {
                    // and no more messages will come.
                    maxSize = 0;
                    maxQueue = null;
                    // outgoingIndex = this.messageQueues.getMaxOutgoingQueueIndex();
                    outgoingIndex = this.messageQueues.getNextOutgoingQueueIndex();
                    if (outgoingIndex != null) {
                        maxSize = this.messageQueues.getOutgoingQueueSize(outgoingIndex);
                    }
                    // When the whole outgoingQueues are empty and no more messages will
                    // come, exit while.
                    if (outgoingIndex == null) {
                        if (this.noMoreMessagesFlag) {
                            if (this.messageQueues.getOutgoingQueuesSize() > 0) {
                                continue;
                            }
                            if (!this.combinerFlag) {
                                /** no more messages and no combiner set */
                                LOG.info("[RPCSender] exits while for no more messages " + "and no combiner set.");
                                break;
                            } else {
                                if (this.combinerTool == null) {
                                    /** no more messages and no combiner created */
                                    LOG.info("[RPCSender] exits while for no more messages "
                                            + "and no combiner created.");
                                    break;
                                } else if (!this.combinerTool.isAlive()) {
                                    /** no more messages and combiner has exited */
                                    LOG.info("[Sender] exits while for no more messages "
                                            + "and combiner has exited.");
                                    break;
                                }
                            }
                        } else {
                            try {
                                Thread.sleep(500);
                            } catch (Exception e) {
                                LOG.error("[Sender] caught: ", e);
                            }
                            continue;
                        }
                    } else if (maxSize > this.sendThreshold || this.noMoreMessagesFlag) {
                        // Get a producer tool to send the maxQueue
                        slave = this.rpcSlavePool.getSlave(outgoingIndex, this.superStepCounter, this);
                        if (slave.isIdle()) {
                            // Get the queue out of the map.
                            maxQueue = this.messageQueues.removeOutgoingQueue(outgoingIndex);
                            if (maxQueue == null) {
                                continue;
                            }
                            maxSize = maxQueue.size();
                            // add by chen
                            for (IMessage m : maxQueue) {
                                this.messageBytesCount += m.size();
                            }
                            slave.setPackSize(this.packSize);
                            LOG.info("current slave id is " + slave.getId());
                            LOG.info("NOW senderSlave will sender messageQueue and size = " + maxSize);
                            slave.setStaffId(this.staffId);
                            slave.addMessages(maxQueue);
                            this.messageCount += maxSize;
                            // Set the producer's state to busy to start it.
                            slave.setIdle(false);
                        }
                        if (slave.isFailed()) {
                            this.messageQueues.removeOutgoingQueue(outgoingIndex);
                        }
                    }
                } // while
                LOG.info("[RPCSender] has started " + this.rpcSlavePool.getSlaveCount() + " slaves totally.");
                // Tell all producers that no more messages.
                this.rpcSlavePool.finishAll();
                // sender???????
                while (true) { // Wait for the producers finish message sending.
                    int running = this.rpcSlavePool.getActiveSlaveCount(this.superStepCounter);
                    LOG.info("[RPCSender] There are still <" + running + "> RPCSendSlaves alive.");
                    if (running == 0) {
                        break;
                    }
                    try {
                        Thread.sleep(500);
                    } catch (Exception e) {
                        LOG.error("[Sender] caught: ", e);
                    }
                } // while
                  // add by chen
                this.communicator.setCombineOutgoMessageCounter(this.messageCount);
                this.communicator.setCombineOutgoMessageBytesCounter(messageBytesCount);
                LOG.info("[RPCSender] has sent " + this.messageCount + " messages totally for super step <"
                        + this.superStepCounter + ">! And enter waiting......");
                LOG.info("[==>Clock<==] <RPCSender's create connection> used " + this.connectTime / TIME_CHANGE
                        + " seconds");
                /** Clock */
                LOG.info("[==>Clock<==] <RPCSender's send messages> used " + this.sendTime / TIME_CHANGE
                        + " seconds");
                /** Clock */
                this.over = true;
                synchronized (this) {
                    try {
                        while (!this.condition) {
                            wait();
                        }
                        this.condition = false;
                    } catch (InterruptedException e) {
                        LOG.error("[RPCSender] caught: ", e);
                    }
                }
            } while (!this.completed);
            LOG.info("[PRCSender] exits.");
        } catch (Exception e) {
            LOG.error("RPCSender caught: ", e);
        }
    }

    /**
     * Get the staffId.
     * @return String
     */
    public String getStaffId() {
        return staffId;
    }

    /**
     * Set the staffId.
     * @param staffId
     */
    public void setStaffId(String staffId) {
        this.staffId = staffId;
    }

    public int getSuperStepCounter() {
        return superStepCounter;
    }

    public void setSuperStepCounter(int superStepCounter) {
        this.superStepCounter = superStepCounter;
    }

    public boolean isCondition() {
        return condition;
    }

    public void setCondition(boolean condition) {
        this.condition = condition;
    }

}