/*
* Copyright (c) 2010 Ecole des Mines de Nantes.
*
* This file is part of Entropy.
*
* Entropy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Entropy 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Entropy. If not, see <http://www.gnu.org/licenses/>.
*/
package entropy.vjob;
import choco.cp.solver.constraints.reified.ReifiedFactory;
import choco.kernel.solver.variables.integer.IntDomainVar;
import entropy.configuration.VirtualMachine;
import entropy.plan.choco.ReconfigurationProblem;
import entropy.plan.choco.actionModel.VirtualMachineActionModel;
import entropy.plan.choco.actionModel.slice.ConsumingSlice;
import entropy.plan.choco.actionModel.slice.DemandingSlice;
/**
* A continuous implementation of Spread with provide stronger guarantee than {@link LazySpread}.
* All the virtual machines involved in the constraints will never be hosted on the same node,
* even during the reconfiguration process. For this purpose, migrations may be delayed to
* enforce the non-overlapping between virtual machines.
* <p/>
* For a set of $n$ VMs, it uses $n*(n-1)$ implies constraints.
* For each couple of VM (Vx,Vy), it enforces (C_x^h = D_y^h => C_x^ed <= D_y^st)
*
* @author Fabien Hermenier
*/
public class ContinuousSpread extends Spread {
/**
* Make a new constraint.
*
* @param vms the involved virtual machines
*/
public ContinuousSpread(VJobSet<VirtualMachine> vms) {
super(vms);
}
@Override
public String toString() {
return new StringBuilder("cSpread(").append(vms.pretty()).append(")").toString();
}
/**
* Apply the constraint to the plan if the VM must be in the running state.
* The constraint is applied on all the future running virtual machines given at instantiation.
* Others are ignored.
*
* @param core the plan to customize. Must implement {@link entropy.plan.choco.ChocoCustomizablePlannerModule}
*/
@Override
public void inject(ReconfigurationProblem core) {
//Consider only the currently running and the future running VMs
ExplodedSet<VirtualMachine> runnings = new ExplodedSet<VirtualMachine>();
ExplodedSet<VirtualMachine> ignored = new ExplodedSet<VirtualMachine>();
for (VirtualMachine vm : getAllVirtualMachines()) {
if (core.getFutureRunnings().contains(vm) || core.getSourceConfiguration().isRunning(vm)) {
runnings.add(vm);
} else {
ignored.add(vm);
}
}
if (runnings.size() == 0) {
VJob.logger.debug(this + " is entailed. No VMs are running");
} else {
if (ignored.size() > 0) {
VJob.logger.debug(this + " ignores non-running VMs: " + ignored);
}
//The lazy spread implementation for the placement
new LazySpread(runnings).inject(core);
for (int i = 0; i < runnings.size(); i++) {
VirtualMachine vmI = runnings.get(i);
VirtualMachineActionModel aI = core.getAssociatedAction(vmI);
for (int j = 0; j < i; j++) {
VirtualMachine vmJ = runnings.get(j);
VirtualMachineActionModel aJ = core.getAssociatedAction(vmJ);
DemandingSlice d = aI.getDemandingSlice();
ConsumingSlice c = aJ.getConsumingSlice();
if (d != null && c != null) {
//if slices already placed, and on different nodes, we can ignore this constraint, otherwise ...
if (!(c.hoster().isInstantiated() && d.hoster().isInstantiated() && c.hoster().getVal() != d.hoster().getVal())) {
IntDomainVar eq = core.createBooleanVar("eq");
core.post(ReifiedFactory.builder(eq, core.eq(d.hoster(), c.hoster()), core));
core.post(core.implies(eq, core.leq(c.end(), d.start())));
}
}
//The inverse relation
d = aJ.getDemandingSlice();
c = aI.getConsumingSlice();
if (d != null && c != null) {
//if slices already placed, and on different nodes, we can ignore this constraint, otherwise ...
if (!(c.hoster().isInstantiated() && d.hoster().isInstantiated() && c.hoster().getVal() != d.hoster().getVal())) {
IntDomainVar eq = core.createBooleanVar("eq");
core.post(ReifiedFactory.builder(eq, core.eq(d.hoster(), c.hoster()), core));
core.post(core.implies(eq, core.leq(c.end(), d.start())));
}
}
}
}
}
}
}