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
;
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
;
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
;
51 List
<String
> hostnameAndPort
;
53 public RetriesExhaustedWithDetailsException(final String msg
) {
57 public RetriesExhaustedWithDetailsException(final String msg
, final IOException e
) {
61 public RetriesExhaustedWithDetailsException(List
<Throwable
> exceptions
,
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() {
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() {
96 // If all of the exceptions are DNRIOE not exception
97 for (Throwable t
: exceptions
) {
98 if (!(t
instanceof DoNotRetryIOException
)) {
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) {
139 pw
.append(" from " + server
+ " for "
140 + ((action
== null) ?
"unknown key" : Bytes
.toStringBinary(action
.getRow())));
143 t
.printStackTrace(pw
);
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;
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();
163 name
= t
.getClass().getSimpleName();
165 Integer i
= cls
.get(name
);
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();