From b81e8bdae909ef0d6633ec0390f69de259181c79 Mon Sep 17 00:00:00 2001
From: Someone <someone@somenet.org>
Date: Thu, 6 Jun 2013 22:16:03 +0200
Subject: [PATCH] SchedB now has Federation and Delaying of apps.

---
 .../ac/tuwien/lsdc/federation/Federation.java |  11 +-
 .../tuwien/lsdc/sched/AbstractScheduler.java  | 173 +++++++++++-------
 src/at/ac/tuwien/lsdc/sched/SchedulerB.java   |  86 ++++++++-
 .../ac/tuwien/lsdc/types/SchedulerEvent.java  |   2 +-
 4 files changed, 190 insertions(+), 82 deletions(-)

diff --git a/src/at/ac/tuwien/lsdc/federation/Federation.java b/src/at/ac/tuwien/lsdc/federation/Federation.java
index adf16f8..78cf678 100644
--- a/src/at/ac/tuwien/lsdc/federation/Federation.java
+++ b/src/at/ac/tuwien/lsdc/federation/Federation.java
@@ -1,5 +1,9 @@
 package at.ac.tuwien.lsdc.federation;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.ac.tuwien.lsdc.sched.SchedulerB;
 import at.ac.tuwien.lsdc.types.Application;
 
 /**
@@ -10,10 +14,14 @@ import at.ac.tuwien.lsdc.types.Application;
  * 
  */
 public class Federation {
+	/**
+	 * Logger.
+	 */
+	private static final Logger LOG = LoggerFactory.getLogger(SchedulerB.class);
 
 	private int numPartners;
 	public final static int fak = 100;
-	public final static int th = 20;
+	public final static int th = 30;
 
 	public Federation(int numPartners) {
 		this.numPartners = numPartners;
@@ -27,6 +35,7 @@ public class Federation {
 	 * @return true, if application can be outsourced.
 	 */
 	public boolean askToOutsource(Application app) {
+		LOG.info("askToOutsource():" + app);
 		for (int i = 0; i < numPartners; i++) {
 			if (Math.random() * fak < th)
 				return true;
diff --git a/src/at/ac/tuwien/lsdc/sched/AbstractScheduler.java b/src/at/ac/tuwien/lsdc/sched/AbstractScheduler.java
index 65ac7b7..f8aee45 100644
--- a/src/at/ac/tuwien/lsdc/sched/AbstractScheduler.java
+++ b/src/at/ac/tuwien/lsdc/sched/AbstractScheduler.java
@@ -9,22 +9,24 @@ import java.util.TreeMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import at.ac.tuwien.lsdc.federation.Federation;
 import at.ac.tuwien.lsdc.management.MachineManager;
 import at.ac.tuwien.lsdc.types.Application;
 import at.ac.tuwien.lsdc.types.ScenarioData;
 import at.ac.tuwien.lsdc.types.ScenarioType;
 import at.ac.tuwien.lsdc.types.SchedulerData;
 import at.ac.tuwien.lsdc.types.SchedulerEvent;
-import at.ac.tuwien.lsdc.types.SchedulerType;
 import at.ac.tuwien.lsdc.types.SchedulerEvent.EventType;
 import at.ac.tuwien.lsdc.types.VirtualMachine.VMType;
 import at.ac.tuwien.lsdc.util.CSVLogger;
 import at.ac.tuwien.lsdc.util.NumberUtils;
 
+/**
+ * Class doing all the generic scheduling work.
+ */
 public abstract class AbstractScheduler {
 
-	private static final Logger log = LoggerFactory
-			.getLogger(AbstractScheduler.class);
+	private static final Logger log = LoggerFactory.getLogger(AbstractScheduler.class);
 
 	// the following types are only needed for correct
 	// log output
@@ -40,52 +42,50 @@ public abstract class AbstractScheduler {
 	protected CSVLogger logger;
 	protected VMType vmType;
 
-	// this map saves the following Type of Events:
-	// start of an Application, end of an Application
-	// (start outSourced, end outSourced, start inSourced, end inSourced)
+	/**
+	 * this map saves the following Type of Events: start of an Application, end
+	 * of an Application(start outSourced, end outSourced, start inSourced, end
+	 * inSourced)
+	 */
 	protected SortedMap<Long, LinkedList<SchedulerEvent>> eventMap;
 
-	// Scheduler has an internal Time "Abstraction"
-	// at every point in time it checks for Events in his "EventList"
-	// and handles them (via the individual scheduling algorithm)
+	/**
+	 * Scheduler has an internal Time "Abstraction" at every point in time it
+	 * checks for Events in his "EventList" and handles them (via the individual
+	 * scheduling algorithm)
+	 */
 	protected long currTime = 0;
 
-	// the timestamp at which the Scheduler is finished
-	// it is updated with every added "EndEvent"
+	/**
+	 * the timestamp at which the Scheduler is finished it is updated with every
+	 * added "EndEvent"
+	 */
 	protected long endTime;
 
-	public AbstractScheduler(int numPMs, int numCloudPartners,
-			File schedulerLog, ScenarioType scenario) throws IOException {
-		this.manager = new MachineManager(numPMs);
+	/**
+	 * All our cloud partners.
+	 */
+	protected Federation federation;
+
+	public AbstractScheduler(int numPMs, int numCloudPartners, File schedulerLog, ScenarioType scenario)
+			throws IOException {
+		manager = new MachineManager(numPMs);
 		this.schedulerLog = schedulerLog;
 		this.scenario = scenario;
-		this.eventMap = new TreeMap<Long, LinkedList<SchedulerEvent>>();
-		this.logger = new CSVLogger(schedulerLog);
-		initCloudPartners(numCloudPartners);
-
-		// Using federation ?
-		// federation = new Federation(numCloudPartners);
+		eventMap = new TreeMap<Long, LinkedList<SchedulerEvent>>();
+		logger = new CSVLogger(schedulerLog);
+		federation = new Federation(numCloudPartners);
 	}
 
-	// intialize cloudpartners for federation
-	private void initCloudPartners(int numCloudPartners) {
-		for (int i = 0; i < numCloudPartners; i++) {
-			// initialize a cloudpartner
-			// add to a member: List<CloudPartner>
-			// CloudPartner should have 2 functions:
-			// insource & outsource
-			// insource randomly gives an application to us
-			// outsource accepts randomly applications from us
-		}
-	}
-
-	// Initialize Scheduler with Data from CSV
-	// CSV will be parsed and sent as List<Application> to Scheduler
+	/**
+	 * Initialize Scheduler with Data from CSV CSV will be parsed and sent as
+	 * List<Application> to Scheduler
+	 */
 	public ScenarioData initAndStart(LinkedList<Application> apps) {
 		for (Application app : apps) {
 			insertStartEvent(app.getTimestamp(), app);
 		}
-		
+
 		endTime = apps.getLast().getTimestamp() + 1;
 
 		startScheduling();
@@ -99,17 +99,37 @@ public abstract class AbstractScheduler {
 	}
 
 	/**
-	 * Insert a start event into the map, at timestamp when the application
-	 * should start
-	 *
+	 * Insert a start event into the map, at timestamp when the application should
+	 * start
+	 * 
 	 * @param timestamp
-	 *            the timestamp when the application should start
+	 *          the timestamp when the application should start
 	 * @param app
-	 *            the application to start
+	 *          the application to start
 	 */
 	protected void insertStartEvent(long timestamp, Application app) {
-		SchedulerEvent evt = new SchedulerEvent(timestamp,
-				EventType.startApplication, app);
+		SchedulerEvent evt = new SchedulerEvent(timestamp, EventType.startApplication, app);
+		if (!eventMap.containsKey(timestamp)) {
+			LinkedList<SchedulerEvent> list = new LinkedList<SchedulerEvent>();
+			list.add(evt);
+			eventMap.put(timestamp, list);
+		} else {
+			LinkedList<SchedulerEvent> list = eventMap.get(timestamp);
+			list.add(evt);
+		}
+	}
+
+	/**
+	 * Insert a start outsourced event into the map, at timestamp when the
+	 * application should start
+	 * 
+	 * @param timestamp
+	 *          the timestamp when the application should start
+	 * @param app
+	 *          the application to start
+	 */
+	protected void insertOutsourcedStartEvent(long timestamp, Application app) {
+		SchedulerEvent evt = new SchedulerEvent(timestamp, EventType.startOutsourcedApplication, app);
 		if (!eventMap.containsKey(timestamp)) {
 			LinkedList<SchedulerEvent> list = new LinkedList<SchedulerEvent>();
 			list.add(evt);
@@ -121,17 +141,40 @@ public abstract class AbstractScheduler {
 	}
 
 	/**
-	 * Insert a stop event into the map, at timestamp when the application
-	 * should stop
-	 *
+	 * Insert a stop event into the map, at timestamp when the application should
+	 * stop.
+	 * 
 	 * @param timestamp
-	 *            the timestamp when the application should stop
+	 *          the timestamp when the application should stop
 	 * @param app
-	 *            the application to stop
+	 *          the application to stop
 	 */
 	protected void insertStopEvent(long timestamp, Application app) {
-		SchedulerEvent evt = new SchedulerEvent(timestamp,
-				EventType.endApplication, app);
+		SchedulerEvent evt = new SchedulerEvent(timestamp, EventType.endApplication, app);
+		if (!eventMap.containsKey(timestamp)) {
+			LinkedList<SchedulerEvent> list = new LinkedList<SchedulerEvent>();
+			list.add(evt);
+			eventMap.put(timestamp, list);
+		} else {
+			LinkedList<SchedulerEvent> list = eventMap.get(timestamp);
+			list.add(evt);
+		}
+		if (endTime < timestamp) {
+			endTime = timestamp;
+		}
+	}
+
+	/**
+	 * Insert a stop event into the map, at timestamp when the application should
+	 * stop.
+	 * 
+	 * @param timestamp
+	 *          the timestamp when the application should stop
+	 * @param app
+	 *          the application to stop
+	 */
+	protected void insertOutsourcedStopEvent(long timestamp, Application app) {
+		SchedulerEvent evt = new SchedulerEvent(timestamp, EventType.endOutsourcedApplication, app);
 		if (!eventMap.containsKey(timestamp)) {
 			LinkedList<SchedulerEvent> list = new LinkedList<SchedulerEvent>();
 			list.add(evt);
@@ -153,7 +196,7 @@ public abstract class AbstractScheduler {
 		while (true) {
 			if (eventMap.containsKey(currTime)) {
 				LinkedList<SchedulerEvent> events = eventMap.get(currTime);
-		//		log.info(events.size() + " events at timestamp " + currTime);
+				// log.info(events.size() + " events at timestamp " + currTime);
 				handleEvents(events);
 			}
 			doStateLogging();
@@ -171,9 +214,9 @@ public abstract class AbstractScheduler {
 	/**
 	 * this method is where the Scheduling Algorithm resides it reads the Events
 	 * (start & stop of applications)
-	 *
+	 * 
 	 * @param events
-	 *            the events to be read and used by the scheduler
+	 *          the events to be read and used by the scheduler
 	 */
 	protected abstract void handleEvents(LinkedList<SchedulerEvent> events);
 
@@ -182,17 +225,9 @@ public abstract class AbstractScheduler {
 	 * directly to the specific scheduler/scenario csv file
 	 */
 	protected void doStateLogging() {
-		SchedulerData data = new SchedulerData(
-									currTime, 
-									manager.getTotalRam(),
-									manager.getTotalCpu(), 
-									manager.getTotalSize(),
-									manager.countCurrentlyRunningPMs(),
-									manager.countCurrentlyRunningVMs(),
-									manager.getCurrentConsumption(), 
-									numCurrInSourced,
-									numCurrOutSourced
-							);
+		SchedulerData data = new SchedulerData(currTime, manager.getTotalRam(), manager.getTotalCpu(),
+				manager.getTotalSize(), manager.countCurrentlyRunningPMs(), manager.countCurrentlyRunningVMs(),
+				manager.getCurrentConsumption(), numCurrInSourced, numCurrOutSourced);
 		totalConsumption += manager.getCurrentConsumption();
 		try {
 			logger.logSchedulerData(data);
@@ -202,17 +237,15 @@ public abstract class AbstractScheduler {
 	}
 
 	/**
-	 * this creates the total summary which should be written to a CSV at the
-	 * end
+	 * this creates the total summary which should be written to a CSV at the end
 	 * 
 	 * @return a ScenarioData Object that holds the values to be logged
 	 */
 	protected ScenarioData doEndLogging() {
-		return new ScenarioData(getSchedulerType(),
-				scenario.toString(), manager.getTotalPMs(), manager.getTotalVMs(), endTime, NumberUtils.roundDouble(totalConsumption), numTotalInSourced,
-				numTotalOutSourced);
+		return new ScenarioData(getSchedulerType(), scenario.toString(), manager.getTotalPMs(), manager.getTotalVMs(),
+				endTime, NumberUtils.roundDouble(totalConsumption), numTotalInSourced, numTotalOutSourced);
 	}
-	
+
 	protected abstract String getSchedulerType();
-	
+
 }
diff --git a/src/at/ac/tuwien/lsdc/sched/SchedulerB.java b/src/at/ac/tuwien/lsdc/sched/SchedulerB.java
index 6103406..b14540d 100644
--- a/src/at/ac/tuwien/lsdc/sched/SchedulerB.java
+++ b/src/at/ac/tuwien/lsdc/sched/SchedulerB.java
@@ -40,7 +40,11 @@ public class SchedulerB extends AbstractScheduler {
 	 */
 	private static final Logger LOG = LoggerFactory.getLogger(SchedulerB.class);
 
-	private final ArrayList<Application> delayedApps;
+	/**
+	 * List of Apps that were delayed due to not enough free resources. TODO: move
+	 * to abstractSched?
+	 */
+	private ArrayList<Application> delayedApps;
 
 	public SchedulerB(int numPMs, int numCloudPartners, File schedulerLog, ScenarioType scenario) throws IOException {
 		super(numPMs, numCloudPartners, schedulerLog, scenario);
@@ -53,22 +57,83 @@ public class SchedulerB extends AbstractScheduler {
 	protected void handleEvents(LinkedList<SchedulerEvent> events) {
 		LOG.debug("handleEvents():" + events);
 		handleEndEvents(events);
-		checkMigration();
-		checkDelayedApps();
+		handleOutsourcedEndEvents(events);
+		runMigration();
+		runDelayedApps();
+		handleOutsourcedStartEvents(events);
 		handleStartEvents(events);
 	}
 
+	/**
+	 * handle running of outsourced apps.
+	 * 
+	 * @param events
+	 *          list of all events that happened in this timeslot.
+	 */
+	private void handleOutsourcedStartEvents(LinkedList<SchedulerEvent> events) {
+		for (SchedulerEvent evt : events) {
+			if (evt.getType() == EventType.startOutsourcedApplication) {
+				insertOutsourcedStopEvent(currTime + evt.getApp().getDuration(), evt.getApp());
+				numCurrOutSourced++;
+				numTotalOutSourced++;
+			}
+		}
+	}
+
+	/**
+	 * handle stopping of outsourced apps.
+	 * 
+	 * @param events
+	 *          list of all events that happened in this timeslot.
+	 */
+	private void handleOutsourcedEndEvents(LinkedList<SchedulerEvent> events) {
+		for (SchedulerEvent evt : events) {
+			if (evt.getType() == EventType.endOutsourcedApplication) {
+				numCurrOutSourced--;
+			}
+		}
+	}
+
 	/**
 	 * Check if we have any delayed apps. Try to launch them.
 	 */
-	private void checkDelayedApps() {
-		// TODO Auto-generated method stub
+	private void runDelayedApps() {
+		ArrayList<Application> newDelayedApps = new ArrayList<Application>();
+		for (int i = 0; i < delayedApps.size(); i++) {
+			Application app = delayedApps.get(i);
+			VirtualMachine vm = null;
+			for (PhysicalMachine pm : manager.getPMs()) {
+				vm = pm.getVirtualMachines().get((pm.getVirtualMachines().keySet().toArray(new Integer[0]))[0]);
+				try {
+					vm.resizeVM(vm.getSize() + app.getSize(), vm.getRAM() + app.getRam(), vm.getCPU() + app.getCpu());
+					break;
+				} catch (VMResizeException ex) {
+					vm = null;
+				}
+			}
+			if (vm == null) {
+				try {
+					vm = manager.startPhysicalMachine().startVirtualMachine(app.getSize(), app.getRam(), app.getCpu(), vmType);
+				} catch (OutOfPMsException e) {
+					// LOG.error("failed to start PM.", e);
+					if (federation.askToOutsource(app)) {
+						insertOutsourcedStartEvent(currTime + 1, app);
+					} else
+						LOG.info("delaying the start of:" + app);
+					return;
+				}
+			}
+			vm.startApplication(app);
+			app.setRunningOn(vm);
+			insertStopEvent(currTime + app.getDuration(), app);
+		}
+		delayedApps = newDelayedApps;
 	}
 
 	/**
 	 * Check if we can free up a VM to shut it down.
 	 */
-	private void checkMigration() {
+	private void runMigration() {
 		// TODO Auto-generated method stub
 	}
 
@@ -90,7 +155,7 @@ public class SchedulerB extends AbstractScheduler {
 					vm.resizeVM(vm.getSize() - evt.getApp().getSize(), vm.getRAM() - evt.getApp().getRam(), vm.getCPU()
 							- evt.getApp().getCpu());
 				} catch (VMResizeException e) {
-					LOG.error("failed to resize VM: " + e.getVm(), e);
+					// LOG.error("failed to resize VM: " + e.getVm(), e);
 				}
 				if (vm.getApplications().size() == 0) {
 					PhysicalMachine pm = vm.getRunningOn();
@@ -114,7 +179,6 @@ public class SchedulerB extends AbstractScheduler {
 			if (evt.getType() == EventType.startApplication) {
 				VirtualMachine vm = null;
 				for (PhysicalMachine pm : manager.getPMs()) {
-					LOG.debug("PMs: " + pm);
 					vm = pm.getVirtualMachines().get((pm.getVirtualMachines().keySet().toArray(new Integer[0]))[0]);
 					try {
 						vm.resizeVM(vm.getSize() + evt.getApp().getSize(), vm.getRAM() + evt.getApp().getRam(), vm.getCPU()
@@ -129,8 +193,10 @@ public class SchedulerB extends AbstractScheduler {
 						vm = manager.startPhysicalMachine().startVirtualMachine(evt.getApp().getSize(), evt.getApp().getRam(),
 								evt.getApp().getCpu(), vmType);
 					} catch (OutOfPMsException e) {
-						LOG.error("failed to start PM.", e);
-						// TODO: try outsourcing here.
+						if (federation.askToOutsource(evt.getApp())) {
+							insertOutsourcedStartEvent(currTime + 1, evt.getApp());
+						} else
+							LOG.info("delaying the start of:" + evt.getApp());
 						delayedApps.add(evt.getApp());
 						return;
 					}
diff --git a/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java b/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java
index 6e96e3a..11f21ba 100644
--- a/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java
+++ b/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java
@@ -3,7 +3,7 @@ package at.ac.tuwien.lsdc.types;
 public class SchedulerEvent {
 
 	public enum EventType {
-		startApplication, endApplication
+		startApplication, endApplication, startOutsourcedApplication, endOutsourcedApplication
 	};
 
 	final private long timestamp;
-- 
2.43.0