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