Package org.objectweb.joram.mom.dest

Source Code of org.objectweb.joram.mom.dest.LoadingFactor$Status

/*
* JORAM: Java(TM) Open Reliable Asynchronous Messaging
* Copyright (C) 2004 - 2010 ScalAgent Distributed Technologies
* Copyright (C) 2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
* USA.
*
* Initial developer(s): ScalAgent Distributed Technologies
* Contributor(s):
*/
package org.objectweb.joram.mom.dest;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.objectweb.joram.mom.notifications.LBMessageGive;
import org.objectweb.joram.mom.notifications.LBMessageHope;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import fr.dyade.aaa.agent.AgentId;
import fr.dyade.aaa.common.Debug;

public class LoadingFactor implements Serializable {

  /** define serialVersionUID for interoperability */
  private static final long serialVersionUID = 1L;

  /** logger */
  public static Logger logger = Debug.getLogger(LoadingFactor.class.getName());

  public static class Status {
    public final static int INIT = 0;
    public final static int RUN = 1;
    public final static int WAIT = 2;

    public final static String[] names = {"INIT", "RUN", "WAIT"};
  }

  public static class ConsumerStatus {
    public final static int CONSUMER_NO_ACTIVITY = 0;
    public final static int CONSUMER_HIGH_ACTIVITY = 1;
    public final static int CONSUMER_NORMAL_ACTIVITY = 2;

    public final static String[] names = {
                                          "CONSUMER_NO_ACTIVITY",
                                          "CONSUMER_HIGH_ACTIVITY",
                                          "CONSUMER_NORMAL_ACTIVITY"
    };
  }

  public static class ProducerStatus {
    public final static int PRODUCER_NO_ACTIVITY = 0;
    public final static int PRODUCER_HIGH_ACTIVITY = 1;
    public final static int PRODUCER_NORMAL_ACTIVITY = 2;

    public final static String[] names =  {
                                           "PRODUCER_NO_ACTIVITY",
                                           "PRODUCER_HIGH_ACTIVITY",
                                           "PRODUCER_NORMAL_ACTIVITY"
    };
  }

  /** status */
  private int status;

  /** status time */
  private long statusTime;

  /** consumer status */
  private int consumerStatus = 0;

  /** producer status */
  private int producerStatus = 0;

  /** reference to clusterQueue */
  public ClusterQueue clusterQueue;

  /** producer threshold */
  public int producThreshold = -1;

  /** consumer threshold */
  public int consumThreshold = -1;

  /** automatic eval threshold */
  public boolean autoEvalThreshold = false;

  /** validity period */
  public long validityPeriod = -1;

  private float rateOfFlow;
  private boolean overLoaded;
  private int nbOfPendingMessages;
  private int nbOfPendingRequests;

  public LoadingFactor(ClusterQueue clusterQueue,
                       int producThreshold,
                       int consumThreshold,
                       boolean autoEvalThreshold,
                       long validityPeriod) {
    this.clusterQueue = clusterQueue;
    this.producThreshold = producThreshold;
    this.consumThreshold = consumThreshold;
    this.autoEvalThreshold = autoEvalThreshold;
    this.validityPeriod = validityPeriod;
    rateOfFlow = 1;
    status = 0;
  }

  public void setRateOfFlow(float rateOfFlow) {
    this.rateOfFlow = rateOfFlow;
  }

  public float getRateOfFlow() {
    return rateOfFlow;
  }

  public String getStatus() {
    return Status.names[status];
  }

  public String getProducerStatus() {
    return ProducerStatus.names[producerStatus];
  }

  public String getConsumerStatus() {
    return ConsumerStatus.names[consumerStatus];
  }

  public void setWait() {
    status = Status.WAIT;
    statusTime = System.currentTimeMillis() + validityPeriod;
  }

  /**
   * this method eval the activity
   * of consumer and producer.
   */
  private void evalActivity() {
    if (nbOfPendingMessages == 0)
      producerStatus = ProducerStatus.PRODUCER_NO_ACTIVITY;
    else if (nbOfPendingMessages > producThreshold)
      producerStatus = ProducerStatus.PRODUCER_HIGH_ACTIVITY;
    else
      producerStatus = ProducerStatus.PRODUCER_NORMAL_ACTIVITY;

    if (nbOfPendingRequests == 0)
      consumerStatus = ConsumerStatus.CONSUMER_NO_ACTIVITY;
    else if (nbOfPendingRequests > consumThreshold)
      consumerStatus = ConsumerStatus.CONSUMER_HIGH_ACTIVITY;
    else
      consumerStatus = ConsumerStatus.CONSUMER_NORMAL_ACTIVITY;
  }

