package org.act.tstream.schedule.default_assign;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.act.tstream.daemon.supervisor.SupervisorInfo;
import org.act.tstream.schedule.IToplogyScheduler;
import org.act.tstream.schedule.TopologyAssignContext;
import org.act.tstream.task.Assignment;
import org.act.tstream.utils.FailedAssignTopologyException;
public class DefaultTopologyScheduler implements IToplogyScheduler {
private static final Logger LOG = Logger
.getLogger(DefaultTopologyScheduler.class);
private Map nimbusConf;
@Override
public void prepare(Map conf) {
nimbusConf = conf;
}
/**
* @@@ Here maybe exist one problem, some dead slots have been free
*
* @param context
*/
protected void freeUsed(TopologyAssignContext context) {
Set<Integer> canFree = new HashSet<Integer>();
canFree.addAll(context.getAllTaskIds());
canFree.removeAll(context.getUnstoppedTaskIds());
Map<String, SupervisorInfo> cluster = context.getCluster();
Assignment oldAssigns = context.getOldAssignment();
for (Integer task : canFree) {
ResourceWorkerSlot worker = oldAssigns.getWorkerByTaskId(task);
if (worker == null) {
LOG.warn("When free rebalance resource, no ResourceAssignment of task "
+ task);
continue;
}
SupervisorInfo supervisorInfo = cluster.get(worker.getNodeId());
if (supervisorInfo == null) {
continue;
}
supervisorInfo.getWorkerPorts().add(worker.getPort());
}
}
private Set<Integer> getNeedAssignTasks(DefaultTopologyAssignContext context) {
Set<Integer> needAssign = new HashSet<Integer>();
int assignType = context.getAssignType();
if (assignType == TopologyAssignContext.ASSIGN_TYPE_NEW) {
needAssign.addAll(context.getAllTaskIds());
} else if (assignType == TopologyAssignContext.ASSIGN_TYPE_REBALANCE) {
needAssign.addAll(context.getAllTaskIds());
needAssign.removeAll(context.getUnstoppedTaskIds());
} else {
// monitor
needAssign.addAll(context.getDeadTaskIds());
}
return needAssign;
}
/**
* Get the task Map which the task is alive and will be kept Only when type
* is ASSIGN_TYPE_MONITOR, it is valid
*
* @param defaultContext
* @param needAssigns
* @return
*/
public Set<ResourceWorkerSlot> getKeepAssign(
DefaultTopologyAssignContext defaultContext,
Set<Integer> needAssigns) {
Set<Integer> keepAssignIds = new HashSet<Integer>();
keepAssignIds.addAll(defaultContext.getAllTaskIds());
keepAssignIds.removeAll(defaultContext.getUnstoppedTaskIds());
keepAssignIds.removeAll(needAssigns);
Set<ResourceWorkerSlot> keeps = new HashSet<ResourceWorkerSlot>();
if (keepAssignIds.isEmpty()) {
return keeps;
}
Assignment oldAssignment = defaultContext.getOldAssignment();
if (oldAssignment == null) {
return keeps;
}
keeps.addAll(defaultContext.getOldWorkers());
for (ResourceWorkerSlot worker : defaultContext.getOldWorkers()) {
for (Integer task : worker.getTasks()) {
if (!keepAssignIds.contains(task)) {
keeps.remove(worker);
break;
}
}
}
return keeps;
}
@Override
public Set<ResourceWorkerSlot> assignTasks(TopologyAssignContext context)
throws FailedAssignTopologyException {
int assignType = context.getAssignType();
if (TopologyAssignContext.isAssignTypeValid(assignType) == false) {
throw new FailedAssignTopologyException("Invalide Assign Type "
+ assignType);
}
DefaultTopologyAssignContext defaultContext = new DefaultTopologyAssignContext(
context);
if (assignType == TopologyAssignContext.ASSIGN_TYPE_REBALANCE) {
freeUsed(defaultContext);
}
LOG.info("Dead tasks:" + defaultContext.getDeadTaskIds());
LOG.info("Unstopped tasks:" + defaultContext.getUnstoppedTaskIds());
Set<Integer> needAssignTasks = getNeedAssignTasks(defaultContext);
Set<ResourceWorkerSlot> keepAssigns = getKeepAssign(defaultContext,
needAssignTasks);
// please use tree map to make task sequence
Set<ResourceWorkerSlot> ret = new HashSet<ResourceWorkerSlot>();
ret.addAll(keepAssigns);
ret.addAll(defaultContext.getUnstoppedWorkers());
int allocWorkerNum = defaultContext.getTotalWorkerNum()
- defaultContext.getUnstoppedWorkerNum() - keepAssigns.size();
if (allocWorkerNum <= 0) {
LOG.warn("Don't need assign workers, all workers are fine "
+ defaultContext.toDetailString());
throw new FailedAssignTopologyException(
"Don't need assign worker, all workers are fine ");
}
List<ResourceWorkerSlot> newAssignList = WorkerMaker.getInstance()
.makeWorkers(defaultContext, needAssignTasks, allocWorkerNum);
TaskGanker ganker = new TaskGanker(defaultContext, needAssignTasks,
newAssignList);
Set<ResourceWorkerSlot> newAssigns = new HashSet<ResourceWorkerSlot>(
ganker.gankTask());
ret.addAll(newAssigns);
LOG.info("Keep Alive slots:" + keepAssigns);
LOG.info("Unstopped slots:" + defaultContext.getUnstoppedWorkers());
LOG.info("New assign slots:" + newAssigns);
return ret;
}
}