package se.chalmers.gdcn.replica; import se.chalmers.gdcn.files.TaskMeta; import se.chalmers.gdcn.network.WorkerID; import se.chalmers.gdcn.replica.ReplicaManager.TaskID; import java.io.Serializable; import java.util.HashMap; import java.util.Map; /** * Created by HalfLeif on 2014-04-15. */ class TaskData implements TaskCompare, Serializable{ private final TaskMeta taskMeta; private final String jobName; private final TaskID taskID; private final Map<WorkerID, Float> reputationMap = new HashMap<>(); private final Map<WorkerID, Float> timeoutMap = new HashMap<>(); private int replicasToGive; private float reputationNeeded; private int replicasToBeReturned; private float reputationToBeReturned; /** * Creates a TaskData instance * @param taskMeta meta info of the task * @param jobName job name * @param replicas minimal number of replicas to complete task * @param reputationNeeded minimal reputation to complete task */ public TaskData(TaskMeta taskMeta, String jobName, int replicas, float reputationNeeded) { this.taskMeta = taskMeta; this.jobName = jobName; this.taskID = new TaskID(jobName + taskMeta.getTaskName()); this.replicasToGive = replicas; this.replicasToBeReturned = replicas; this.reputationNeeded = reputationNeeded; this.reputationToBeReturned = reputationNeeded; } /** * Assigns worker to task depending on its reputation. Ie Smart assign * OBS! Changes the state of this object, if it is inside a sorted collection, it must be re-sorted! * @param reputation the workers reputation * @return task for that worker to work on */ public TaskMeta giveTask(WorkerID workerID, float reputation){ reputationMap.put(workerID, reputation); replicasToGive--; reputationNeeded -= reputation; return taskMeta; } /** * Call when a worker has timed out * @param workerID worker * @return if state has changed */ public boolean timedOut(WorkerID workerID){ Float oldReputation = reputationMap.remove(workerID); if(oldReputation == null){ return false; } replicasToGive++; reputationNeeded += oldReputation; timeoutMap.put(workerID, oldReputation); return true; } /** * Call when a worker has returned a result for this task * @param workerID worker * @return true */ public boolean returned(WorkerID workerID){ Float oldReputation = timeoutMap.remove(workerID); if(oldReputation != null){ reputationMap.put(workerID, oldReputation); replicasToGive--; reputationNeeded -= oldReputation; } else { oldReputation = reputationMap.get(workerID); } replicasToBeReturned--; reputationToBeReturned -= oldReputation; return true; } /** * * @return if enough replicas have been given already */ public boolean enoughGiven(){ return replicasToGive <=0 && reputationNeeded <= 0; } /** * Enough replicas with high enough reputation has been returned for this task. * @return true if this task can be validated. */ public boolean enoughReturned(){ return replicasToBeReturned <=0 && reputationToBeReturned <= 0; } public TaskMeta getTaskMeta() { return taskMeta; } public String getJobName() { return jobName; } /** * @return id of this task */ public TaskID taskID(){ return taskID; } /** * {@inheritDoc} */ @Override public float value(){ //Remember that floor() is called before ceiling() if(reputationNeeded > 0 && replicasToGive > 0){ //Most common case: give this task to a worker with appropriate reputation return reputationNeeded/ replicasToGive; } if(reputationNeeded <=0 && replicasToGive > 0){ //If two tasks have sufficient reputation already, work on the one with the fewest replicas left. return -replicasToGive; } if(reputationNeeded > 0 && replicasToGive <= 0){ //Should be worked on by someone with high reputation //Want this last reputation to optimally be solved in one replica return reputationNeeded; } //Should be chosen as the very last task to work on //This can happen when there are no other tasks and some replicas was recently given. return Float.MAX_VALUE; } /** * {@inheritDoc} */ @Override public String order() { return taskID().toString(); } /** * {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof TaskData)) return false; TaskData taskData = (TaskData) o; if (!jobName.equals(taskData.jobName)) return false; if (!taskMeta.equals(taskData.taskMeta)) return false; return true; } /** * {@inheritDoc} */ @Override public int hashCode() { int result = taskMeta.hashCode(); result = 31 * result + jobName.hashCode(); return result; } /** * {@inheritDoc} */ @Override public String toString() { return "TaskData{" + "taskMeta=" + taskMeta + ", jobName='" + jobName + '\'' + '}'; } }