package org.act.tstream.schedule.default_assign; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.log4j.Logger; import org.act.tstream.client.ConfigExtension; import org.act.tstream.cluster.Common; import org.act.tstream.schedule.default_assign.Selector.ComponentNumSelector; import org.act.tstream.schedule.default_assign.Selector.InputComponentNumSelector; import org.act.tstream.schedule.default_assign.Selector.Selector; import org.act.tstream.schedule.default_assign.Selector.TotalTaskNumSelector; import org.act.tstream.utils.FailedAssignTopologyException; public class TaskGanker { public static Logger LOG = Logger.getLogger(TaskGanker.class); public static final String ACKER_NAME = "__acker"; private final TaskGankerContext taskContext; private List<ResourceWorkerSlot> assignments = new ArrayList<ResourceWorkerSlot>(); private int workerNum; private int baseNum; private int otherNum; private Set<Integer> tasks; private DefaultTopologyAssignContext context; private Selector componentSelector; private Selector inputComponentSelector; private Selector totalTaskNumSelector; public TaskGanker(DefaultTopologyAssignContext context, Set<Integer> tasks, List<ResourceWorkerSlot> workers) { this.tasks = tasks; this.context = context; context.getRawTopology().get_spouts().keySet(); this.taskContext = new TaskGankerContext( this.buildSupervisorToWorker(workers), Common.buildSpoutOutoputAndBoltInputMap(context)); this.componentSelector = new ComponentNumSelector(taskContext); this.inputComponentSelector = new InputComponentNumSelector(taskContext); this.totalTaskNumSelector = new TotalTaskNumSelector(taskContext); if (tasks.size() == 0) return; this.setTaskNum(); } public List<ResourceWorkerSlot> gankTask() { if (tasks.size() == 0) return assignments; Set<Integer> hadGanked = this.gankOnDifferentNodeTask(); tasks.removeAll(hadGanked); Set<Integer> ackers = new HashSet<Integer>(); for (Integer task : tasks) { String name = context.getTaskToComponent().get(task); if (name.equals(TaskGanker.ACKER_NAME)) { ackers.add(task); continue; } this.beginGank(name, task); } for (Integer task : ackers) { this.beginGank(TaskGanker.ACKER_NAME, task); } return assignments; } private void beginGank(String name, Integer task) { ResourceWorkerSlot worker = this.chooseWorker(name, new ArrayList<ResourceWorkerSlot>(taskContext .getWorkerToTaskNum().keySet())); this.pushTaskToWorker(task, name, worker); } private Set<Integer> gankOnDifferentNodeTask() { Set<Integer> result = new HashSet<Integer>(); for (Integer task : tasks) { Map conf = Common.getComponentMap(context, task); if (ConfigExtension.isTaskOnDifferentNode(conf)) result.add(task); } for (Integer task : result) { String name = context.getTaskToComponent().get(task); ResourceWorkerSlot worker = this.chooseWorker(name, this.getDifferentNodeTaskWokres(name)); this.pushTaskToWorker(task, name, worker); } return result; } private Map<String, List<ResourceWorkerSlot>> buildSupervisorToWorker( List<ResourceWorkerSlot> workers) { Map<String, List<ResourceWorkerSlot>> supervisorToWorker = new HashMap<String, List<ResourceWorkerSlot>>(); for (ResourceWorkerSlot worker : workers) { if (worker.getTasks() == null || worker.getTasks().size() == 0) { List<ResourceWorkerSlot> supervisor = supervisorToWorker .get(worker.getNodeId()); if (supervisor == null) { supervisor = new ArrayList<ResourceWorkerSlot>(); supervisorToWorker.put(worker.getNodeId(), supervisor); } supervisor.add(worker); } else { assignments.add(worker); } } this.workerNum = workers.size() - assignments.size(); return supervisorToWorker; } private ResourceWorkerSlot chooseWorker(String name, List<ResourceWorkerSlot> workers) { List<ResourceWorkerSlot> result = this.componentSelector.select( workers, name); result = this.totalTaskNumSelector.select(result, name); if (name.equals(TaskGanker.ACKER_NAME)) return result.iterator().next(); return this.inputComponentSelector.select(result, name).iterator() .next(); } private void pushTaskToWorker(Integer task, String name, ResourceWorkerSlot worker) { Set<Integer> tasks = worker.getTasks(); if (tasks == null) { tasks = new HashSet<Integer>(); worker.setTasks(tasks); } tasks.add(task); int taskNum = taskContext.getWorkerToTaskNum().get(worker); taskContext.getWorkerToTaskNum().put(worker, ++taskNum); if (otherNum <= 0) { if (taskNum == baseNum) { taskContext.getWorkerToTaskNum().remove(worker); assignments.add(worker); } } else { if (taskNum == (baseNum + 1)) { taskContext.getWorkerToTaskNum().remove(worker); otherNum--; assignments.add(worker); } if (otherNum <= 0) { List<ResourceWorkerSlot> needDelete = new ArrayList<ResourceWorkerSlot>(); for (Entry<ResourceWorkerSlot, Integer> entry : taskContext .getWorkerToTaskNum().entrySet()) { if (entry.getValue() == baseNum) needDelete.add(entry.getKey()); } for (ResourceWorkerSlot workerToDelete : needDelete) { taskContext.getWorkerToTaskNum().remove(workerToDelete); assignments.add(workerToDelete); } } } Map<String, Integer> components = taskContext.getWorkerToComponentNum() .get(worker); if (components == null) { components = new HashMap<String, Integer>(); taskContext.getWorkerToComponentNum().put(worker, components); } Integer componentNum = components.get(name); if (componentNum == null) { componentNum = 0; } components.put(name, ++componentNum); } private void setTaskNum() { this.baseNum = tasks.size() / workerNum; this.otherNum = tasks.size() % workerNum; for (Entry<String, List<ResourceWorkerSlot>> entry : taskContext .getSupervisorToWorker().entrySet()) { for (ResourceWorkerSlot worker : entry.getValue()) { taskContext.getWorkerToTaskNum().put(worker, 0); } } } private List<ResourceWorkerSlot> getDifferentNodeTaskWokres(String name) { List<ResourceWorkerSlot> workers = new ArrayList<ResourceWorkerSlot>(); workers.addAll(taskContext.getWorkerToTaskNum().keySet()); for (Entry<String, List<ResourceWorkerSlot>> entry : taskContext .getSupervisorToWorker().entrySet()) { if (taskContext.getComponentNumOnSupervisor(entry.getKey(), name) != 0) workers.removeAll(entry.getValue()); } if (workers.size() == 0) throw new FailedAssignTopologyException( "there's no enough supervisor for making component: " + name + " 's tasks on different node"); return workers; } }