/** * Copyright 2012-2013 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.workflowsim; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.cloudbus.cloudsim.Cloudlet; import org.cloudbus.cloudsim.Log; import org.cloudbus.cloudsim.Vm; import org.cloudbus.cloudsim.core.CloudSimTags; import org.cloudbus.cloudsim.core.SimEntity; import org.cloudbus.cloudsim.core.SimEvent; import org.workflowsim.reclustering.ReclusteringEngine; import org.workflowsim.utils.Parameters; /** * WorkflowEngine represents a engine acting on behalf of a user. It hides VM * management, as vm creation, submission of cloudlets to this VMs and * destruction of VMs. * * @author Weiwei Chen * @since WorkflowSim Toolkit 1.0 * @date Apr 9, 2013 */ public final class WorkflowEngine extends SimEntity { /** * The job list. */ protected List<? extends Cloudlet> jobsList; /** * The job submitted list. */ protected List<? extends Cloudlet> jobsSubmittedList; /** * The job received list. */ protected List<? extends Cloudlet> jobsReceivedList; /** * The job submitted. */ protected int jobsSubmitted; protected List<? extends Vm> vmList; /** * The associated scheduler id* */ private List<Integer> schedulerId; private List<WorkflowScheduler> scheduler; /** * Created a new WorkflowEngine object. * * @param name name to be associated with this entity (as required by * Sim_entity class from simjava package) * @throws Exception the exception * @pre name != null * @post $none */ public WorkflowEngine(String name) throws Exception { this(name, 1); } public WorkflowEngine(String name, int schedulers) throws Exception { super(name); setJobsList(new ArrayList<>()); setJobsSubmittedList(new ArrayList<>()); setJobsReceivedList(new ArrayList<>()); jobsSubmitted = 0; setSchedulers(new ArrayList<>()); setSchedulerIds(new ArrayList<>()); for (int i = 0; i < schedulers; i++) { WorkflowScheduler wfs = new WorkflowScheduler(name + "_Scheduler_" + i); getSchedulers().add(wfs); getSchedulerIds().add(wfs.getId()); wfs.setWorkflowEngineId(this.getId()); } } /** * This method is used to send to the broker the list with virtual machines * that must be created. * * @param list the list * @param schedulerId the scheduler id */ public void submitVmList(List<? extends Vm> list, int schedulerId) { getScheduler(schedulerId).submitVmList(list); } public void submitVmList(List<? extends Vm> list) { //bug here, not sure whether we should have different workflow schedulers getScheduler(0).submitVmList(list); setVmList(list); } public List<? extends Vm> getAllVmList(){ if(this.vmList != null && !this.vmList.isEmpty()){ return this.vmList; } else{ List list = new ArrayList(); for(int i = 0;i < getSchedulers().size();i ++){ list.addAll(getScheduler(i).getVmList()); } return list; } } /** * This method is used to send to the broker the list of cloudlets. * * @param list the list */ public void submitCloudletList(List<? extends Cloudlet> list) { getJobsList().addAll(list); } /** * Processes events available for this Broker. * * @param ev a SimEvent object */ @Override public void processEvent(SimEvent ev) { switch (ev.getTag()) { // Resource characteristics request case CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST: processResourceCharacteristicsRequest(ev); break; //this call is from workflow scheduler when all vms are created case CloudSimTags.CLOUDLET_SUBMIT: submitJobs(); break; case CloudSimTags.CLOUDLET_RETURN: processJobReturn(ev); break; case CloudSimTags.END_OF_SIMULATION: shutdownEntity(); break; case WorkflowSimTags.JOB_SUBMIT: processJobSubmit(ev); break; default: processOtherEvent(ev); break; } } /** * Process a request for the characteristics of a PowerDatacenter. * * @param ev a SimEvent object */ protected void processResourceCharacteristicsRequest(SimEvent ev) { for (int i = 0; i < getSchedulerIds().size(); i++) { schedule(getSchedulerId(i), 0, CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST); } } /** * Binds a scheduler with a datacenter. * * @param datacenterId the data center id * @param schedulerId the scheduler id */ public void bindSchedulerDatacenter(int datacenterId, int schedulerId) { getScheduler(schedulerId).bindSchedulerDatacenter(datacenterId); } /** * Binds a datacenter to the default scheduler (id=0) * * @param datacenterId dataceter Id */ public void bindSchedulerDatacenter(int datacenterId) { bindSchedulerDatacenter(datacenterId, 0); } /** * Process a submit event * * @param ev a SimEvent object */ protected void processJobSubmit(SimEvent ev) { List<? extends Cloudlet> list = (List) ev.getData(); setJobsList(list); } /** * Process a job return event. * * @param ev a SimEvent object * @pre ev != $null * @post $none */ protected void processJobReturn(SimEvent ev) { Job job = (Job) ev.getData(); if (job.getCloudletStatus() == Cloudlet.FAILED) { // Reclusteringengine will add retry job to jobList int newId = getJobsList().size() + getJobsSubmittedList().size(); getJobsList().addAll(ReclusteringEngine.process(job, newId)); } getJobsReceivedList().add(job); jobsSubmitted--; if (getJobsList().isEmpty() && jobsSubmitted == 0) { //send msg to all the schedulers for (int i = 0; i < getSchedulerIds().size(); i++) { sendNow(getSchedulerId(i), CloudSimTags.END_OF_SIMULATION, null); } } else { sendNow(this.getId(), CloudSimTags.CLOUDLET_SUBMIT, null); } } /** * Overrides this method when making a new and different type of Broker. * This method is called by {@link #body()} for incoming unknown tags. * * @param ev a SimEvent object */ protected void processOtherEvent(SimEvent ev) { if (ev == null) { Log.printLine(getName() + ".processOtherEvent(): " + "Error - an event is null."); return; } Log.printLine(getName() + ".processOtherEvent(): " + "Error - event unknown by this DatacenterBroker."); } /** * Checks whether a job list contains a id * * @param jobList the job list * @param id the job id * @return */ private boolean hasJobListContainsID(List jobList, int id) { for (Iterator it = jobList.iterator(); it.hasNext();) { Job job = (Job) it.next(); if (job.getCloudletId() == id) { return true; } } return false; } /** * Submit jobs to the created VMs. * * @pre $none * @post $none */ protected void submitJobs() { List<Job> list = getJobsList(); Map<Integer, List> allocationList = new HashMap<>(); for (int i = 0; i < getSchedulers().size(); i++) { List<Job> submittedList = new ArrayList<>(); allocationList.put(getSchedulerId(i), submittedList); } int num = list.size(); for (int i = 0; i < num; i++) { //at the beginning Job job = list.get(i); //Dont use job.isFinished() it is not right if (!hasJobListContainsID(this.getJobsReceivedList(), job.getCloudletId())) { List<Job> parentList = job.getParentList(); boolean flag = true; for (Job parent : parentList) { if (!hasJobListContainsID(this.getJobsReceivedList(), parent.getCloudletId())) { flag = false; break; } } /** * This job's parents have all completed successfully. Should * submit. */ if (flag) { List submittedList = allocationList.get(job.getUserId()); submittedList.add(job); jobsSubmitted++; getJobsSubmittedList().add(job); list.remove(job); i--; num--; } } } /** * If we have multiple schedulers. Divide them equally. */ for (int i = 0; i < getSchedulers().size(); i++) { List submittedList = allocationList.get(getSchedulerId(i)); //divid it into sublist int interval = Parameters.getOverheadParams().getWEDInterval(); double delay = 0.0; if(Parameters.getOverheadParams().getWEDDelay()!=null){ delay = Parameters.getOverheadParams().getWEDDelay(submittedList); } double delaybase = delay; int size = submittedList.size(); if (interval > 0 && interval <= size) { int index = 0; List subList = new ArrayList(); while (index < size) { subList.add(submittedList.get(index)); index++; if (index % interval == 0) { //create a new one schedule(getSchedulerId(i), delay, CloudSimTags.CLOUDLET_SUBMIT, subList); delay += delaybase; subList = new ArrayList(); } } if (!subList.isEmpty()) { schedule(getSchedulerId(i), delay, CloudSimTags.CLOUDLET_SUBMIT, subList); } } else if (!submittedList.isEmpty()) { sendNow(this.getSchedulerId(i), CloudSimTags.CLOUDLET_SUBMIT, submittedList); } } } /* * (non-Javadoc) * @see cloudsim.core.SimEntity#shutdownEntity() */ @Override public void shutdownEntity() { Log.printLine(getName() + " is shutting down..."); } /* * (non-Javadoc) * @see cloudsim.core.SimEntity#startEntity() * Here we creata a message when it is started */ @Override public void startEntity() { Log.printLine(getName() + " is starting..."); schedule(getId(), 0, CloudSimTags.RESOURCE_CHARACTERISTICS_REQUEST); } /** * Gets the job list. * * @param <T> the generic type * @return the job list */ @SuppressWarnings("unchecked") public <T extends Cloudlet> List<T> getJobsList() { return (List<T>) jobsList; } /** * Sets the job list. * * @param <T> the generic type * @param cloudletList the new job list */ private <T extends Cloudlet> void setJobsList(List<T> jobsList) { this.jobsList = jobsList; } /** * Gets the job submitted list. * * @param <T> the generic type * @return the job submitted list */ @SuppressWarnings("unchecked") public <T extends Cloudlet> List<T> getJobsSubmittedList() { return (List<T>) jobsSubmittedList; } /** * Sets the job submitted list. * * @param <T> the generic type * @param jobsSubmittedList the new job submitted list */ private <T extends Cloudlet> void setJobsSubmittedList(List<T> jobsSubmittedList) { this.jobsSubmittedList = jobsSubmittedList; } /** * Gets the job received list. * * @param <T> the generic type * @return the job received list */ @SuppressWarnings("unchecked") public <T extends Cloudlet> List<T> getJobsReceivedList() { return (List<T>) jobsReceivedList; } /** * Sets the job received list. * * @param <T> the generic type * @param cloudletReceivedList the new job received list */ private <T extends Cloudlet> void setJobsReceivedList(List<T> jobsReceivedList) { this.jobsReceivedList = jobsReceivedList; } /** * Gets the vm list. * * @param <T> the generic type * @return the vm list */ @SuppressWarnings("unchecked") public <T extends Vm> List<T> getVmList() { return (List<T>) vmList; } /** * Sets the vm list. * * @param <T> the generic type * @param vmList the new vm list */ private <T extends Vm> void setVmList(List<T> vmList) { this.vmList = vmList; } /** * Gets the schedulers. * * @return the schedulers */ public List<WorkflowScheduler> getSchedulers() { return this.scheduler; } /** * Sets the scheduler list. * * @param <T> the generic type * @param vmList the new scheduler list */ private void setSchedulers(List list) { this.scheduler = list; } /** * Gets the scheduler id. * * @return the scheduler id */ public List<Integer> getSchedulerIds() { return this.schedulerId; } /** * Sets the scheduler id list. * * @param <T> the generic type * @param vmList the new scheduler id list */ private void setSchedulerIds(List list) { this.schedulerId = list; } /** * Gets the scheduler id list. * * @param index * @return the scheduler id list */ public int getSchedulerId(int index) { if (this.schedulerId != null) { return this.schedulerId.get(index); } return 0; } /** * Gets the scheduler . * * @param schedulerId * @return the scheduler */ public WorkflowScheduler getScheduler(int schedulerId) { if (this.scheduler != null) { return this.scheduler.get(schedulerId); } return null; } }