package edu.ucsb.jpregel.system;
import api.Aggregator;
import api.Vertex;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
// TODO Implement topology mutations:
// * - Refactor code to work with stepToInboxMap instead of superstepToMessageQMap.
// * - Put AddEdge messageQ in Inbox.
// * - Design and implement VertexImpl AddEdge conflict "handler". Use combiner concept, where feasible.
// * - Put RemoveEdge messageQ in Inbox.
// * - Design and implement VertexImpl RemoveEdge conflict "handler". Use combiner concept, where feasible.
// * - Put AddVertex messageQ in Inbox. This is tricky, since the VertexImpl typically does not exist. If it does, it is a conflict.
// * Have Part add 1st, and let that VertexImpl resolve subsequent conflicts?
// * - Design and implement VertexImpl AddVertex conflict "handler". Use combiner concept. where feasible.
// * - Put RemoveVertex message in Inbox. Use combiners to resolve multiple requests.
// * How to handle request where no such VertexImpl exists?
// * - Design and implement VertexImpl AddVertex conflict "handler". Use combiner concept, where feasible.
/*
* I currently think that vertex does not need the bit of state designating it
* active/inactive. Instead I:
*
* 1. make it the responsibility of the graph maker to add source vertices in
* the active set for the initial super step;
* 2. thereafter regard a vertex as active during superStep s if and only if
* its MessageQ for superStep s is nonempty.
*
* The opinion assumes that a vertex has no basis for activity unless it
* receives a message; otherwise nothing has changed since it last sent messages
* to other vertices. This assumption implies that changing the superStep does
* not itself constitute a state change for the vertex. If I encounter an
* algorithm that falsifies this assumption, I will revise this view.
*
* In the meantime, the compute method no longer needs to vote to halt.
* This method thus has been removed from the API.
*
* When a vertex completes the compute method for a super step, it may not have
* received all its messages for the next super step. When the compute method
* for the next super step is invoked, it has all its messages for that step.
* Messages that arrive after the compute method for super step n completes, but
* before the compute method for step n + 1 begins may be for either super step
* n + 1 or super step n + 2. The vertex cannot determine which, without
* additional information. Thus, each message is associated with a super step
* number.
*
* @author Peter Cappello
*/
abstract public class VertexImpl<VertexIdType, VertexValueType, EdgeValueType, MessageValueType>
implements Vertex<VertexIdType, VertexValueType, EdgeValueType, MessageValueType>, java.io.Serializable
{
public static Combiner combiner; // null means no combining
protected static int numVertices;
protected static int availableProcessors = Runtime.getRuntime().availableProcessors();
private final VertexIdType vertexId;
private VertexValueType vertexValue;
private Part part;
private Map<VertexIdType, EdgeValueType> edgeMap;
private OntoMap<MessageQ> superstepToMessageQMap;
// private OntoMap<MessageValueType> superstepToInboxMap;
private static final Factory<MessageQ> MESSAGE_Q_COMBINER = new MessageQ( null );
public VertexImpl() { vertexId = null; }
public VertexImpl( VertexIdType vertexId, Map<VertexIdType, EdgeValueType> edgeMap, int numOutgoingEdges)
{
this.vertexId = vertexId;
this.edgeMap = edgeMap;
superstepToMessageQMap = new OntoMap<MessageQ>(numOutgoingEdges, getMessageQType() );
}
public VertexImpl( VertexIdType vertexId, Map<VertexIdType, EdgeValueType> edgeMap)
{
this(vertexId, edgeMap,100);
}
/* _________________________________________
*
* Begin API
* _________________________________________
*/
@Override
synchronized public void addEdge( VertexIdType target, EdgeValueType edgeValue ) { edgeMap.put( target, edgeValue ); }
@Override
synchronized public void addEdge( VertexIdType vertexId, VertexIdType target, EdgeValueType edgeValue ) { }
@Override
synchronized public void addVertex( VertexIdType vertexId, Object vertexValue ) { /* combiner */ }
@Override
public void aggregateOutputProblemAggregator( Aggregator aggregator ) { part.aggregateOutputProblemAggregator( aggregator ); }
@Override
public void aggregateOutputStepAggregator( Aggregator aggregator ) { part.aggregateOutputStepAggregator( aggregator ); }
@Override
abstract public void compute();
@Override
abstract public boolean isInitiallyActive();
@Override
abstract public String output();
// TODO: VertexImpl: Omit this method to disallow applications from modifying the edgeMap.
// Replace with 1. Collection<VertexIdType> getEdgeTargetIds()
// 2. EdgeValueType getEdgeValue( VertexIdType targetId )
@Override
public Map<VertexIdType, EdgeValueType> getEdgeMap() { return edgeMap; }
@Override
public Aggregator getInputStepAggregator() { return part.getStepAggregator(); }
@Override
public Aggregator getInputProblemAggregator() { return part.getComputeInput().getProblemAggregator(); }
@Override
synchronized public Iterator<Message<VertexIdType, MessageValueType>> getMessageIterator()
{
return getMessageQ().iterator();
}
@Override
synchronized public MessageQ<VertexIdType, MessageValueType> getMessageQ()
{
MessageQ<VertexIdType, MessageValueType> messageQ = superstepToMessageQMap.remove( getSuperStep() );
if ( messageQ == null )
{
messageQ = new MessageQ<VertexIdType, MessageValueType>( combiner );
}
return messageQ;
}
@Override
public int getNumVertices() { return part.getComputeInput().getNumVertices(); }
@Override
synchronized public Collection<VertexIdType> getEdgeTargets() { return edgeMap.keySet(); }
@Override
synchronized public int getEdgeMapSize() { return edgeMap.size(); }
@Override
public int getPartId( VertexIdType vertexId, int numParts )
{
return vertexId.hashCode() % numParts;
}
@Override
public long getSuperStep() { return part.getSuperStep(); }
@Override
public VertexIdType getVertexId() { return vertexId; }
@Override
public VertexValueType getVertexValue() { return vertexValue; }
@Override
public abstract VertexImpl make( String line );
@Override
synchronized public void removeEdge( VertexIdType vertexId ) { edgeMap.remove( vertexId ); }
@Override
synchronized public void removeEdge( VertexIdType vertexId, Object targetVertexId ) { }
@Override
synchronized public void removeVertex() { part.removeVertex( vertexId ); }
@Override
synchronized public void removeVertex( VertexIdType vertexId ) { part.removeVertex( vertexId ); }
@Override
public void sendMessage( Object targetVertexId, Message message )
{
part.sendMessage( targetVertexId, message, getSuperStep() + 1 );
}
@Override
public void setVertexValue( VertexValueType vertexValue ) { this.vertexValue = vertexValue; }
/* vertex deactivates itself by voting to halt.
* vertex is activated only if it receives a message, in which case it
* must explicitly deactivate, when it again wishes to halt.
*/
// synchronized protected void voteToHalt()
// {
// MessageQ messageQ = superstepToMessageQMap.get( getSuperStep() + 1 );
// if ( messageQ.isEmpty() )
// {
// nextStepIsActive = false;
// }
// }
/* _________________________________________
*
* End API
* _________________________________________
*/
// synchronized public boolean isNextStepActive() { return nextStepIsActive; }
Combiner getCombiner() { return combiner; }
void receiveMessage( Message newMessage, long superStep )
{
superstepToMessageQMap.get( superStep ).add( newMessage );
}
void receiveMessageQ( MessageQ newMessageQ, long superStep ) { superstepToMessageQMap.get( superStep ).addAll( newMessageQ ); }
void removeMessageQ( long superStep ) { superstepToMessageQMap.remove( superStep ); }
void setPart( Part part ) { this.part = part; }
void setNumVertices( int numV ) { numVertices = numV; }
protected Factory<MessageQ> getMessageQType() { return MESSAGE_Q_COMBINER; }
}