001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hbase.client; 020 021import java.io.IOException; 022import java.io.PrintWriter; 023import java.io.StringWriter; 024import java.util.Collection; 025import java.util.HashMap; 026import java.util.HashSet; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031import org.apache.hadoop.hbase.DoNotRetryIOException; 032import org.apache.hadoop.hbase.RegionTooBusyException; 033import org.apache.yetus.audience.InterfaceAudience; 034import org.apache.hadoop.hbase.util.Bytes; 035 036/** 037 * This subclass of {@link org.apache.hadoop.hbase.client.RetriesExhaustedException} 038 * is thrown when we have more information about which rows were causing which 039 * exceptions on what servers. You can call {@link #mayHaveClusterIssues()} 040 * and if the result is false, you have input error problems, otherwise you 041 * may have cluster issues. You can iterate over the causes, rows and last 042 * known server addresses via {@link #getNumExceptions()} and 043 * {@link #getCause(int)}, {@link #getRow(int)} and {@link #getHostnamePort(int)}. 044 */ 045@SuppressWarnings("serial") 046@InterfaceAudience.Public 047public class RetriesExhaustedWithDetailsException 048extends RetriesExhaustedException { 049 List<Throwable> exceptions; 050 List<Row> actions; 051 List<String> hostnameAndPort; 052 053 public RetriesExhaustedWithDetailsException(final String msg) { 054 super(msg); 055 } 056 057 public RetriesExhaustedWithDetailsException(final String msg, final IOException e) { 058 super(msg, e); 059 } 060 061 public RetriesExhaustedWithDetailsException(List<Throwable> exceptions, 062 List<Row> actions, 063 List<String> hostnameAndPort) { 064 super("Failed " + exceptions.size() + " action" + 065 pluralize(exceptions) + ": " + 066 getDesc(exceptions, actions, hostnameAndPort)); 067 068 this.exceptions = exceptions; 069 this.actions = actions; 070 this.hostnameAndPort = hostnameAndPort; 071 } 072 073 public List<Throwable> getCauses() { 074 return exceptions; 075 } 076 077 public int getNumExceptions() { 078 return exceptions.size(); 079 } 080 081 public Throwable getCause(int i) { 082 return exceptions.get(i); 083 } 084 085 public Row getRow(int i) { 086 return actions.get(i); 087 } 088 089 public String getHostnamePort(final int i) { 090 return this.hostnameAndPort.get(i); 091 } 092 093 public boolean mayHaveClusterIssues() { 094 boolean res = false; 095 096 // If all of the exceptions are DNRIOE not exception 097 for (Throwable t : exceptions) { 098 if (!(t instanceof DoNotRetryIOException)) { 099 res = true; 100 } 101 } 102 return res; 103 } 104 105 106 public static String pluralize(Collection<?> c) { 107 return pluralize(c.size()); 108 } 109 110 public static String pluralize(int c) { 111 return c > 1 ? "s" : ""; 112 } 113 114 public static String getDesc(List<Throwable> exceptions, 115 List<? extends Row> actions, 116 List<String> hostnamePort) { 117 String s = getDesc(classifyExs(exceptions)); 118 StringBuilder addrs = new StringBuilder(s); 119 addrs.append("servers with issues: "); 120 Set<String> uniqAddr = new HashSet<>(); 121 uniqAddr.addAll(hostnamePort); 122 123 for (String addr : uniqAddr) { 124 addrs.append(addr).append(", "); 125 } 126 return uniqAddr.isEmpty() ? addrs.toString() : addrs.substring(0, addrs.length() - 2); 127 } 128 129 public String getExhaustiveDescription() { 130 StringWriter errorWriter = new StringWriter(); 131 PrintWriter pw = new PrintWriter(errorWriter); 132 for (int i = 0; i < this.exceptions.size(); ++i) { 133 Throwable t = this.exceptions.get(i); 134 Row action = this.actions.get(i); 135 String server = this.hostnameAndPort.get(i); 136 pw.append("exception"); 137 if (this.exceptions.size() > 1) { 138 pw.append(" #" + i); 139 } 140 pw.append(" from " + server + " for " 141 + ((action == null) ? "unknown key" : Bytes.toStringBinary(action.getRow()))); 142 if (t != null) { 143 pw.println(); 144 t.printStackTrace(pw); 145 } 146 } 147 pw.flush(); 148 return errorWriter.toString(); 149 } 150 151 152 public static Map<String, Integer> classifyExs(List<Throwable> ths) { 153 Map<String, Integer> cls = new HashMap<>(); 154 for (Throwable t : ths) { 155 if (t == null) continue; 156 String name = ""; 157 if (t instanceof DoNotRetryIOException || 158 t instanceof RegionTooBusyException) { 159 // If RegionTooBusyException, print message since it has Region name in it. 160 // RegionTooBusyException message was edited to remove variance. Has regionname, server, 161 // and why the exception; no longer has duration it waited on lock nor current memsize. 162 name = t.getMessage(); 163 } else { 164 name = t.getClass().getSimpleName(); 165 } 166 Integer i = cls.get(name); 167 if (i == null) { 168 i = 0; 169 } 170 i += 1; 171 cls.put(name, i); 172 } 173 return cls; 174 } 175 176 public static String getDesc(Map<String,Integer> classificaton) { 177 StringBuilder classificatons =new StringBuilder(11); 178 for (Map.Entry<String, Integer> e : classificaton.entrySet()) { 179 classificatons.append(e.getKey()); 180 classificatons.append(": "); 181 classificatons.append(e.getValue()); 182 classificatons.append(" time"); 183 classificatons.append(pluralize(e.getValue())); 184 classificatons.append(", "); 185 } 186 return classificatons.toString(); 187 } 188}