From 3695858e78f1e576d8f0f0ba13b666cc77bcbbfa Mon Sep 17 00:00:00 2001
From: Someone <someone@somenet.org>
Date: Mon, 3 Jun 2013 04:57:24 +0200
Subject: [PATCH] Sched B. Ein wenig getestet.

---
 .../ActiveApplicationsException.java          |  2 +-
 .../lsdc/exception/OutOfPMsException.java     | 15 ++++
 .../lsdc/exception/VMResizeException.java     | 22 +++++
 .../lsdc/exception/VMsRunningException.java   |  2 +-
 .../lsdc/management/MachineManager.java       | 23 +++---
 src/at/ac/tuwien/lsdc/sched/SchedulerB.java   | 81 +++++++++++++++++--
 .../ac/tuwien/lsdc/types/PhysicalMachine.java |  9 +++
 .../ac/tuwien/lsdc/types/SchedulerEvent.java  | 10 ++-
 .../ac/tuwien/lsdc/types/VirtualMachine.java  | 55 ++++++++-----
 9 files changed, 175 insertions(+), 44 deletions(-)
 create mode 100644 src/at/ac/tuwien/lsdc/exception/OutOfPMsException.java
 create mode 100644 src/at/ac/tuwien/lsdc/exception/VMResizeException.java

diff --git a/src/at/ac/tuwien/lsdc/exception/ActiveApplicationsException.java b/src/at/ac/tuwien/lsdc/exception/ActiveApplicationsException.java
index 1de3c8d..8d087fc 100644
--- a/src/at/ac/tuwien/lsdc/exception/ActiveApplicationsException.java
+++ b/src/at/ac/tuwien/lsdc/exception/ActiveApplicationsException.java
@@ -1,6 +1,6 @@
 package at.ac.tuwien.lsdc.exception;
 
