
org.btrplace.model.view.ShareableResource Maven / Gradle / Ivy
/*
* Copyright (c) 2016 University Nice Sophia Antipolis
*
* This file is part of btrplace.
* This library 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.
*
* This library 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 this program. If not, see .
*/
package org.btrplace.model.view;
import gnu.trove.impl.Constants;
import gnu.trove.map.hash.TObjectIntHashMap;
import org.btrplace.model.Model;
import org.btrplace.model.Node;
import org.btrplace.model.VM;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
/**
* A view to denote a resource that nodes share among the VMs they host
*
* The view allows to specify the physical resource capacity of the nodes
* and the amount of virtual resources allocated to the VMs.
*
* Associated constraints:
*
* - {@link org.btrplace.model.constraint.Preserve} to ensure the availability of a certain amount of virtual resources for a VM
* - {@link org.btrplace.model.constraint.ResourceCapacity} to cap the amount of physical resources that can be used on a node
* - {@link org.btrplace.model.constraint.Overbook} to specify a mapping between the virtual and the physical resources.
*
*
* By default, if there is no {@link org.btrplace.model.constraint.Preserve} constraint for a VM, it is considered the VM requires
* the same amount of virtual resources it is currently consuming.
*
* By default, if there is no {@link org.btrplace.model.constraint.Overbook} constraint for a node, a conservative ratio
* of 1 is used. This means one unit of virtual resources consumes one unit of physical resources.
*
* @author Fabien Hermenier
*/
public class ShareableResource implements ModelView {
/**
* The base of the view identifier. Once instantiated, it is completed
* by the resource identifier.
*/
public static final String VIEW_ID_BASE = "ShareableResource.";
private TObjectIntHashMap vmsConsumption;
private TObjectIntHashMap nodesCapacity;
private String viewId;
private String rcId;
public static final int DEFAULT_NO_VALUE = 0;
/**
* Make a new resource that use {@link #DEFAULT_NO_VALUE}
* for both VMs and nodes.
*
* @param r the resource identifier
*/
public ShareableResource(String r) {
this(r, DEFAULT_NO_VALUE, DEFAULT_NO_VALUE);
}
/**
* Make a new resource.
*
* @param id the resource identifier
* @param defCapacity the nodes default capacity
* @param defConsumption the VM default consumption
*/
public ShareableResource(String id, int defCapacity, int defConsumption) {
vmsConsumption = new TObjectIntHashMap<>(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, defConsumption);
nodesCapacity = new TObjectIntHashMap<>(Constants.DEFAULT_CAPACITY, Constants.DEFAULT_LOAD_FACTOR, defCapacity);
if (defCapacity < 0) {
throw new IllegalArgumentException("The '" + rcId + "' default capacity must be >= 0");
}
if (defConsumption < 0) {
throw new IllegalArgumentException("The '" + rcId + "' default consumption must be >= 0");
}
this.rcId = id;
this.viewId = VIEW_ID_BASE + rcId;
}
/**
* Get the VM consumption.
*
* @param vm the VM
* @return its consumption if it was defined otherwise the default value.
*/
public int getConsumption(VM vm) {
return vmsConsumption.get(vm);
}
/**
* Get the node capacity.
*
* @param n the node
* @return its capacity if it was defined otherwise the default value.
*/
public int getCapacity(Node n) {
return nodesCapacity.get(n);
}
/**
* Get the VMs with defined consumptions.
*
* @return a set that may be empty
*/
public Set getDefinedVMs() {
return vmsConsumption.keySet();
}
/**
* Get the nodes with defined capacities
*
* @return a set that may be empty
*/
public Set getDefinedNodes() {
return nodesCapacity.keySet();
}
/**
* Set the resource consumption of a VM.
*
* @param vm the VM
* @param val the value to set
* @return the current resource
*/
public ShareableResource setConsumption(VM vm, int val) {
if (val < 0) {
throw new IllegalArgumentException("The '" + rcId + "' consumption of '" + vm + "' must be >= 0");
}
vmsConsumption.put(vm, val);
return this;
}
/**
* Set the resource consumption of a node.
*
* @param n the node
* @param val the value to set
* @return the current resource
*/
public ShareableResource setCapacity(Node n, int val) {
if (val < 0) {
throw new IllegalArgumentException("The '" + rcId + "' capacity of '" + n + "' must be >= 0");
}
nodesCapacity.put(n, val);
return this;
}
/**
* Unset a VM consumption.
*
* @param vm the VM
*/
public void unset(VM vm) {
vmsConsumption.remove(vm);
}
/**
* Unset a node capacity.
*
* @param n the node
*/
public void unset(Node n) {
nodesCapacity.remove(n);
}
/**
* Check if the resource consumption is defined for a VM.
*
* @param vm the VM
* @return {@code true} iff the consumption is defined.
*/
public boolean consumptionDefined(VM vm) {
return vmsConsumption.containsKey(vm);
}
/**
* Check if the resource capacity is defined for a node.
*
* @param n the node identifier
* @return {@code true} iff the capacity is defined}.
*/
public boolean capacityDefined(Node n) {
return nodesCapacity.containsKey(n);
}
/**
* Get the view identifier.
*
* @return {@code "ShareableResource.rcId"} where rcId equals {@link #getResourceIdentifier()}
*/
@Override
public String getIdentifier() {
return viewId;
}
/**
* Get the resource identifier
*
* @return a non-empty string
*/
public String getResourceIdentifier() {
return rcId;
}
/**
* Get the default VM consumption.
*
* @return the value.
*/
public int getDefaultConsumption() {
return vmsConsumption.getNoEntryValue();
}
/**
* Get the default node capacity.
*
* @return the value.
*/
public int getDefaultCapacity() {
return nodesCapacity.getNoEntryValue();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ShareableResource that = (ShareableResource) o;
if (!this.vmsConsumption.equals(that.vmsConsumption) ||
!this.nodesCapacity.equals(that.nodesCapacity)) {
return false;
}
return rcId.equals(that.getResourceIdentifier()) && getDefaultCapacity() == that.getDefaultCapacity()
&& getDefaultConsumption() == that.getDefaultConsumption();
}
@Override
public int hashCode() {
return Objects.hash(rcId, vmsConsumption, nodesCapacity);
}
@Override
public ShareableResource copy() {
ShareableResource rc = new ShareableResource(rcId, nodesCapacity.getNoEntryValue(), vmsConsumption.getNoEntryValue());
vmsConsumption.forEachEntry((vm, c) -> {
rc.vmsConsumption.put(vm, c);
return true;
});
nodesCapacity.forEachEntry((n, c) -> {
rc.nodesCapacity.put(n, c);
return true;
});
return rc;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder("rc:").append(rcId).append(':');
for (Iterator ite = nodesCapacity.keySet().iterator(); ite.hasNext(); ) {
Node n = ite.next();
int c = nodesCapacity.get(n);
buf.append("');
if (ite.hasNext()) {
buf.append(',');
}
}
for (Iterator ite = vmsConsumption.keySet().iterator(); ite.hasNext(); ) {
VM vm = ite.next();
int c = vmsConsumption.get(vm);
buf.append("');
if (ite.hasNext()) {
buf.append(',');
}
}
return buf.toString();
}
@Override
public boolean substituteVM(VM oldRef, VM newRef) {
setConsumption(newRef, getConsumption(oldRef));
return true;
}
/**
* Get the cumulative VMs consumption.
*
* @param ids the VMs.
* @param undef {@code true} to include the undefined elements using the default value
* @return the value
*/
public int sumConsumptions(Collection ids, boolean undef) {
int s = 0;
for (VM u : ids) {
if (consumptionDefined(u) || undef) {
s += vmsConsumption.get(u);
}
}
return s;
}
/**
* Get the cumulative nodes capacity.
*
* @param ids the nodes.
* @param undef {@code true} to include the undefined elements using the default value
* @return the value
*/
public int sumCapacities(Collection ids, boolean undef) {
int s = 0;
for (Node u : ids) {
if (capacityDefined(u) || undef) {
s += nodesCapacity.get(u);
}
}
return s;
}
/**
* Get the view associated to a model if exists
*
* @param mo the model to look at
* @return the view if attached. {@code null} otherwise
*/
public static ShareableResource get(Model mo, String id) {
return (ShareableResource) mo.getView(VIEW_ID_BASE + id);
}
}