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