Package jmt.engine.NodeSections

Source Code of jmt.engine.NodeSections.Queue

/**   
  * Copyright (C) 2012, Laboratorio di Valutazione delle Prestazioni - Politecnico di Milano

  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.

  * This program 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 General Public License for more details.

  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */

package jmt.engine.NodeSections;

import java.util.Arrays;

import jmt.common.exception.NetException;
import jmt.engine.NetStrategies.QueueGetStrategy;
import jmt.engine.NetStrategies.QueuePutStrategy;
import jmt.engine.NetStrategies.QueueGetStrategies.FCFSstrategy;
import jmt.engine.NetStrategies.QueuePutStrategies.TailStrategy;
import jmt.engine.QueueNet.BlockingRegion;
import jmt.engine.QueueNet.Job;
import jmt.engine.QueueNet.JobClass;
import jmt.engine.QueueNet.JobClassList;
import jmt.engine.QueueNet.JobInfo;
import jmt.engine.QueueNet.JobInfoList;
import jmt.engine.QueueNet.LinkedJobInfoList;
import jmt.engine.QueueNet.NetEvent;
import jmt.engine.QueueNet.NetMessage;
import jmt.engine.QueueNet.NetNode;
import jmt.engine.QueueNet.NodeSection;
import jmt.engine.QueueNet.PSJobInfoList;
import jmt.engine.QueueNet.WaitingRequest;
import jmt.engine.random.engine.RandomEngine;

/**
* This class implements a generic finite/infinite queue. In finite queue, if
* the queue is full, new jobs could be dropped or not. It could implement
* different job strategy and/or waiting requests strategy.
*
* <br><br>
* It can also define the queue of a station which is inside a blocking region.
* When a job arrives at this node section, the source node of the message is found out.
* If the source node is inside the same region, there are no problems and the message
* is processed as usual.
* Otherwise, if the source node is outside the blocking region, this message is not
* processed but redirected to the fictitious station (called "region input station")
* which controls the access to the blocking region.
* <br><br>
*
* The class has different constructors to create a generic queue or a redirecting queue.
* <br>
* However it's also possible to create a generic queue and then to turn on/off the
* "redirecting queue" behaviour using the <tt>redirectionTurnON(..)</tt> and
* <tt>redirectionTurnOFF()</tt> methods.
*
* @author Francesco Radaelli, Stefano Omini, Bertoli Marco
*
* Modified by Ashanka (Oct 2009) for FCR Bug fix: Events are created with job instead of null for EVENT_JOB_OUT_OF_REGION
*/
/**
* <p><b>Name:</b> Queue</p>
* <p><b>Description:</b>
*
* </p>
* <p><b>Date:</b> 15/nov/2009
* <b>Time:</b> 23.08.16</p>
* @author Bertoli Marco [marco.bertoli@neptuny.com]
* @version 3.0
*/
public class Queue extends InputSection {

  /** Property Identifier: infinite. */
  public static final int PROPERTY_ID_INFINITE = 0x0101;
  /** Property Identifier: drop.*/
  public static final int PROPERTY_ID_DROP = 0x0102;
  /** Property Identifier: size.*/
  public static final int PROPERTY_ID_SIZE = 0x0103;
  /** Property Identifier: Waiting request.*/
  public static final int PROPERTY_ID_WAITING_REQUESTS = 0x0104;
  /** Property Identifier: Queue get strategy.*/
  public static final int PROPERTY_ID_GET_STRATEGY = 0x0105;
  /** Property Identifier: Queue put strategy.*/
  public static final int PROPERTY_ID_PUT_STRATEGY = 0x0106;
  /** Property Identifier: Dropped jobs.*/
  public static final int PROPERTY_ID_DROPPED_JOBS = 0x0107;

  public static final String FINITE_DROP = "drop";
  public static final String FINITE_BLOCK = "BAS blocking";
  public static final String FINITE_WAITING = "waiting queue";

  private int size;

