hu.unimiskolc.iit.distsys.MultiCloudUser.java Source code

Java tutorial

Introduction

Here is the source code for hu.unimiskolc.iit.distsys.MultiCloudUser.java

Source

/*
 *  ========================================================================
 *  dcf-exercises
 *  ========================================================================
 *  
 *  This file is part of dcf-exercises.
 *  
 *  dcf-exercises 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 3 of the License, or (at
 *  your option) any later version.
 *  
 *  dcf-exercises 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 dcf-exercises.  If not, see <http://www.gnu.org/licenses/>.
 *  
 *  (C) Copyright 2015, Gabor Kecskemeti (kecskemeti@iit.uni-miskolc.hu)
 */
package hu.unimiskolc.iit.distsys;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.RandomUtils;

import hu.mta.sztaki.lpds.cloud.simulator.DeferredEvent;
import hu.mta.sztaki.lpds.cloud.simulator.Timed;
import hu.mta.sztaki.lpds.cloud.simulator.helpers.job.Job;
import hu.mta.sztaki.lpds.cloud.simulator.helpers.job.JobListAnalyser;
import hu.mta.sztaki.lpds.cloud.simulator.helpers.trace.random.RepetitiveRandomTraceGenerator;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.IaaSService;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.VMManager.VMManagementException;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.VirtualMachine;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.VirtualMachine.State;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.constraints.ConstantConstraints;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.constraints.ResourceConstraints;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.resourcemodel.ConsumptionEventAdapter;
import hu.mta.sztaki.lpds.cloud.simulator.io.NetworkNode.NetworkException;
import hu.mta.sztaki.lpds.cloud.simulator.io.Repository;
import hu.mta.sztaki.lpds.cloud.simulator.io.VirtualAppliance;
import hu.unimiskolc.iit.distsys.forwarders.IaaSForwarder;

public class MultiCloudUser extends Timed {
    public interface CompletionCallback {
        void alljobsComplete();
    }

    public static class ProviderRecord implements VirtualMachine.StateChange {
        int vmsRequested = 0;
        int vmsDestroyedbyUser = 0;

        private ArrayList<VirtualMachine> myVMSet = new ArrayList<VirtualMachine>();
        private IaaSService service;
        private VirtualAppliance va;
        private Repository repo;

        public ProviderRecord(IaaSService s) {
            service = s;
            repo = s.repositories.get(0);
            va = (VirtualAppliance) repo.contents().iterator().next();
        }

        public VirtualMachine[] getNewVM(ResourceConstraints rc, int count)
                throws VMManagementException, NetworkException {
            vmsRequested += count;
            VirtualMachine[] vms = service.requestVM(va, rc, repo, count);
            for (VirtualMachine vm : vms) {
                vm.subscribeStateChange(this);
                myVMSet.add(vm);
            }
            return vms;
        }

        public VirtualMachine getFreeVM(ResourceConstraints rc) {
            for (VirtualMachine vm : myVMSet) {
                if (isVMAccessible(vm) && vm.getResourceAllocation().allocated.compareTo(rc) >= 0) {
                    return vm;
                }
            }
            return null;
        }

        @Override
        public void stateChanged(VirtualMachine vm, State oldState, State newState) {
            if (newState.equals(VirtualMachine.State.DESTROYED)) {
                myVMSet.remove(vm);
            }
        }

        public void destroyVM(VirtualMachine vm) throws VMManagementException {
            if (myVMSet.contains(vm)) {
                vm.destroy(true);
                vmsDestroyedbyUser++;
            }
        }

        public double getSuccessRatio() {
            return vmsRequested < 20 ? 1 : ((double) vmsDestroyedbyUser) / vmsRequested;
        }
    }

    private static boolean isVMAccessible(final VirtualMachine vm) {
        if (vm.getState().equals(VirtualMachine.State.RUNNING)) {
            if (vm.underProcessing.size() + vm.toBeAdded.size() == 0) {
                return true;
            }
        }
        return false;
    }

    private final ProviderRecord[] records;
    private final List<Job> jobs;
    protected int minindex = 0;
    public int successfulJobCount = 0;
    private boolean prepareForCompletion = false;
    private final CompletionCallback callback;

