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