Пример #1
0
void Scheduler::startNewRound() {
  // update flows so that they can be moved to the new round
  std::vector<Flow*> flowVec;
  while (pendingEvents.empty() == false) {
    Flow* f = const_cast<Flow*> (pendingEvents.top());
    pendingEvents.pop();
    if (f->getFlowType() == FlowType::WATCH) {
      // there is no point in carrying over watch flows, as they will be discarded
      BOOST_LOG_TRIVIAL(trace) << "Deleting watch flow for chunk" << f->getChunkId()
              << " of content " << f->getContent()->getName() << " for user "
              << f->getDestination().first << "," << f->getDestination().second;
      delete f;
      continue;
    }
    f->updateSizeDownloaded(this->roundDuration);
    f->setLastUpdate(0);
    f->setStart(f->getStart() - this->roundDuration); // negative
    SimTime oldEta = f->getEta();
    if (oldEta < this->roundDuration) {
      BOOST_LOG_TRIVIAL(error) << "Scheduler::startNewRound() - unresolved event has eta "
              << oldEta << " < roundDuration";
      abort();
    }
    f->setEta(oldEta - this->roundDuration);
    if (this->mode == IPTV && f->getContent()->getReleaseDay() <= currentRound-6) {
      // expired contents in IPTV will be deleted so flows can't be completed, 
      // this event should have been truncated last round
      BOOST_LOG_TRIVIAL(info) << "Scheduler::startNewRound() - carried over flow "
              "with expired content will not be completed";
      if (f->getFlowType() == FlowType::TRANSFER) {
        // this is hacky, but needs to be done. Ideally we should not get here at all.
        oracle->getTopology()->updateCapacity(f, this, false);
        f->setContent(nullptr);
      }
    } else
      flowVec.push_back(f);
  }
  handleMap.clear();
  BOOST_FOREACH (Flow* f, flowVec) {
    this->schedule(f);
  }
Пример #2
0
bool Scheduler::advanceClock() {
  if (pendingEvents.size() == 0) {
    BOOST_LOG_TRIVIAL(warning) << "Scheduler::advanceClock() - Empty event queue before "
            "reaching the termination event" << std::endl;
    return false;
  }
  Flow* nextEvent = const_cast<Flow*> (pendingEvents.top());
  // Check that the event is not scheduled in the past
  if (nextEvent->getSimTime() < this->getSimTime()) {
    BOOST_LOG_TRIVIAL(error) << "Scheduler::advanceClock() - Event scheduled in the past!";
    BOOST_LOG_TRIVIAL(error) << "Simulation time: " << this->getSimTime()
            << ", event time: " << nextEvent->getSimTime()
            << ", content: " << nextEvent->getContent()->getName();
    abort();
  }
  // Update the clock with the current event time (if > previous time)
  else if (nextEvent->getSimTime() > this->getSimTime()) {
    this->setSimTime(nextEvent->getSimTime());
    /* print current time on the screen at the current line (note: will mess up
     * printing with debug verbose
     */
    std::cout<<"Current simulation time: " << this->simTime << "/"
          << this->roundDuration << "\r" << std::flush;
  }
  handleMap.erase(pendingEvents.top());
  pendingEvents.pop();
  // Determine what kind of event is this
  switch(nextEvent->getFlowType()) {
    case FlowType::TERMINATE:
      BOOST_LOG_TRIVIAL(info) << std::endl  
             << "Scheduler::advanceClock() - intercepted termination event";
      delete nextEvent;
      return false;
    
    case FlowType::SNAPSHOT:
      oracle->takeSnapshot(this->getSimTime(), this->getCurrentRound());
      delete nextEvent;
      if (this->getSimTime() + snapshotFreq <= roundDuration) {
        this->snapshot = new Flow(nullptr, UNKNOWN,
                this->getSimTime() + snapshotFreq);
        snapshot->setFlowType(FlowType::SNAPSHOT);
        this->schedule(this->snapshot);
      } else {
        this->snapshot = nullptr;
      }
      return true;
    
    case FlowType::REQUEST: {
      // Change the start time to now and the eta to +1s until we know the 
      // available bandwidth 
      nextEvent->setStart(this->getSimTime());
      nextEvent->setEta(this->getSimTime()+1);
      nextEvent->setLastUpdate(this->getSimTime());
      // Ask the TopologyOracle to find a source for this content
      // TODO: reschedule request in case of congestion
      bool success = oracle->serveRequest(nextEvent, this);
      // Check that the flow wasn't "virtual" (i.e. content was cached at the dest)
      // also in that case we need to put the chunk in the watching buffer
      if (nextEvent->getSource() == nextEvent->getDestination()) {
        oracle->notifyCompletedFlow(nextEvent, this);
        delete nextEvent;
      }
      else if (!success) {
        //TODO: retry to fetch the content at a later time
        delete nextEvent;
      }
      return true;
    }
    case FlowType::TRANSFER:
    case FlowType::WATCH:
      // Notify the oracle, which will update the cache mapping and free resources
      // in the topology
      oracle->notifyCompletedFlow(nextEvent, this);
      delete nextEvent;
      return true;      
  }  
  
/*  if (nextEvent->getSource() == UNKNOWN) {
    // This is a request, as the source hasn't been assigned yet
    handleMap.erase(pendingEvents.top());
    pendingEvents.pop();
    // Check whether this is a special event
    if (nextEvent->getDestination() == UNKNOWN && nextEvent->getContent() == nullptr) {
      // termination event?
      if (nextEvent->getSizeRequested() == 0) {
      std::cout << std::endl  
             << "Scheduler::advanceClock() - intercepted termination event"
              << std::endl;
      delete nextEvent;
      return false;
      } // snapshot event?
      else if (nextEvent->getFlowType() == FlowType::SNAPSHOT) {
        oracle->takeSnapshot(this->getSimTime(), this->getCurrentRound());
        delete nextEvent;
        if (this->getSimTime() + snapshotFreq <= roundDuration) {
          this->snapshot = new Flow(nullptr, UNKNOWN, 0, 
                  this->getSimTime() + snapshotFreq);
          snapshot->setFlowType(FlowType::SNAPSHOT);
          this->schedule(this->snapshot);
        }
        else {
          this->snapshot = nullptr;
        }
        return true;
      }
    }
    
    // Change the start time to now and the eta to INF_TIME until we know the 
    // available bandwidth 
    nextEvent->setStart(this->getSimTime());
    nextEvent->setEta(INF_TIME);
    nextEvent->setLastUpdate(this->getSimTime());
    // Ask the TopologyOracle to find a source for this content
    // TODO: reschedule request in case of congestion
    bool success = oracle->serveRequest(nextEvent, this);
    // Check that the flow wasn't "virtual" (i.e. content was cached at the dest)
    if (!success || nextEvent->getSource() == nextEvent->getDestination()) {
      handleMap.erase(nextEvent);
      delete nextEvent;
    }
    return true;
  } else {
//    std::cout << this->getSimTime() << ": Completed transfer of content " 
//            << flow->getContent()->getName()
//            << " from source " << flow->getSource().first
//            << " to destination " << flow->getDestination().first << std::endl;
    // Remove flow from top of the queue
    pendingEvents.pop();
    handleMap.erase(nextEvent);
    // Notify the oracle, which will update the cache mapping and free resources
    // in the topology
    oracle->notifyCompletedFlow(nextEvent, this);
    delete nextEvent;
    return true;
  }  
 */ 
}
//------------------------------------------------------------------------------
//  Path SamcraBeforeAlgorithm::compute(const Flow &flow)
//------------------------------------------------------------------------------
Path SamcraBeforeAlgorithm::compute(const Flow &flow)
{
    TRACE("SamcraBeforeAlgorithm::compute -->");

    Path result;
    Topology *topology = flow.getTopology();
    int number_of_nodes = topology->getNumNodes();
    int number_of_qos = topology->getNumQos();
	int min_k = 0; int k_used = 0; // used by samcra
	int* max = (int*) calloc(number_of_nodes + 1, sizeof(int));
	int** adj = (int**) allocMatrix(number_of_nodes + 1,
	                                number_of_nodes + 1, sizeof(int));

	double* flow_qos = (double*) calloc(number_of_qos + 1, sizeof(double));
	double*** datadj = (double***) calloc(number_of_qos + 1, sizeof(double**));
	for (int counter=1; counter <= number_of_qos; ++counter)
	{
		datadj[counter] = (double**) allocMatrix(number_of_nodes + 1,
		                  number_of_nodes + 1, sizeof(double));
		flow_qos[counter] = flow.getQosCons()[counter-1];
    }

	// filling adj and datadj, while pruning links with insuf. available cap.
    for (LinkListIterator iter = topology->getLinkIterator(); iter(); ++iter)
   {
        Link* link = *iter;
		if (link->getReservableCapacity() >= flow.getRequestedCapacity())
	    {
	        int source = link->getSource();
	        int destination = link->getDestination();
			adj[source + 1][++max[source + 1]] = destination + 1;
			for (int qos=1; qos <= number_of_qos; ++qos)
			{
				datadj[qos][source+1][max[source+1]] = link->getQoS(qos-1);
			} // end: for (qos
		} // end: if (link
    } // end: for (LinkListIterator

	// allocating memory for the path
	int path_length = 0;
	int* path = (int*) calloc(number_of_nodes + 1, sizeof(int));

	// invoking SAMCRA
    TRACE("SamcraBeforeAlgorithm::compute: Invoking SAMCRA");
#ifndef NO_TIMER
    Timer timer;
    timer.start();
#endif // NO_TIMER
    samcrapath( flow.getSource()+1, flow.getDestination()+1,
	            adj, max, datadj, number_of_qos, flow_qos,
	            number_of_nodes, path, &path_length, &min_k, &k_used);
    TRACE("SamcraBeforeAlgorithm::compute: End SAMCRA");


	// because function returns the path vector from the destination "d" to the
	// source "s" it is necessary to invert the array
	for (int counter=1; counter <= path_length; ++counter)
	{
	    result.push_front(path[counter]-1);
	}
#ifndef NO_TIMER
    const_cast<Flow&>(flow).setTime(timer.read());
#endif // NO_TIMER

	// freeing memory
	free(path);
	for (int counter = 1; counter <= number_of_qos; ++counter)
	{
		freeMatrix((void**) datadj[counter], number_of_nodes + 1);
	}
	free(datadj);
	free(flow_qos);
	freeMatrix((void**) adj, number_of_nodes + 1);
	free(max);

    TRACE("SamcraBeforeAlgorithm::compute <--");
    return result;
}
Пример #4
0
Path NewMIRAAlgorithm::compute(const Flow &flow)
{
    TRACE("NewMIRAAlgorithm::compute -->");

    Topology *topology = flow.getTopology();
    const int f_src = flow.getSource();
    const int f_dst = flow.getDestination();

    // if link (i,j) exists, its metric is initialized with 0 (it increases each
    // time a maxflow computation is performed) and it is added to the list that
    // feeds the maxflow function
    int numarcs = 0;
    int number_of_nodes = topology->getNumNodes();

    // data structure passed to maxflow function
    char** network = (char**) calloc(4, sizeof(char*));

    for (LinkListIterator iter = topology->getLinkIterator(); iter(); ++iter)
    {
        Link* link = *iter;
        if (link->getCapacity() > 0.0)
        {
            link->metric = 0.0;
            ++numarcs;
            network = (char**) realloc(network, (numarcs+4)*sizeof(char*));
            network[numarcs+2] = (char*) calloc(20, sizeof(char));
            sprintf(network[numarcs+2],"a %d %d %d",
                    link->getSource(), link->getDestination(),
                    (int) floor(link->getReservableCapacity()));
        } // end: if (link->
    } // end: for (LinkListIterator iter

    network[0] = (char*) calloc(20, sizeof(char));   // problem description
    network[1] = (char*) calloc(20, sizeof(char));   // source node
    network[2] = (char*) calloc(20, sizeof(char));   // destination node
    network[numarcs+3] = (char*) 0;       // NULL terminated array
    sprintf(network[0],"p max %d %d", number_of_nodes, numarcs);

#ifndef NO_TIMER
    Timer timer;
    timer.start();
#endif // NO_TIMER
    // Compute maxflow for each ingress-egress pair except (source,dest).
    // Each computation updates link weights

    //Timer timemaxflow;
    //timemaxflow.start();
    //int n = 0;

    const IntVector edge_nodes = topology->getEdgeNodes();

    for (IntVector::const_iterator s_iter = edge_nodes.begin();
            s_iter != edge_nodes.end(); ++s_iter)
    {
        for (IntVector::const_iterator d_iter = edge_nodes.begin();
                d_iter != edge_nodes.end(); ++d_iter)
        {
            if (*s_iter != *d_iter && !(f_src == *s_iter && f_dst == *d_iter))
            {

                //PRINTLN("s: " << *s_iter << "\td: " << *d_iter << "\tn: " << n);
                //n++;

                // complete network with current ingress-egress pair
                sprintf(network[1],"n %d s", *s_iter);
                sprintf(network[2],"n %d t", *d_iter);

                // needed by maxflow function
                node *ndp;
                arc *arp;
                long *cap;
                double mflow;
                long nmin;

                //compute maxflow
                //Timer t;
                //t.start();
                maxflow(network,&ndp,&arp,&cap,&mflow,&nmin);

                //PRINTLN("\tTimer: " << t.read());

                // update link weights
                for (node* in = ndp; in < (ndp + number_of_nodes); ++in)
                {
                    for (arc* a = in->first; a != 0; a = a->next)
                    {
                        long ni = N_NODE(in);
                        long na = N_ARC(a);
                        if ( cap[na] > 0 )
                        {
                            Link* link = topology->link(ni, N_NODE(a->head));
                            link->metric +=(cap[na] - a->r_cap) /
                                           (mflow*link->getReservableCapacity());
                        } // end: if ( cap[na] > 0 )
                    } // end: for ( arc*
                } // end: for (node*
                // free memory
                free(ndp);
                free(arp);
                free(cap);
            } // end: if ( (source
        } // end: for (int dest
    } // end: for (int source

    //PRINTLN("Timer: " << timemaxflow.read() << "\tn:" << n);

    // free memory
    for (int i=0; i<numarcs+3; ++i)
    {
        free(network[i]);
    }
    free(network);

    double f_cap = flow.getRequestedCapacity();
    // pruning of the links with insufficient bandwidth
    for (LinkListIterator iter = topology->getLinkIterator(); iter(); ++iter)
    {
        if ((*iter)->getReservableCapacity() < f_cap)
        {
            (*iter)->metric = -1.0;
        }
    }
    // invoking Dijkstra
    Path result(routing_alg->compute(flow));
#ifndef NO_TIMER
    const_cast<Flow&>(flow).setTime(timer.read());
#endif // NO_TIMER

    TRACE("NewMIRAAlgorithm::compute <--");
    return result;
}