    public MultiCloudUser(IaaSService[] theProviders, CompletionCallback cb) throws Exception {
        callback = cb;
        records = new ProviderRecord[theProviders.length];
        for (int i = 0; i < records.length; i++) {
            records[i] = new ProviderRecord(theProviders[i]);
        }

        // Preparing the jobs for the VMs
        RepetitiveRandomTraceGenerator rrtg = new RepetitiveRandomTraceGenerator(ComplexDCFJob.class);
        // total number of jobs
        rrtg.setJobNum(RandomUtils.nextInt(100, 10000));
        // joblist properties
        rrtg.setExecmin(10);
        rrtg.setExecmax(7200);
        rrtg.setMaxgap(0);
        rrtg.setMingap(0);
        rrtg.setMaxStartSpread((int) (Constants.machineLifeTime / 1000));
        rrtg.setMaxTotalProcs(10000);
        rrtg.setMinNodeProcs(1);
        rrtg.setMaxNodeprocs(ExercisesBase.maxCoreCount);
        rrtg.setParallel(rrtg.getJobNum());
        jobs = rrtg.getAllJobs();
        Collections.sort(jobs, JobListAnalyser.startTimeComparator);
        long adjustTime = 1 + Timed.getFireCount() / 1000;
        for (Job j : jobs) {
            j.adjust(adjustTime);
            ((ComplexDCFJob) j).setAvailabilityLevel(0.5);
        }
        subscribe((jobs.get(0).getSubmittimeSecs() - adjustTime) * 1000);
    }

    private void allocateVMforJob(final VirtualMachine vm, final Job toprocess) {
        try {
            ((ComplexDCFJob) toprocess).startNowOnVM(vm, new ConsumptionEventAdapter() {
                @Override
                public void conComplete() {
                    super.conComplete();
                    successfulJobCount++;

                    new DeferredEvent(Constants.anHour) {
                        @Override
                        protected void eventAction() {
                            if (isVMAccessible(vm)) {
                                boolean allComplete = true;
                                for (ProviderRecord pr : records) {
                                    try {
                                        pr.destroyVM(vm);
                                        allComplete |= pr.myVMSet.size() == 0;
                                    } catch (VMManagementException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                                if (allComplete && prepareForCompletion) {
                                    callback.alljobsComplete();
                                }
                            }
                        }
                    };
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void tick(long fires) {
        for (int i = minindex; i < jobs.size(); i++) {
            final Job toprocess = jobs.get(i);
            long submittime = toprocess.getSubmittimeSecs() * 1000;
            if (minindex == jobs.size() - 3) {
                minindex += 0;
            }
            if (fires == submittime) {
                minindex++;
                ConstantConstraints cc = new ConstantConstraints(toprocess.nprocs, ExercisesBase.minProcessingCap,
                        ExercisesBase.minMem / toprocess.nprocs);
                VirtualMachine vm = null;
                for (ProviderRecord pr : records) {
                    vm = pr.getFreeVM(cc);
                    if (vm != null)
                        break;
                }
                if (vm == null) {
                    ProviderRecord prBest = null;
                    double priceSuccessCombined = Double.MAX_VALUE;
                    for (ProviderRecord pr : records) {
                        double currPriceCombo = ((IaaSForwarder) pr.service).getResourceQuote(cc)
                                / pr.getSuccessRatio();
                        if (currPriceCombo < priceSuccessCombined) {
                            priceSuccessCombined = currPriceCombo;
                            prBest = pr;
                        }
                    }
                    try {
                        final ProviderRecord theProvider = prBest;
                        final VirtualMachine theNewVM = theProvider.getNewVM(cc, 1)[0];
                        theNewVM.subscribeStateChange(new VirtualMachine.StateChange() {
                            @Override
                            public void stateChanged(VirtualMachine vm, State oldState, State newState) {
                                switch (newState) {
                                case RUNNING:
                                    // our VM is working great!

                                    // we dispatch the job for it
                                    allocateVMforJob(theNewVM, toprocess);

                                    // then cancel our listener
                                case DESTROYED:
                                case SHUTDOWN:
                                case NONSERVABLE:
                                    // cancel our listener
                                    vm.unsubscribeStateChange(this);
                                default:
                                    // do nothing
                                }
                            }
                        });
                        // do not queue the VM forever if it is not scheduled in
                        // 20 minutes then it is cancelled and the job is forgot
                        // about forever
                        new DeferredEvent(1200000) {
                            @Override
                            protected void eventAction() {
                                if (theNewVM.getState().equals(VirtualMachine.State.DESTROYED)
                                        && theNewVM.getTotalProcessed() == 0) {
                                    try {
                                        theProvider.service.terminateVM(theNewVM, false);
                                    } catch (Exception e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                            }
                        };
                    } catch (VMManagementException e) {
                        // The job has failed prematurely , we ignore it, but
                        // the getNewVM function above reports the failure and
                        // reduces the chances of choosing the particular
                        // provider for a while.
                    } catch (Exception e) {
                        // This is unexpected behavior!
                        throw new RuntimeException(e);
                    }
                } else {
                    // There was a VM already that is good for this job
                    allocateVMforJob(vm, toprocess);
                }
            } else if (fires < submittime) {
                updateFrequency(submittime - fires);
                break;
            } else {
                minindex += 0;
            }
        }
        if (minindex == jobs.size()) {
            unsubscribe();
            prepareForCompletion = true;
        }
    }

    public int getJobTotJobCount() {
        return jobs.size();
    }

}