View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.client;
21  
22  import org.apache.hadoop.hbase.classification.InterfaceAudience;
23  import org.apache.hadoop.hbase.classification.InterfaceStability;
24  import org.apache.hadoop.hbase.DoNotRetryIOException;
25  import org.apache.hadoop.hbase.util.Bytes;
26  
27  import java.io.IOException;
28  import java.io.PrintWriter;
29  import java.io.StringWriter;
30  import java.util.Collection;
31  import java.util.HashMap;
32  import java.util.HashSet;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  
37  /**
38   * This subclass of {@link org.apache.hadoop.hbase.client.RetriesExhaustedException}
39   * is thrown when we have more information about which rows were causing which
40   * exceptions on what servers.  You can call {@link #mayHaveClusterIssues()}
41   * and if the result is false, you have input error problems, otherwise you
42   * may have cluster issues.  You can iterate over the causes, rows and last
43   * known server addresses via {@link #getNumExceptions()} and
44   * {@link #getCause(int)}, {@link #getRow(int)} and {@link #getHostnamePort(int)}.
45   */
46  @SuppressWarnings("serial")
47  @InterfaceAudience.Public
48  @InterfaceStability.Stable
49  public class RetriesExhaustedWithDetailsException
50  extends RetriesExhaustedException {
51    List<Throwable> exceptions;
52    List<Row> actions;
53    List<String> hostnameAndPort;
54  
55    public RetriesExhaustedWithDetailsException(final String msg) {
56      super(msg);
57    }
58  
59    public RetriesExhaustedWithDetailsException(final String msg, final IOException e) {
60      super(msg, e);
61    }
62  
63    public RetriesExhaustedWithDetailsException(List<Throwable> exceptions,
64                                                List<Row> actions,
65                                                List<String> hostnameAndPort) {
66      super("Failed " + exceptions.size() + " action" +
67          pluralize(exceptions) + ": " +
68          getDesc(exceptions, actions, hostnameAndPort));
69  
70      this.exceptions = exceptions;
71      this.actions = actions;
72      this.hostnameAndPort = hostnameAndPort;
73    }
74  
75    public List<Throwable> getCauses() {
76      return exceptions;
77    }
78  
79    public int getNumExceptions() {
80      return exceptions.size();
81    }
82  
83    public Throwable getCause(int i) {
84      return exceptions.get(i);
85    }
86  
87    public Row getRow(int i) {
88      return actions.get(i);
89    }
90  
91    public String getHostnamePort(final int i) {
92      return this.hostnameAndPort.get(i);
93    }
94  
95    public boolean mayHaveClusterIssues() {
96      boolean res = false;
97  
98      // If all of the exceptions are DNRIOE not exception
99      for (Throwable t : exceptions) {
100       if ( !(t instanceof DoNotRetryIOException ||
101              t instanceof NeedUnmanagedConnectionException)) {
102         res = true;
103       }
104     }
105     return res;
106   }
107 
108 
109   public static String pluralize(Collection<?> c) {
110     return pluralize(c.size());
111   }
112 
113   public static String pluralize(int c) {
114     return c > 1 ? "s" : "";
115   }
116 
117   public static String getDesc(List<Throwable> exceptions,
118                                List<? extends Row> actions,
119                                List<String> hostnamePort) {
120     String s = getDesc(classifyExs(exceptions));
121     StringBuilder addrs = new StringBuilder(s);
122     addrs.append("servers with issues: ");
123     Set<String> uniqAddr = new HashSet<String>();
124     uniqAddr.addAll(hostnamePort);
125 
126     for (String addr : uniqAddr) {
127       addrs.append(addr).append(", ");
128     }
129     return uniqAddr.isEmpty() ? addrs.toString() : addrs.substring(0, addrs.length() - 2);
130   }
131 
132   public String getExhaustiveDescription() {
133     StringWriter errorWriter = new StringWriter();
134     PrintWriter pw = new PrintWriter(errorWriter);
135     for (int i = 0; i < this.exceptions.size(); ++i) {
136       Throwable t = this.exceptions.get(i);
137       Row action = this.actions.get(i);
138       String server = this.hostnameAndPort.get(i);
139       pw.append("exception");
140       if (this.exceptions.size() > 1) {
141         pw.append(" #" + i);
142       }
143       pw.append(" from " + server + " for "
144         + ((action == null) ? "unknown key" : Bytes.toStringBinary(action.getRow())));
145       if (t != null) {
146         pw.println();
147         t.printStackTrace(pw);
148       }
149     }
150     pw.flush();
151     return errorWriter.toString();
152   }
153 
154 
155   public static Map<String, Integer> classifyExs(List<Throwable> ths) {
156     Map<String, Integer> cls = new HashMap<String, Integer>();
157     for (Throwable t : ths) {
158       if (t == null) continue;
159       String name = "";
160       if (t instanceof DoNotRetryIOException) {
161         name = t.getMessage();
162       } else {
163         name = t.getClass().getSimpleName();
164       }
165       Integer i = cls.get(name);
166       if (i == null) {
167         i = 0;
168       }
169       i += 1;
170       cls.put(name, i);
171     }
172     return cls;
173   }
174 
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(", ");
184     }
185     return classificatons.toString();
186   }
187 
188 }