  //coolStart is true if there are no waiting jobs when the queue is started
  private boolean coolStart, infinite;

  private boolean[] drop, block;

  //the JobInfoList of the owner NetNode (use to control the number of jobs in
  //case of finite queue)
  private JobInfoList nodeJobsList;

  /** This jobinfolist should be used instead of jobsList to support Processor Sharing */
  private JobInfoList queueJobInfoList;

  //number of dropped jobs
  private int droppedJobs;
  private int[] droppedJobsPerClass;

  private JobInfoList waitingRequests;

  private QueueGetStrategy getStrategy;

  private QueuePutStrategy putStrategy[];

  //-------------------BLOCKING REGION PROPERTIES----------------------------//
  //@author Stefano Omini

  //true if the queue belongs to a blocking region and has to redirect the jobs
  //arriving from the outside of the region
  private boolean redirectionON;
  //the blocking region the node belongs to
  private BlockingRegion myRegion;
  //the input station of the blocking region
  private NetNode regionInputStation;

  //-------------------end BLOCKING REGION PROPERTIES----------------------------//

  /**
   * Creates a new instance of finite Queue.
   * @param size Queue size (-1 = infinite queue).
   * @param getStrategy Queue get strategy: if null FCFS strategy is used.
   * @param putStrategy Queue put strategy: if null Tail strategy is used.
   * @param drop True if the queue should rejects new jobs when it's full,
   * false otherwise.
   */
  public Queue(int size, boolean drop, QueueGetStrategy getStrategy, QueuePutStrategy putStrategy[]) {

    //OLD
    //super();

    //NEW
    //auto = false, otherwise when a JOB message is received,
    //the corresponding Job object is automatically added to
    //JobInfoList

    super(false);
    //end NEW

    if (size == -1) {
      infinite = true;
    } else {
      this.size = size;
      infinite = false;
    }
    if (getStrategy == null) {
      this.getStrategy = new FCFSstrategy();
    } else {
      this.getStrategy = getStrategy;
    }
    this.putStrategy = putStrategy;
    // Uses putstrategy.length to estimate number of classes. It's a bit unclean but we are forced for compatibility.
    this.drop = new boolean[putStrategy.length];
    this.block = new boolean[putStrategy.length];
    Arrays.fill(this.drop, drop);
    Arrays.fill(this.block, false);
    coolStart = true;

    //this node doesn't belong to any blocking region
    redirectionON = false;
    myRegion = null;
    regionInputStation = null;

    //NEW
    //@author Stefano Omini
    //log = NetSystem.getLog();
    //end NEW
  }

  /**
   * Creates a new instance of finite Queue.
   * @param size Queue size (-1 = infinite queue).
   * @param getStrategy Queue get strategy: if null FCFS strategy is used.
   * @param putStrategy Queue put strategy: if null Tail strategy is used.
   * @param drop True if the queue should rejects new jobs when it's full,
   * false otherwise.
   */
  public Queue(Integer size, Boolean drop, QueueGetStrategy getStrategy, QueuePutStrategy putStrategy[]) {
    this(size.intValue(), drop.booleanValue(), getStrategy, putStrategy);
  }

  /** Creates a new instance of finite redirecting Queue.
   * @param size Queue size (-1 = infinite queue).
   * @param getStrategy Queue get strategy: if null FCFS strategy is used.
   * @param putStrategy Queue put strategy: if null Tail strategy is used.
   * @param drop True if the queue should rejects new jobs when it's full,
   * false otherwise.
   * @param myReg the blocking region to which the owner node of this queue belongs
   */
  public Queue(int size, boolean drop, QueueGetStrategy getStrategy, QueuePutStrategy putStrategy[], BlockingRegion myReg) {
    //uses constructor for generic queue
    this(size, drop, getStrategy, putStrategy);

    //sets blocking region properties
    redirectionON = true;
    myRegion = myReg;
    regionInputStation = myRegion.getInputStation();
  }

