/* * 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.pig.backend.hadoop.executionengine.physicalLayer.plans; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.pig.PigException; import org.apache.pig.backend.hadoop.executionengine.physicalLayer.PhysicalOperator; import org.apache.pig.backend.hadoop.executionengine.physicalLayer.relationalOperators.*; import org.apache.pig.impl.plan.DepthFirstWalker; import org.apache.pig.impl.plan.Operator; import org.apache.pig.impl.plan.OperatorPlan; import org.apache.pig.impl.plan.PlanVisitor; import org.apache.pig.impl.plan.VisitorException; import org.apache.pig.impl.util.MultiMap; public class PlanPrinter<O extends Operator, P extends OperatorPlan<O>> extends PlanVisitor<O, P> { String TAB1 = " "; String TABMore = "| "; String LSep = "|\n|---"; String USep = "| |\n| "; int levelCntr = -1; PrintStream stream = System.out; boolean isVerbose = true; public PlanPrinter(P plan) { super(plan, new DepthFirstWalker<O, P>(plan)); } public PlanPrinter(P plan, PrintStream stream) { super(plan, new DepthFirstWalker<O, P>(plan)); this.stream = stream; } public void setVerbose(boolean verbose) { isVerbose = verbose; } @Override public void visit() throws VisitorException { try { stream.write(depthFirstPP().getBytes()); } catch (IOException ioe) { int errCode = 2079; String msg = "Unexpected error while printing physical plan."; throw new VisitorException(msg, errCode, PigException.BUG, ioe); } } public void print(OutputStream printer) throws VisitorException, IOException { printer.write(depthFirstPP().getBytes()); } protected void breadthFirst() throws VisitorException { List<O> leaves = mPlan.getLeaves(); Set<O> seen = new HashSet<O>(); breadthFirst(leaves, seen); } @SuppressWarnings("unchecked") private void breadthFirst(Collection<O> predecessors, Set<O> seen) throws VisitorException { ++levelCntr; dispTabs(); List<O> newPredecessors = new ArrayList<O>(); for (O pred : predecessors) { if (seen.add(pred)) { List<O> predLst = mPlan.getPredecessors(pred); if (predLst != null) newPredecessors.addAll(predLst); pred.visit(this); } } if (newPredecessors.size() > 0) { stream.println(); breadthFirst(newPredecessors, seen); } } @SuppressWarnings("unchecked") protected String depthFirstPP() throws VisitorException { StringBuilder sb = new StringBuilder(); List<O> leaves = mPlan.getLeaves(); Collections.sort(leaves); for (O leaf : leaves) { sb.append(depthFirst(leaf)); sb.append("\n"); } sb.delete(sb.length() - "\n".length(), sb.length()); sb.delete(sb.length() - "\n".length(), sb.length()); return sb.toString(); } private String planString(PhysicalPlan pp){ StringBuilder sb = new StringBuilder(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if(pp!=null) pp.explain(baos, isVerbose); else return ""; sb.append(USep); sb.append(shiftStringByTabs(baos.toString(), 2)); return sb.toString(); } private String planString(List<PhysicalPlan> lep){ StringBuilder sb = new StringBuilder(); if(lep!=null) for (PhysicalPlan ep : lep) { sb.append(planString(ep)); } return sb.toString(); } @SuppressWarnings("unchecked") private String depthFirst(O node) throws VisitorException { StringBuilder sb = new StringBuilder(node.name() + "\n"); if (isVerbose) { if(node instanceof POFilter){ sb.append(planString(((POFilter)node).getPlan())); } else if(node instanceof POLocalRearrange){ sb.append(planString(((POLocalRearrange)node).getPlans())); } else if(node instanceof POPartialAgg){ sb.append(planString(((POPartialAgg)node).getKeyPlan())); sb.append(planString(((POPartialAgg)node).getValuePlans())); } else if(node instanceof POCollectedGroup){ sb.append(planString(((POCollectedGroup)node).getPlans())); } else if(node instanceof PORank){ sb.append(planString(((PORank)node).getRankPlans())); } else if(node instanceof POCounter){ sb.append(planString(((POCounter)node).getCounterPlans())); } else if(node instanceof POSort){ sb.append(planString(((POSort)node).getSortPlans())); } else if(node instanceof POForEach){ sb.append(planString(((POForEach)node).getInputPlans())); } else if (node instanceof POMultiQueryPackage) { List<POPackage> pkgs = ((POMultiQueryPackage)node).getPackages(); for (POPackage pkg : pkgs) { sb.append(LSep + pkg.name() + "\n"); } } else if(node instanceof POFRJoin){ POFRJoin frj = (POFRJoin)node; List<List<PhysicalPlan>> joinPlans = frj.getJoinPlans(); if(joinPlans!=null) for (List<PhysicalPlan> list : joinPlans) { sb.append(planString(list)); } } else if(node instanceof POSkewedJoin){ POSkewedJoin skewed = (POSkewedJoin)node; MultiMap<PhysicalOperator, PhysicalPlan> joinPlans = skewed.getJoinPlans(); if(joinPlans!=null) { List<PhysicalPlan> inner_plans = new ArrayList<PhysicalPlan>(); inner_plans.addAll(joinPlans.values()); sb.append(planString(inner_plans)); } } } if (node instanceof POSplit) { sb.append(planString(((POSplit)node).getPlans())); } else if (node instanceof PODemux) { List<PhysicalPlan> plans = new ArrayList<PhysicalPlan>(); Set<PhysicalPlan> pl = new HashSet<PhysicalPlan>(); pl.addAll(((PODemux)node).getPlans()); plans.addAll(pl); sb.append(planString(plans)); } List<O> originalPredecessors = mPlan.getPredecessors(node); if (originalPredecessors == null) return sb.toString(); List<O> predecessors = new ArrayList<O>(originalPredecessors); Collections.sort(predecessors); int i = 0; for (O pred : predecessors) { i++; String DFStr = depthFirst(pred); if (DFStr != null) { sb.append(LSep); if (i < predecessors.size()) sb.append(shiftStringByTabs(DFStr, 2)); else sb.append(shiftStringByTabs(DFStr, 1)); } } return sb.toString(); } private String shiftStringByTabs(String DFStr, int TabType) { StringBuilder sb = new StringBuilder(); String[] spl = DFStr.split("\n"); String tab = (TabType == 1) ? TAB1 : TABMore; sb.append(spl[0] + "\n"); for (int i = 1; i < spl.length; i++) { sb.append(tab); sb.append(spl[i]); sb.append("\n"); } return sb.toString(); } private void dispTabs() { for (int i = 0; i < levelCntr; i++) stream.print(TAB1); } public void visitLoad(POLoad op) { stream.print(op.name() + " "); } public void visitStore(POStore op) { stream.print(op.name() + " "); } public void visitFilter(POFilter op) { stream.print(op.name() + " "); } public void visitLocalRearrange(POLocalRearrange op) { stream.print(op.name() + " "); } public void visitGlobalRearrange(POGlobalRearrange op) { stream.print(op.name() + " "); } public void visitPackage(POPackage op) { stream.print(op.name() + " "); } public void visitStartMap(POUnion op) { stream.print(op.name() + " "); } }