  /**
   * update the threshold if autoEvalThreshold is true.
   */
  private void updateThreshold() {
    if (autoEvalThreshold) {

      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG,
                   "LoadingFactor.updateThreshold before" +
                   " rateOfFlow=" + rateOfFlow +
                   ", producThreshold=" + producThreshold +
                   ", consumThreshold=" + consumThreshold );

      int deltaProd;
      int deltaCons;

      if (rateOfFlow < 1) {
        deltaProd = (int) ((nbOfPendingMessages - producThreshold) * rateOfFlow);
        deltaCons = (int) ((nbOfPendingRequests - consumThreshold) * rateOfFlow);
      } else {
        deltaProd = (int) ((nbOfPendingMessages - producThreshold) / rateOfFlow);
        deltaCons = (int) ((nbOfPendingRequests - consumThreshold) / rateOfFlow);
      }

      if (nbOfPendingMessages > 0) {
        if (deltaProd < producThreshold)
          producThreshold = producThreshold + deltaProd;
        else
          producThreshold = deltaProd;
      }

      if (nbOfPendingRequests > 0) {
        if (deltaCons < consumThreshold)
          consumThreshold = consumThreshold + deltaCons;
        else
          consumThreshold = deltaCons;
      }

      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG,
                   "LoadingFactor.updateThreshol after" +
                   " rateOfFlow=" + rateOfFlow +
                   ", producThreshold=" + producThreshold +
                   ", consumThreshold=" + consumThreshold );
    }
  }

  /**
   * Evaluates the average rate of flow.
   * If rateOfFlow is greater than 1 the queue are more pending requests
   * than pending messages else if rateOfFlow is lower than 1 the queue are
   * more pending messages than pending requests.
   * This value is set in all QueueClusterNot notification.
   *
   * @param pendingMessages   the number of pending messages.
   * @param pendingRequests   the number of pending requests.
   * @return the rate of flow
   */
  public float evalRateOfFlow(int pendingMessages,
                              int pendingRequests) {
    float currentROF;
    nbOfPendingMessages = pendingMessages;
    nbOfPendingRequests = pendingRequests;

    // TODO (AF): Be careful this evaluation is not really useful as either pendingMessages
    // or pendingRequests is equal to zero!
   
    if (pendingMessages == 0 && pendingRequests == 0)
      currentROF = 1;
    else if (pendingMessages == 0 && pendingRequests != 0)
      currentROF = pendingRequests + 1;
    else
      currentROF = (float) pendingRequests / (float) pendingMessages;

    rateOfFlow = (currentROF + rateOfFlow ) / 2;

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 "LoadingFactor.evalRateOfFlow" +
                 " pendingMessages = " + pendingMessages + ", pendingRequests = " + pendingRequests +
                 ", rateOfFlow = " + rateOfFlow + ", currentROF = " + currentROF);

    return rateOfFlow;
  }

  /**
   * This method evaluates the rate of flow and activity.
   * If necessary send "give" or "hope" messages, and update threshold.
   *
   * @param clusters
   * @param pendingMessages
   * @param pendingRequests
   */
  public void factorCheck(Map clusters,
                          int pendingMessages,
                          int pendingRequests) {

    nbOfPendingMessages = pendingMessages;
    nbOfPendingRequests = pendingRequests;

    if (status == Status.WAIT &&
        statusTime < System.currentTimeMillis())
      status = Status.RUN;


    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 ">> LoadingFactor.factorCheck " +
                 this + "\nclusters = " + clusters);

    evalRateOfFlow(pendingMessages, pendingRequests);

    evalActivity();

    if ( status == Status.INIT || status == Status.RUN) {
      if (isOverloaded()) {
        dispatchAndSendTo(clusters,
                          pendingMessages,
                          pendingRequests);
        status = Status.WAIT;
        statusTime = System.currentTimeMillis() + validityPeriod;
      }
    }

    updateThreshold();

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 "<< LoadingFactor.factorCheck "
                 + this);
  }

  /**
   * true if cluster queue is overloaded.
   * depends on activity.
   *
   * @return  true if cluster queue is overloaded.
   */
  public boolean isOverloaded() {
    overLoaded = false;
    if ((consumerStatus ==
      ConsumerStatus.CONSUMER_HIGH_ACTIVITY) ||
      (producerStatus ==
        ProducerStatus.PRODUCER_HIGH_ACTIVITY))
      overLoaded = true;

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 "LoadingFactor.isOverloaded "
                 + overLoaded);
    return overLoaded;
  }

  /**
   * use to dispatch request hope or give messages
   * in clusters.
   *
   * @param clusters
   * @param nbOfPendingMessages
   * @param nbOfPendingRequests
   */
  private void dispatchAndSendTo(Map clusters,
                                 int nbOfPendingMessages,
                                 int nbOfPendingRequests) {
    int nbMsgHope = -1;
    int nbMsgGive = -1;

    if ((consumerStatus == ConsumerStatus.CONSUMER_NO_ACTIVITY) &&
        (producerStatus == ProducerStatus.PRODUCER_NO_ACTIVITY))
      return;

    if (producThreshold < nbOfPendingMessages) {
      nbMsgGive = nbOfPendingMessages - producThreshold;
      if (nbOfPendingRequests < 1)
        nbMsgGive = nbOfPendingMessages;
    }
   
    if (consumThreshold < nbOfPendingRequests)
      nbMsgHope = 10 * nbOfPendingRequests;

    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 "LoadingFactor.dispatchAndSendTo" +
                 "\nnbMsgHope=" + nbMsgHope +
                 ", nbMsgGive=" + nbMsgGive);

    if (consumerStatus == ConsumerStatus.CONSUMER_HIGH_ACTIVITY)
      processHope(nbMsgHope,clusters);

    if (producerStatus == ProducerStatus.PRODUCER_HIGH_ACTIVITY)
      processGive(nbMsgGive,clusters);
  }

  /**
   * send nb messages on clusters.
   *
   * @param nbMsgGive
   * @param clusters Map of cluster Queue
   */
  private void processGive(int nbMsgGive, Map clusters) {
    if (nbMsgGive < 1) return;

    // select queue in cluster who have a rateOfFlow > 1
    List selected = new ArrayList();
    for (Iterator e = clusters.keySet().iterator(); e.hasNext();) {
      AgentId id = (AgentId) e.next();
      if (((Float) clusters.get(id)).floatValue() >= 1 && !id.equals(clusterQueue.getId()))
        selected.add(id);
    }

    if (selected.size() == 0) return;

    int nbGivePerQueue = nbMsgGive / selected.size();
    LBMessageGive msgGive = new LBMessageGive(validityPeriod, rateOfFlow);

    if (nbGivePerQueue == 0 && nbMsgGive > 0) {
      // send all to the first element of clusterQueue.
      AgentId id = (AgentId) selected.get(0);
      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG,
                   "LoadingFactor.processGive" +
                   " nbMsgGive = " + nbMsgGive +
                   ", id = " + id);
      msgGive.setClientMessages(clusterQueue.getClientMessages(nbMsgGive, null, true));
      clusterQueue.forward(id, msgGive);
    } else {
      // dispatch to cluster.
      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG,
                   "LoadingFactor.processGive" +
                   " givePerQueue = " + nbGivePerQueue +
                   ", selected = " + selected);
      for (Iterator e = selected.iterator(); e.hasNext();) {
        AgentId id = (AgentId) e.next();
        msgGive.setClientMessages(clusterQueue.getClientMessages(nbGivePerQueue, null, true));
        clusterQueue.forward(id, msgGive);
      }
    }
  }

  /**
   * send a hope request on a cluster queue.
   *
   * @param nbMsgHope
   * @param clusters Map of cluster Queue
   */
  private void processHope(int nbMsgHope, Map clusters) {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG,
                 "LoadingFactor.processHope" +
                 " nbMsgHope = " + nbMsgHope);
    if (nbMsgHope < 1) return;

    List selected = new ArrayList();
    for (Iterator e = clusters.keySet().iterator(); e.hasNext();) {
      AgentId id = (AgentId) e.next();
      if (((Float) clusters.get(id)).floatValue() <= 1 && !id.equals(clusterQueue.getId()))
        selected.add(id);
    }

    if (selected.size() == 0) return;

    int nbHopePerQueue = nbMsgHope / selected.size();
    if (nbHopePerQueue == 0 && nbMsgHope > 0) {
      // send the hope request to the first element of clusterQueue.
      AgentId id = (AgentId) selected.get(0);

      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG,
                   "LoadingFactor.processHope" +
                   " nbMsgHope = " + nbMsgHope +
                   ", id = " + id);
      LBMessageHope msgHope = new LBMessageHope(validityPeriod,rateOfFlow);
      msgHope.setNbMsg(nbMsgHope);
      clusterQueue.forward(id, msgHope);

    } else {
      // dispatch the hope request to clusterQueue.
      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG,
                   "LoadingFactor.processHope" +
                   " hopePerQueue = " + nbHopePerQueue +
                   ", selected = " + selected);

      LBMessageHope msgHope = new LBMessageHope(validityPeriod,rateOfFlow);
      for (Iterator e = selected.iterator(); e.hasNext();) {
        AgentId id = (AgentId) e.next();
        msgHope.setNbMsg(nbHopePerQueue);
        clusterQueue.forward(id, msgHope);
      }
    }
  }

  public String toString() {
    StringBuffer str = new StringBuffer();
    str.append("LoadingFactor (status=");
    str.append(Status.names[status]);
    str.append(", consumerStatus=");
    str.append(ConsumerStatus.names[consumerStatus]);
    str.append(", producerStatus=");
    str.append(ProducerStatus.names[producerStatus]);
    str.append(", producThreshold=");
    str.append(producThreshold);
    str.append(", consumThreshold=");
    str.append(consumThreshold);
    str.append(", autoEvalThreshold=");
    str.append(autoEvalThreshold);
    str.append(", nbOfPendingMessages=");
    str.append(nbOfPendingMessages);
    str.append(", nbOfPendingRequests=");
    str.append(nbOfPendingRequests);
    str.append(", rateOfFlow=");
    str.append(rateOfFlow);
    str.append(", overLoaded=");
    str.append(overLoaded);
    str.append(")");
    return str.toString();
  }
}
TOP

Related Classes of org.objectweb.joram.mom.dest.LoadingFactor$Status

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.