All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hama.graph.Vertex Maven / Gradle / Ivy

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hama.graph;

import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.MapWritable;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hama.HamaConfiguration;
import org.apache.hama.bsp.BSPPeer;
import org.apache.hama.bsp.Counters.Counter;

/**
 * Vertex is a abstract definition of Google Pregel Vertex. For implementing a
 * graph application, one must implement a sub-class of Vertex and define, the
 * message passing and message processing for each vertex.
 * 
 * Every vertex should be assigned an ID. This ID object should obey the
 * equals-hashcode contract and would be used for partitioning.
 * 
 * The edges for a vertex could be accessed and modified using the
 * {@link Vertex#getEdges()} call. The self value of the vertex could be changed
 * by {@link Vertex#setValue(Writable)}.
 * 
 * @param  Vertex ID object type
 * @param  Edge cost object type
 * @param  Vertex value object type
 */
@SuppressWarnings("rawtypes")
public abstract class Vertex
    implements VertexInterface {

  private transient GraphJobRunner runner;

  private V vertexID;
  private M oldValue;
  private M value;
  private List> edges;

  private boolean votedToHalt = false;
  private long lastComputedSuperstep = 0;

  public HamaConfiguration getConf() {
    return runner.getPeer().getConfiguration();
  }

  public Vertex() {
  }

  @Override
  public V getVertexID() {
    return this.vertexID;
  }

  @Override
  public void setup(HamaConfiguration conf) {
  }

  @Override
  public void sendMessage(Edge e, M msg) throws IOException {
    runner.sendMessage(e.getDestinationVertexID(), msg);
  }

  @Override
  public void sendMessage(V destinationVertexID, M msg) throws IOException {
    runner.sendMessage(destinationVertexID, msg);
  }

  @Override
  public void sendMessageToNeighbors(M msg) throws IOException {
    runner.sendMessage(this.getEdges(), msg);
  }

  private void alterVertexCounter(int i) throws IOException {
    this.runner.setChangedVertexCnt(this.runner.getChangedVertexCnt() + i);
  }

  @Override
  public void addVertex(V vertexID, List> edges, M value)
      throws IOException {
    MapWritable msg = new MapWritable();
    // Create the new vertex.
    Vertex vertex = GraphJobRunner
        . newVertexInstance(GraphJobRunner.VERTEX_CLASS);
    vertex.setEdges(edges);
    vertex.setValue(value);
    vertex.setVertexID(vertexID);

    msg.put(GraphJobRunner.FLAG_VERTEX_INCREASE, vertex);
    runner.getPeer().send(runner.getHostName(vertexID),
        new GraphJobMessage(msg));

    alterVertexCounter(1);
  }

  @Override
  public void remove() throws IOException {
    MapWritable msg = new MapWritable();
    msg.put(GraphJobRunner.FLAG_VERTEX_DECREASE, this.vertexID);

    // Get master task peer.
    String destPeer = GraphJobRunner.getMasterTask(this.getPeer());
    runner.getPeer().send(destPeer, new GraphJobMessage(msg));

    alterVertexCounter(-1);
  }

  @Override
  public long getSuperstepCount() {
    return runner.getNumberIterations();
  }

  public void setEdges(List> list) {
    this.edges = list;
  }

  public void addEdge(Edge edge) {
    if (edges == null) {
      this.edges = new ArrayList>();
    }
    this.edges.add(edge);
  }

  @Override
  public List> getEdges() {
    return (edges == null) ? new ArrayList>() : edges;
  }

  @Override
  public M getValue() {
    return this.value;
  }

  @Override
  public void setValue(M value) {
    this.oldValue = this.value;
    this.value = value;
  }

  public void setVertexID(V vertexID) {
    this.vertexID = vertexID;
  }

  public int getMaxIteration() {
    return runner.getMaxIteration();
  }

  public int getNumPeers() {
    return runner.getPeer().getNumPeers();
  }

  /**
   * Gives access to the BSP primitives and additional features by a peer.
   */
  public BSPPeer getPeer() {
    return runner.getPeer();
  }

  @Override
  public long getTotalNumVertices() {
    return runner.getNumberVertices();
  }

  @Override
  public void voteToHalt() {
    this.votedToHalt = true;
  }

  void setActive() {
    this.votedToHalt = false;
  }

  public boolean isHalted() {
    return votedToHalt;
  }

  void setComputed() {
    this.lastComputedSuperstep = this.getSuperstepCount();
  }

  public boolean isComputed() {
    return (lastComputedSuperstep == this.getSuperstepCount()) ? true : false;
  }

  void setVotedToHalt(boolean votedToHalt) {
    this.votedToHalt = votedToHalt;
  }

  @Override
  public int hashCode() {
    return ((vertexID == null) ? 0 : vertexID.hashCode());
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Vertex other = (Vertex) obj;
    if (vertexID == null) {
      if (other.vertexID != null)
        return false;
    } else if (!vertexID.equals(other.vertexID))
      return false;
    return true;
  }

  @Override
  public String toString() {
    return "Active: " + !votedToHalt + " -> ID: " + getVertexID()
        + (getValue() != null ? " = " + getValue() : "") + " // " + edges;
  }

  @Override
  public void readFields(DataInput in) throws IOException {
    if (in.readBoolean()) {
      if (this.vertexID == null) {
        this.vertexID = GraphJobRunner.createVertexIDObject();
      }
      this.vertexID.readFields(in);
    }
    if (in.readBoolean()) {
      if (this.value == null) {
        this.value = GraphJobRunner.createVertexValue();
      }
      this.value.readFields(in);
    }

    this.lastComputedSuperstep = in.readLong();

    this.edges = new ArrayList>();
    if (in.readBoolean()) {
      int num = in.readInt();
      if (num > 0) {
        for (int i = 0; i < num; ++i) {
          V vertex = GraphJobRunner.createVertexIDObject();
          vertex.readFields(in);
          E edgeCost = null;
          if (in.readBoolean()) {
            edgeCost = GraphJobRunner.createEdgeCostObject();
            edgeCost.readFields(in);
          }
          Edge edge = new Edge(vertex, edgeCost);
          this.edges.add(edge);
        }

      }
    }
    votedToHalt = in.readBoolean();

    boolean hasMoreContents = in.readBoolean();
    if (hasMoreContents) {
      readState(in);
    }
  }

  @Override
  public void write(DataOutput out) throws IOException {
    if (vertexID == null) {
      out.writeBoolean(false);
    } else {
      out.writeBoolean(true);
      vertexID.write(out);
    }

    if (value == null) {
      out.writeBoolean(false);
    } else {
      out.writeBoolean(true);
      value.write(out);
    }

    out.writeLong(lastComputedSuperstep);

    if (this.edges == null) {
      out.writeBoolean(false);
    } else {
      out.writeBoolean(true);
      out.writeInt(this.edges.size());
      for (Edge edge : this.edges) {
        edge.getDestinationVertexID().write(out);
        if (edge.getValue() == null) {
          out.writeBoolean(false);
        } else {
          out.writeBoolean(true);
          edge.getValue().write(out);
        }
      }
    }
    out.writeBoolean(votedToHalt);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutput customOut = new DataOutputStream(baos);
    boolean hasMoreContents = true;
    try {
      writeState(customOut);
    } catch (NullPointerException e) {
      // do nothing
    }

    // if all states are null, set hasContents to false.
    if (baos.size() == 0) {
      hasMoreContents = false;
    }

    out.writeBoolean(hasMoreContents);
    if (hasMoreContents)
      out.write(baos.toByteArray());
  }

  // compare across the vertex ID
  @SuppressWarnings("unchecked")
  @Override
  public final int compareTo(VertexInterface o) {
    return getVertexID().compareTo(o.getVertexID());
  }

  /**
   * Read the state of the vertex from the input stream. The framework would
   * have already constructed and loaded the vertex-id, edges and voteToHalt
   * state. This function is essential if there is any more properties of vertex
   * to be read from.
   */
  public void readState(DataInput in) throws IOException {

  }

  /**
   * Writes the state of vertex to the output stream. The framework writes the
   * vertex and edge information to the output stream. This function could be
   * used to save the state variable of the vertex added in the implementation
   * of object.
   */
  public void writeState(DataOutput out) throws IOException {

  }

  protected void setRunner(GraphJobRunner runner) {
    this.runner = runner;
  }

  protected GraphJobRunner getRunner() {
    return runner;
  }

  @Override
  public void aggregate(int index, M value) throws IOException {
    this.runner.getAggregationRunner().aggregateVertex(index, oldValue, value);
  }

  /**
   * Get the last aggregated value of the defined aggregator, null if nothing
   * was configured or not returned a result. You have to supply an index, the
   * index is defined by the order you set the aggregator classes in
   * {@link GraphJob#setAggregatorClass(Class...)}. Index is starting at zero,
   * so if you have a single aggregator you can retrieve it via
   * {@link GraphJobRunner#getLastAggregatedValue}(0).
   */
  @SuppressWarnings("unchecked")
  @Override
  public M getAggregatedValue(int index) {
    return (M) runner.getLastAggregatedValue(index);
  }

  /**
   * Get the number of aggregated vertices in the last superstep. Or null if no
   * aggregator is available.You have to supply an index, the index is defined
   * by the order you set the aggregator classes in
   * {@link GraphJob#setAggregatorClass(Class...)}. Index is starting at zero,
   * so if you have a single aggregator you can retrieve it via
   * {@link #getNumLastAggregatedVertices}(0).
   */
  public IntWritable getNumLastAggregatedVertices(int index) {
    return runner.getNumLastAggregatedVertices(index);
  }

  @Override
  public Counter getCounter(Enum name) {
    return runner.getPeer().getCounter(name);
  }

  @Override
  public Counter getCounter(String group, String name) {
    return runner.getPeer().getCounter(group, name);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy