HBASE-26688 Threads shared EMPTY_RESULT may lead to unexpected client job down. ...
[hbase.git] / hbase-client / src / main / java / org / apache / hadoop / hbase / client / RetriesExhaustedWithDetailsException.java
blobecbada95c2a11c5be4f7d7e1e64b8cc80561f8db
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org.apache.hadoop.hbase.client;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
31 import org.apache.hadoop.hbase.DoNotRetryIOException;
32 import org.apache.hadoop.hbase.RegionTooBusyException;
33 import org.apache.yetus.audience.InterfaceAudience;
34 import org.apache.hadoop.hbase.util.Bytes;
36 /**
37 * This subclass of {@link org.apache.hadoop.hbase.client.RetriesExhaustedException}
38 * is thrown when we have more information about which rows were causing which
39 * exceptions on what servers. You can call {@link #mayHaveClusterIssues()}
40 * and if the result is false, you have input error problems, otherwise you
41 * may have cluster issues. You can iterate over the causes, rows and last
42 * known server addresses via {@link #getNumExceptions()} and
43 * {@link #getCause(int)}, {@link #getRow(int)} and {@link #getHostnamePort(int)}.
45 @SuppressWarnings("serial")
46 @InterfaceAudience.Public
47 public class RetriesExhaustedWithDetailsException
48 extends RetriesExhaustedException {
49 List<Throwable> exceptions;
50 List<Row> actions;
51 List<String> hostnameAndPort;
53 public RetriesExhaustedWithDetailsException(final String msg) {
54 super(msg);
57 public RetriesExhaustedWithDetailsException(final String msg, final IOException e) {
58 super(msg, e);
61 public RetriesExhaustedWithDetailsException(List<Throwable> exceptions,
62 List<Row> actions,
63 List<String> hostnameAndPort) {
64 super("Failed " + exceptions.size() + " action" +
65 pluralize(exceptions) + ": " +
66 getDesc(exceptions, actions, hostnameAndPort));
68 this.exceptions = exceptions;
69 this.actions = actions;
70 this.hostnameAndPort = hostnameAndPort;
73 public List<Throwable> getCauses() {
74 return exceptions;
77 public int getNumExceptions() {
78 return exceptions.size();
81 public Throwable getCause(int i) {
82 return exceptions.get(i);
85 public Row getRow(int i) {
86 return actions.get(i);
89 public String getHostnamePort(final int i) {
90 return this.hostnameAndPort.get(i);
93 public boolean mayHaveClusterIssues() {
94 boolean res = false;
96 // If all of the exceptions are DNRIOE not exception
97 for (Throwable t : exceptions) {
98 if (!(t instanceof DoNotRetryIOException)) {
99 res = true;
102 return res;
106 public static String pluralize(Collection<?> c) {
107 return pluralize(c.size());
110 public static String pluralize(int c) {
111 return c > 1 ? "s" : "";
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<>(hostnamePort);
122 for (String addr : uniqAddr) {
123 addrs.append(addr).append(", ");
125 return uniqAddr.isEmpty() ? addrs.toString() : addrs.substring(0, addrs.length() - 2);
128 public String getExhaustiveDescription() {
129 StringWriter errorWriter = new StringWriter();
130 PrintWriter pw = new PrintWriter(errorWriter);
131 for (int i = 0; i < this.exceptions.size(); ++i) {
132 Throwable t = this.exceptions.get(i);
133 Row action = this.actions.get(i);
134 String server = this.hostnameAndPort.get(i);
135 pw.append("exception");
136 if (this.exceptions.size() > 1) {
137 pw.append(" #" + i);
139 pw.append(" from " + server + " for "
140 + ((action == null) ? "unknown key" : Bytes.toStringBinary(action.getRow())));
141 if (t != null) {
142 pw.println();
143 t.printStackTrace(pw);
146 pw.flush();
147 return errorWriter.toString();
151 public static Map<String, Integer> classifyExs(List<Throwable> ths) {
152 Map<String, Integer> cls = new HashMap<>();
153 for (Throwable t : ths) {
154 if (t == null) continue;
155 String name = "";
156 if (t instanceof DoNotRetryIOException ||
157 t instanceof RegionTooBusyException) {
158 // If RegionTooBusyException, print message since it has Region name in it.
159 // RegionTooBusyException message was edited to remove variance. Has regionname, server,
160 // and why the exception; no longer has duration it waited on lock nor current memsize.
161 name = t.getMessage();
162 } else {
163 name = t.getClass().getSimpleName();
165 Integer i = cls.get(name);
166 if (i == null) {
167 i = 0;
169 i += 1;
170 cls.put(name, i);
172 return cls;
175 public static String getDesc(Map<String,Integer> classificaton) {
176 StringBuilder classificatons =new StringBuilder(11);
177 for (Map.Entry<String, Integer> e : classificaton.entrySet()) {
178 classificatons.append(e.getKey());
179 classificatons.append(": ");
180 classificatons.append(e.getValue());
181 classificatons.append(" time");
182 classificatons.append(pluralize(e.getValue()));
183 classificatons.append(", ");
185 return classificatons.toString();