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