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

eu.stratosphere.nephele.managementgraph.ManagementGroupVertexIterator Maven / Gradle / Ivy

/***********************************************************************************************************************
 * Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
 *
 * Licensed 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 eu.stratosphere.nephele.managementgraph;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;

/**
 * This class provides an implementation of the {@link Iterator} interface which allows to
 * traverse a management graph and visit every reachable group vertex exactly once. The order
 * in which the group vertices are visited corresponds to the order of their discovery in a depth first
 * search.
 * This class is not thread-safe.
 * 
 */
public final class ManagementGroupVertexIterator implements Iterator {

	/**
	 * Stores whether the group graph is traversed starting from the input or the output vertices.
	 */
	private final boolean forward;

	/**
	 * The stage to traverse, -1 to traverse all stages of the graph.
	 */
	private final int stage;

	/**
	 * List of entry vertices for the traversal (either input or output vertices).
	 */
	private final List entryVertices = new ArrayList();

	/**
	 * Number of already visited entry vertices.
	 */
	private int numVisitedEntryVertices = 0;

	/**
	 * Stack used for the traversal.
	 */
	private final Stack traversalStack = new Stack();

	/**
	 * Set storing the vertices already visited during traversal.
	 */
	private final Set alreadyVisited = new HashSet();

	/**
	 * Auxiliary class which stores which vertices have already been visited.
	 * 
	 */
	private static class TraversalEntry {

		/**
		 * The group vertex this entry is created for.
		 */
		private final ManagementGroupVertex groupVertex;

		/**
		 * The current outgoing edge of the group vertex.
		 */
		private int currentEdge = 0;

		/**
		 * Constructs a new traversal entry.
		 * 
		 * @param groupVertex
		 *        the group vertex this traversal entry belongs to
		 * @param currentEdge
		 *        the edge index to use to visit the next group vertex
		 */
		public TraversalEntry(final ManagementGroupVertex groupVertex, final int currentEdge) {
			this.groupVertex = groupVertex;
			this.currentEdge = currentEdge;
		}

		/**
		 * Returns the group vertex this traversal entry belongs to.
		 * 
		 * @return the group vertex this traversal entry belongs to
		 */
		public ManagementGroupVertex getGroupVertex() {
			return this.groupVertex;
		}

		/**
		 * Returns the edge index to use to visit the next group vertex.
		 * 
		 * @return the edge index to use to visit the next group vertex
		 */
		public int getCurrentEdge() {
			return this.currentEdge;
		}

		/**
		 * Increases the edge index by one.
		 */
		public void increaseCurrentEdge() {
			this.currentEdge++;
		}
	}

	/**
	 * Creates a new management group vertex iterator.
	 * 
	 * @param managementGraph
	 *        the management graph that should be traversed
	 * @param forward
	 *        true if the graph should be traversed in correct order, false to reverse it in
	 *        reverse order
	 * @param stage
	 *        the number of the stage whose vertices should be traversed or -1 if all stages should be included in the
	 *        traversal
	 */
	public ManagementGroupVertexIterator(final ManagementGraph managementGraph, final boolean forward, final int stage) {

		this.forward = forward;
		this.stage = stage;

		// Collect start vertices
		if (stage < 0) {

			for (int i = 0; i < managementGraph.getNumberOfStages(); i++) {
				collectStartVertices(managementGraph.getStage(i));
			}
		} else {
			if (stage < managementGraph.getNumberOfStages()) {
				collectStartVertices(managementGraph.getStage(stage));
			}
		}

		if (this.entryVertices.size() > 0) {
			final TraversalEntry te = new TraversalEntry(this.entryVertices.get(0), 0);
			this.traversalStack.push(te);
			this.alreadyVisited.add(te.getGroupVertex());
		}
	}

	/**
	 * Collects all input group vertices (i.e. vertices with no incoming edge or incoming edges from other stages) in
	 * the given stage and adds them to an internal list.
	 * 
	 * @param stage
	 *        the number of the stage whose input vertices should be collected
	 */
	private void collectStartVertices(final ManagementStage stage) {

		for (int i = 0; i < stage.getNumberOfGroupVertices(); i++) {

			final ManagementGroupVertex groupVertex = stage.getGroupVertex(i);

			if (this.forward) {
				if ((groupVertex.getNumberOfBackwardEdges() == 0)
					|| ((this.stage >= 0) && allConnectionsFromOtherStage(groupVertex, true))) {
					this.entryVertices.add(groupVertex);
				}
			} else {
				if ((groupVertex.getNumberOfForwardEdges() == 0)
					|| ((this.stage >= 0) && allConnectionsFromOtherStage(groupVertex, false))) {
					this.entryVertices.add(groupVertex);
				}
			}
		}
	}

