1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.client;
22
23 import java.io.IOException;
24 import java.lang.reflect.UndeclaredThrowableException;
25 import java.net.ConnectException;
26 import java.net.SocketTimeoutException;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.concurrent.Callable;
30
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.hbase.DoNotRetryIOException;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.HRegionLocation;
35 import org.apache.hadoop.hbase.NotServingRegionException;
36 import org.apache.hadoop.hbase.ipc.HBaseRPC;
37 import org.apache.hadoop.hbase.ipc.HRegionInterface;
38 import org.apache.hadoop.hbase.util.Bytes;
39 import org.apache.hadoop.ipc.RemoteException;
40
41
42
43
44
45
46
47
48
49
50
51
52 public abstract class ServerCallable<T> implements Callable<T> {
53 protected final HConnection connection;
54 protected final byte [] tableName;
55 protected final byte [] row;
56 protected HRegionLocation location;
57 protected HRegionInterface server;
58 protected int callTimeout;
59 protected long startTime, endTime;
60
61
62
63
64
65
66 public ServerCallable(HConnection connection, byte [] tableName, byte [] row) {
67 this(connection, tableName, row, HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT);
68 }
69
70 public ServerCallable(HConnection connection, byte [] tableName, byte [] row, int callTimeout) {
71 this.connection = connection;
72 this.tableName = tableName;
73 this.row = row;
74 this.callTimeout = callTimeout;
75 }
76
77
78
79
80
81
82 public void connect(final boolean reload) throws IOException {
83 this.location = connection.getRegionLocation(tableName, row, reload);
84 this.server = connection.getHRegionConnection(location.getHostname(),
85 location.getPort());
86 }
87
88
89
90
91 public String getServerName() {
92 if (location == null) return null;
93 return location.getHostnamePort();
94 }
95
96
97
98
99 public byte[] getRegionName() {
100 if (location == null) return null;
101 return location.getRegionInfo().getRegionName();
102 }
103
104
105
106
107 public byte [] getRow() {
108 return row;
109 }
110
111 public void beforeCall() {
112 HBaseRPC.setRpcTimeout(this.callTimeout);
113 this.startTime = System.currentTimeMillis();
114 }
115
116 public void afterCall() {
117 HBaseRPC.resetRpcTimeout();
118 this.endTime = System.currentTimeMillis();
119 }
120
121 public void shouldRetry(Throwable throwable) throws IOException {
122 if (this.callTimeout != HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT)
123 if (throwable instanceof SocketTimeoutException
124 || (this.endTime - this.startTime > this.callTimeout)) {
125 throw (SocketTimeoutException) (SocketTimeoutException) new SocketTimeoutException(
126 "Call to access row '" + Bytes.toString(row) + "' on table '"
127 + Bytes.toString(tableName)
128 + "' failed on socket timeout exception: " + throwable)
129 .initCause(throwable);
130 } else {
131 this.callTimeout = ((int) (this.endTime - this.startTime));
132 }
133 }
134
135
136
137
138 HConnection getConnection() {
139 return this.connection;
140 }
141
142
143
144
145
146
147
148
149
150
151 public T withRetries()
152 throws IOException, RuntimeException {
153 Configuration c = getConnection().getConfiguration();
154 final long pause = c.getLong(HConstants.HBASE_CLIENT_PAUSE,
155 HConstants.DEFAULT_HBASE_CLIENT_PAUSE);
156 final int numRetries = c.getInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER,
157 HConstants.DEFAULT_HBASE_CLIENT_RETRIES_NUMBER);
158 List<RetriesExhaustedException.ThrowableWithExtraContext> exceptions =
159 new ArrayList<RetriesExhaustedException.ThrowableWithExtraContext>();
160 for (int tries = 0; tries < numRetries; tries++) {
161 try {
162 beforeCall();
163 connect(tries != 0);
164 return call();
165 } catch (Throwable t) {
166 shouldRetry(t);
167 t = translateException(t);
168 if (t instanceof SocketTimeoutException ||
169 t instanceof ConnectException ||
170 t instanceof RetriesExhaustedException) {
171
172
173
174 HRegionLocation hrl = location;
175 if (hrl != null) {
176 getConnection().clearCaches(hrl.getHostnamePort());
177 }
178 } else if (t instanceof NotServingRegionException && numRetries == 1) {
179
180
181 getConnection().deleteCachedRegionLocation(location);
182 }
183 RetriesExhaustedException.ThrowableWithExtraContext qt =
184 new RetriesExhaustedException.ThrowableWithExtraContext(t,
185 System.currentTimeMillis(), toString());
186 exceptions.add(qt);
187 if (tries == numRetries - 1) {
188 throw new RetriesExhaustedException(tries, exceptions);
189 }
190 } finally {
191 afterCall();
192 }
193 try {
194 Thread.sleep(ConnectionUtils.getPauseTime(pause, tries));
195 } catch (InterruptedException e) {
196 Thread.currentThread().interrupt();
197 throw new IOException("Giving up after tries=" + tries, e);
198 }
199 }
200 return null;
201 }
202
203
204
205
206
207
208
209
210 public T withoutRetries()
211 throws IOException, RuntimeException {
212 try {
213 beforeCall();
214 connect(false);
215 return call();
216 } catch (Throwable t) {
217 Throwable t2 = translateException(t);
218 if (t2 instanceof IOException) {
219 throw (IOException)t2;
220 } else {
221 throw new RuntimeException(t2);
222 }
223 } finally {
224 afterCall();
225 }
226 }
227
228 private static Throwable translateException(Throwable t) throws IOException {
229 if (t instanceof UndeclaredThrowableException) {
230 t = t.getCause();
231 }
232 if (t instanceof RemoteException) {
233 t = ((RemoteException)t).unwrapRemoteException();
234 }
235 if (t instanceof DoNotRetryIOException) {
236 throw (DoNotRetryIOException)t;
237 }
238 return t;
239 }
240 }