package com.breakersoft.plow.dispatcher; import java.util.List; import java.util.UUID; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.breakersoft.plow.Cluster; import com.breakersoft.plow.JobId; import com.breakersoft.plow.Proc; import com.breakersoft.plow.Project; import com.breakersoft.plow.Task; import com.breakersoft.plow.dao.QuotaDao; import com.breakersoft.plow.dispatcher.dao.DispatchDao; import com.breakersoft.plow.dispatcher.dao.DispatchTaskDao; import com.breakersoft.plow.dispatcher.dao.ProcDao; import com.breakersoft.plow.dispatcher.domain.DispatchJob; import com.breakersoft.plow.dispatcher.domain.DispatchNode; import com.breakersoft.plow.dispatcher.domain.DispatchProc; import com.breakersoft.plow.dispatcher.domain.DispatchProject; import com.breakersoft.plow.dispatcher.domain.DispatchResource; import com.breakersoft.plow.dispatcher.domain.DispatchTask; import com.breakersoft.plow.event.EventManager; import com.breakersoft.plow.exceptions.PlowDispatcherException; import com.breakersoft.plow.monitor.PlowStats; import com.breakersoft.plow.rnd.thrift.RunTaskCommand; import com.breakersoft.plow.thrift.SlotMode; import com.breakersoft.plow.thrift.TaskState; @Service @Transactional public class DispatchServiceImpl implements DispatchService { private static final Logger logger = org.slf4j.LoggerFactory.getLogger(DispatchServiceImpl.class); @Autowired private DispatchDao dispatchDao; @Autowired private ProcDao procDao; @Autowired private DispatchTaskDao dispatchTaskDao; @Autowired private QuotaDao quotaDao; @Autowired private EventManager eventManager; @Override @Transactional(readOnly=true) public List<DispatchJob> getDispatchJobs(DispatchProject project, DispatchNode node) { return dispatchDao.getDispatchJobs(project, node); } @Transactional(readOnly=true) public DispatchJob getDispatchJob(UUID id) { return dispatchDao.getDispatchJob(id); } @Override @Transactional(readOnly=true) public List<DispatchProject> getSortedProjectList(DispatchNode node) { return dispatchDao.getSortedProjectList(node); } @Override @Transactional(readOnly=true) public DispatchProc getDispatchProc(String id) { return dispatchDao.getDispatchProc(UUID.fromString(id)); } @Override @Transactional(readOnly=true) public DispatchProc getDispatchProc(Task task) { return dispatchDao.getDispatchProc(task); } @Override @Transactional(readOnly=true) public DispatchNode getDispatchNode(String name) { return dispatchDao.getDispatchNode(name); } @Override public boolean reserveTask(Task task) { return dispatchTaskDao.reserve(task); } @Override public boolean unreserveTask(Task task) { return dispatchTaskDao.unreserve(task); } @Override @Transactional(readOnly=true) public List<DispatchProc> getOrphanProcs() { return dispatchDao.getOrphanProcs(); } @Override @Transactional(readOnly=true) public List<DispatchProc> getDeallocatedProcs() { return dispatchDao.getDeallocatedProcs(); } @Override public boolean startTask(DispatchTask task, DispatchProc proc) { if (dispatchTaskDao.start(task, proc)) { task.started = true; return true; } return false; } @Override public boolean stopTask(Task task, TaskState state, int exitStatus, int exitSignal) { if (dispatchTaskDao.stop(task, state, exitStatus, exitSignal)) { return true; } return false; } @Override public boolean dependQueueProcessed(Task task) { return dispatchTaskDao.dependQueueProcessed(task); } @Override public void unassignProc(DispatchProc proc) { procDao.unassign(proc); proc.setTaskId(null); } @Override public void assignProc(DispatchProc proc, DispatchTask task) { procDao.assign(proc, task); proc.setTaskId(task.getTaskId()); } @Override @Transactional(readOnly=true) public boolean quotaCheck(Cluster cluster, Project project) { return quotaDao.check(cluster, project); } @Override public DispatchProc allocateProc(DispatchNode node, DispatchTask task) { final DispatchProc proc = new DispatchProc(); proc.setJobId(task.jobId); proc.setTaskId(task.taskId); proc.setLayerId(task.getLayerId()); proc.setHostname(node.getName()); proc.setNodeId(node.getNodeId()); proc.setAllocated(true); proc.setTags(node.getTags()); proc.setClusterId(node.getClusterId()); proc.setQuotaId(quotaDao.getQuota(node, task).getQuotaId()); int cores; int ram; if (node.getSlotMode().equals(SlotMode.SINGLE)) { cores = node.getIdleCores(); ram = node.getIdleRam(); } else if (node.getSlotMode().equals(SlotMode.SLOTS)) { // Check to see if we're dispatching the runt slot (if any) and handle that situation. if (node.getIdleCores() < node.getSlotCores() || node.getIdleRam() < node.getSlotRam()) { cores = Math.min(node.getSlotCores(), node.getIdleCores()); ram = Math.min(node.getSlotRam(), node.getIdleRam()); } else { int factor = Math.max( (int) (Math.ceil(task.minCores / (float) node.getSlotCores())), (int) (Math.ceil(task.minRam / (float) node.getSlotRam()))); cores = factor * node.getSlotCores(); ram = factor * node.getSlotRam(); } } else { // Dynamic. // If the ram left on the node is less than the minimum amount of // ram for the node to be considered for dispatch, then just take // the rest of the cores. if (node.getIdleRam() - task.minRam < DispatchConfig.MIN_RAM_FOR_DISPATCH) { cores = node.getIdleCores(); } else { cores = task.minCores; } ram = task.minRam; } if (cores < task.minCores || ram < task.minRam) { throw new PlowDispatcherException( "Failed to allocate a proc from " + node + ", " + cores + "/" + ram + " not enough to run task " + task.minCores + "/" + task.minRam); } proc.setCores(cores); proc.setRam(ram); try { procDao.create(proc); //PlowStats.procAllocCount.incrementAndGet(); return proc; } catch (Exception e) { //PlowStats.procAllocFailCount.incrementAndGet(); throw new PlowDispatcherException( "Failed to allocatae a proc from " + node.getName() + "," + e, e); } } @Override public void deallocateProc(Proc proc, String why) { if (proc == null) { return; } if (!procDao.delete(proc)) { PlowStats.procUnallocFailCount.incrementAndGet(); logger.warn("{} was alredy deallocated.", proc); } else { logger.info("deallocating {}, {}", proc, why); PlowStats.procUnallocCount.incrementAndGet(); } } @Override public void markAsDeallocated(Proc proc) { procDao.setProcDeallocated(proc); } @Override public void unassignAndMarkForDeallocation(Proc proc) { procDao.unassignAndMarkForDeallocation(proc); } @Override @Transactional(readOnly=true) public List<DispatchTask> getDispatchableTasks(JobId job, DispatchResource resource, int limit) { return dispatchTaskDao.getDispatchableTasks(job, resource, limit); } @Override @Transactional(readOnly=true) public List<DispatchTask> getDispatchableTasks(JobId job, DispatchResource resource) { return dispatchTaskDao.getDispatchableTasks(job, resource, 10); } @Override @Transactional(readOnly=true) public RunTaskCommand getRuntaskCommand(Task task) { return dispatchTaskDao.getRunTaskCommand(task); } @Override @Transactional(readOnly=true) public boolean isAtMaxRetries(Task task) { return dispatchTaskDao.isAtMaxRetries(task); } }