package com.breakersoft.plow.dao.pgsql;
import java.nio.ByteBuffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.object.BatchSqlUpdate;
import org.springframework.stereotype.Repository;
import com.breakersoft.plow.Defaults;
import com.breakersoft.plow.Depend;
import com.breakersoft.plow.DependE;
import com.breakersoft.plow.Job;
import com.breakersoft.plow.Layer;
import com.breakersoft.plow.Task;
import com.breakersoft.plow.TaskOnTaskBatch;
import com.breakersoft.plow.TaskOnTaskBatch.TaskOnTaskBatchEntry;
import com.breakersoft.plow.dao.AbstractDao;
import com.breakersoft.plow.dao.DependDao;
import com.breakersoft.plow.exceptions.DependencyException;
import com.breakersoft.plow.thrift.DependType;
import com.breakersoft.plow.util.JdbcUtils;
import com.breakersoft.plow.util.UUIDGen;
@Repository
public class DependDaoImpl extends AbstractDao implements DependDao {
private Logger logger = org.slf4j.LoggerFactory.getLogger(DependDaoImpl.class);
public static final RowMapper<Depend> MAPPER = new RowMapper<Depend>() {
@Override
public Depend mapRow(ResultSet rs, int rowNum)
throws SQLException {
DependE depend = new DependE();
depend.setDependId((UUID) rs.getObject("pk_depend"));
depend.setActive(rs.getBoolean("bool_active"));
depend.setType(DependType.findByValue(rs.getInt("int_type")));
depend.setDependentJobId((UUID) rs.getObject("pk_dependent_job"));
depend.setDependOnJobId((UUID) rs.getObject("pk_dependon_job"));
if (depend.getType().equals(DependType.JOB_ON_JOB)) {
return depend;
}
depend.setDependentLayerId((UUID) rs.getObject("pk_dependent_layer"));
depend.setDependOnLayerId((UUID) rs.getObject("pk_dependon_layer"));
switch (depend.getType()) {
case LAYER_ON_TASK:
depend.setDependOnTaskId((UUID) rs.getObject("pk_dependon_task"));
break;
case TASK_ON_LAYER:
depend.setDependentTaskId((UUID) rs.getObject("pk_dependent_task"));
break;
case TASK_ON_TASK:
depend.setDependentTaskId((UUID) rs.getObject("pk_dependent_task"));
depend.setDependOnTaskId((UUID) rs.getObject("pk_dependon_task"));
break;
}
return depend;
}
};
private static final String GET =
"SELECT " +
"depend.* " +
"FROM " +
"depend " +
"WHERE " +
"pk_depend=?";
@Override
public Depend get(UUID id) {
return jdbc.queryForObject(GET, MAPPER, id);
}
private static final String BASE_INC =
"UPDATE plow.task SET int_depend_count=int_depend_count +1 WHERE ";
@Override
public void incrementDependCounts(Depend depend) {
int result = 0;
switch (depend.getType()) {
case JOB_ON_JOB:
result = jdbc.update(BASE_INC + "task.pk_job=?", depend.getDependentJobId());
break;
case LAYER_ON_LAYER:
case LAYER_ON_TASK:
result = jdbc.update(BASE_INC + "task.pk_layer=?", depend.getDependentLayerId());
break;
case TASK_ON_LAYER:
case TASK_ON_TASK:
result = jdbc.update(BASE_INC + "task.pk_task=?", depend.getDependentTaskId());
break;
}
logger.info("Incremented {} depend counts {}", depend, result);
}
private static final String BASE_DEC =
"UPDATE plow.task SET int_depend_count=int_depend_count -1 WHERE ";
public void decrementDependCounts(Depend depend) {
int result = 0;
switch (depend.getType()) {
case JOB_ON_JOB:
result = jdbc.update(BASE_DEC + "task.pk_job=?", depend.getDependentJobId());
break;
case LAYER_ON_LAYER:
case LAYER_ON_TASK:
result = jdbc.update(BASE_DEC + "task.pk_layer=?", depend.getDependentLayerId());
break;
case TASK_ON_LAYER:
case TASK_ON_TASK:
result = jdbc.update(BASE_DEC + "task.pk_task=?", depend.getDependentTaskId());
break;
}
logger.info("Decreement depend counts {}", depend, result);
}
private static final String GET_BY_TASK =
"SELECT " +
"depend.* " +
"FROM " +
"depend " +
"WHERE " +
"bool_active='t' " +
"AND " +
"int_type IN (?,?) " +
"AND " +
"pk_dependon_task=? " +
"ORDER BY " +
"depend.pk_depend ";
@Override
public List<Depend> getOnTaskDepends(Task task) {
return jdbc.query(GET_BY_TASK, MAPPER,
DependType.LAYER_ON_TASK.ordinal(),
DependType.TASK_ON_TASK.ordinal(),
task.getTaskId());
}
private static final String GET_BY_LAYER =
"SELECT " +
"depend.* " +
"FROM " +
"depend " +
"WHERE " +
"bool_active='t' " +
"AND " +
"int_type IN (?,?) " +
"AND " +
"pk_dependon_layer=? " +
"ORDER BY " +
"depend.pk_depend ";
@Override
public List<Depend> getOnLayerDepends(Layer layer) {
return jdbc.query(GET_BY_LAYER, MAPPER,
DependType.LAYER_ON_LAYER.ordinal(),
DependType.TASK_ON_LAYER.ordinal(),
layer.getLayerId());
}
private static final String GET_BY_JOB =
"SELECT " +
"depend.* " +
"FROM " +
"depend " +
"WHERE " +
"bool_active='t' " +
"AND " +
"int_type = ? " +
"AND " +
"pk_dependon_job=? " +
"ORDER BY " +
"depend.pk_depend ";
@Override
public List<Depend> getOnJobDepends(Job job) {
return jdbc.query(GET_BY_JOB, MAPPER,
DependType.JOB_ON_JOB.ordinal(),
job.getJobId());
}
private static final String SATISFY =
"UPDATE depend SET uuid_sig=NULL, bool_active='f', time_satisfied=plow.txTimeMillis() WHERE pk_depend=? AND bool_active='t'";
@Override
public boolean satisfyDepend(Depend depend) {
return jdbc.update(SATISFY, depend.getDependId()) == 1;
}
private static final String UNSATISFY =
"UPDATE depend SET uuid_sig=?, bool_active='t', time_satisfied=plow.txTimeMillis() WHERE pk_depend=? AND bool_active='f'";
@Override
public boolean unsatisfyDepend(Depend depend) {
return jdbc.update(UNSATISFY, depend.genSig(), depend.getDependId()) == 1;
}
private static final String INSERT =
JdbcUtils.Insert(
"plow.depend",
"pk_depend",
"uuid_sig",
"int_type",
"pk_dependent_job",
"pk_dependon_job",
"pk_dependent_layer",
"pk_dependon_layer",
"pk_dependent_task",
"pk_dependon_task",
"str_dependent_job_name",
"str_dependon_job_name",
"str_dependent_layer_name",
"str_dependon_layer_name",
"str_dependent_task_name",
"str_dependon_task_name");
@Override
public Depend createJobOnJob(Job dependent, Job dependOn) {
if (dependent.equals(dependOn)) {
throw new DependencyException("A job cannot depend on itself.");
}
final DependType type = DependType.JOB_ON_JOB;
final UUID id = UUID.randomUUID();
final DependE result = new DependE();
result.setActive(true);
result.setType(type);
result.setDependId(id);
result.setDependentJobId(dependent.getJobId());
result.setDependOnJobId(dependOn.getJobId());
logger.info("Setting up Job on Job depend: {} -> {}", dependent, dependOn);
jdbc.update(INSERT,
id,
result.genSig(),
type.ordinal(),
dependent.getJobId(),
dependOn.getJobId(),
null, null, null, null,
dependent.getName(),
dependOn.getName(),
null, null, null, null);
return result;
}
@Override
public Depend createLayerOnLayer(Job dependentJob, Layer dependent, Job dependOnJob, Layer dependOn) {
if (dependent.equals(dependOn)) {
throw new DependencyException("A layer cannot depend on itself.");
}
final DependType type = DependType.LAYER_ON_LAYER;
final UUID id = UUID.randomUUID();
final DependE result = new DependE();
result.setActive(true);
result.setType(type);
result.setDependId(id);
result.setDependentJobId(dependent.getJobId());
result.setDependOnJobId(dependOn.getJobId());
result.setDependentLayerId(dependent.getLayerId());
result.setDependOnLayerId(dependOn.getLayerId());
logger.info("Setting up Layer on Layer depend: {} -> {}", dependent, dependOn);
jdbc.update(INSERT,
id,
result.genSig(),
type.ordinal(),
dependent.getJobId(),
dependOn.getJobId(),
dependent.getLayerId(),
dependOn.getLayerId(),
null, null,
dependentJob.getName(),
dependOnJob.getName(),
dependent.getName(),
dependOn.getName(),
null, null);
return result;
}
@Override
public Depend createLayerOnTask(
Job dependentJob,
Layer dependent,
Job dependOnJob,
Layer dependOnLayer,
Task dependOn) {
final DependType type = DependType.LAYER_ON_TASK;
final UUID id = UUID.randomUUID();
final DependE result = new DependE();
result.setActive(true);
result.setType(type);
result.setDependId(id);
result.setDependentJobId(dependent.getJobId());
result.setDependOnJobId(dependOn.getJobId());
result.setDependentLayerId(dependent.getLayerId());
result.setDependOnLayerId(dependOn.getLayerId());
result.setDependOnTaskId(dependOn.getTaskId());
logger.info("Setting up Layer on Task depend: {} -> {}", dependent, dependOn);
jdbc.update(INSERT,
id,
result.genSig(),
type.ordinal(),
dependent.getJobId(),
dependOn.getJobId(),
dependent.getLayerId(),
dependOn.getLayerId(),
null,
dependOn.getTaskId(),
dependentJob.getName(),
dependent.getName(),
null,
dependOnJob.getName(),
dependOnLayer.getName(),
dependOn.getName());
return result;
}
@Override
public Depend createTaskOnLayer(
Job dependentJob,
Layer dependentLayer,
Task dependentTask,
Job dependOnJob,
Layer dependOnLayer) {
final DependType type = DependType.TASK_ON_LAYER;
final UUID id = UUID.randomUUID();
final DependE result = new DependE();
result.setActive(true);
result.setType(type);
result.setDependId(id);
result.setDependentJobId(dependentJob.getJobId());
result.setDependOnJobId(dependOnJob.getJobId());
result.setDependentLayerId(dependentLayer.getLayerId());
result.setDependOnLayerId(dependOnLayer.getLayerId());
result.setDependentTaskId(dependentTask.getTaskId());
logger.info("Setting up Task on Layer depend: {} -> {}", dependentTask, dependOnLayer);
jdbc.update(INSERT,
id,
result.genSig(),
type.ordinal(),
dependentTask.getJobId(),
dependOnJob.getJobId(),
dependentTask.getLayerId(),
dependOnLayer.getLayerId(),
dependentTask.getTaskId(),
null,
dependentJob.getName(),
dependOnJob.getName(),
dependentLayer.getName(),
dependOnLayer.getName(),
dependentTask.getName(),
null);
return result;
}
private static final int[] BATCH_TYPES = new int[] {
Types.OTHER,
Types.OTHER,
Types.INTEGER,
Types.OTHER,
Types.OTHER,
Types.OTHER,
Types.OTHER,
Types.OTHER,
Types.OTHER,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR
};
@Override
public void batchCreateTaskOnTask(TaskOnTaskBatch batch) {
final BatchSqlUpdate update = new BatchSqlUpdate(
jdbc.getDataSource(), INSERT, BATCH_TYPES);
update.setBatchSize(Defaults.JDBC_DEFAULT_BATCH_SIZE);
final int type = DependType.TASK_ON_TASK.ordinal();
final ByteBuffer buffer = ByteBuffer.allocate(12);
for (TaskOnTaskBatchEntry entry: batch.entries) {
final String dependentTaskName = String.format("%04d-%s",
entry.dependentTaskNumber, batch.dependentLayer.getName());
for (int i=0; i<entry.dependOnTasksIds.length; i++) {
buffer.clear();
buffer.putInt(type);
buffer.putInt(entry.dependentTask.hashCode());
buffer.putInt(entry.dependOnTasksIds[i].hashCode());
update.update(
UUIDGen.random(),
UUID.nameUUIDFromBytes(buffer.array()),
type,
batch.dependentJob.getJobId(),
batch.dependOnJob.getJobId(),
batch.dependentLayer.getLayerId(),
batch.dependOnLayer.getLayerId(),
entry.dependentTask,
entry.dependOnTasksIds[i],
batch.dependentJob.getName(),
batch.dependOnJob.getName(),
batch.dependentLayer.getName(),
batch.dependOnLayer.getName(),
dependentTaskName,
String.format("%04d-%s", entry.dependOnTaskNumbers[i], batch.dependOnLayer.getName()));
}
}
update.flush();
}
private static final int[] INC_BATCH_TYPES = new int[] {
Types.INTEGER,
Types.OTHER
};
private static final String TASK_INC =
"UPDATE plow.task SET int_depend_count=int_depend_count + ? WHERE task.pk_task=?";
@Override
public void batchIncrementDependCounts(TaskOnTaskBatch batch) {
final BatchSqlUpdate update = new BatchSqlUpdate(
jdbc.getDataSource(), TASK_INC, INC_BATCH_TYPES);
update.setBatchSize(Defaults.JDBC_DEFAULT_BATCH_SIZE);
for (TaskOnTaskBatchEntry entry: batch.entries) {
update.update(entry.dependOnTaskNumbers.length, entry.dependentTask);
}
update.flush();
}
@Override
public Depend createTaskOnTask(
Job dependentJob,
Layer dependentLayer,
Task dependentTask,
Job dependOnJob,
Layer dependOnLayer,
Task dependOnTask) {
if (dependentTask.equals(dependOnTask)) {
throw new DependencyException("A task cannot depend on itself.");
}
final DependType type = DependType.TASK_ON_TASK;
final UUID id = UUID.randomUUID();
final DependE result = new DependE();
result.setActive(true);
result.setType(type);
result.setDependId(id);
result.setDependentJobId(dependentTask.getJobId());
result.setDependOnJobId(dependOnTask.getJobId());
result.setDependentLayerId(dependentTask.getLayerId());
result.setDependOnLayerId(dependOnTask.getLayerId());
result.setDependentTaskId(dependentTask.getTaskId());
result.setDependOnTaskId(dependOnTask.getTaskId());
logger.info("Setting up Task on Task depend: {} -> {}", dependentTask, dependOnTask);
jdbc.update(INSERT,
id,
result.genSig(),
type.ordinal(),
dependentTask.getJobId(),
dependOnTask.getJobId(),
dependentTask.getLayerId(),
dependOnTask.getLayerId(),
dependentTask.getTaskId(),
dependOnTask.getTaskId(),
dependentJob.getName(),
dependOnJob.getName(),
dependentLayer.getName(),
dependOnLayer.getName(),
dependentTask.getName(),
dependOnTask.getName());
return result;
}
}