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.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25
26 import java.io.IOException;
27 import java.net.InetSocketAddress;
28 import java.util.ArrayList;
29 import java.util.List;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.conf.Configuration;
34 import org.apache.hadoop.hbase.HBaseConfiguration;
35 import org.apache.hadoop.hbase.HConstants;
36 import org.apache.hadoop.hbase.testclassification.MediumTests;
37 import org.apache.hadoop.hbase.ServerName;
38 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestDelayedRpcProtos;
39 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestDelayedRpcProtos.TestArg;
40 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestDelayedRpcProtos.TestResponse;
41 import org.apache.hadoop.hbase.security.User;
42 import org.apache.log4j.AppenderSkeleton;
43 import org.apache.log4j.Level;
44 import org.apache.log4j.Logger;
45 import org.apache.log4j.spi.LoggingEvent;
46 import org.junit.Test;
47 import org.junit.experimental.categories.Category;
48
49 import com.google.common.collect.Lists;
50 import com.google.protobuf.BlockingRpcChannel;
51 import com.google.protobuf.BlockingService;
52 import com.google.protobuf.RpcController;
53 import com.google.protobuf.ServiceException;
54
55
56
57
58
59
60 @Category(MediumTests.class)
61 public class TestDelayedRpc {
62 private static final Log LOG = LogFactory.getLog(TestDelayedRpc.class);
63 public static RpcServerInterface rpcServer;
64 public static final int UNDELAYED = 0;
65 public static final int DELAYED = 1;
66 private static final int RPC_CLIENT_TIMEOUT = 30000;
67
68 @Test (timeout=60000)
69 public void testDelayedRpcImmediateReturnValue() throws Exception {
70 testDelayedRpc(false);
71 }
72
73 @Test (timeout=60000)
74 public void testDelayedRpcDelayedReturnValue() throws Exception {
75 testDelayedRpc(true);
76 }
77
78 private void testDelayedRpc(boolean delayReturnValue) throws Exception {
79 LOG.info("Running testDelayedRpc delayReturnValue=" + delayReturnValue);
80 Configuration conf = HBaseConfiguration.create();
81 InetSocketAddress isa = new InetSocketAddress("localhost", 0);
82 TestDelayedImplementation instance = new TestDelayedImplementation(delayReturnValue);
83 BlockingService service =
84 TestDelayedRpcProtos.TestDelayedService.newReflectiveBlockingService(instance);
85 rpcServer = new RpcServer(null, "testDelayedRpc",
86 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(service, null)),
87 isa,
88 conf,
89 new FifoRpcScheduler(conf, 1));
90 rpcServer.start();
91 RpcClient rpcClient = RpcClientFactory.createClient(
92 conf, HConstants.DEFAULT_CLUSTER_ID.toString());
93 try {
94 BlockingRpcChannel channel = rpcClient.createBlockingRpcChannel(
95 ServerName.valueOf(rpcServer.getListenerAddress().getHostName(),
96 rpcServer.getListenerAddress().getPort(), System.currentTimeMillis()),
97 User.getCurrent(), RPC_CLIENT_TIMEOUT);
98 TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub =
99 TestDelayedRpcProtos.TestDelayedService.newBlockingStub(channel);
100 List<Integer> results = new ArrayList<Integer>();
101
102 TestThread th1 = new TestThread(stub, true, results);
103
104 TestThread th2 = new TestThread(stub, false, results);
105 TestThread th3 = new TestThread(stub, false, results);
106 th1.start();
107 Thread.sleep(100);
108 th2.start();
109 Thread.sleep(200);
110 th3.start();
111
112 th1.join();
113 th2.join();
114 th3.join();
115
116
117 assertEquals(UNDELAYED, results.get(0).intValue());
118 assertEquals(UNDELAYED, results.get(1).intValue());
119 assertEquals(results.get(2).intValue(), delayReturnValue ? DELAYED : 0xDEADBEEF);
120 } finally {
121 rpcClient.close();
122 }
123 }
124
125 private static class ListAppender extends AppenderSkeleton {
126 private final List<String> messages = new ArrayList<String>();
127
128 @Override
129 protected void append(LoggingEvent event) {
130 messages.add(event.getMessage().toString());
131 }
132
133 @Override
134 public void close() {
135 }
136
137 @Override
138 public boolean requiresLayout() {
139 return false;
140 }
141
142 public List<String> getMessages() {
143 return messages;
144 }
145 }
146
147
148
149
150
151 @Test (timeout=60000)
152 public void testTooManyDelayedRpcs() throws Exception {
153 Configuration conf = HBaseConfiguration.create();
154 final int MAX_DELAYED_RPC = 10;
155 conf.setInt("hbase.ipc.warn.delayedrpc.number", MAX_DELAYED_RPC);
156
157 ListAppender listAppender = new ListAppender();
158 Logger log = Logger.getLogger(RpcServer.class);
159 log.addAppender(listAppender);
160 log.setLevel(Level.WARN);
161
162
163 InetSocketAddress isa = new InetSocketAddress("localhost", 0);
164 TestDelayedImplementation instance = new TestDelayedImplementation(true);
165 BlockingService service =
166 TestDelayedRpcProtos.TestDelayedService.newReflectiveBlockingService(instance);
167 rpcServer = new RpcServer(null, "testTooManyDelayedRpcs",
168 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(service, null)),
169 isa,
170 conf,
171 new FifoRpcScheduler(conf, 1));
172 rpcServer.start();
173 RpcClient rpcClient = RpcClientFactory.createClient(
174 conf, HConstants.DEFAULT_CLUSTER_ID.toString());
175 try {
176 BlockingRpcChannel channel = rpcClient.createBlockingRpcChannel(
177 ServerName.valueOf(rpcServer.getListenerAddress().getHostName(),
178 rpcServer.getListenerAddress().getPort(), System.currentTimeMillis()),
179 User.getCurrent(), RPC_CLIENT_TIMEOUT);
180 TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub =
181 TestDelayedRpcProtos.TestDelayedService.newBlockingStub(channel);
182 Thread threads[] = new Thread[MAX_DELAYED_RPC + 1];
183 for (int i = 0; i < MAX_DELAYED_RPC; i++) {
184 threads[i] = new TestThread(stub, true, null);
185 threads[i].start();
186 }
187
188
189 assertTrue(listAppender.getMessages().isEmpty());
190
191
192 threads[MAX_DELAYED_RPC] = new TestThread(stub, true, null);
193 threads[MAX_DELAYED_RPC].start();
194
195 for (int i = 0; i < MAX_DELAYED_RPC; i++) {
196 threads[i].join();
197 }
198
199 assertFalse(listAppender.getMessages().isEmpty());
200 assertTrue(listAppender.getMessages().get(0).startsWith("Too many delayed calls"));
201
202 log.removeAppender(listAppender);
203 } finally {
204 rpcClient.close();
205 }
206 }
207
208 public static class TestDelayedImplementation
209 implements TestDelayedRpcProtos.TestDelayedService.BlockingInterface {
210
211
212
213
214 private final boolean delayReturnValue;
215
216
217
218
219
220 public TestDelayedImplementation(boolean delayReturnValue) {
221 this.delayReturnValue = delayReturnValue;
222 }
223
224 @Override
225 public TestResponse test(final RpcController rpcController, final TestArg testArg)
226 throws ServiceException {
227 boolean delay = testArg.getDelay();
228 TestResponse.Builder responseBuilder = TestResponse.newBuilder();
229 if (!delay) {
230 responseBuilder.setResponse(UNDELAYED);
231 return responseBuilder.build();
232 }
233 final Delayable call = RpcServer.getCurrentCall();
234 call.startDelay(delayReturnValue);
235 new Thread() {
236 @Override
237 public void run() {
238 try {
239 Thread.sleep(500);
240 TestResponse.Builder responseBuilder = TestResponse.newBuilder();
241 call.endDelay(delayReturnValue ?
242 responseBuilder.setResponse(DELAYED).build() : null);
243 } catch (Exception e) {
244 e.printStackTrace();
245 }
246 }
247 }.start();
248
249
250 responseBuilder.setResponse(0xDEADBEEF);
251 return responseBuilder.build();
252 }
253 }
254
255 public static class TestThread extends Thread {
256 private final TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub;
257 private final boolean delay;
258 private final List<Integer> results;
259
260 public TestThread(TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub,
261 boolean delay, List<Integer> results) {
262 this.stub = stub;
263 this.delay = delay;
264 this.results = results;
265 }
266
267 @Override
268 public void run() {
269 Integer result;
270 try {
271 result = new Integer(stub.test(null, TestArg.newBuilder().setDelay(delay).build()).
272 getResponse());
273 } catch (ServiceException e) {
274 throw new RuntimeException(e);
275 }
276 if (results != null) {
277 synchronized (results) {
278 results.add(result);
279 }
280 }
281 }
282 }
283
284 @Test
285 public void testEndDelayThrowing() throws IOException {
286 Configuration conf = HBaseConfiguration.create();
287 InetSocketAddress isa = new InetSocketAddress("localhost", 0);
288 FaultyTestDelayedImplementation instance = new FaultyTestDelayedImplementation();
289 BlockingService service =
290 TestDelayedRpcProtos.TestDelayedService.newReflectiveBlockingService(instance);
291 rpcServer = new RpcServer(null, "testEndDelayThrowing",
292 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(service, null)),
293 isa,
294 conf,
295 new FifoRpcScheduler(conf, 1));
296 rpcServer.start();
297 RpcClient rpcClient = RpcClientFactory.createClient(
298 conf, HConstants.DEFAULT_CLUSTER_ID.toString());
299 try {
300 BlockingRpcChannel channel = rpcClient.createBlockingRpcChannel(
301 ServerName.valueOf(rpcServer.getListenerAddress().getHostName(),
302 rpcServer.getListenerAddress().getPort(), System.currentTimeMillis()),
303 User.getCurrent(), 1000);
304 TestDelayedRpcProtos.TestDelayedService.BlockingInterface stub =
305 TestDelayedRpcProtos.TestDelayedService.newBlockingStub(channel);
306
307 int result = 0xDEADBEEF;
308
309 try {
310 result = stub.test(null, TestArg.newBuilder().setDelay(false).build()).getResponse();
311 } catch (Exception e) {
312 fail("No exception should have been thrown.");
313 }
314 assertEquals(result, UNDELAYED);
315
316 boolean caughtException = false;
317 try {
318 result = stub.test(null, TestArg.newBuilder().setDelay(true).build()).getResponse();
319 } catch(Exception e) {
320
321 if (e.getCause().getMessage().contains("java.lang.Exception: Something went wrong")) {
322 caughtException = true;
323 }
324 LOG.warn("Caught exception, expected=" + caughtException);
325 }
326 assertTrue(caughtException);
327 } finally {
328 rpcClient.close();
329 }
330 }
331
332
333
334
335 private static class FaultyTestDelayedImplementation extends TestDelayedImplementation {
336 public FaultyTestDelayedImplementation() {
337 super(false);
338 }
339
340 @Override
341 public TestResponse test(RpcController rpcController, TestArg arg)
342 throws ServiceException {
343 LOG.info("In faulty test, delay=" + arg.getDelay());
344 if (!arg.getDelay()) return TestResponse.newBuilder().setResponse(UNDELAYED).build();
345 Delayable call = RpcServer.getCurrentCall();
346 call.startDelay(true);
347 LOG.info("In faulty test, delaying");
348 try {
349 call.endDelayThrowing(new Exception("Something went wrong"));
350 } catch (IOException e) {
351 e.printStackTrace();
352 }
353
354 return TestResponse.newBuilder().setResponse(DELAYED).build();
355 }
356 }
357 }