  /** Creates a new instance of finite redirecting Queue.
   * @param size Queue size (-1 = infinite queue).
   * @param getStrategy Queue get strategy: if null FCFS strategy is used.
   * @param putStrategy Queue put strategy: if null Tail strategy is used.
   * @param drop True if the queue should rejects new jobs when it's full,
   * false otherwise.
   * @param myReg the blocking region to which the owner node of this queue belongs
   */
  public Queue(Integer size, Boolean drop, QueueGetStrategy getStrategy, QueuePutStrategy putStrategy[], BlockingRegion myReg) {
    this(size.intValue(), drop.booleanValue(), getStrategy, putStrategy, myReg);
  }

  /**
   * Creates a new instance of finite Queue. This is the newest constructor that supports
   * different drop strategies. Other constructors are left for compatibility.
   * @param size Queue size (-1 = infinite queue).
   * @param getStrategy Queue get strategy: if null FCFS strategy is used.
   * @param putStrategy Queue put strategy: if null Tail strategy is used.
   * @param dropStrategies 
   */
  public Queue(Integer size, String[] dropStrategies, QueueGetStrategy getStrategy, QueuePutStrategy putStrategy[]) {
    this(size.intValue(), false, getStrategy, putStrategy);
    // Decodes drop strategies
    for (int i = 0; i < dropStrategies.length; i++) {
      if (dropStrategies[i].equals(FINITE_DROP)) {
        drop[i] = true;
        block[i] = false;
      } else if (dropStrategies[i].equals(FINITE_BLOCK)) {
        drop[i] = false;
        block[i] = true;
      } else if (dropStrategies[i].equals(FINITE_WAITING)) {
        drop[i] = false;
        block[i] = false;
      }
    }
  }

  /**
   * Turns on the "redirecting queue" behaviour.
   * @param region the blocking region to which the owner node
   * of this queue belongs
   */
  public void redirectionTurnON(BlockingRegion region) {
    //sets blocking region properties
    redirectionON = true;
    myRegion = region;
    regionInputStation = myRegion.getInputStation();
  }

  /**
   * Turns off the "redirecting queue" behaviour.
   */
  public void redirectionTurnOFF() {
    //sets blocking region properties
    redirectionON = false;
    myRegion = null;
    regionInputStation = null;
  }

  /**
   * Tells whether the "redirecting queue" behaviour has been turned on.
   * @return true, if the "redirecting queue" behaviour is on; false otherwise.
   */
  public boolean isRedirectionON() {
    return redirectionON;
  }

  //end NEW

  @Override
  public boolean isEnabled(int id) throws jmt.common.exception.NetException {
    switch (id) {
      case PROPERTY_ID_INFINITE:
        return infinite;
      default:
        return super.isEnabled(id);
    }
  }

  @Override
  public int getIntSectionProperty(int id) throws jmt.common.exception.NetException {
    switch (id) {
      case PROPERTY_ID_SIZE:
        return size;
      case PROPERTY_ID_WAITING_REQUESTS:
        return waitingRequests.size();
        //NEW
        //@author Stefano Omini
      case PROPERTY_ID_DROPPED_JOBS:
        return droppedJobs;
        //end NEW
      default:
        return super.getIntSectionProperty(id);
    }
  }

  @Override
  public int getIntSectionProperty(int id, JobClass jobClass) throws jmt.common.exception.NetException {
    switch (id) {
      case PROPERTY_ID_WAITING_REQUESTS:
        return waitingRequests.size(jobClass);
        //NEW
        //@author Stefano Omini
      case PROPERTY_ID_DROPPED_JOBS:
        return droppedJobsPerClass[jobClass.getId()];
        //end NEW
      default:
        return super.getIntSectionProperty(id, jobClass);
    }
  }

  @Override
  public Object getObject(int id) throws jmt.common.exception.NetException {
    switch (id) {
      case PROPERTY_ID_GET_STRATEGY:
        return getStrategy;
      case PROPERTY_ID_PUT_STRATEGY:
        return putStrategy;
      default:
        return super.getObject(id);
    }
  }

