
org.btrplace.scheduler.choco.constraint.CAmong Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scheduler-choco Show documentation
Show all versions of scheduler-choco Show documentation
Implementation of the VM scheduler that use
the Constraint Programming solver CHOCO to compute solutions.
The newest version!
/*
* Copyright 2021 The BtrPlace Authors. All rights reserved.
* Use of this source code is governed by a LGPL-style
* license that can be found in the LICENSE.txt file.
*/
package org.btrplace.scheduler.choco.constraint;
import org.btrplace.model.Instance;
import org.btrplace.model.Mapping;
import org.btrplace.model.Node;
import org.btrplace.model.VM;
import org.btrplace.model.constraint.Among;
import org.btrplace.model.constraint.Fence;
import org.btrplace.scheduler.SchedulerException;
import org.btrplace.scheduler.choco.Parameters;
import org.btrplace.scheduler.choco.ReconfigurationProblem;
import org.chocosolver.solver.constraints.Constraint;
import org.chocosolver.solver.variables.IntVar;
import java.util.*;
/**
* Choco implementation of the {@link org.btrplace.model.constraint.Among} constraint.
*
* @author Fabien Hermenier
*/
public class CAmong implements ChocoConstraint {
private final Among cstr;
private IntVar vmGrpId;
/**
* The label of the variable denoting the group of VMs.
*/
public static final String GROUP_LABEL = "among#grp";
/**
* Make a new constraint.
*
* @param a the constraint to rely on
*/
public CAmong(Among a) {
cstr = a;
}
/**
* Get the group variable that indicate on which group the VMs are running.
*
* @return a variable that may be instantiated but {@code null} until
* {@link ChocoConstraint#inject(Parameters, ReconfigurationProblem)} has been called
*/
public IntVar getGroupVariable() {
return vmGrpId;
}
@Override
public boolean inject(Parameters ps, ReconfigurationProblem rp) throws SchedulerException {
int nextGrp = -1;
int curGrp = -1;
List> groups = new ArrayList<>();
groups.addAll(cstr.getGroupsOfNodes());
Set running = new HashSet<>();
Mapping src = rp.getSourceModel().getMapping();
for (VM vm : cstr.getInvolvedVMs()) {
if (rp.getFutureRunningVMs().contains(vm)) {
//The VM will be running
running.add(vm);
IntVar vAssign = rp.getVMAction(vm).getDSlice().getHoster();
//If one of the VM is already placed, no need for the constraint, the group will be known
if (vAssign.isInstantiated()) {
//Get the group of nodes that match the selected node
int g = getGroup(rp.getNode(vAssign.getValue()), groups);
if (errorReported(rp, vm, nextGrp, g)) {
return false;
}
nextGrp = g;
}
}
if (cstr.isContinuous() && src.isRunning(vm)) {
//The VM is already running, so we get its current group
Node curNode = src.getVMLocation(vm);
int g = getGroup(curNode, groups);
if (errorReported(rp, vm, curGrp, g)) {
return false;
}
curGrp = g;
}
}
if (cstr.isContinuous() && curGrp != -1) {
return restrictGroup(ps, rp, running, groups, curGrp);
} else if (groups.size() == 1) {
return restrictGroup(ps, rp, running, groups, 0);
}
return restrictGroup(ps, rp, running, groups, nextGrp);
}
private boolean errorReported(ReconfigurationProblem rp, VM vm, int futureGroup, int g) {
if (futureGroup == -1) {
//It is not possible to state
return false;
}
if (g == -1) {
rp.getLogger().debug("The VM in '{}' will be placed out of any of the allowed group", vm);
return true;
} else if (futureGroup != g) {
rp.getLogger().debug("The VMs in '{}' cannot be spread over multiple group of nodes", cstr.getInvolvedVMs());
return true;
}
return false;
}
private boolean restrictGroup(Parameters ps, ReconfigurationProblem rp, Set running, List> groups, int selected) {
if (selected == -1) {
//Now, we create a variable to indicate on which group of nodes the VMs will be
vmGrpId = rp.getModel().intVar(rp.makeVarLabel(GROUP_LABEL), 0, groups.size() - 1, false);
//grp: A table to indicate the group each node belong to, -1 for no group
int[] grp = new int[rp.getNodes().size()];
for (int i = 0; i < grp.length; i++) {
Node n = rp.getNode(i);
int idx = getGroup(n, groups);
if (idx >= 0) {
grp[i] = idx;
} else {
grp[i] = -1;
}
}
//We link the VM placement variable with the group variable
for (VM vm : running) {
IntVar assign = rp.getVMAction(vm).getDSlice().getHoster();
Constraint c = rp.getModel().element(vmGrpId, grp, assign, 0/*, "detect"*/);
rp.getModel().post(c);
}
} else {
//As the group is already known, it's now just a fence constraint
vmGrpId = rp.fixed(selected, GROUP_LABEL);
return fence(ps, rp, running, groups.get(selected));
}
return true;
}
private static boolean fence(Parameters ps, ReconfigurationProblem rp, Collection vms, Collection group) {
for (VM v : vms) {
if (!new CFence(new Fence(v, group)).inject(ps, rp)) {
return false;
}
}
return true;
}
/**
* Get the group the node belong to.
*
* @param n the node
* @param grps the group of nodes.
* @return the group identifier, {@code -1} if the node does not belong to a group
*/
public int getGroup(Node n, List> grps) {
int i = 0;
for (Collection pGrp : grps) {
if (pGrp.contains(n)) {
return i;
}
i++;
}
return -1;
}
@Override
public Set getMisPlacedVMs(Instance i) {
if (!cstr.isSatisfied(i.getModel())) {
return new HashSet<>(cstr.getInvolvedVMs());
}
return Collections.emptySet();
}
@Override
public String toString() {
return cstr.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy