View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.ipc;
19  
20  import static org.junit.Assert.assertTrue;
21  import static org.junit.Assert.fail;
22  import io.netty.channel.ChannelHandlerContext;
23  import io.netty.channel.ChannelInitializer;
24  import io.netty.channel.ChannelOutboundHandlerAdapter;
25  import io.netty.channel.ChannelPromise;
26  import io.netty.channel.epoll.EpollEventLoopGroup;
27  import io.netty.channel.nio.NioEventLoopGroup;
28  import io.netty.channel.socket.SocketChannel;
29  
30  import java.io.IOException;
31  import java.net.InetSocketAddress;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.List;
35  import java.util.concurrent.atomic.AtomicBoolean;
36  
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.CellScannable;
41  import org.apache.hadoop.hbase.CellUtil;
42  import org.apache.hadoop.hbase.HBaseConfiguration;
43  import org.apache.hadoop.hbase.HBaseTestingUtility;
44  import org.apache.hadoop.hbase.HConstants;
45  import org.apache.hadoop.hbase.HRegionInfo;
46  import org.apache.hadoop.hbase.KeyValue;
47  import org.apache.hadoop.hbase.ServerName;
48  import org.apache.hadoop.hbase.Waiter;
49  import org.apache.hadoop.hbase.client.Put;
50  import org.apache.hadoop.hbase.client.RowMutations;
51  import org.apache.hadoop.hbase.codec.Codec;
52  import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoRequestProto;
53  import org.apache.hadoop.hbase.protobuf.RequestConverter;
54  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
55  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto;
56  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionAction;
57  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier;
58  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType;
59  import org.apache.hadoop.hbase.security.User;
60  import org.apache.hadoop.hbase.testclassification.SmallTests;
61  import org.apache.hadoop.util.StringUtils;
62  import org.junit.Test;
63  import org.junit.experimental.categories.Category;
64  import org.junit.runner.RunWith;
65  import org.junit.runners.Parameterized;
66  import org.junit.runners.Parameterized.Parameters;
67  
68  import com.google.protobuf.ByteString;
69  import com.google.protobuf.Descriptors.MethodDescriptor;
70  import com.google.protobuf.Message;
71  import com.google.protobuf.RpcCallback;
72  import com.google.protobuf.RpcChannel;
73  
74  @RunWith(Parameterized.class)
75  @Category({ SmallTests.class })
76  public class TestAsyncIPC extends AbstractTestIPC {
77  
78    private static final Log LOG = LogFactory.getLog(TestAsyncIPC.class);
79  
80    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
81  
82    @Parameters
83    public static Collection<Object[]> parameters() {
84      List<Object[]> paramList = new ArrayList<Object[]>();
85      paramList.add(new Object[] { false, false });
86      paramList.add(new Object[] { false, true });
87      paramList.add(new Object[] { true, false });
88      paramList.add(new Object[] { true, true });
89      return paramList;
90    }
91  
92    private final boolean useNativeTransport;
93  
94    private final boolean useGlobalEventLoopGroup;
95  
96    public TestAsyncIPC(boolean useNativeTransport, boolean useGlobalEventLoopGroup) {
97      this.useNativeTransport = useNativeTransport;
98      this.useGlobalEventLoopGroup = useGlobalEventLoopGroup;
99    }
100 
101   private void setConf(Configuration conf) {
102     conf.setBoolean(AsyncRpcClient.USE_NATIVE_TRANSPORT, useNativeTransport);
103     conf.setBoolean(AsyncRpcClient.USE_GLOBAL_EVENT_LOOP_GROUP, useGlobalEventLoopGroup);
104     if (useGlobalEventLoopGroup && AsyncRpcClient.GLOBAL_EVENT_LOOP_GROUP != null) {
105       if (useNativeTransport
106           && !(AsyncRpcClient.GLOBAL_EVENT_LOOP_GROUP.getFirst() instanceof EpollEventLoopGroup)
107           || (!useNativeTransport
108           && !(AsyncRpcClient.GLOBAL_EVENT_LOOP_GROUP.getFirst() instanceof NioEventLoopGroup))) {
109         AsyncRpcClient.GLOBAL_EVENT_LOOP_GROUP.getFirst().shutdownGracefully();
110         AsyncRpcClient.GLOBAL_EVENT_LOOP_GROUP = null;
111       }
112     }
113   }
114 
115   @Override
116   protected AsyncRpcClient createRpcClientNoCodec(Configuration conf) {
117     setConf(conf);
118     return new AsyncRpcClient(conf, HConstants.CLUSTER_ID_DEFAULT, null) {
119 
120       @Override
121       Codec getCodec() {
122         return null;
123       }
124 
125     };
126   }
127 
128   @Override
129   protected AsyncRpcClient createRpcClient(Configuration conf) {
130     setConf(conf);
131     return new AsyncRpcClient(conf, HConstants.CLUSTER_ID_DEFAULT, null);
132   }
133 
134   @Override
135   protected AsyncRpcClient createRpcClientRTEDuringConnectionSetup(Configuration conf) {
136     setConf(conf);
137     return new AsyncRpcClient(conf, HConstants.CLUSTER_ID_DEFAULT, null,
138         new ChannelInitializer<SocketChannel>() {
139 
140           @Override
141           protected void initChannel(SocketChannel ch) throws Exception {
142             ch.pipeline().addFirst(new ChannelOutboundHandlerAdapter() {
143               @Override
144               public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
145                   throws Exception {
146                 promise.setFailure(new RuntimeException("Injected fault"));
147               }
148             });
149           }
150         });
151   }
152 
153   @Test
154   public void testAsyncConnectionSetup() throws Exception {
155     TestRpcServer rpcServer = new TestRpcServer();
156     AsyncRpcClient client = createRpcClient(CONF);
157     try {
158       rpcServer.start();
159       InetSocketAddress address = rpcServer.getListenerAddress();
160       if (address == null) {
161         throw new IOException("Listener channel is closed");
162       }
163       MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
164       EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
165 
166       RpcChannel channel =
167           client.createRpcChannel(ServerName.valueOf(address.getHostName(), address.getPort(),
168             System.currentTimeMillis()), User.getCurrent(), 0);
169 
170       final AtomicBoolean done = new AtomicBoolean(false);
171 
172       channel.callMethod(md, new PayloadCarryingRpcController(), param, md.getOutputType()
173           .toProto(), new RpcCallback<Message>() {
174         @Override
175         public void run(Message parameter) {
176           done.set(true);
177         }
178       });
179 
180       TEST_UTIL.waitFor(1000, new Waiter.Predicate<Exception>() {
181         @Override
182         public boolean evaluate() throws Exception {
183           return done.get();
184         }
185       });
186     } finally {
187       client.close();
188       rpcServer.stop();
189     }
190   }
191 
192   @Test
193   public void testRTEDuringAsyncConnectionSetup() throws Exception {
194     TestRpcServer rpcServer = new TestRpcServer();
195     AsyncRpcClient client = createRpcClientRTEDuringConnectionSetup(CONF);
196     try {
197       rpcServer.start();
198       InetSocketAddress address = rpcServer.getListenerAddress();
199       if (address == null) {
200         throw new IOException("Listener channel is closed");
201       }
202       MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
203       EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
204 
205       RpcChannel channel =
206           client.createRpcChannel(ServerName.valueOf(address.getHostName(), address.getPort(),
207             System.currentTimeMillis()), User.getCurrent(), 0);
208 
209       final AtomicBoolean done = new AtomicBoolean(false);
210 
211       PayloadCarryingRpcController controller = new PayloadCarryingRpcController();
212       controller.notifyOnFail(new RpcCallback<IOException>() {
213         @Override
214         public void run(IOException e) {
215           done.set(true);
216           LOG.info("Caught expected exception: " + e.toString());
217           assertTrue(StringUtils.stringifyException(e).contains("Injected fault"));
218         }
219       });
220 
221       channel.callMethod(md, controller, param, md.getOutputType().toProto(),
222         new RpcCallback<Message>() {
223           @Override
224           public void run(Message parameter) {
225             done.set(true);
226             fail("Expected an exception to have been thrown!");
227           }
228         });
229 
230       TEST_UTIL.waitFor(1000, new Waiter.Predicate<Exception>() {
231         @Override
232         public boolean evaluate() throws Exception {
233           return done.get();
234         }
235       });
236     } finally {
237       client.close();
238       rpcServer.stop();
239     }
240   }
241 
242   public static void main(String[] args) throws IOException, SecurityException,
243       NoSuchMethodException, InterruptedException {
244     if (args.length != 2) {
245       System.out.println("Usage: TestAsyncIPC <CYCLES> <CELLS_PER_CYCLE>");
246       return;
247     }
248     // ((Log4JLogger)HBaseServer.LOG).getLogger().setLevel(Level.INFO);
249     // ((Log4JLogger)HBaseClient.LOG).getLogger().setLevel(Level.INFO);
250     int cycles = Integer.parseInt(args[0]);
251     int cellcount = Integer.parseInt(args[1]);
252     Configuration conf = HBaseConfiguration.create();
253     TestRpcServer rpcServer = new TestRpcServer();
254     MethodDescriptor md = SERVICE.getDescriptorForType().findMethodByName("echo");
255     EchoRequestProto param = EchoRequestProto.newBuilder().setMessage("hello").build();
256     AsyncRpcClient client = new AsyncRpcClient(conf, HConstants.CLUSTER_ID_DEFAULT, null);
257     KeyValue kv = BIG_CELL;
258     Put p = new Put(CellUtil.cloneRow(kv));
259     for (int i = 0; i < cellcount; i++) {
260       p.add(kv);
261     }
262     RowMutations rm = new RowMutations(CellUtil.cloneRow(kv));
263     rm.add(p);
264     try {
265       rpcServer.start();
266       InetSocketAddress address = rpcServer.getListenerAddress();
267       if (address == null) {
268         throw new IOException("Listener channel is closed");
269       }
270       long startTime = System.currentTimeMillis();
271       User user = User.getCurrent();
272       for (int i = 0; i < cycles; i++) {
273         List<CellScannable> cells = new ArrayList<CellScannable>();
274         // Message param = RequestConverter.buildMultiRequest(HConstants.EMPTY_BYTE_ARRAY, rm);
275         ClientProtos.RegionAction.Builder builder =
276             RequestConverter.buildNoDataRegionAction(HConstants.EMPTY_BYTE_ARRAY, rm, cells,
277               RegionAction.newBuilder(), ClientProtos.Action.newBuilder(),
278               MutationProto.newBuilder());
279         builder.setRegion(RegionSpecifier
280             .newBuilder()
281             .setType(RegionSpecifierType.REGION_NAME)
282             .setValue(
283               ByteString.copyFrom(HRegionInfo.FIRST_META_REGIONINFO.getEncodedNameAsBytes())));
284         if (i % 100000 == 0) {
285           LOG.info("" + i);
286           // Uncomment this for a thread dump every so often.
287           // ReflectionUtils.printThreadInfo(new PrintWriter(System.out),
288           // "Thread dump " + Thread.currentThread().getName());
289         }
290         PayloadCarryingRpcController pcrc =
291             new PayloadCarryingRpcController(CellUtil.createCellScanner(cells));
292         // Pair<Message, CellScanner> response =
293         client.call(pcrc, md, builder.build(), param, user, address);
294         /*
295          * int count = 0; while (p.getSecond().advance()) { count++; } assertEquals(cells.size(),
296          * count);
297          */
298       }
299       LOG.info("Cycled " + cycles + " time(s) with " + cellcount + " cell(s) in "
300           + (System.currentTimeMillis() - startTime) + "ms");
301     } finally {
302       client.close();
303       rpcServer.stop();
304     }
305   }
306 }