/* * 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.FileWriter; import java.io.IOException; 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 { FileWriter fout = new FileWriter(filepath); fout.write(generateGraphViz()); fout.close(); } 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; } }