	/**
	 * Checks if for the given group vertex all incoming (if forward is true) or outgoing edges (if forward
	 * is false) come from
	 * other stages than the one the given vertex is in.
	 * 
	 * @param groupVertex
	 *        the group vertex to check for
	 * @param forward
	 *        true if incoming edges should be considered, false for outgoing edges
	 * @return true if all incoming or outgoing edges (depends on the forward switch) come from other
	 *         stages, false otherwise
	 */
	private boolean allConnectionsFromOtherStage(final ManagementGroupVertex groupVertex, final boolean forward) {

		if (forward) {
			for (int i = 0; i < groupVertex.getNumberOfBackwardEdges(); i++) {
				if (this.stage == groupVertex.getBackwardEdge(i).getSource().getStageNumber()) {
					return false;
				}
			}
		} else {
			for (int i = 0; i < groupVertex.getNumberOfForwardEdges(); i++) {
				if (this.stage == groupVertex.getForwardEdge(i).getTarget().getStageNumber()) {
					return false;
				}
			}
		}

		return true;
	}


	@Override
	public boolean hasNext() {

		if (this.traversalStack.isEmpty()) {

			this.numVisitedEntryVertices++;
			if (this.entryVertices.size() <= this.numVisitedEntryVertices) {
				return false;
			}
		}

		return true;

	}


	@Override
	public ManagementGroupVertex next() {

		if (this.traversalStack.isEmpty()) {

			final TraversalEntry newentry = new TraversalEntry(this.entryVertices.get(this.numVisitedEntryVertices), 0);
			this.traversalStack.push(newentry);
			this.alreadyVisited.add(newentry.getGroupVertex());
		}

		final ManagementGroupVertex returnVertex = this.traversalStack.peek().getGroupVertex();

		// Propose vertex to be visited next
		do {

			final TraversalEntry te = this.traversalStack.peek();

			// Check if we can traverse deeper into the graph
			final ManagementGroupVertex candidateVertex = getCandidateVertex(te, forward);
			if (candidateVertex == null) {
				// Pop it from the stack
				this.traversalStack.pop();
			} else {
				// Create new entry and put it on the stack
				final TraversalEntry newte = new TraversalEntry(candidateVertex, 0);
				this.traversalStack.push(newte);
				this.alreadyVisited.add(newte.getGroupVertex());
				break;
			}

		} while (!this.traversalStack.isEmpty());

		return returnVertex;

	}

	/**
	 * Returns a candidate group vertex which could potentially be visited next because it is reachable from the
	 * currently considered group vertex.
	 * 
	 * @param te
	 *        the traversal entry for the current source group vertex
	 * @param forward
	 *        true if the graph should be traversed in correct order, false to traverse it in
	 *        reverse order
	 * @return a candidate group vertex which could potentially be visited next
	 */
	private ManagementGroupVertex getCandidateVertex(final TraversalEntry te, final boolean forward) {

		while (true) {

			if (forward) {
				// No more outgoing edges to consider
				if (te.getCurrentEdge() >= te.getGroupVertex().getNumberOfForwardEdges()) {
					break;
				}
			} else {
				// No more outgoing edges to consider
				if (te.getCurrentEdge() >= te.getGroupVertex().getNumberOfBackwardEdges()) {
					break;
				}
			}

			ManagementGroupVertex tmp = null;
			if (forward) {
				tmp = te.getGroupVertex().getForwardEdge(te.getCurrentEdge()).getTarget();
			} else {
				tmp = te.getGroupVertex().getBackwardEdge(te.getCurrentEdge()).getSource();
			}

			// Increase the current edge index by one
			te.increaseCurrentEdge();

			// If stage >= 0, tmp must be in the same stage as te.getGroupVertex()
			if (this.stage >= 0) {
				if (tmp.getStageNumber() != this.stage) {
					continue;
				}
			}

			if (!this.alreadyVisited.contains(tmp)) {
				return tmp;
			}
		}

		return null;
	}


	@Override
	public void remove() {
		// According to the documentation this method is optional and does not need to be implemented

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy