1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
249
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
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
287
288
289 }
290 PayloadCarryingRpcController pcrc =
291 new PayloadCarryingRpcController(CellUtil.createCellScanner(cells));
292
293 client.call(pcrc, md, builder.build(), param, user, address);
294
295
296
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 }