blob: 6fb9119e21d380477f93b9ea215d280a720427f4 [file] [log] [blame]
/*
* 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.hadoop.yarn.state;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.hadoop.classification.InterfaceAudience.Private;
@Private
public class Graph {
public class Edge {
Node from;
Node to;
String label;
public Edge(Node from, Node to, String info) {
this.from = from;
this.to = to;
this.label = info;
}
public boolean sameAs(Edge rhs) {
if (this.from == rhs.from &&
this.to == rhs.to) {
return true;
}
return false;
}
public Edge combine(Edge rhs) {
String newlabel = this.label + "," + rhs.label;
return new Edge(this.from, this.to, newlabel);
}
}
public class Node {
Graph parent;
String id;
List<Edge> ins;
List<Edge> outs;
public Node(String id) {
this.id = id;
this.parent = Graph.this;
this.ins = new ArrayList<Graph.Edge>();
this.outs = new ArrayList<Graph.Edge>();
}
public Graph getParent() {
return parent;
}
public Node addEdge(Node to, String info) {
Edge e = new Edge(this, to, info);
outs.add(e);
to.ins.add(e);
return this;
}
public String getUniqueId() {
return Graph.this.name + "." + id;
}
}
private String name;
private Graph parent;
private Set<Graph.Node> nodes = new HashSet<Graph.Node>();
private Set<Graph> subgraphs = new HashSet<Graph>();
public Graph(String name, Graph parent) {
this.name = name;
this.parent = parent;
}
public Graph(String name) {
this(name, null);
}
public Graph() {
this("graph", null);
}
public String getName() {
return name;
}
public Graph getParent() {
return parent;
}
private Node newNode(String id) {
Node ret = new Node(id);
nodes.add(ret);
return ret;
}
public Node getNode(String id) {
for (Node node : nodes) {
if (node.id.equals(id)) {
return node;
}
}
return newNode(id);
}
public Graph newSubGraph(String name) {
Graph ret = new Graph(name, this);
subgraphs.add(ret);
return ret;
}
public void addSubGraph(Graph graph) {
subgraphs.add(graph);
graph.parent = this;
}
private static String wrapSafeString(String label) {
if (label.indexOf(',') >= 0) {
if (label.length()>14) {
label = label.replaceAll(",", ",\n");
}
}
label = "\"" + StringEscapeUtils.escapeJava(label) + "\"";
return label;
}
public String generateGraphViz(String indent) {
StringBuilder sb = new StringBuilder();
if (this.parent == null) {
sb.append("digraph " + name + " {\n");
sb.append(String.format("graph [ label=%s, fontsize=24, fontname=Helvetica];%n",
wrapSafeString(name)));
sb.append("node [fontsize=12, fontname=Helvetica];\n");
sb.append("edge [fontsize=9, fontcolor=blue, fontname=Arial];\n");
} else {
sb.append("subgraph cluster_" + name + " {\nlabel=\"" + name + "\"\n");
}
for (Graph g : subgraphs) {
String ginfo = g.generateGraphViz(indent+" ");
sb.append(ginfo);
sb.append("\n");
}
for (Node n : nodes) {
sb.append(String.format(
"%s%s [ label = %s ];%n",
indent,
wrapSafeString(n.getUniqueId()),
n.id));
List<Edge> combinedOuts = combineEdges(n.outs);
for (Edge e : combinedOuts) {
sb.append(String.format(
"%s%s -> %s [ label = %s ];%n",
indent,
wrapSafeString(e.from.getUniqueId()),
wrapSafeString(e.to.getUniqueId()),
wrapSafeString(e.label)));
}
}
sb.append("}\n");
return sb.toString();
}
public String generateGraphViz() {
return generateGraphViz("");
}
public void save(String filepath) throws IOException {
try (OutputStreamWriter fout = new OutputStreamWriter(
new FileOutputStream(filepath), Charset.forName("UTF-8"))) {
fout.write(generateGraphViz());
}
}
public static List<Edge> combineEdges(List<Edge> edges) {
List<Edge> ret = new ArrayList<Edge>();
for (Edge edge : edges) {
boolean found = false;
for (int i = 0; i < ret.size(); i++) {
Edge current = ret.get(i);
if (edge.sameAs(current)) {
ret.set(i, current.combine(edge));
found = true;
break;
}
}
if (!found) {
ret.add(edge);
}
}
return ret;
}
}