/*
* Copyright (C) 2008 Universidade Federal de Campina Grande
*
* This file is part of OurGrid.
*
* OurGrid is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.ourgrid.common.job;
import java.io.Serializable;
import java.util.Map;
import org.ourgrid.broker.business.dao.WorkerEntry;
import org.ourgrid.broker.business.scheduler.RunningState;
import org.ourgrid.broker.business.scheduler.extensions.GenericTransferProgress;
import org.ourgrid.broker.communication.operations.GridProcessOperations;
import org.ourgrid.common.interfaces.to.GenericTransferHandle;
import org.ourgrid.common.interfaces.to.GridProcessAccounting;
import org.ourgrid.common.interfaces.to.GridProcessExecutionResult;
import org.ourgrid.common.interfaces.to.GridProcessHandle;
import org.ourgrid.common.interfaces.to.GridProcessPhase;
import org.ourgrid.common.interfaces.to.GridProcessState;
import org.ourgrid.common.interfaces.to.RequestSpecification;
import org.ourgrid.common.specification.job.TaskSpecification;
import org.ourgrid.common.util.CommonUtils;
/**
* A replica is the lower level abstraction that is executed on the
* <code>Worker</code>s. It contains all necessary information to run a a job
* task. <br>
* All replicas of a task differ only in their identification, the remaining
* information is the same to all replicas. In other words, a replica is a
* representation of a task to be executed on the remote machines.
*
* @see Job
* @see Task
*/
public class GridProcess implements Serializable {
private static final long serialVersionUID = 40L;
/** The task */
private transient final Task task;
/** Current state for this <code>Replica</code> * */
private GridProcessState state;
/**
* Result for this <code>Replica</code>'s execution.
*/
private GridProcessExecutionResult replicaResult;
private GridProcessHandle replicaHandle;
private WorkerEntry workerEntry;
private Map<GenericTransferHandle, GenericTransferProgress> transfersProgress;
private GridProcessPhase currentPhase;
/**
* Creation time of this Replica
*/
private long creationTime;
/**
* Time when this Replica finished its execution
*/
private long finalizationTime;
private transient GridProcessOperations operations;
private transient RunningState runningState;
private transient GridProcessAccounting replicaAccounting;
/**
* Constant used to indicated that this task has not been finalized.
*/
public static final int TIME_NOT_FINALIZED = -1;
/**
* The constructor.
*
* @param id The replica id
* @param taskid The task id
* @param jobid The job id
*/
public GridProcess( int id, Task task) {
this.task = task;
this.state = GridProcessState.UNSTARTED;
this.currentPhase = GridProcessPhase.INIT;
this.replicaHandle = new GridProcessHandle( task.getJob().getJobId(), task.getTaskid(), id );
this.creationTime = System.currentTimeMillis();
this.finalizationTime = TIME_NOT_FINALIZED;
this.transfersProgress = CommonUtils.createSerializableMap();
this.replicaResult = new GridProcessExecutionResult(
new GridProcessHandle(getJobId(), getTaskId(), getId()));
}
/**
* Set the result for this <code>Replica</code> and changes state.
*
* @param replicaResult Result of the <code>Replica</code>.
* @param newState New state of the <code>Replica</code>.
*/
public void setGridProcessState( GridProcessState newState ) {
this.state = newState;
}
/**
* Set the result for this <code>Replica</code> and changes state.
*
* @param replicaResult Result of the <code>Replica</code>.
* @param newState New state of the <code>Replica</code>.
*/
public void setGridProcessResult( GridProcessState newState ) {
this.setGridProcessState(newState);
this.finalizationTime = System.currentTimeMillis();
}
/**
* Mark's this <code>GridProcess</code> as running, in other words this
* replica will change state to <code>GridProcessState.RUNNING</code> if it
* is in <code>GridProcessState.UNSTARTED</code>.
*
* @param chosenWorker Spec of the worker that will run this replica.
*/
public void allocate( WorkerEntry chosenWorker ) {
if ( !GridProcessState.UNSTARTED.equals( this.state ) ) {
throw new IllegalResultException( "This replica is already running or has already finished execution",
replicaHandle );
}
this.workerEntry = chosenWorker;
RequestSpecification requestSpec = workerEntry.getRequestSpecification();
if (requestSpec != null) {
this.replicaAccounting = new GridProcessAccounting(requestSpec.getRequestId(), requestSpec.getJobId(),
requestSpec.getRequiredWorkers(), requestSpec.getMaxFails(), requestSpec.getMaxReplicas(),
getWorkerEntry().getWorkerID(), getWorkerEntry().getWorkerPublicKey(),
workerEntry.getWorkerSpecification());
}
}
/**
* Get's the result for this <code>GridProcess</code>'s execution.
*
* @return Result for the <code>Replica</code> or null if no result
* exists.
*/
public GridProcessExecutionResult getResult() {
return replicaResult;
}
/**
* Returns the <code>TaskSpec</code> of this replica.
*
* @return The <code>TaskSpec</code>
*/
public TaskSpecification getSpec() {
return task.getSpec();
}
/**
* Get's the current state of this <code>Replica</code>.
*
* @return Current state of the <code>Replica</code>.
*/
public GridProcessState getState() {
return state;
}
/**
* Returns the owner job identification.
*
* @return The job identification
*/
public int getJobId() {
return this.replicaHandle.getJobID();
}
/**
* Returns the owner task identification.
*
* @return The task identification
*/
public int getTaskId() {
return this.replicaHandle.getTaskID();
}
/**
* Returns the identification of this replica.
*
* @return The identification
*/
public int getId() {
return this.replicaHandle.getReplicaID();
}
/**
* Get's the specification of the <code>Worker</code> that will execute
* this replica.
*
* @return <code>WorkerSpec</code> specification of the
* <code>Worker</code>.
*/
public WorkerEntry getWorkerEntry() {
return workerEntry;
}
/**
* Return the timestamp on which the task was added
*
* @return timestamp in milliseconds since epoch
* @see System#currentTimeMillis()
*/
public long getCreationTime() {
return this.creationTime;
}
/**
* Return the timestamp on which task was finished
*
* @return timestamp in milliseconds since epoch
* @see System#currentTimeMillis()
*/
public long getFinalizationTime() {
return finalizationTime;
}
/**
* Returns a unique string representation for this replica.
*
* @return A string representation for this replica.
*/
@Override
public String toString() {
return getJobId() + "." + getTaskId() + "." + getId();
}
@Override
public boolean equals( Object o ) {
if ( o instanceof GridProcess ) {
GridProcess otherReplica = (GridProcess) o;
return otherReplica.getHandle().equals( this.getHandle() );
}
return false;
}
public boolean isReadyToRun() {
return this.state.equals(GridProcessState.UNSTARTED) && (this.workerEntry != null);
}
@Override
public int hashCode() {
return this.getHandle().hashCode();
}
public GridProcessHandle getHandle() {
return replicaHandle;
}
public void setAsCancelled() {
if ( state == GridProcessState.RUNNING || state == GridProcessState.UNSTARTED ) {
state = GridProcessState.CANCELLED;
this.finalizationTime = System.currentTimeMillis();
}
}
public void fileTransferProgressUpdate( GenericTransferProgress fileTransferProgress ) {
transfersProgress.put( fileTransferProgress.getHandle(), fileTransferProgress );
}
public void gridProcessPhaseUpdate( GridProcessPhase newPhase ) {
this.currentPhase = newPhase;
}
public GridProcessPhase getCurrentPhase() {
return this.currentPhase;
}
public Map<GenericTransferHandle, GenericTransferProgress> getTransfersProgress() {
return this.transfersProgress;
}
public GenericTransferProgress getTransferProgress( GenericTransferHandle handle ) {
return this.transfersProgress.get( handle );
}
public void setAsRunning() {
if ( !GridProcessState.UNSTARTED.equals( this.state ) ) {
throw new IllegalResultException( "This replica is already running or has already finished execution",
replicaHandle );
}
this.state = GridProcessState.RUNNING;
}
public void setOperations(GridProcessOperations executionOperations) {
this.operations = executionOperations;
}
public GridProcessOperations getOperations() {
return operations;
}
public void setRunningState(RunningState state) {
this.runningState = state;
}
public RunningState getRunningState() {
return runningState;
}
public Job getJob() {
return this.task.getJob();
}
public Task getTask() {
return this.task;
}
public void incDataTransfered(long dataTransfered) {
this.replicaAccounting.incDataTransfered(dataTransfered);
}
public void startCPUTiming() {
this.replicaAccounting.startCPUTiming();
}
public void stopCPUTiming() {
this.replicaAccounting.stopCPUTiming();
}
public GridProcessAccounting getReplicaAccounting() {
return replicaAccounting;
}
public String getWorkerProviderID() {
return getWorkerEntry().getPeerID();
}
public boolean hasFinalStateStarted() {
return replicaResult.getFinalData().getStartTime() > -1;
}
}