  public boolean hasInfiniteQueue() {
    return infinite;
  }

  @Override
  protected void nodeLinked(NetNode node) {
    // Sets netnode dependent properties
    waitingRequests = new LinkedJobInfoList(getJobClasses().size(), true);
    if (putStrategy == null) {
      putStrategy = new QueuePutStrategy[getJobClasses().size()];
      for (int i = 0; i < getJobClasses().size(); i++) {
        putStrategy[i] = new TailStrategy();
      }
    }

    // TODO the following line its not clean. The correct behavior should be implemented without this hack.
    try {
      if (getOwnerNode().getSection(SERVICE) instanceof PSServer) {
        jobsList = new PSJobInfoList(getJobClasses().size(), true);
        queueJobInfoList = ((PSJobInfoList) jobsList).getInternalList();
      }
    } catch (NetException ex) {
      logger.error(ex);
    }
    if (jobsList == null) {
      jobsList = new LinkedJobInfoList(getJobClasses().size(), true);
    }
    if (queueJobInfoList == null) {
      queueJobInfoList = jobsList;
    }

    if (!infinite) {
      droppedJobs = 0;
      droppedJobsPerClass = new int[getJobClasses().size()];
      for (int i = 0; i < droppedJobsPerClass.length; i++) {
        droppedJobsPerClass[i] = 0;
      }
    }

    //retrieves the job info list of the owner node
    nodeJobsList = getOwnerNode().getJobInfoList();

  }

