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.ipc;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.conf.Configurable;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.hbase.client.RetriesExhaustedException;
28 import org.apache.hadoop.hbase.io.HbaseObjectWritable;
29 import org.apache.hadoop.io.Writable;
30 import org.apache.hadoop.ipc.VersionedProtocol;
31 import org.apache.hadoop.net.NetUtils;
32 import org.apache.hadoop.security.UserGroupInformation;
33
34 import javax.net.SocketFactory;
35 import java.io.DataInput;
36 import java.io.DataOutput;
37 import java.io.IOException;
38 import java.lang.reflect.Array;
39 import java.lang.reflect.InvocationHandler;
40 import java.lang.reflect.InvocationTargetException;
41 import java.lang.reflect.Method;
42 import java.lang.reflect.Proxy;
43 import java.net.ConnectException;
44 import java.net.InetSocketAddress;
45 import java.net.SocketTimeoutException;
46 import java.util.HashMap;
47 import java.util.Map;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public class HBaseRPC {
75
76
77
78 protected static final Log LOG =
79 LogFactory.getLog("org.apache.hadoop.ipc.HbaseRPC");
80
81 private HBaseRPC() {
82 super();
83 }
84
85
86 private static class Invocation implements Writable, Configurable {
87 private String methodName;
88 @SuppressWarnings("unchecked")
89 private Class[] parameterClasses;
90 private Object[] parameters;
91 private Configuration conf;
92
93
94 public Invocation() {
95 super();
96 }
97
98
99
100
101
102 public Invocation(Method method, Object[] parameters) {
103 this.methodName = method.getName();
104 this.parameterClasses = method.getParameterTypes();
105 this.parameters = parameters;
106 }
107
108
109 public String getMethodName() { return methodName; }
110
111
112 @SuppressWarnings("unchecked")
113 public Class[] getParameterClasses() { return parameterClasses; }
114
115
116 public Object[] getParameters() { return parameters; }
117
118 public void readFields(DataInput in) throws IOException {
119 methodName = in.readUTF();
120 parameters = new Object[in.readInt()];
121 parameterClasses = new Class[parameters.length];
122 HbaseObjectWritable objectWritable = new HbaseObjectWritable();
123 for (int i = 0; i < parameters.length; i++) {
124 parameters[i] = HbaseObjectWritable.readObject(in, objectWritable,
125 this.conf);
126 parameterClasses[i] = objectWritable.getDeclaredClass();
127 }
128 }
129
130 public void write(DataOutput out) throws IOException {
131 out.writeUTF(this.methodName);
132 out.writeInt(parameterClasses.length);
133 for (int i = 0; i < parameterClasses.length; i++) {
134 HbaseObjectWritable.writeObject(out, parameters[i], parameterClasses[i],
135 conf);
136 }
137 }
138
139 @Override
140 public String toString() {
141 StringBuilder buffer = new StringBuilder(256);
142 buffer.append(methodName);
143 buffer.append("(");
144 for (int i = 0; i < parameters.length; i++) {
145 if (i != 0)
146 buffer.append(", ");
147 buffer.append(parameters[i]);
148 }
149 buffer.append(")");
150 return buffer.toString();
151 }
152
153 public void setConf(Configuration conf) {
154 this.conf = conf;
155 }
156
157 public Configuration getConf() {
158 return this.conf;
159 }
160 }
161
162
163 static private class ClientCache {
164 private Map<SocketFactory, HBaseClient> clients =
165 new HashMap<SocketFactory, HBaseClient>();
166
167 protected ClientCache() {}
168
169
170
171
172
173
174
175
176
177 protected synchronized HBaseClient getClient(Configuration conf,
178 SocketFactory factory) {
179
180
181
182
183
184 HBaseClient client = clients.get(factory);
185 if (client == null) {
186
187 client = new HBaseClient(HbaseObjectWritable.class, conf, factory);
188 clients.put(factory, client);
189 } else {
190 client.incCount();
191 }
192 return client;
193 }
194
195
196
197
198
199
200
201
202 protected synchronized HBaseClient getClient(Configuration conf) {
203 return getClient(conf, SocketFactory.getDefault());
204 }
205
206
207
208
209
210
211 protected void stopClient(HBaseClient client) {
212 synchronized (this) {
213 client.decCount();
214 if (client.isZeroReference()) {
215 clients.remove(client.getSocketFactory());
216 }
217 }
218 if (client.isZeroReference()) {
219 client.stop();
220 }
221 }
222 }
223
224 protected final static ClientCache CLIENTS = new ClientCache();
225
226 private static class Invoker implements InvocationHandler {
227 private InetSocketAddress address;
228 private UserGroupInformation ticket;
229 private HBaseClient client;
230 private boolean isClosed = false;
231
232
233
234
235
236
237
238 public Invoker(InetSocketAddress address, UserGroupInformation ticket,
239 Configuration conf, SocketFactory factory) {
240 this.address = address;
241 this.ticket = ticket;
242 this.client = CLIENTS.getClient(conf, factory);
243 }
244
245 public Object invoke(Object proxy, Method method, Object[] args)
246 throws Throwable {
247 final boolean logDebug = LOG.isDebugEnabled();
248 long startTime = 0;
249 if (logDebug) {
250 startTime = System.currentTimeMillis();
251 }
252 HbaseObjectWritable value = (HbaseObjectWritable)
253 client.call(new Invocation(method, args), address, ticket);
254 if (logDebug) {
255 long callTime = System.currentTimeMillis() - startTime;
256 LOG.debug("Call: " + method.getName() + " " + callTime);
257 }
258 return value.get();
259 }
260
261
262 synchronized protected void close() {
263 if (!isClosed) {
264 isClosed = true;
265 CLIENTS.stopClient(client);
266 }
267 }
268 }
269
270
271
272
273 @SuppressWarnings("serial")
274 public static class VersionMismatch extends IOException {
275 private String interfaceName;
276 private long clientVersion;
277 private long serverVersion;
278
279
280
281
282
283
284
285 public VersionMismatch(String interfaceName, long clientVersion,
286 long serverVersion) {
287 super("Protocol " + interfaceName + " version mismatch. (client = " +
288 clientVersion + ", server = " + serverVersion + ")");
289 this.interfaceName = interfaceName;
290 this.clientVersion = clientVersion;
291 this.serverVersion = serverVersion;
292 }
293
294
295
296
297
298
299 public String getInterfaceName() {
300 return interfaceName;
301 }
302
303
304
305
306 public long getClientVersion() {
307 return clientVersion;
308 }
309
310
311
312
313 public long getServerVersion() {
314 return serverVersion;
315 }
316 }
317
318
319
320
321
322
323
324
325
326
327
328 @SuppressWarnings("unchecked")
329 public static VersionedProtocol waitForProxy(Class protocol,
330 long clientVersion,
331 InetSocketAddress addr,
332 Configuration conf,
333 int maxAttempts,
334 long timeout
335 ) throws IOException {
336
337 long startTime = System.currentTimeMillis();
338 IOException ioe;
339 int reconnectAttempts = 0;
340 while (true) {
341 try {
342 return getProxy(protocol, clientVersion, addr, conf);
343 } catch(ConnectException se) {
344 ioe = se;
345 if (maxAttempts >= 0 && ++reconnectAttempts >= maxAttempts) {
346 LOG.info("Server at " + addr + " could not be reached after " +
347 reconnectAttempts + " tries, giving up.");
348 throw new RetriesExhaustedException("Failed setting up proxy to " +
349 addr.toString() + " after attempts=" + reconnectAttempts);
350 }
351 } catch(SocketTimeoutException te) {
352 LOG.info("Problem connecting to server: " + addr);
353 ioe = te;
354 }
355
356 if (System.currentTimeMillis()-timeout >= startTime) {
357 throw ioe;
358 }
359
360
361 try {
362 Thread.sleep(1000);
363 } catch (InterruptedException ie) {
364
365 }
366 }
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381 public static VersionedProtocol getProxy(Class<?> protocol,
382 long clientVersion, InetSocketAddress addr, Configuration conf,
383 SocketFactory factory) throws IOException {
384 return getProxy(protocol, clientVersion, addr, null, conf, factory);
385 }
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400 public static VersionedProtocol getProxy(Class<?> protocol,
401 long clientVersion, InetSocketAddress addr, UserGroupInformation ticket,
402 Configuration conf, SocketFactory factory)
403 throws IOException {
404 VersionedProtocol proxy =
405 (VersionedProtocol) Proxy.newProxyInstance(
406 protocol.getClassLoader(), new Class[] { protocol },
407 new Invoker(addr, ticket, conf, factory));
408 long serverVersion = proxy.getProtocolVersion(protocol.getName(),
409 clientVersion);
410 if (serverVersion == clientVersion) {
411 return proxy;
412 }
413 throw new VersionMismatch(protocol.getName(), clientVersion,
414 serverVersion);
415 }
416
417
418
419
420
421
422
423
424
425
426
427 public static VersionedProtocol getProxy(Class<?> protocol,
428 long clientVersion, InetSocketAddress addr, Configuration conf)
429 throws IOException {
430
431 return getProxy(protocol, clientVersion, addr, conf, NetUtils
432 .getDefaultSocketFactory(conf));
433 }
434
435
436
437
438
439 public static void stopProxy(VersionedProtocol proxy) {
440 if (proxy!=null) {
441 ((Invoker)Proxy.getInvocationHandler(proxy)).close();
442 }
443 }
444
445
446
447
448
449
450
451
452
453
454
455 public static Object[] call(Method method, Object[][] params,
456 InetSocketAddress[] addrs, Configuration conf)
457 throws IOException {
458
459 Invocation[] invocations = new Invocation[params.length];
460 for (int i = 0; i < params.length; i++)
461 invocations[i] = new Invocation(method, params[i]);
462 HBaseClient client = CLIENTS.getClient(conf);
463 try {
464 Writable[] wrappedValues = client.call(invocations, addrs);
465
466 if (method.getReturnType() == Void.TYPE) {
467 return null;
468 }
469
470 Object[] values =
471 (Object[])Array.newInstance(method.getReturnType(), wrappedValues.length);
472 for (int i = 0; i < values.length; i++)
473 if (wrappedValues[i] != null)
474 values[i] = ((HbaseObjectWritable)wrappedValues[i]).get();
475
476 return values;
477 } finally {
478 CLIENTS.stopClient(client);
479 }
480 }
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495 public static Server getServer(final Object instance,
496 final Class<?>[] ifaces,
497 final String bindAddress, final int port,
498 final int numHandlers,
499 final boolean verbose, Configuration conf)
500 throws IOException {
501 return new Server(instance, ifaces, conf, bindAddress, port, numHandlers, verbose);
502 }
503
504
505 public static class Server extends HBaseServer {
506 private Object instance;
507 private Class<?> implementation;
508 private Class<?> ifaces[];
509 private boolean verbose;
510
511 private static String classNameBase(String className) {
512 String[] names = className.split("\\.", -1);
513 if (names == null || names.length == 0) {
514 return className;
515 }
516 return names[names.length-1];
517 }
518
519
520
521
522
523
524
525
526
527
528 public Server(Object instance, final Class<?>[] ifaces,
529 Configuration conf, String bindAddress, int port,
530 int numHandlers, boolean verbose) throws IOException {
531 super(bindAddress, port, Invocation.class, numHandlers, conf, classNameBase(instance.getClass().getName()));
532 this.instance = instance;
533 this.implementation = instance.getClass();
534
535 this.verbose = verbose;
536
537 this.ifaces = ifaces;
538
539
540 this.rpcMetrics.createMetrics(this.ifaces);
541 }
542
543 @Override
544 public Writable call(Writable param, long receivedTime) throws IOException {
545 try {
546 Invocation call = (Invocation)param;
547 if(call.getMethodName() == null) {
548 throw new IOException("Could not find requested method, the usual " +
549 "cause is a version mismatch between client and server.");
550 }
551 if (verbose) log("Call: " + call);
552 Method method =
553 implementation.getMethod(call.getMethodName(),
554 call.getParameterClasses());
555
556 long startTime = System.currentTimeMillis();
557 Object value = method.invoke(instance, call.getParameters());
558 int processingTime = (int) (System.currentTimeMillis() - startTime);
559 int qTime = (int) (startTime-receivedTime);
560 if (LOG.isDebugEnabled()) {
561 LOG.debug("Served: " + call.getMethodName() +
562 " queueTime= " + qTime +
563 " procesingTime= " + processingTime);
564 }
565 rpcMetrics.rpcQueueTime.inc(qTime);
566 rpcMetrics.rpcProcessingTime.inc(processingTime);
567 rpcMetrics.inc(call.getMethodName(), processingTime);
568 if (verbose) log("Return: "+value);
569
570 return new HbaseObjectWritable(method.getReturnType(), value);
571
572 } catch (InvocationTargetException e) {
573 Throwable target = e.getTargetException();
574 if (target instanceof IOException) {
575 throw (IOException)target;
576 }
577 IOException ioe = new IOException(target.toString());
578 ioe.setStackTrace(target.getStackTrace());
579 throw ioe;
580 } catch (Throwable e) {
581 IOException ioe = new IOException(e.toString());
582 ioe.setStackTrace(e.getStackTrace());
583 throw ioe;
584 }
585 }
586 }
587
588 protected static void log(String value) {
589 String v = value;
590 if (v != null && v.length() > 55)
591 v = v.substring(0, 55)+"...";
592 LOG.info(v);
593 }
594 }