1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.ipc;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.Matchers.anyInt;
25 import static org.mockito.Matchers.anyObject;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.internal.verification.VerificationModeFactory.times;
30
31 import java.io.IOException;
32 import java.net.InetAddress;
33 import java.net.InetSocketAddress;
34 import java.net.Socket;
35 import java.util.ArrayList;
36 import java.util.List;
37
38 import javax.net.SocketFactory;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42 import org.apache.hadoop.conf.Configuration;
43 import org.apache.hadoop.hbase.Cell;
44 import org.apache.hadoop.hbase.CellScannable;
45 import org.apache.hadoop.hbase.CellScanner;
46 import org.apache.hadoop.hbase.CellUtil;
47 import org.apache.hadoop.hbase.HBaseConfiguration;
48 import org.apache.hadoop.hbase.HConstants;
49 import org.apache.hadoop.hbase.HRegionInfo;
50 import org.apache.hadoop.hbase.KeyValue;
51 import org.apache.hadoop.hbase.KeyValueUtil;
52 import org.apache.hadoop.hbase.ServerName;
53 import org.apache.hadoop.hbase.client.MetricsConnection;
54 import org.apache.hadoop.hbase.client.Put;
55 import org.apache.hadoop.hbase.client.RowMutations;
56 import org.apache.hadoop.hbase.codec.Codec;
57 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoRequestProto;
58 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoResponseProto;
59 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyRequestProto;
60 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyResponseProto;
61 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
62 import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
63 import org.apache.hadoop.hbase.protobuf.RequestConverter;
64 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
65 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
66 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionAction;
67 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
68 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
69 import org.apache.hadoop.hbase.security.User;
70 import org.apache.hadoop.hbase.testclassification.SmallTests;
71 import org.apache.hadoop.hbase.util.Bytes;
72 import org.apache.hadoop.hbase.util.Pair;
73 import org.apache.hadoop.io.compress.GzipCodec;
74 import org.apache.hadoop.net.NetUtils;
75 import org.apache.hadoop.util.StringUtils;
76 import org.junit.Test;
77 import org.junit.experimental.categories.Category;
78 import org.mockito.Mockito;
79 import org.mockito.invocation.InvocationOnMock;
80 import org.mockito.stubbing.Answer;
81
82 import com.google.common.collect.ImmutableList;
83 import com.google.common.collect.Lists;
84 import com.google.protobuf.BlockingRpcChannel;
85 import com.google.protobuf.BlockingService;
86 import com.google.protobuf.ByteString;
87 import com.google.protobuf.Descriptors.MethodDescriptor;
88 import com.google.protobuf.Message;
89 import com.google.protobuf.RpcController;
90 import com.google.protobuf.ServiceException;
91
92
93
94
95 @Category(SmallTests.class)
96 public class TestIPC {
97 public static final Log LOG = LogFactory.getLog(TestIPC.class);
98 static byte [] CELL_BYTES = Bytes.toBytes("xyz");
99 static Cell CELL = new KeyValue(CELL_BYTES, CELL_BYTES, CELL_BYTES, CELL_BYTES);
100 static byte [] BIG_CELL_BYTES = new byte [10 * 1024];
101 static Cell BIG_CELL = new KeyValue(CELL_BYTES, CELL_BYTES, CELL_BYTES, BIG_CELL_BYTES);
102 private final static Configuration CONF = HBaseConfiguration.create();
103
104
105
106
107 private static final BlockingService SERVICE =
108 TestRpcServiceProtos.TestProtobufRpcProto.newReflectiveBlockingService(
109 new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
110
111 @Override
112 public EmptyResponseProto ping(RpcController controller,
113 EmptyRequestProto request) throws ServiceException {
114
115 return null;
116 }
117
118 @Override
119 public EmptyResponseProto error(RpcController controller,
120 EmptyRequestProto request) throws ServiceException {
121
122 return null;
123 }
124
125 @Override
126 public EchoResponseProto echo(RpcController controller, EchoRequestProto request)
127 throws ServiceException {
128 if (controller instanceof PayloadCarryingRpcController) {
129 PayloadCarryingRpcController pcrc = (PayloadCarryingRpcController)controller;
130
131
132
133 CellScanner cellScanner = pcrc.cellScanner();
134 List<Cell> list = null;
135 if (cellScanner != null) {
136 list = new ArrayList<Cell>();
137 try {
138 while(cellScanner.advance()) {
139 list.add(cellScanner.current());
140 }
141 } catch (IOException e) {
142 throw new ServiceException(e);
143 }
144 }
145 cellScanner = CellUtil.createCellScanner(list);
146 ((PayloadCarryingRpcController)controller).setCellScanner(cellScanner);
147 }
148 return EchoResponseProto.newBuilder().setMessage(request.getMessage()).build();
149 }
150 });
151
152
153
154
155
156 private static class TestRpcServer extends RpcServer {
157
158 TestRpcServer() throws IOException {
159 this(new FifoRpcScheduler(CONF, 1));
160 }
161
162 TestRpcServer(RpcScheduler scheduler) throws IOException {
163 super(null, "testRpcServer",
164 Lists.newArrayList(new BlockingServiceAndInterface(SERVICE, null)),
165 new InetSocketAddress("localhost", 0), CONF, scheduler);
166 }
167
168 @Override
169 public Pair<Message, CellScanner> call(BlockingService service,
170 MethodDescriptor md, Message param, CellScanner cellScanner,
171 long receiveTime, MonitoredRPCHandler status) throws IOException {
172 return super.call(service, md, param, cellScanner, receiveTime, status);
173 }
174 }
175
176
177
178
179
180
181 @Test
182 public void testNoCodec() throws InterruptedException, IOException {
183 Configuration conf = HBaseConfiguration.create();
184 RpcClient client = new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT) {
185 @Override
186 Codec getCodec() {
187 return null;
188 }
189 };
190 TestRpcServer rpcServer = new TestRpcServer();
191 try {
192 rpcServer.start();
193 InetSocketAddress address = rpcServer.getListenerAddress();
194 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
195 final String message = "hello";
196 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage(message).build();
197 Pair<Message, CellScanner> r = client.call(md, param, null,
198 md.getOutputType().toProto(), User.getCurrent(), address, 0);
199 assertTrue(r.getSecond() == null);
200
201 assertTrue(r.getFirst().toString().contains(message));
202 } finally {
203 client.stop();
204 rpcServer.stop();
205 }
206 }
207
208
209
210
211
212
213
214
215
216
217 @Test
218 public void testCompressCellBlock()
219 throws IOException, InterruptedException, SecurityException, NoSuchMethodException {
220 Configuration conf = new Configuration(HBaseConfiguration.create());
221 conf.set("hbase.client.rpc.compressor", GzipCodec.class.getCanonicalName());
222 doSimpleTest(conf, new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT));
223 }
224
225 private void doSimpleTest(final Configuration conf, final RpcClient client)
226 throws InterruptedException, IOException {
227 TestRpcServer rpcServer = new TestRpcServer();
228 List<Cell> cells = new ArrayList<Cell>();
229 int count = 3;
230 for (int i = 0; i < count; i++) cells.add(CELL);
231 try {
232 rpcServer.start();
233 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
234 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
235 InetSocketAddress address = rpcServer.getListenerAddress();
236 if (address == null) {
237 throw new IOException("Listener channel is closed");
238 }
239 Pair<Message, CellScanner> r = client.call(md, param, CellUtil.createCellScanner(cells),
240 md.getOutputType().toProto(), User.getCurrent(), address, 0);
241 int index = 0;
242 while (r.getSecond().advance()) {
243 assertTrue(CELL.equals(r.getSecond().current()));
244 index++;
245 }
246 assertEquals(count, index);
247 } finally {
248 client.stop();
249 rpcServer.stop();
250 }
251 }
252
253 @Test
254 public void testRTEDuringConnectionSetup() throws Exception {
255 Configuration conf = HBaseConfiguration.create();
256 SocketFactory spyFactory = spy(NetUtils.getDefaultSocketFactory(conf));
257 Mockito.doAnswer(new Answer<Socket>() {
258 @Override
259 public Socket answer(InvocationOnMock invocation) throws Throwable {
260 Socket s = spy((Socket)invocation.callRealMethod());
261 doThrow(new RuntimeException("Injected fault")).when(s).setSoTimeout(anyInt());
262 return s;
263 }
264 }).when(spyFactory).createSocket();
265
266 TestRpcServer rpcServer = new TestRpcServer();
267 RpcClient client = new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT, spyFactory);
268 try {
269 rpcServer.start();
270 InetSocketAddress address = rpcServer.getListenerAddress();
271 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
272 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
273 client.call(md, param, null, null, User.getCurrent(), address, 0);
274 fail("Expected an exception to have been thrown!");
275 } catch (Exception e) {
276 LOG.info("Caught expected exception: " + e.toString());
277 assertTrue(StringUtils.stringifyException(e).contains("Injected fault"));
278 } finally {
279 client.stop();
280 rpcServer.stop();
281 }
282 }
283
284
285 @Test
286 public void testRpcScheduler() throws IOException, InterruptedException {
287 RpcScheduler scheduler = spy(new FifoRpcScheduler(CONF, 1));
288 RpcServer rpcServer = new TestRpcServer(scheduler);
289 verify(scheduler).init((RpcScheduler.Context) anyObject());
290 RpcClient client = new RpcClient(CONF, HConstants.CLUSTER_ID_DEFAULT);
291 try {
292 rpcServer.start();
293 verify(scheduler).start();
294 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
295 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
296 for (int i = 0; i < 10; i++) {
297 client.call(md, param, CellUtil.createCellScanner(ImmutableList.of(CELL)),
298 md.getOutputType().toProto(), User.getCurrent(), rpcServer.getListenerAddress(), 0);
299 }
300 verify(scheduler, times(10)).dispatch((CallRunner) anyObject());
301 } finally {
302 rpcServer.stop();
303 verify(scheduler).stop();
304 }
305 }
306
307
308
309
310 static class TestRpcServer1 extends RpcServer {
311
312 private static TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface SERVICE1 =
313 new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
314 @Override
315 public EmptyResponseProto ping(RpcController unused, EmptyRequestProto request)
316 throws ServiceException {
317 return EmptyResponseProto.newBuilder().build();
318 }
319
320 @Override
321 public EchoResponseProto echo(RpcController unused, EchoRequestProto request)
322 throws ServiceException {
323 final InetAddress remoteAddr = TestRpcServer1.getRemoteAddress();
324 final String message = remoteAddr == null ? "NULL" : remoteAddr.getHostAddress();
325 return EchoResponseProto.newBuilder().setMessage(message).build();
326 }
327
328 @Override
329 public EmptyResponseProto error(RpcController unused, EmptyRequestProto request)
330 throws ServiceException {
331 throw new ServiceException("error", new IOException("error"));
332 }
333 };
334
335 TestRpcServer1() throws IOException {
336 this(new FifoRpcScheduler(CONF, 1));
337 }
338
339 TestRpcServer1(RpcScheduler scheduler) throws IOException {
340 super(null, "testRemoteAddressInCallObject", Lists
341 .newArrayList(new BlockingServiceAndInterface(TestRpcServiceProtos.TestProtobufRpcProto
342 .newReflectiveBlockingService(SERVICE1), null)),
343 new InetSocketAddress("localhost", 0), CONF, scheduler);
344 }
345 }
346
347
348
349
350
351
352 @Test
353 public void testRpcServerForNotNullRemoteAddressInCallObject() throws IOException,
354 ServiceException {
355 final RpcScheduler scheduler = new FifoRpcScheduler(CONF, 1);
356 final TestRpcServer1 rpcServer = new TestRpcServer1(scheduler);
357 final InetSocketAddress localAddr = new InetSocketAddress("localhost", 0);
358 final RpcClient client =
359 new RpcClient(CONF, HConstants.CLUSTER_ID_DEFAULT, localAddr, null);
360 try {
361 rpcServer.start();
362 final InetSocketAddress isa = rpcServer.getListenerAddress();
363 if (isa == null) {
364 throw new IOException("Listener channel is closed");
365 }
366 final BlockingRpcChannel channel =
367 client.createBlockingRpcChannel(
368 ServerName.valueOf(isa.getHostName(), isa.getPort(), System.currentTimeMillis()),
369 User.getCurrent(), 0);
370 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub =
371 TestRpcServiceProtos.TestProtobufRpcProto.newBlockingStub(channel);
372 final EchoRequestProto echoRequest =
373 EchoRequestProto.newBuilder().setMessage("GetRemoteAddress").build();
374 final EchoResponseProto echoResponse = stub.echo(null, echoRequest);
375 assertEquals(localAddr.getAddress().getHostAddress(), echoResponse.getMessage());
376 } finally {
377 client.stop();
378 rpcServer.stop();
379 }
380 }
381
382 public static void main(String[] args)
383 throws IOException, SecurityException, NoSuchMethodException, InterruptedException {
384 if (args.length != 2) {
385 System.out.println("Usage: TestIPC <CYCLES> <CELLS_PER_CYCLE>");
386 return;
387 }
388
389
390 int cycles = Integer.parseInt(args[0]);
391 int cellcount = Integer.parseInt(args[1]);
392 Configuration conf = HBaseConfiguration.create();
393 TestRpcServer rpcServer = new TestRpcServer();
394 MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
395 EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
396 RpcClient client = new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT);
397 KeyValue kv = KeyValueUtil.ensureKeyValue(BIG_CELL);
398 Put p = new Put(kv.getRow());
399 for (int i = 0; i < cellcount; i++) {
400 p.add(kv);
401 }
402 RowMutations rm = new RowMutations(kv.getRow());
403 rm.add(p);
404 try {
405 rpcServer.start();
406 long startTime = System.currentTimeMillis();
407 User user = User.getCurrent();
408 InetSocketAddress address = rpcServer.getListenerAddress();
409 if (address == null) {
410 throw new IOException("Listener channel is closed");
411 }
412 for (int i = 0; i < cycles; i++) {
413 List<CellScannable> cells = new ArrayList<CellScannable>();
414
415 ClientProtos.RegionAction.Builder builder = RequestConverter.buildNoDataRegionAction(
416 HConstants.EMPTY_BYTE_ARRAY, rm, cells,
417 RegionAction.newBuilder(),
418 ClientProtos.Action.newBuilder(),
419 MutationProto.newBuilder());
420 builder.setRegion(RegionSpecifier.newBuilder().setType(RegionSpecifierType.REGION_NAME).
421 setValue(ByteString.copyFrom(HRegionInfo.FIRST_META_REGIONINFO.getEncodedNameAsBytes())));
422 if (i % 100000 == 0) {
423 LOG.info("" + i);
424
425
426
427 }
428 CellScanner cellScanner = CellUtil.createCellScanner(cells);
429 Pair<Message, CellScanner> response =
430 client.call(md, builder.build(), cellScanner, param, user, address, 0,
431 HConstants.NORMAL_QOS, new MetricsConnection.CallStats());
432
433
434
435
436
437
438 }
439 LOG.info("Cycled " + cycles + " time(s) with " + cellcount + " cell(s) in " +
440 (System.currentTimeMillis() - startTime) + "ms");
441 } finally {
442 client.stop();
443 rpcServer.stop();
444 }
445 }
446 }