1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.ipc;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.io.IOException;
28 import java.lang.reflect.Method;
29 import java.net.InetSocketAddress;
30 import java.util.ArrayList;
31 import java.util.List;
32
33 import junit.framework.Assert;
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.hbase.*;
36 import org.apache.hadoop.hbase.ipc.VersionedProtocol;
37 import org.apache.log4j.AppenderSkeleton;
38 import org.apache.log4j.Logger;
39 import org.apache.log4j.spi.LoggingEvent;
40 import org.apache.log4j.Level;
41 import org.junit.Test;
42 import org.junit.experimental.categories.Category;
43
44
45
46
47
48
49 @Category(MediumTests.class)
50 public class TestDelayedRpc {
51 public static RpcServer rpcServer;
52
53 public static final int UNDELAYED = 0;
54 public static final int DELAYED = 1;
55
56 @Test
57 public void testDelayedRpcImmediateReturnValue() throws Exception {
58 testDelayedRpc(false);
59 }
60
61 @Test
62 public void testDelayedRpcDelayedReturnValue() throws Exception {
63 testDelayedRpc(true);
64 }
65
66 private void testDelayedRpc(boolean delayReturnValue) throws Exception {
67 Configuration conf = HBaseConfiguration.create();
68 InetSocketAddress isa = new InetSocketAddress("localhost", 0);
69
70 rpcServer = HBaseRPC.getServer(new TestRpcImpl(delayReturnValue),
71 new Class<?>[]{ TestRpcImpl.class },
72 isa.getHostName(), isa.getPort(), 1, 0, true, conf, 0);
73 RpcEngine rpcEngine = null;
74 try {
75 rpcServer.start();
76 rpcEngine = HBaseRPC.getProtocolEngine(conf);
77
78 TestRpc client = rpcEngine.getProxy(TestRpc.class, 0,
79 rpcServer.getListenerAddress(), conf, 1000);
80
81 List<Integer> results = new ArrayList<Integer>();
82
83 TestThread th1 = new TestThread(client, true, results);
84 TestThread th2 = new TestThread(client, false, results);
85 TestThread th3 = new TestThread(client, false, results);
86 th1.start();
87 Thread.sleep(100);
88 th2.start();
89 Thread.sleep(200);
90 th3.start();
91
92 th1.join();
93 th2.join();
94 th3.join();
95
96 assertEquals(UNDELAYED, results.get(0).intValue());
97 assertEquals(UNDELAYED, results.get(1).intValue());
98 assertEquals(results.get(2).intValue(), delayReturnValue ? DELAYED :
99 0xDEADBEEF);
100 } finally {
101 if (rpcEngine != null) {
102 rpcEngine.close();
103 }
104 }
105 }
106
107 private static class ListAppender extends AppenderSkeleton {
108 private List<String> messages = new ArrayList<String>();
109
110 @Override
111 protected void append(LoggingEvent event) {
112 messages.add(event.getMessage().toString());
113 }
114
115 @Override
116 public void close() {
117 }
118
119 @Override
120 public boolean requiresLayout() {
121 return false;
122 }
123
124 public List<String> getMessages() {
125 return messages;
126 }
127 }
128
129 @Test
130 public void testTooManyDelayedRpcs() throws Exception {
131 Configuration conf = HBaseConfiguration.create();
132 final int MAX_DELAYED_RPC = 10;
133 conf.setInt("hbase.ipc.warn.delayedrpc.number", MAX_DELAYED_RPC);
134
135 ListAppender listAppender = new ListAppender();
136 Logger log = Logger.getLogger("org.apache.hadoop.ipc.HBaseServer");
137 log.addAppender(listAppender);
138 log.setLevel(Level.WARN);
139
140 InetSocketAddress isa = new InetSocketAddress("localhost", 0);
141 rpcServer = HBaseRPC.getServer(new TestRpcImpl(true),
142 new Class<?>[]{ TestRpcImpl.class },
143 isa.getHostName(), isa.getPort(), 1, 0, true, conf, 0);
144 RpcEngine rpcEngine = null;
145 try {
146 rpcServer.start();
147 rpcEngine = HBaseRPC.getProtocolEngine(conf);
148
149 TestRpc client = rpcEngine.getProxy(TestRpc.class, 0,
150 rpcServer.getListenerAddress(), conf, 1000);
151
152 Thread threads[] = new Thread[MAX_DELAYED_RPC + 1];
153
154 for (int i = 0; i < MAX_DELAYED_RPC; i++) {
155 threads[i] = new TestThread(client, true, null);
156 threads[i].start();
157 }
158
159
160 assertTrue(listAppender.getMessages().isEmpty());
161
162
163 threads[MAX_DELAYED_RPC] = new TestThread(client, true, null);
164 threads[MAX_DELAYED_RPC].start();
165
166 for (int i = 0; i < MAX_DELAYED_RPC; i++) {
167 threads[i].join();
168 }
169
170 assertFalse(listAppender.getMessages().isEmpty());
171 assertTrue(listAppender.getMessages().get(0).startsWith(
172 "Too many delayed calls"));
173
174 log.removeAppender(listAppender);
175 } finally {
176 if (rpcEngine != null) {
177 rpcEngine.close();
178 }
179 }
180 }
181
182 public interface TestRpc extends VersionedProtocol {
183 public static final long VERSION = 1L;
184 int test(boolean delay);
185 }
186
187 private static class TestRpcImpl implements TestRpc {
188
189
190
191
192 private boolean delayReturnValue;
193
194
195
196
197
198 public TestRpcImpl(boolean delayReturnValue) {
199 this.delayReturnValue = delayReturnValue;
200 }
201
202 @Override
203 public int test(final boolean delay) {
204 if (!delay) {
205 return UNDELAYED;
206 }
207 final Delayable call = HBaseServer.getCurrentCall();
208 call.startDelay(delayReturnValue);
209 new Thread() {
210 public void run() {
211 try {
212 Thread.sleep(500);
213 call.endDelay(delayReturnValue ? DELAYED : null);
214 } catch (Exception e) {
215 e.printStackTrace();
216 }
217 }
218 }.start();
219
220
221 return 0xDEADBEEF;
222 }
223
224 @Override
225 public long getProtocolVersion(String arg0, long arg1) throws IOException {
226 return 0;
227 }
228
229 @Override
230 public ProtocolSignature getProtocolSignature(String protocol,
231 long clientVersion, int clientMethodsHash) throws IOException {
232 Method [] methods = this.getClass().getMethods();
233 int [] hashes = new int [methods.length];
234 for (int i = 0; i < methods.length; i++) {
235 hashes[i] = methods[i].hashCode();
236 }
237 return new ProtocolSignature(clientVersion, hashes);
238 }
239 }
240
241 private static class TestThread extends Thread {
242 private TestRpc server;
243 private boolean delay;
244 private List<Integer> results;
245
246 public TestThread(TestRpc server, boolean delay, List<Integer> results) {
247 this.server = server;
248 this.delay = delay;
249 this.results = results;
250 }
251
252 @Override
253 public void run() {
254 try {
255 Integer result = new Integer(server.test(delay));
256 if (results != null) {
257 synchronized (results) {
258 results.add(result);
259 }
260 }
261 } catch (Exception e) {
262 fail("Unexpected exception: "+e.getMessage());
263 }
264 }
265 }
266
267 @Test
268 public void testEndDelayThrowing() throws IOException {
269 Configuration conf = HBaseConfiguration.create();
270 InetSocketAddress isa = new InetSocketAddress("localhost", 0);
271
272 rpcServer = HBaseRPC.getServer(new FaultyTestRpc(),
273 new Class<?>[]{ TestRpcImpl.class },
274 isa.getHostName(), isa.getPort(), 1, 0, true, conf, 0);
275 RpcEngine rpcEngine = null;
276 try {
277 rpcServer.start();
278 rpcEngine = HBaseRPC.getProtocolEngine(conf);
279
280 TestRpc client = rpcEngine.getProxy(TestRpc.class, 0,
281 rpcServer.getListenerAddress(), conf, 1000);
282
283 int result = 0xDEADBEEF;
284
285 try {
286 result = client.test(false);
287 } catch (Exception e) {
288 fail("No exception should have been thrown.");
289 }
290 assertEquals(result, UNDELAYED);
291
292 boolean caughtException = false;
293 try {
294 result = client.test(true);
295 } catch(Exception e) {
296
297 if (e.getCause().getMessage().startsWith(
298 "java.lang.Exception: Something went wrong"))
299 caughtException = true;
300 }
301 assertTrue(caughtException);
302 } finally {
303 if (rpcEngine != null) {
304 rpcEngine.close();
305 }
306 }
307 }
308
309
310
311
312 private static class FaultyTestRpc implements TestRpc {
313 @Override
314 public int test(boolean delay) {
315 if (!delay)
316 return UNDELAYED;
317 Delayable call = HBaseServer.getCurrentCall();
318 call.startDelay(true);
319 try {
320 call.endDelayThrowing(new Exception("Something went wrong"));
321 } catch (IOException e) {
322 e.printStackTrace();
323 }
324
325 return DELAYED;
326 }
327
328 @Override
329 public long getProtocolVersion(String arg0, long arg1) throws IOException {
330 return 0;
331 }
332
333 @Override
334 public ProtocolSignature getProtocolSignature(String protocol,
335 long clientVersion, int clientMethodsHash) throws IOException {
336 return new ProtocolSignature(clientVersion, new int [] {});
337 }
338 }
339
340 @org.junit.Rule
341 public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
342 new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
343 }
344