-public class ActiveApplicationsException extends Exception {
+public class ActiveApplicationsException extends RuntimeException {
 
 	public ActiveApplicationsException(String msg) {
 		super(msg);
diff --git a/src/at/ac/tuwien/lsdc/exception/OutOfPMsException.java b/src/at/ac/tuwien/lsdc/exception/OutOfPMsException.java
new file mode 100644
index 0000000..a35daae
--- /dev/null
+++ b/src/at/ac/tuwien/lsdc/exception/OutOfPMsException.java
@@ -0,0 +1,15 @@
+package at.ac.tuwien.lsdc.exception;
+
+/**
+ * Exception to be thrown, if no new PMs can be started as all our PMs are
+ * allready running.
+ * 
+ * @author jan
+ * 
+ */
+public class OutOfPMsException extends RuntimeException {
+
+	public OutOfPMsException(String msg) {
+		super(msg);
+	}
+}
diff --git a/src/at/ac/tuwien/lsdc/exception/VMResizeException.java b/src/at/ac/tuwien/lsdc/exception/VMResizeException.java
new file mode 100644
index 0000000..4010145
--- /dev/null
+++ b/src/at/ac/tuwien/lsdc/exception/VMResizeException.java
@@ -0,0 +1,22 @@
+package at.ac.tuwien.lsdc.exception;
+
+import at.ac.tuwien.lsdc.types.VirtualMachine;
+
+/**
+ * Exception to be thrown if a VM could not be resized.
+ * 
+ * @author jan
+ * 
+ */
+public class VMResizeException extends RuntimeException {
+	private final VirtualMachine vm;
+
+	public VMResizeException(String message, VirtualMachine vm) {
+		super(message);
+		this.vm = vm;
+	}
+
+	public VirtualMachine getVm() {
+		return vm;
+	}
+}
diff --git a/src/at/ac/tuwien/lsdc/exception/VMsRunningException.java b/src/at/ac/tuwien/lsdc/exception/VMsRunningException.java
index 113e7ee..c4f299a 100644
--- a/src/at/ac/tuwien/lsdc/exception/VMsRunningException.java
+++ b/src/at/ac/tuwien/lsdc/exception/VMsRunningException.java
@@ -1,6 +1,6 @@
 package at.ac.tuwien.lsdc.exception;
 
-public class VMsRunningException extends Exception {
+public class VMsRunningException extends RuntimeException {
 
 	public VMsRunningException(String message) {
 		super(message);
diff --git a/src/at/ac/tuwien/lsdc/management/MachineManager.java b/src/at/ac/tuwien/lsdc/management/MachineManager.java
index 9b23ba5..d41ecb5 100644
--- a/src/at/ac/tuwien/lsdc/management/MachineManager.java
+++ b/src/at/ac/tuwien/lsdc/management/MachineManager.java
@@ -3,6 +3,7 @@ package at.ac.tuwien.lsdc.management;
 import java.util.Collection;
 import java.util.HashMap;
 
+import at.ac.tuwien.lsdc.exception.OutOfPMsException;
 import at.ac.tuwien.lsdc.exception.VMsRunningException;
 import at.ac.tuwien.lsdc.types.PhysicalMachine;
 import at.ac.tuwien.lsdc.util.NumberUtils;
@@ -17,7 +18,7 @@ public class MachineManager {
 	private HashMap<Integer, PhysicalMachine> PMs = new HashMap<Integer, PhysicalMachine>();
 
 	private int numPMs;
-	
+
 	private int totalPMs = 0;
 	private int totalVMs = 0;
 
@@ -31,23 +32,23 @@ public class MachineManager {
 	 * @return the PM that was started, null if all machines already running
 	 */
 	public PhysicalMachine startPhysicalMachine() {
-		if (PMs.size() < numPMs) {
-			PhysicalMachine pm = new PhysicalMachine();
-			PMs.put(pm.getId(), pm);
-			pm.start();
-			totalPMs++;
-			return pm;
-		}
-		return null;
+		if (PMs.size() >= numPMs)
+			throw new OutOfPMsException("We cannot start another PM. All out PMs are already running!: " + numPMs);
+
+		PhysicalMachine pm = new PhysicalMachine();
+		PMs.put(pm.getId(), pm);
+		pm.start();
+		totalPMs++;
+		return pm;
 	}
 
 	/**
 	 * Stops a physical machine with the given id
 	 * 
 	 * @param id
-	 *            the id of the PM to stop
+	 *          the id of the PM to stop
 	 * @throws VMsRunningException
-	 *             is thrown when there are still VMs running on this PM
+	 *           is thrown when there are still VMs running on this PM
 	 */
 	public void stopPhysicalMachine(int id) throws VMsRunningException {
 		if (PMs.containsKey(id)) {
diff --git a/src/at/ac/tuwien/lsdc/sched/SchedulerB.java b/src/at/ac/tuwien/lsdc/sched/SchedulerB.java
index cf985f2..12d026f 100644
--- a/src/at/ac/tuwien/lsdc/sched/SchedulerB.java
+++ b/src/at/ac/tuwien/lsdc/sched/SchedulerB.java
@@ -7,25 +7,92 @@ import java.util.LinkedList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import at.ac.tuwien.lsdc.types.ScenarioData;
+import at.ac.tuwien.lsdc.exception.OutOfPMsException;
+import at.ac.tuwien.lsdc.exception.VMResizeException;
+import at.ac.tuwien.lsdc.types.PhysicalMachine;
 import at.ac.tuwien.lsdc.types.ScenarioType;
 import at.ac.tuwien.lsdc.types.SchedulerEvent;
+import at.ac.tuwien.lsdc.types.SchedulerEvent.EventType;
 import at.ac.tuwien.lsdc.types.SchedulerType;
+import at.ac.tuwien.lsdc.types.VirtualMachine;
+import at.ac.tuwien.lsdc.types.VirtualMachine.VMType;
 
-
+/**
+ * Scheduler B.
+ * 
+ * Initial State: All PMs switched off. If an application arrives, try to modify
+ * size, CPU and RAM of an existing VM to run the application. If no VM is
+ * running, create a new one (start a new PM if necessary). If the application
+ * has finished decrease the size, CPU and RAM of the VM. If no applications are
+ * running on a VM, shut down the VM. If no VM is running on a PM, shut down the
+ * PM. Try to get a maximum of utilization on every PM. Migration: Try to move
+ * applications from VMs to other VMs to get a better utilization and to use
+ * less PMs.
+ * 
+ * @author jan
+ * 
+ */
 public class SchedulerB extends AbstractScheduler {
 
 	private static final Logger log = LoggerFactory.getLogger(SchedulerB.class);
-	
-	public SchedulerB(int numPMs, int numCloudPartners, File schedulerLog, 
-						ScenarioType scenario) throws IOException {
+
+	public SchedulerB(int numPMs, int numCloudPartners, File schedulerLog, ScenarioType scenario) throws IOException {
 		super(numPMs, numCloudPartners, schedulerLog, scenario);
+
+		vmType = VMType.Resizable;
 	}
 
 	@Override
 	protected void handleEvents(LinkedList<SchedulerEvent> events) {
-		// TODO Auto-generated method stub
-		log.info("Sched B handle events");
+		log.debug("handleEvents():" + events);
+		for (SchedulerEvent evt : events) {
+			if (evt.getType() == EventType.endApplication) {
+				VirtualMachine vm = evt.getApp().getRunningOn();
+				evt.getApp().setRunningOn(null);
+				vm.stopApplication(evt.getApp());
+				try {
+					vm.resizeVM(vm.getSize() - evt.getApp().getSize(), vm.getRAM() - evt.getApp().getRam(), vm.getCPU()
+							- evt.getApp().getCpu());
+				} catch (VMResizeException e) {
+					log.error("lol: " + e.getVm(), e);
+				}
+				if (vm.getApplications().size() == 0) {
+					PhysicalMachine pm = vm.getRunningOn();
+					pm.stopVirtualMachine(vm);
+					manager.stopPhysicalMachine(pm.getId());
+				}
+			}
+		}
+
+		for (SchedulerEvent evt : events) {
+			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()
+								+ evt.getApp().getCpu());
+						break;
+					} catch (VMResizeException ex) {
+						vm = null;
+					}
+				}
+				if (vm == null) {
+					try {
+						vm = manager.startPhysicalMachine().startVirtualMachine(evt.getApp().getSize(), evt.getApp().getRam(),
+								evt.getApp().getCpu(), vmType);
+					} catch (OutOfPMsException e) {
+						log.error("OOP!", e);
+						// TODO: delay APP start.
+						return;
+					}
+				}
+				vm.startApplication(evt.getApp());
+				evt.getApp().setRunningOn(vm);
+				insertStopEvent(currTime + evt.getApp().getDuration(), evt.getApp());
+			}
+		}
 	}
 
 	@Override
diff --git a/src/at/ac/tuwien/lsdc/types/PhysicalMachine.java b/src/at/ac/tuwien/lsdc/types/PhysicalMachine.java
index f8a268d..292df62 100644
--- a/src/at/ac/tuwien/lsdc/types/PhysicalMachine.java
+++ b/src/at/ac/tuwien/lsdc/types/PhysicalMachine.java
@@ -157,6 +157,15 @@ public class PhysicalMachine {
 		return VMs.get(id);
 	}
 
+  /**
+   * return a list of all VMs running on this PM.
+   * 
+   * @return a HashMap with all VMs running on this PM.
+   */
+  public HashMap<Integer, VirtualMachine> getVirtualMachines() {
+    return VMs;
+  }
+
 	public int countCurrentlyRunningVMs() {
 		return VMs.values().size();
 	}
diff --git a/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java b/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java
index eb471a1..6e96e3a 100644
--- a/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java
+++ b/src/at/ac/tuwien/lsdc/types/SchedulerEvent.java
@@ -1,7 +1,7 @@
 package at.ac.tuwien.lsdc.types;
 
 public class SchedulerEvent {
-	
+
 	public enum EventType {
 		startApplication, endApplication
 	};
@@ -27,6 +27,10 @@ public class SchedulerEvent {
 	public Application getApp() {
 		return app;
 	}
-	
-	
+
+	@Override
+	public String toString() {
+		return "SchedulerEvent [timestamp=" + timestamp + ", type=" + type + ", app=" + app + "]";
+	}
+
 }
\ No newline at end of file
diff --git a/src/at/ac/tuwien/lsdc/types/VirtualMachine.java b/src/at/ac/tuwien/lsdc/types/VirtualMachine.java
index a6476bd..d1c7491 100644
--- a/src/at/ac/tuwien/lsdc/types/VirtualMachine.java
+++ b/src/at/ac/tuwien/lsdc/types/VirtualMachine.java
@@ -3,16 +3,17 @@ package at.ac.tuwien.lsdc.types;
 import java.util.ArrayList;
 import java.util.HashMap;
 
+import at.ac.tuwien.lsdc.exception.VMResizeException;
+
 public class VirtualMachine {
 
 	public enum VMType {
 		Resizable, NonResizable
 	}
-	
-	
+
 	private static int count = 0;
 	private int posOnPM;
-	
+
 	private PhysicalMachine runningOn;
 
 	private HashMap<Integer, Application> applications = new HashMap<Integer, Application>();
@@ -26,17 +27,17 @@ public class VirtualMachine {
 	private int reservedSize;
 	private int reservedRAM;
 	private int reservedCPU;
-	
+
 	private VMType type;
 
 	public VirtualMachine(int size, int RAM, int CPU, PhysicalMachine pm, VMType type) {
-		this.id = count;
+		id = count;
 		count++;
-		this.reservedSize = size + initialSize;
-		this.reservedRAM = RAM + initialRAM;
-		this.reservedCPU = CPU + initialCPU;
-		this.runningOn = pm;
-		this.posOnPM = pm.countCurrentlyRunningVMs();
+		reservedSize = size + initialSize;
+		reservedRAM = RAM + initialRAM;
+		reservedCPU = CPU + initialCPU;
+		runningOn = pm;
+		posOnPM = pm.countCurrentlyRunningVMs();
 		this.type = type;
 	}
 
@@ -48,16 +49,24 @@ public class VirtualMachine {
 		} else
 			return false;
 	}
-	
+
+	/**
+	 * Set the VM size to the given new values.
+	 * 
+	 * @param newSize
+	 * @param newRAM
+	 * @param newCPU
+	 * @return
+	 */
 	public boolean resizeVM(int newSize, int newRAM, int newCPU) {
-		if (type == VMType.Resizable  &&  runningOn.checkVM(newSize-reservedSize, newRAM-reservedRAM, newCPU-reservedCPU )) {
-			//Resize VM
-			reservedSize = reservedSize + newSize;
-			reservedRAM = reservedRAM + newRAM;
-			reservedCPU = reservedCPU + newCPU;
+		if (type == VMType.Resizable && runningOn.checkVM(newSize, newRAM, newCPU)) {
+			// Resize VM
+			reservedSize = initialSize + newSize;
+			reservedRAM = initialRAM + newRAM;
+			reservedCPU = initialCPU + newCPU;
 			return true;
 		} else
-			return false;
+			throw new VMResizeException("Could not resize VM!", this);
 	}
 
 	public boolean stopApplication(Application app) {
@@ -70,9 +79,7 @@ public class VirtualMachine {
 	}
 
 	private boolean enoughResources(Application app) {
-		return (app.getSize() <= availableSize())
-				&& (app.getRam() <= availableRAM())
-				&& (app.getCpu() <= availableCPU());
+		return (app.getSize() <= availableSize()) && (app.getRam() <= availableRAM()) && (app.getCpu() <= availableCPU());
 	}
 
 	private int availableSize() {
@@ -94,7 +101,7 @@ public class VirtualMachine {
 	public PhysicalMachine getRunningOn() {
 		return runningOn;
 	}
-	
+
 	public int getPositionOnPM() {
 		return posOnPM;
 	}
@@ -136,4 +143,10 @@ public class VirtualMachine {
 		return reservedCPU;
 	}
 
+	@Override
+	public String toString() {
+		return "VirtualMachine [posOnPM=" + posOnPM + ", runningOn=" + runningOn + ", id=" + id + ", reservedSize="
+				+ reservedSize + ", reservedRAM=" + reservedRAM + ", reservedCPU=" + reservedCPU + ", type=" + type + "]";
+	}
+
 }
-- 
2.43.0