View Javadoc

1   /**
2     *
3     * Licensed to the Apache Software Foundation (ASF) under one
4     * or more contributor license agreements.  See the NOTICE file
5     * distributed with this work for additional information
6     * regarding copyright ownership.  The ASF licenses this file
7     * to you under the Apache License, Version 2.0 (the
8     * "License"); you may not use this file except in compliance
9     * with the License.  You may obtain a copy of the License at
10    *
11    *     http://www.apache.org/licenses/LICENSE-2.0
12    *
13    * Unless required by applicable law or agreed to in writing, software
14    * distributed under the License is distributed on an "AS IS" BASIS,
15    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    * See the License for the specific language governing permissions and
17    * limitations under the License.
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.Mockito.doThrow;
26  import static org.mockito.Mockito.spy;
27  
28  import java.io.IOException;
29  import java.net.InetSocketAddress;
30  import java.net.Socket;
31  import java.util.ArrayList;
32  import java.util.List;
33  
34  import javax.net.SocketFactory;
35  
36  import com.google.common.collect.Lists;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.hadoop.conf.Configuration;
40  import org.apache.hadoop.hbase.Cell;
41  import org.apache.hadoop.hbase.CellScannable;
42  import org.apache.hadoop.hbase.CellScanner;
43  import org.apache.hadoop.hbase.CellUtil;
44  import org.apache.hadoop.hbase.HBaseConfiguration;
45  import org.apache.hadoop.hbase.HConstants;
46  import org.apache.hadoop.hbase.HRegionInfo;
47  import org.apache.hadoop.hbase.KeyValue;
48  import org.apache.hadoop.hbase.KeyValueUtil;
49  import org.apache.hadoop.hbase.SmallTests;
50  import org.apache.hadoop.hbase.client.Put;
51  import org.apache.hadoop.hbase.client.RowMutations;
52  import org.apache.hadoop.hbase.codec.Codec;
53  import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoRequestProto;
54  import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoResponseProto;
55  import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyRequestProto;
56  import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyResponseProto;
57  import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
58  import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
59  import org.apache.hadoop.hbase.protobuf.RequestConverter;
60  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
61  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
62  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionAction;
63  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
64  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
65  import org.apache.hadoop.hbase.security.User;
66  import org.apache.hadoop.hbase.util.Bytes;
67  import org.apache.hadoop.hbase.util.Pair;
68  import org.apache.hadoop.io.compress.GzipCodec;
69  import org.apache.hadoop.net.NetUtils;
70  import org.apache.hadoop.util.StringUtils;
71  import org.junit.Test;
72  import org.junit.experimental.categories.Category;
73  import org.mockito.Mockito;
74  import org.mockito.invocation.InvocationOnMock;
75  import org.mockito.stubbing.Answer;
76  
77  import com.google.protobuf.BlockingService;
78  import com.google.protobuf.ByteString;
79  import com.google.protobuf.Descriptors.MethodDescriptor;
80  import com.google.protobuf.Message;
81  import com.google.protobuf.RpcController;
82  import com.google.protobuf.ServiceException;
83  import com.google.common.collect.ImmutableList;
84  import com.google.common.collect.Lists;
85  
86  /**
87   * Some basic ipc tests.
88   */
89  @Category(SmallTests.class)
90  public class TestIPC {
91    public static final Log LOG = LogFactory.getLog(TestIPC.class);
92    static byte [] CELL_BYTES =  Bytes.toBytes("xyz");
93    static Cell CELL = new KeyValue(CELL_BYTES, CELL_BYTES, CELL_BYTES, CELL_BYTES);
94    static byte [] BIG_CELL_BYTES = new byte [10 * 1024];
95    static Cell BIG_CELL = new KeyValue(CELL_BYTES, CELL_BYTES, CELL_BYTES, BIG_CELL_BYTES);
96    // We are using the test TestRpcServiceProtos generated classes and Service because they are
97    // available and basic with methods like 'echo', and ping.  Below we make a blocking service
98    // by passing in implementation of blocking interface.  We use this service in all tests that
99    // follow.
100   private static final BlockingService SERVICE =
101    TestRpcServiceProtos.TestProtobufRpcProto.newReflectiveBlockingService(
102      new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
103 
104     @Override
105     public EmptyResponseProto ping(RpcController controller,
106         EmptyRequestProto request) throws ServiceException {
107       // TODO Auto-generated method stub
108       return null;
109     }
110 
111     @Override
112     public EmptyResponseProto error(RpcController controller,
113         EmptyRequestProto request) throws ServiceException {
114       // TODO Auto-generated method stub
115       return null;
116     }
117 
118     @Override
119     public EchoResponseProto echo(RpcController controller, EchoRequestProto request)
120     throws ServiceException {
121       if (controller instanceof PayloadCarryingRpcController) {
122         PayloadCarryingRpcController pcrc = (PayloadCarryingRpcController)controller;
123         // If cells, scan them to check we are able to iterate what we were given and since this is
124         // an echo, just put them back on the controller creating a new block.  Tests our block
125         // building.
126         CellScanner cellScanner = pcrc.cellScanner();
127         List<Cell> list = null;
128         if (cellScanner != null) {
129           list = new ArrayList<Cell>();
130           try {
131             while(cellScanner.advance()) {
132               list.add(cellScanner.current());
133             }
134           } catch (IOException e) {
135             throw new ServiceException(e);
136           }
137         }
138         cellScanner = CellUtil.createCellScanner(list);
139         ((PayloadCarryingRpcController)controller).setCellScanner(cellScanner);
140       }
141       return EchoResponseProto.newBuilder().setMessage(request.getMessage()).build();
142     }
143   });
144 
145   /**
146    * Instance of server.  We actually don't do anything speical in here so could just use
147    * HBaseRpcServer directly.
148    */
149   private static class TestRpcServer extends RpcServer {
150     TestRpcServer() throws IOException {
151       super(null, "testRpcServer",
152           Lists.newArrayList(new BlockingServiceAndInterface(SERVICE, null)),
153         new InetSocketAddress("0.0.0.0", 0), 1, 1,
154         HBaseConfiguration.create(), 0);
155     }
156 
157     @Override
158     public Pair<Message, CellScanner> call(BlockingService service,
159         MethodDescriptor md, Message param, CellScanner cellScanner,
160         long receiveTime, MonitoredRPCHandler status) throws IOException {
161       return super.call(service, md, param, cellScanner, receiveTime, status);
162     }
163   }
164 
165   /**
166    * Ensure we do not HAVE TO HAVE a codec.
167    * @throws InterruptedException
168    * @throws IOException
169    */
170   @Test
171   public void testNoCodec() throws InterruptedException, IOException {
172     Configuration conf = HBaseConfiguration.create();
173     RpcClient client = new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT) {
174       @Override
175       Codec getCodec() {
176         return null;
177       }
178     };
179     TestRpcServer rpcServer = new TestRpcServer();
180     try {
181       rpcServer.start();
182       InetSocketAddress address = rpcServer.getListenerAddress();
183       MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
184       final String message = "hello";
185       EchoRequestProto param = EchoRequestProto.newBuilder().setMessage(message).build();
186       Pair<Message, CellScanner> r = client.call(md, param, null,
187         md.getOutputType().toProto(), User.getCurrent(), address, 0);
188       assertTrue(r.getSecond() == null);
189       // Silly assertion that the message is in the returned pb.
190       assertTrue(r.getFirst().toString().contains(message));
191     } finally {
192       client.stop();
193       rpcServer.stop();
194     }
195   }
196 
197   /**
198    * It is hard to verify the compression is actually happening under the wraps.  Hope that if
199    * unsupported, we'll get an exception out of some time (meantime, have to trace it manually
200    * to confirm that compression is happening down in the client and server).
201    * @throws IOException
202    * @throws InterruptedException
203    * @throws SecurityException
204    * @throws NoSuchMethodException
205    */
206   @Test
207   public void testCompressCellBlock()
208   throws IOException, InterruptedException, SecurityException, NoSuchMethodException {
209     Configuration conf = new Configuration(HBaseConfiguration.create());
210     conf.set("hbase.client.rpc.compressor", GzipCodec.class.getCanonicalName());
211     doSimpleTest(conf, new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT));
212   }
213 
214   private void doSimpleTest(final Configuration conf, final RpcClient client)
215   throws InterruptedException, IOException {
216     TestRpcServer rpcServer = new TestRpcServer();
217     List<Cell> cells = new ArrayList<Cell>();
218     int count = 3;
219     for (int i = 0; i < count; i++) cells.add(CELL);
220     try {
221       rpcServer.start();
222       InetSocketAddress address = rpcServer.getListenerAddress();
223       MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
224       EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
225       Pair<Message, CellScanner> r = client.call(md, param, CellUtil.createCellScanner(cells),
226         md.getOutputType().toProto(), User.getCurrent(), address, 0);
227       int index = 0;
228       while (r.getSecond().advance()) {
229         assertTrue(CELL.equals(r.getSecond().current()));
230         index++;
231       }
232       assertEquals(count, index);
233     } finally {
234       client.stop();
235       rpcServer.stop();
236     }
237   }
238 
239   @Test
240   public void testRTEDuringConnectionSetup() throws Exception {
241     Configuration conf = HBaseConfiguration.create();
242     SocketFactory spyFactory = spy(NetUtils.getDefaultSocketFactory(conf));
243     Mockito.doAnswer(new Answer<Socket>() {
244       @Override
245       public Socket answer(InvocationOnMock invocation) throws Throwable {
246         Socket s = spy((Socket)invocation.callRealMethod());
247         doThrow(new RuntimeException("Injected fault")).when(s).setSoTimeout(anyInt());
248         return s;
249       }
250     }).when(spyFactory).createSocket();
251 
252     TestRpcServer rpcServer = new TestRpcServer();
253     RpcClient client = new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT, spyFactory);
254     try {
255       rpcServer.start();
256       InetSocketAddress address = rpcServer.getListenerAddress();
257       MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
258       EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
259       client.call(md, param, null, null, User.getCurrent(), address, 0);
260       fail("Expected an exception to have been thrown!");
261     } catch (Exception e) {
262       LOG.info("Caught expected exception: " + e.toString());
263       assertTrue(StringUtils.stringifyException(e).contains("Injected fault"));
264     } finally {
265       client.stop();
266       rpcServer.stop();
267     }
268   }
269 
270   public static void main(String[] args)
271   throws IOException, SecurityException, NoSuchMethodException, InterruptedException {
272     if (args.length != 2) {
273       System.out.println("Usage: TestIPC <CYCLES> <CELLS_PER_CYCLE>");
274       return;
275     }
276     // ((Log4JLogger)HBaseServer.LOG).getLogger().setLevel(Level.INFO);
277     // ((Log4JLogger)HBaseClient.LOG).getLogger().setLevel(Level.INFO);
278     int cycles = Integer.parseInt(args[0]);
279     int cellcount = Integer.parseInt(args[1]);
280     Configuration conf = HBaseConfiguration.create();
281     TestRpcServer rpcServer = new TestRpcServer();
282     MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
283     EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
284     RpcClient client = new RpcClient(conf, HConstants.CLUSTER_ID_DEFAULT);
285     KeyValue kv = KeyValueUtil.ensureKeyValue(BIG_CELL);
286     Put p = new Put(kv.getRow());
287     for (int i = 0; i < cellcount; i++) {
288       p.add(kv);
289     }
290     RowMutations rm = new RowMutations(kv.getRow());
291     rm.add(p);
292     try {
293       rpcServer.start();
294       InetSocketAddress address = rpcServer.getListenerAddress();
295       long startTime = System.currentTimeMillis();
296       User user = User.getCurrent();
297       for (int i = 0; i < cycles; i++) {
298         List<CellScannable> cells = new ArrayList<CellScannable>();
299         // Message param = RequestConverter.buildMultiRequest(HConstants.EMPTY_BYTE_ARRAY, rm);
300         ClientProtos.RegionAction.Builder builder = RequestConverter.buildNoDataRegionAction(
301           HConstants.EMPTY_BYTE_ARRAY, rm, cells,
302           RegionAction.newBuilder(),
303           ClientProtos.Action.newBuilder(),
304           MutationProto.newBuilder());
305         builder.setRegion(RegionSpecifier.newBuilder().setType(RegionSpecifierType.REGION_NAME).
306           setValue(ByteString.copyFrom(HRegionInfo.FIRST_META_REGIONINFO.getEncodedNameAsBytes())));
307         if (i % 100000 == 0) {
308           LOG.info("" + i);
309           // Uncomment this for a thread dump every so often.
310           // ReflectionUtils.printThreadInfo(new PrintWriter(System.out),
311           //  "Thread dump " + Thread.currentThread().getName());
312         }
313         CellScanner cellScanner = CellUtil.createCellScanner(cells);
314         Pair<Message, CellScanner> response =
315           client.call(md, builder.build(), cellScanner, param, user, address, 0);
316         /*
317         int count = 0;
318         while (p.getSecond().advance()) {
319           count++;
320         }
321         assertEquals(cells.size(), count);*/
322       }
323       LOG.info("Cycled " + cycles + " time(s) with " + cellcount + " cell(s) in " +
324          (System.currentTimeMillis() - startTime) + "ms");
325     } finally {
326       client.stop();
327       rpcServer.stop();
328     }
329   }
330 }