  /** This method implements a generic finite/infinite queue
   * @param message message to be processed.
   * @throws jmt.common.exception.NetException
   */
  @Override
  protected int process(NetMessage message) throws jmt.common.exception.NetException {
    Job job;
    switch (message.getEvent()) {

      case NetEvent.EVENT_START:

        //EVENT_START
        //If there are jobs in queue, the first (chosen using the specified
        //get strategy) is forwarded and coolStart becomes false.

        if (queueJobInfoList.size() > 0) {
          //the first job is forwarded to service section
          forward(getStrategy.get(queueJobInfoList));
          coolStart = false;
        }

        break;

      case NetEvent.EVENT_ACK:

        //EVENT_ACK
        //If there are waiting requests, the first is taken (if the source node of this request
        //is the owner node of this section, an ack message is sent).
        //The job contained is put into the queue using the specified put strategy.
        //
        //At this point, if there are jobs in queue, the first is taken (using the
        //specified get strategy) and forwarded. Otherwise, if there are no jobs, coolStart
        //is set true.

        // if there is a waiting request send ack to the first node
        //(note that with infinite queue there are no waitinq requests)
        if (waitingRequests.size() != 0) {
          WaitingRequest wr;
          wr = (WaitingRequest) waitingRequests.removeFirst();

          // If the source is not the owner node sends ack if blocking is enabled. Otherwise
          // ack was already sent.
          if (!isMyOwnerNode(wr.getNode()) && block[wr.getJob().getJobClass().getId()]) {
            send(NetEvent.EVENT_ACK, wr.getJob(), 0.0, wr.getSection(), wr.getNode());
          }

          //the class ID of this job
          int c = wr.getJob().getJobClass().getId();
          //the job is put into the queue according to its own class put strategy
          putStrategy[c].put(wr.getJob(), queueJobInfoList, message.getSourceSection(), message.getSource(), this);
        }

        // if there is at least one job, sends it
        if (queueJobInfoList.size() > 0) {
          // Gets job using a specific strategy and sends job
          Job jobSent = getStrategy.get(queueJobInfoList);
          forward(jobSent);
        } else {
          // else set coolStart to true
          coolStart = true;

        }
        break;

      case NetEvent.EVENT_JOB:

        //EVENT_JOB
        //If the queue is a redirecting queue, jobs arriving from the outside of
        //the blocking region must be redirected to the region input station
        //
        //Otherwise the job is processed as usual.
        //
        //If coolStart is true, the queue is empty, so the job is added to the job list
        //and immediately forwarded to the next section. An ack is sent and coolStart is
        //set to false.
        //
        //If the queue is not empty, it should be distinguished between finite/infinite queue.
        //
        //If the queue is finite, checks the size: if it's not full the job is put into the
        //queue and an ack is sent. Else, if it's full, checks the owner node: if the
        //source node is the owner node of this section, an ack is sent and a waiting
        //request is created. If the source is another node the waiting request is created
        //only if drop is false, otherwise an ack is sent but the job is rejected.
        //
        //If the queue is infinite, the job is put into the queue and an ack is sent

        job = message.getJob();

        //----REDIRECTION BEHAVIOUR----------//
        if (isRedirectionON()) {

          NetNode source = message.getSource();
          boolean fromTheInside = myRegion.belongsToRegion(source);

          //the first time input station isn't known yet
          if (regionInputStation == null) {
            regionInputStation = myRegion.getInputStation();
          }

          if (!fromTheInside) {
            //this message has arrived from the outside of the blocking region
            if ((source != regionInputStation)) {
              //the external source is not the input station
              //the message must be redirected to the input station,
              //without processing it

              //redirects the message to the inputStation
              redirect(NetEvent.EVENT_JOB, job, 0.0, NodeSection.INPUT, regionInputStation);
              //send a ack to the source
              send(NetEvent.EVENT_ACK, job, 0.0, message.getSourceSection(), message.getSource());

              return MSG_PROCESSED;
            }
          }
        }
        //----END REDIRECTION BEHAVIOUR-------//

        //
        //two possible cases:
        //1 - the queue is a generic queue (redirectionOn == false)
        //2 - the queue is a redirecting queue, but the message has arrived
        //from the inside of the region or from the inputStation:
        //in this case the redirecting queue acts as a normal queue
        //
        //therefore in both cases the behaviour is the same
        //

        // Check if there is still capacity.
        // <= size because the arriving job hasn't been inserted in Queue
        // job list but has been inserted in NetNode job list !!
        if (infinite || nodeJobsList.size() <= size) {
          // Queue is not full. Okay.

          // If coolStart is true, this is the first job received or the
          // queue was empty: this job is sent immediately to the next
          // section and coolStart set to false.
          if (coolStart) {
            // No jobs in queue: Refresh jobsList and sends job (don't use put strategy, because queue is empty)
            queueJobInfoList.add(new JobInfo(job));
            //forward without any delay
            forward(queueJobInfoList.removeFirst().getJob());

            coolStart = false;
          } else {
            putStrategy[job.getJobClass().getId()].put(job, queueJobInfoList, message.getSourceSection(), message.getSource(), this);
          }
          //sends an ACK backward
          send(NetEvent.EVENT_ACK, job, 0.0, message.getSourceSection(), message.getSource());
        } else {
          // Queue is full. Now we use an additional queue or drop.

          // if the job has been sent by the owner node of this queue section
          if (isMyOwnerNode(message.getSource())) {
            send(NetEvent.EVENT_ACK, job, 0.0, message.getSourceSection(), message.getSource());

            waitingRequests.add(new WaitingRequest(message.getSource(), message.getSourceSection(), job));
          }
          // otherwise if job has been sent by another node
          else if (!drop[job.getJobClass().getId()]) {
            // if drop is true reject the job, else add the job to waitingRequests
            waitingRequests.add(new WaitingRequest(message.getSource(), message.getSourceSection(), job));
            //if blocking is disabled, sends ack otherwise router of the previous node remains busy
            if (!block[job.getJobClass().getId()]) {
              send(NetEvent.EVENT_ACK, job, 0.0, message.getSourceSection(), message.getSource());
            }
          } else {
            // if drop, send ack event to source
            droppedJobs++;
            droppedJobsPerClass[job.getJobClass().getId()]++;

            // Removes job from global jobInfoList - Bertoli Marco
            getOwnerNode().getQueueNet().getJobInfoList().dropJob(job);

            //after arriving to this section, the job has been inserted in the job
            //lists of both node section and node.
            //If drop = true, the job must be removed if the queue is full.
            //Using the "general" send method, however, the dropped job wasn't removed
            //from the job info list of node section and of node, then it was
            //sent later, after receiving one or more ack.

            sendAckAfterDrop(job, 0.0, message.getSourceSection(), message.getSource());

            //if the queue is inside a blocking region, the jobs
            //counter must be decreased
            if (isRedirectionON()) {
              //decrease the number of jobs
              myRegion.decreaseOccupation(job.getJobClass());
              //sends an event to the input station (which may be blocked)
              send(NetEvent.EVENT_JOB_OUT_OF_REGION, job, 0.0, NodeSection.INPUT, regionInputStation);
              //Since now for blocking regions the job dropping is handles manually at node
              //level hence need to create events with Jobs ..Modified for FCR Bug Fix
            }
          }
        }

        break;

      default:
        return MSG_NOT_PROCESSED;
    }
    return MSG_PROCESSED;
  }

