/**
*
*/
package system;
import exceptions.DataNotFoundException;
import exceptions.IllegalInputException;
import graphs.GraphPartition;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.logging.Logger;
import utility.JPregelLogger;
import api.Vertex;
/**
*
* Represents a worker thread executing in every Worker Manager
*
* @author Manasa Chandrasekhar
* @author Kowshik Prakasam
*
*/
public class Worker implements Runnable {
private int superStep;
public int getSuperStep() {
return superStep;
}
public void setSuperStep(int superStep) {
this.superStep = superStep;
}
private Thread t;
private List<GraphPartition> listOfPartitions;
private int partitionSize;
public int getPartitionSize() {
return partitionSize;
}
public void setPartitionSize(int partitionSize) {
this.partitionSize = partitionSize;
}
private String id;
private Logger logger;
private static final String LOG_FILE_PREFIX = JPregelConstants.LOG_DIR
+ "worker_";
private static final String LOG_FILE_SUFFIX = ".log";
public static enum WorkerState {
EXECUTE, DONE, STOP
};
private WorkerManagerImpl mgr;
private String vertexClassName;
private WorkerState state;
private Communicator aCommunicator;
private int numVertices;
public int getNumVertices() {
return numVertices;
}
private Worker(WorkerManagerImpl mgr, String vertexClassName,
int partitionSize, Communicator aCommunicator, int numVertices)
throws IOException {
this.state = WorkerState.STOP;
this.setSuperStep(JPregelConstants.DEFAULT_SUPERSTEP);
this.mgr = mgr;
this.vertexClassName = vertexClassName;
this.partitionSize = partitionSize;
this.aCommunicator = aCommunicator;
this.numVertices = numVertices;
this.listOfPartitions = new Vector<GraphPartition>();
this.setId(mgr.getId() + "_" + Worker.getRandomChars());
this.initLogger();
t = new Thread(this, this.getId());
t.start();
}
/**
* @throws IOException
*
*/
private void initLogger() throws IOException {
this.logger = JPregelLogger.getLogger(this.getId(), LOG_FILE_PREFIX
+ this.getId() + LOG_FILE_SUFFIX);
}
/**
* @param string
*/
private void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Worker(List<Integer> partitionNumers, int partitionSize,
WorkerManagerImpl mgr, String vertexClassName,
Communicator aCommunicator, int numVertices)
throws DataNotFoundException, IOException, IllegalInputException,
InstantiationException, IllegalAccessException,
ClassNotFoundException {
this(mgr, vertexClassName, partitionSize, aCommunicator, numVertices);
logger.info("Worker : " + this.getId() + " received partitions : "
+ partitionNumers);
DataLocator aDataLocator = DataLocator.getDataLocator(partitionSize);
for (Integer partitionNumber : partitionNumers) {
String partitionFile = aDataLocator
.getPartitionFile(partitionNumber);
GraphPartition aGraphPartition = new GraphPartition(
partitionNumber, partitionFile, this.vertexClassName, this,
aDataLocator);
logger.info("Worker : " + this.getId()
+ " initialized partition : " + partitionFile);
this.listOfPartitions.add(aGraphPartition);
}
logger.info("Initialized worker with " + this.listOfPartitions.size()
+ " partitions");
logger.info("Partitions are : \n\n" + this.listOfPartitions);
}
@Override
public void run() {
while (true) {
if (this.getState() == WorkerState.EXECUTE) {
boolean stopStep = false;
logger.info("Executing");
for (GraphPartition gPartition : this.listOfPartitions) {
if (this.getState() == WorkerState.EXECUTE) {
for (Vertex v : gPartition.getVertices()) {
if (this.getState() == WorkerState.EXECUTE) {
logger.info("Starting initCompute() on vertex : "
+ v.toString()
+ " at superstep : "
+ getSuperStep());
v.initCompute();
}else{
logger.info("Skipping vertices for this partition as worker state is : "+this.getState());
break;
}
}
}else{
logger.info("Skipping partition "+gPartition.getPartitionID()+" as worker state is : "+this.getState());
}
}
if (this.getState() == WorkerState.EXECUTE) {
this.setState(WorkerState.DONE);
}
}
}
}
/**
* @return
*/
public synchronized WorkerState getState() {
return this.state;
}
/**
* @return
*/
public synchronized void setState(WorkerState newState) {
logger.info("Setting worker state to : " + newState);
this.state = newState;
}
/**
*
* @return A random name made up of exactly three alphabets
*/
public static String getRandomChars() {
char first = (char) ((new Random().nextInt(26)) + 65);
char second = (char) ((new Random().nextInt(26)) + 65);
char third = (char) ((new Random().nextInt(26)) + 65);
return "" + first + second + third;
}
public String toString() {
StringBuffer strBuf = new StringBuffer();
strBuf.append("Worker ID : " + this.getId() + "\n");
strBuf.append("Partitions : " + this.listOfPartitions.size() + "\n\n");
return strBuf.toString();
}
// queue message in communicator for next superstep
public void send(Message msg) {
logger.info("Attempting to queue msg : " + msg);
this.aCommunicator.queueMessage(msg);
}
// a hashmap of all vertexID->vertex managed by this worker, so the lookup
// time to distribute messages will be constant
public Map<Integer, Vertex> getVertices() {
Map<Integer, Vertex> idVertexMap = new HashMap<Integer, Vertex>();
for (GraphPartition gPartition : listOfPartitions) {
for (Vertex aVertex : gPartition.getVertices()) {
idVertexMap.put(aVertex.getVertexID(), aVertex);
}
}
return idVertexMap;
}
public void writeSolutions() throws IOException {
for (GraphPartition gp : this.listOfPartitions) {
gp.writeSolutions();
}
}
/**
* @throws DataNotFoundException
* @throws IOException
*
*/
public void saveState() throws IOException, DataNotFoundException {
for (GraphPartition gp : this.listOfPartitions) {
gp.saveState();
}
}
/**
* Clears the message queue of every vertex
*/
public void clearVertexQueues() {
for (GraphPartition gp : this.listOfPartitions) {
gp.clearVertexQueues();
}
}
/**
*
* Restores the state of the vertices after a failure
* @throws IOException
* @throws DataNotFoundException
* @throws ClassNotFoundException
*
*/
public void restoreState( int checkPointNumber,List<Integer> chkPointPartitions) throws IOException, DataNotFoundException, ClassNotFoundException {
DataLocator aDataLocator = DataLocator.getDataLocator(this.getPartitionSize());
List<GraphPartition> restoredList = new Vector<GraphPartition>();
for(int partition : chkPointPartitions){
logger.info("Restoring state of partition : "+partition);
String chkPointFile = aDataLocator.getCheckpointFile(checkPointNumber,
partition);
FileInputStream fis = new FileInputStream(chkPointFile);
ObjectInputStream in = new ObjectInputStream(fis);
GraphPartition aPartition=(GraphPartition) in.readObject();
aPartition.setWorker(this);
aPartition.setDataLocator(aDataLocator);
fis.close();
in.close();
restoredList.add(aPartition);
logger.info("Restored : "+aPartition);
}
this.listOfPartitions=restoredList;
}
/**
* @return
*/
public List<Message> retrieveAllMsgs() {
List<Message> allMsgs=new Vector<Message>();
for(GraphPartition gp : this.listOfPartitions){
allMsgs.addAll(gp.retrieveAllMsgs());
}
return allMsgs;
}
}