1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.executor;
20
21 import static org.junit.Assert.*;
22 import java.io.IOException;
23 import java.io.StringWriter;
24 import java.util.concurrent.ThreadPoolExecutor;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import java.util.concurrent.atomic.AtomicInteger;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.hbase.*;
32 import org.apache.hadoop.hbase.Waiter.Predicate;
33 import org.apache.hadoop.hbase.executor.ExecutorService.Executor;
34 import org.apache.hadoop.hbase.executor.ExecutorService.ExecutorStatus;
35 import org.apache.hadoop.hbase.testclassification.SmallTests;
36 import org.junit.Test;
37 import org.junit.experimental.categories.Category;
38
39 import static org.mockito.Mockito.*;
40
41 @Category(SmallTests.class)
42 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="JLM_JSR166_UTILCONCURRENT_MONITORENTER",
43 justification="Use of an atomic type both as monitor and condition variable is intended")
44 public class TestExecutorService {
45 private static final Log LOG = LogFactory.getLog(TestExecutorService.class);
46
47 @Test
48 public void testExecutorService() throws Exception {
49 int maxThreads = 5;
50 int maxTries = 10;
51 int sleepInterval = 10;
52
53 Server mockedServer = mock(Server.class);
54 when(mockedServer.getConfiguration()).thenReturn(HBaseConfiguration.create());
55
56
57 ExecutorService executorService = new ExecutorService("unit_test");
58 executorService.startExecutorService(
59 ExecutorType.MASTER_SERVER_OPERATIONS, maxThreads);
60
61 Executor executor =
62 executorService.getExecutor(ExecutorType.MASTER_SERVER_OPERATIONS);
63 ThreadPoolExecutor pool = executor.threadPoolExecutor;
64
65
66 assertEquals(0, pool.getPoolSize());
67
68 AtomicBoolean lock = new AtomicBoolean(true);
69 AtomicInteger counter = new AtomicInteger(0);
70
71
72 for (int i = 0; i < maxThreads; i++) {
73 executorService.submit(
74 new TestEventHandler(mockedServer, EventType.M_SERVER_SHUTDOWN,
75 lock, counter));
76 }
77
78
79 int tries = 0;
80 while (counter.get() < maxThreads && tries < maxTries) {
81 LOG.info("Waiting for all event handlers to start...");
82 Thread.sleep(sleepInterval);
83 tries++;
84 }
85
86
87 assertEquals(maxThreads, counter.get());
88 assertEquals(maxThreads, pool.getPoolSize());
89
90 ExecutorStatus status = executor.getStatus();
91 assertTrue(status.queuedEvents.isEmpty());
92 assertEquals(5, status.running.size());
93 checkStatusDump(status);
94
95
96
97 synchronized (lock) {
98 lock.set(false);
99 lock.notifyAll();
100 }
101
102
103 while (counter.get() < (maxThreads * 2) && tries < maxTries) {
104 System.out.println("Waiting for all event handlers to finish...");
105 Thread.sleep(sleepInterval);
106 tries++;
107 }
108
109 assertEquals(maxThreads * 2, counter.get());
110 assertEquals(maxThreads, pool.getPoolSize());
111
112
113
114 for (int i = 0; i < (2 * maxThreads); i++) {
115 executorService.submit(
116 new TestEventHandler(mockedServer, EventType.M_SERVER_SHUTDOWN,
117 lock, counter));
118 }
119
120 synchronized (lock) {
121 lock.set(false);
122 lock.notifyAll();
123 }
124
125
126 Thread.sleep(ExecutorService.Executor.keepAliveTimeInMillis * 2);
127 assertEquals(maxThreads, pool.getPoolSize());
128
129 executorService.shutdown();
130
131 assertEquals(0, executorService.getAllExecutorStatuses().size());
132
133
134 executorService.submit(
135 new TestEventHandler(mockedServer, EventType.M_SERVER_SHUTDOWN,
136 lock, counter));
137 }
138
139 private void checkStatusDump(ExecutorStatus status) throws IOException {
140 StringWriter sw = new StringWriter();
141 status.dumpTo(sw, "");
142 String dump = sw.toString();
143 LOG.info("Got status dump:\n" + dump);
144
145 assertTrue(dump.contains("Waiting on java.util.concurrent.atomic.AtomicBoolean"));
146 }
147
148 public static class TestEventHandler extends EventHandler {
149 private AtomicBoolean lock;
150 private AtomicInteger counter;
151
152 public TestEventHandler(Server server, EventType eventType,
153 AtomicBoolean lock, AtomicInteger counter) {
154 super(server, eventType);
155 this.lock = lock;
156 this.counter = counter;
157 }
158
159 @Override
160 public void process() throws IOException {
161 int num = counter.incrementAndGet();
162 LOG.info("Running process #" + num + ", threadName=" +
163 Thread.currentThread().getName());
164 synchronized (lock) {
165 while (lock.get()) {
166 try {
167 lock.wait();
168 } catch (InterruptedException e) {
169
170 }
171 }
172 }
173 counter.incrementAndGet();
174 }
175 }
176
177 @Test
178 public void testAborting() throws Exception {
179 final Configuration conf = HBaseConfiguration.create();
180 final Server server = mock(Server.class);
181 when(server.getConfiguration()).thenReturn(conf);
182
183 ExecutorService executorService = new ExecutorService("unit_test");
184 executorService.startExecutorService(
185 ExecutorType.MASTER_SERVER_OPERATIONS, 1);
186
187
188 executorService.submit(new EventHandler(server, EventType.M_SERVER_SHUTDOWN) {
189 @Override
190 public void process() throws IOException {
191 throw new RuntimeException("Should cause abort");
192 }
193 });
194
195 Waiter.waitFor(conf, 30000, new Predicate<Exception>() {
196 @Override
197 public boolean evaluate() throws Exception {
198 try {
199 verify(server, times(1)).abort(anyString(), (Throwable) anyObject());
200 return true;
201 } catch (Throwable t) {
202 return false;
203 }
204 }
205 });
206
207 executorService.shutdown();
208 }
209
210 }
211