package cz.cuni.mff.d3s.been.manager.selector;
import static cz.cuni.mff.d3s.been.core.task.TaskExclusivity.EXCLUSIVE;
import static cz.cuni.mff.d3s.been.core.task.TaskExclusivity.NON_EXCLUSIVE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.hazelcast.core.MapEntry;
import com.hazelcast.query.Predicate;
import cz.cuni.mff.d3s.been.cluster.context.ClusterContext;
import cz.cuni.mff.d3s.been.core.ri.RuntimeInfo;
import cz.cuni.mff.d3s.been.core.ri.RuntimeInfos;
import cz.cuni.mff.d3s.been.core.task.TaskEntry;
import cz.cuni.mff.d3s.been.core.task.TaskExclusivity;
/**
* Finds a free Host Runtime for a task.
*
* This selector randomly chooses a Host Runtime.
*
* @author Martin Sixta
*/
final class RandomRuntimeSelection implements IRuntimeSelection {
private ClusterContext clusterCtx;
private final TaskEntry entry;
/**
* Creates RandomRuntimeSelection.
*
* @param clusterCtx
* connection to the cluster
* @param entry
* targeted task entry
*/
public RandomRuntimeSelection(final ClusterContext clusterCtx, final TaskEntry entry) {
this.clusterCtx = clusterCtx;
this.entry = entry;
}
@Override
public String select() throws NoRuntimeFoundException {
TaskExclusivity exclusivity = entry.getTaskDescriptor().getExclusive();
String contextId = entry.getTaskContextId();
Predicate<?, ?> predicate = new ExclusivityPredicate(exclusivity, contextId);
List<RuntimeInfo> runtimes = new ArrayList<>(clusterCtx.getRuntimes().getRuntimeMap().values(predicate));
if (runtimes.size() == 0) {
throw new NoRuntimeFoundException("Cannot find suitable Host Runtime");
}
Collections.shuffle(runtimes);
Collections.sort(runtimes, new RuntimesComparable());
return (runtimes.get(0).getId());
}
/**
*
* Predicate for filtering RuntimeInfo based on Host Runtime Exclusivity
*
* @author Martin Sixta
*/
private static final class ExclusivityPredicate implements Predicate<String, RuntimeInfo> {
private final TaskExclusivity taskExclusivity;
private final String contextId;
ExclusivityPredicate(TaskExclusivity taskExclusivity, String contextId) {
this.taskExclusivity = taskExclusivity;
this.contextId = contextId;
}
@Override
public boolean apply(MapEntry<String, RuntimeInfo> mapEntry) {
RuntimeInfo info = mapEntry.getValue();
if (info.getExclusivity() == null) {
// workaround for JAXB not setting default value on elements
info.setExclusivity(TaskExclusivity.NON_EXCLUSIVE.toString());
}
// Runtime Overload conditions
if (RuntimeInfos.isMaxTasksReached(info)) {
return false;
}
if (RuntimeInfos.isMemoryThresholdReached(info)) {
return false;
}
TaskExclusivity runtimeExclusivity;
try {
runtimeExclusivity = TaskExclusivity.valueOf(info.getExclusivity());
} catch (IllegalArgumentException e) {
// something fishy is going on, just skip this host runtime
runtimeExclusivity = EXCLUSIVE;
}
switch (runtimeExclusivity) {
case NON_EXCLUSIVE:
boolean isExclusive = (taskExclusivity != NON_EXCLUSIVE);
boolean hasTasks = (info.getTaskCount() > 0);
return !(isExclusive && hasTasks);
case CONTEXT_EXCLUSIVE:
return contextId.equals(info.getExclusiveId());
case EXCLUSIVE:
return false;
}
return true;
}
}
}