  private void forward(Job job) throws jmt.common.exception.NetException {
    sendForward(job, 0.0);
  }

  /**
   * Gets the total number of dropped jobs
   * @return the total number of dropped jobs, -1 otherwise
   */
  public int getDroppedJobs() {
    if (!infinite) {
      return droppedJobs;
    } else {
      return -1;
    }
  }

  /**
   * Gets the numbers of dropped jobs for each class
   * @return the numbers of dropped jobs for each class, null otherwise
   */
  public int[] getDroppedJobsPerClass() {
    if (!infinite) {
      return droppedJobsPerClass;
    } else {
      return null;
    }

  }

  /**   * Gets the number of dropped jobs for the specified class
   * @return the number of dropped jobs for the specified class, -1 otherwise
   */
  public int getDroppedJobPerClass(int jobClass) {
    if (!infinite) {
      return droppedJobsPerClass[jobClass];
    } else {
      return -1;
    }

  }

  /**
   * Adds the specified numbers of jobs for each class
   * @param preload_jobPerClass the numbers of jobs for each class
   */
  public void preloadJobs(int[] preload_jobPerClass) {

    //total jobs
    int totJobs = 0;

    //number of classes
    int classNumber = preload_jobPerClass.length;

    //jobs that haven't been inserted yet
    int[] residualClassJobs = new int[classNumber];

    //first of all computes the total number of jobs to be added
    for (int c = 0; c < classNumber; c++) {
      totJobs += preload_jobPerClass[c];
      residualClassJobs[c] = preload_jobPerClass[c];
    }

    RandomEngine randomEng = RandomEngine.makeDefault();
    int randomClassIndex;

    JobClassList jobClasses = getJobClasses();

    while (totJobs > 0) {
      //jobs of different classes must be mixed.. use random numbers

      randomClassIndex = (int) Math.floor((randomEng.raw()) * classNumber);

      if (residualClassJobs[randomClassIndex] > 0) {
        //other jobs to be added
        Job newJob = new Job(jobClasses.get(randomClassIndex));
        JobInfo newJobInfo = new JobInfo(newJob);
       
        // Signals to node jobInfoList otherwise measures and Load dependent code are wrong
        this.getOwnerNode().getJobInfoList().add(newJobInfo);
        // Adds this job to the queue jobinfolist
        queueJobInfoList.add(newJobInfo);

        //job has been added: decrease class e total counters
        residualClassJobs[randomClassIndex]--;
        totJobs--;
       
        // Signals to global jobInfoList new added job - Bertoli Marco
        this.getOwnerNode().getQueueNet().getJobInfoList().addJob(newJob);
       
       
      }

      //else no other jobs of this class must be added

      //continue

    }

  }
}
TOP

Related Classes of jmt.engine.NodeSections.Queue

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.