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