package com.breakersoft.plow.service; import static com.breakersoft.plow.util.PlowUtils.checkEmpty; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.breakersoft.plow.Depend; import com.breakersoft.plow.FrameRange; import com.breakersoft.plow.Job; import com.breakersoft.plow.Layer; import com.breakersoft.plow.Task; import com.breakersoft.plow.TaskOnTaskBatch; import com.breakersoft.plow.dao.DependDao; import com.breakersoft.plow.dao.JobDao; import com.breakersoft.plow.dao.LayerDao; import com.breakersoft.plow.dao.TaskDao; import com.breakersoft.plow.exceptions.DependencyException; import com.breakersoft.plow.thrift.DependSpecT; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @Service @Transactional public class DependServiceImpl implements DependService { private static final Logger logger = org.slf4j.LoggerFactory.getLogger(DependServiceImpl.class); @Autowired JobDao jobDao; @Autowired LayerDao layerDao; @Autowired TaskDao taskDao; @Autowired DependDao dependDao; public Depend createDepend(Job job, DependSpecT spec) { spec.dependentJob = job.getName(); spec.dependOnJob = job.getName(); return createDepend(spec); } public Depend createDepend(DependSpecT spec) { Job dependentJob; Job dependOnJob; Layer dependentLayer; Layer dependOnLayer; Task dependentTask; Task dependOnTask; Depend depend = null; if (spec.getType() == null) { throw new DependencyException("Dependency type is not set to a value."); } switch(spec.getType()) { case JOB_ON_JOB: dependentJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependentJob)); dependOnJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependOnJob)); depend = dependDao.createJobOnJob(dependentJob, dependOnJob); break; case LAYER_ON_LAYER: dependentJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependentJob)); dependOnJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependOnJob)); dependentLayer = layerDao.get(dependentJob,checkEmpty(spec.dependentLayer)); dependOnLayer = layerDao.get(dependOnJob,checkEmpty(spec.dependOnLayer)); depend = dependDao.createLayerOnLayer( dependentJob, dependentLayer, dependentJob, dependOnLayer); break; case LAYER_ON_TASK: dependentJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependentJob)); dependentLayer = layerDao.get(dependentJob, checkEmpty(spec.dependentLayer)); dependOnJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependOnJob)); dependOnTask = taskDao.getByNameOrId(dependOnJob, checkEmpty(spec.dependOnTask)); dependOnLayer = layerDao.get(dependOnTask.getLayerId()); depend = dependDao.createLayerOnTask(dependentJob, dependentLayer, dependOnJob, dependOnLayer, dependOnTask); break; case TASK_ON_LAYER: dependentJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependentJob)); dependentTask = taskDao.getByNameOrId(dependentJob, checkEmpty(spec.dependentTask)); dependentLayer = layerDao.get(dependentTask.getLayerId()); dependOnJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependOnJob)); dependOnLayer = layerDao.get(dependOnJob, checkEmpty(spec.dependOnLayer)); depend = dependDao.createTaskOnLayer( dependentJob, dependentLayer, dependentTask, dependOnJob, dependOnLayer); break; case TASK_ON_TASK: dependentJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependentJob)); dependentTask = taskDao.getByNameOrId(dependentJob,checkEmpty(spec.dependentTask)); dependentLayer = layerDao.get(dependentTask.getLayerId()); dependOnJob = jobDao.getByActiveNameOrId(checkEmpty(spec.dependOnJob)); dependOnTask = taskDao.getByNameOrId(dependOnJob,checkEmpty(spec.dependOnTask)); dependOnLayer = layerDao.get(dependOnTask.getLayerId()); depend = dependDao.createTaskOnTask(dependentJob, dependentLayer, dependentTask, dependOnJob, dependOnLayer, dependOnTask); break; case TASK_BY_TASK: dependentJob = jobDao.getByActiveNameOrId( checkEmpty(spec.dependentJob)); dependOnJob = jobDao.getByActiveNameOrId( checkEmpty(spec.dependOnJob)); dependentLayer = layerDao.get(dependentJob, checkEmpty(spec.dependentLayer)); dependOnLayer = layerDao.get(dependOnJob, checkEmpty(spec.dependOnLayer)); createTaskByTask(dependentJob, dependentLayer, dependOnJob, dependOnLayer); break; default: throw new DependencyException("Unhandled dependency type " + spec.getType()); } if (depend != null) { dependDao.incrementDependCounts(depend); } return depend; } @Override public boolean satisfyDepend(Depend depend) { if (dependDao.satisfyDepend(depend)) { dependDao.decrementDependCounts(depend); return true; } return false; } @Override public boolean unsatisfyDepend(Depend depend) { if (dependDao.unsatisfyDepend(depend)) { dependDao.incrementDependCounts(depend); return true; } return false; } @Override @Transactional(readOnly=true) public Depend getDepend(UUID id) { return dependDao.get(id); } @Override @Transactional(readOnly=true) public List<Depend> getOnJobDepends(Job job) { return dependDao.getOnJobDepends(job); } @Override @Transactional(readOnly=true) public List<Depend> getOnLayerDepends(Layer layer) { return dependDao.getOnLayerDepends(layer); } @Override @Transactional(readOnly=true) public List<Depend> getOnTaskDepends(Task task) { return dependDao.getOnTaskDepends(task); } private void createTaskByTask(Job dependentJob, Layer dependentLayer, Job dependOnJob, Layer dependOnLayer) { /* * Task by task depends requires both layers to actually * have a frame range. */ final FrameRange dependentRange = layerDao.getFrameRange(dependentLayer); final FrameRange dependOnRange = layerDao.getFrameRange(dependOnLayer); final Set<Integer> dependOnTaskNumbers = Sets.newLinkedHashSet(); final Map<Integer, UUID> dependentTaskCache = taskDao.buildTaskCache(dependentLayer, dependentRange.numFrames); final Map<Integer, UUID> dependOnTaskCache = taskDao.buildTaskCache(dependOnLayer, dependOnRange.numFrames); final TaskOnTaskBatch batch = new TaskOnTaskBatch( dependentRange.frameSet.size() / dependentRange.chunkSize); batch.dependentJob = dependentJob; batch.dependentLayer = dependentLayer; batch.dependOnJob = dependOnJob; batch.dependOnLayer = dependOnLayer; for (int i=0; i<dependentRange.frameSet.size(); i=i+dependentRange.chunkSize) { dependOnTaskNumbers.clear(); // get the task number for the given index. int depTaskNum = dependentRange.frameSet.get(i); for (int c=0; c<dependentRange.chunkSize; c++) { int onTaskNum = depTaskNum + c; if (dependOnRange.frameSet.contains(onTaskNum)) { if (dependOnRange.chunkSize == 1) { dependOnTaskNumbers.add(onTaskNum); } else if (dependOnRange.chunkSize > 1) { int idx = (dependOnRange.frameSet.indexOf(onTaskNum) / dependOnRange.chunkSize) * dependOnRange.chunkSize; dependOnTaskNumbers.add(dependOnRange.frameSet.get(idx)); } else if (dependOnRange.chunkSize <=0 ) { dependOnTaskNumbers.add(dependOnRange.frameSet.get(0)); } } } if (dependOnTaskNumbers.isEmpty()) { continue; } final UUID[] dependOns = new UUID[dependOnTaskNumbers.size()]; final int[] dependOnNumbers = new int[dependOnTaskNumbers.size()]; int index = 0; for (int taskNum: dependOnTaskNumbers) { final UUID dependOnId = dependOnTaskCache.get(taskNum); if (dependOnId == null) { throw new DependencyException("Unable to find task " + "" + taskNum + " in " + dependOnLayer.getName() + ", " + "while setting up dependencies."); } dependOns[index] = dependOnId; dependOnNumbers[index] = taskNum; index++; } batch.addEntry(dependentTaskCache.get(depTaskNum), depTaskNum, dependOns, dependOnNumbers); } dependDao.batchCreateTaskOnTask(batch); dependDao.batchIncrementDependCounts(batch); } }