Package org.goldenorb.queue

Source Code of org.goldenorb.queue.OutboundMessageQueue

/**
* Licensed to Ravel, Inc. under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  Ravel, Inc. 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 org.goldenorb.queue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.hadoop.io.Writable;
import org.goldenorb.Message;
import org.goldenorb.Messages;
import org.goldenorb.OrbPartitionCommunicationProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This class constructs an OutboundMessageQueue which collects Messages to be sent out to other partitions
* once a certain number has been collected.
*
*/
public class OutboundMessageQueue {
  private Logger omqLogger;
 
  private int numberOfPartitions;
  private int maxMessages;
  private Map<Integer,OrbPartitionCommunicationProtocol> orbClients;
  private Class<? extends Message<? extends Writable>> messageClass;
  private int partitionId;
 
  PartitionMessagingObject pmo;
 
  /**
   * This constructs the OutboundMessageQueue and creates the underlying data structures to be sent to a
   * PartitionMessagingObject.
   *
   * @param numberOfPartitions
   *          - the number of partitions to be used in the Job
   * @param maxMessages
   *          - the maximum number of messages to be queued up before a send operation
   * @param orbClients
   *          - a Map of the communication protocol used by each Orb client
   * @param messageClass
   *          - the type of Message to be queued. User-defined by extension of Message
   * @param partitionId
   *          - the ID of the partition that creates and owns this OutboundMessageQueue
   */
  public OutboundMessageQueue(int numberOfPartitions,
                              int maxMessages,
                              Map<Integer,OrbPartitionCommunicationProtocol> orbClients,
                              Class<? extends Message<? extends Writable>> messageClass,
                              int partitionId) {
    omqLogger = LoggerFactory.getLogger(OutboundMessageQueue.class);
   
    this.numberOfPartitions = numberOfPartitions;
    this.maxMessages = maxMessages;
    this.orbClients = orbClients;
    this.messageClass = messageClass;
    this.partitionId = partitionId;
   
    List<Map<String,List<Message<? extends Writable>>>> partitionMessageMapsList;
    List<Integer> partitionMessageCounter;
   
    // creates a HashMap<Vertex,Message List> for each outbound partition
    partitionMessageMapsList = new ArrayList<Map<String,List<Message<? extends Writable>>>>(
        numberOfPartitions);
    for (int i = 0; i < numberOfPartitions; i++) {
      partitionMessageMapsList.add(Collections
          .synchronizedMap(new HashMap<String,List<Message<? extends Writable>>>()));
    }
   
    // initializes a message counter for each outbound partition
    partitionMessageCounter = new ArrayList<Integer>(numberOfPartitions);
    for (int i = 0; i < numberOfPartitions; i++) {
      partitionMessageCounter.add(0);
    }
   
    this.pmo = new PartitionMessagingObject(partitionMessageMapsList, partitionMessageCounter);
  }
 
  /**
   * This method queues up a Message to be sent. Once the Message count reaches the maximum number, it sends
   * the vertices via Hadoop RPC.
   *
   * @param m
   *          - a Message to be sent
   */
  public void sendMessage(Message<? extends Writable> m) {
    synchronized (pmo) {
      // get the HashMap bin that is unique to the DestinationVertex
      int messageHash = Math.abs(m.getDestinationVertex().hashCode()) % numberOfPartitions;
      Map<String,List<Message<? extends Writable>>> currentPartition = pmo.partitionMessageMapsList
          .get(messageHash);
     
      Integer messageCounter;
      synchronized (pmo.partitionMessageCounter) {
        synchronized (currentPartition) {
          messageCounter = pmo.partitionMessageCounter.get(messageHash);
          messageCounter++; // increment the message counter
          pmo.partitionMessageCounter.set(messageHash, messageCounter);
        }
       
        // if Vertex exists as a key, add the Message
        // else create a new synchronized list for the key on demand, then put the list in the map
        if (currentPartition.containsKey(m.getDestinationVertex())) {
          currentPartition.get(m.getDestinationVertex()).add(m);
        } else {
          List<Message<? extends Writable>> messageList = Collections
              .synchronizedList(new ArrayList<Message<? extends Writable>>());
          messageList.add(m);
          currentPartition.put(m.getDestinationVertex(), messageList);
        }
       
        // once the expected number of messages is met, begins the message sending operation
        if (messageCounter >= maxMessages) {
          Messages messagesToBeSent = new Messages(messageClass);
         
          // collects the messages associated to each key and adds them to a Messages object to be sent
          for (Collection<Message<? extends Writable>> ms : currentPartition.values()) {
            for (Message<? extends Writable> message : ms) {
              messagesToBeSent.add(message);
            }
          }
         
          // logger stuff
          omqLogger
              .info(this.toString() + " Partition: " + Integer.toString(partitionId)
                    + "Sending bulk messages. Count: " + messageCounter + ", " + messagesToBeSent.size());
          omqLogger.info(messageClass.getName());
         
          // sends the Messages to the partition as specified over RPC, then creates a fresh, empty Map in its
          // place
          orbClients.get(messageHash).sendMessages(messagesToBeSent);
          pmo.partitionMessageMapsList.set(messageHash,
            Collections.synchronizedMap(new HashMap<String,List<Message<? extends Writable>>>()));
          pmo.partitionMessageCounter.set(messageHash, new Integer(0)); // reset counter to 0
        }
      }
    }
  }
 
  /**
   * Sends any remaining messages if the maximum number of messages is not met.
   */
  public void sendRemainingMessages() {
   
    for (int partitionID = 0; partitionID < numberOfPartitions; partitionID++) {
      Messages messagesToBeSent = new Messages(messageClass);
     
      for (Collection<Message<? extends Writable>> ms : pmo.partitionMessageMapsList.get(partitionID)
          .values()) {
        for (Message<? extends Writable> message : ms) {
          messagesToBeSent.add(message);
        }
      }
     
      if (messagesToBeSent.size() > 0) {
        omqLogger.info("Partition {} sending bulk messages.  Count: " + pmo.partitionMessageCounter.get(partitionID) + ", "
                       + messagesToBeSent.size(), partitionID);
        orbClients.get(partitionID).sendMessages(messagesToBeSent);
      }
      else {
        omqLogger.debug("No messages to be sent from Partition {}", partitionID);
      }
    }
  }
 
  /**
   * This inner class defines a PartitionMessagingObject, which is used strictly to encapsulate
   * partitionMessageMapsList and partitionMessageCounter into one object for synchronization purposes.
   *
   */
  class PartitionMessagingObject {
   
    List<Map<String,List<Message<? extends Writable>>>> partitionMessageMapsList;
    List<Integer> partitionMessageCounter;
   
    /**
     * Constructor
     *
     * @param partitionMessageMapsList
     * @param partitionMessageCounter
     */
    public PartitionMessagingObject(List<Map<String,List<Message<? extends Writable>>>> partitionMessageMapsList,
                                    List<Integer> partitionMessageCounter) {
      this.partitionMessageMapsList = partitionMessageMapsList;
      this.partitionMessageCounter = partitionMessageCounter;
    }
   
    /**
     * Return the mapsList.
     */
    public List<Map<String,List<Message<? extends Writable>>>> getMapsList() {
      return partitionMessageMapsList;
    }
   
    /**
     * Return the messageCounter.
     */
    public List<Integer> getMessageCounter() {
      return partitionMessageCounter;
    }
   
  }
}
TOP

Related Classes of org.goldenorb.queue.OutboundMessageQueue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.