1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master;
20
21 import static org.junit.Assert.assertEquals;
22
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicInteger;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.Abortable;
34 import org.apache.hadoop.hbase.HBaseTestingUtility;
35 import org.apache.hadoop.hbase.HConstants;
36 import org.apache.hadoop.hbase.HRegionInfo;
37 import org.apache.hadoop.hbase.MiniHBaseCluster;
38 import org.apache.hadoop.hbase.ServerLoad;
39 import org.apache.hadoop.hbase.ServerName;
40 import org.apache.hadoop.hbase.TableName;
41 import org.apache.hadoop.hbase.client.Admin;
42 import org.apache.hadoop.hbase.client.HTable;
43 import org.apache.hadoop.hbase.client.Put;
44 import org.apache.hadoop.hbase.client.Table;
45 import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoResponse.CompactionState;
46 import org.apache.hadoop.hbase.regionserver.HRegion;
47 import org.apache.hadoop.hbase.regionserver.Region;
48 import org.apache.hadoop.hbase.testclassification.MediumTests;
49 import org.apache.hadoop.hbase.util.Bytes;
50 import org.apache.hadoop.hbase.util.JVMClusterUtil;
51 import org.apache.hadoop.hbase.util.RetryCounter;
52 import org.apache.hadoop.hbase.zookeeper.DrainingServerTracker;
53 import org.apache.hadoop.hbase.zookeeper.RegionServerTracker;
54 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
55 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
56 import org.junit.AfterClass;
57 import org.junit.Assert;
58 import org.junit.BeforeClass;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61 import org.mockito.Mockito;
62
63 @Category(MediumTests.class)
64 public class TestAssignmentListener {
65 private static final Log LOG = LogFactory.getLog(TestAssignmentListener.class);
66
67 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
68 private static final Abortable abortable = new Abortable() {
69 @Override
70 public boolean isAborted() {
71 return false;
72 }
73
74 @Override
75 public void abort(String why, Throwable e) {
76 }
77 };
78
79 static class DummyListener {
80 protected AtomicInteger modified = new AtomicInteger(0);
81
82 public void awaitModifications(int count) throws InterruptedException {
83 while (!modified.compareAndSet(count, 0)) {
84 Thread.sleep(100);
85 }
86 }
87 }
88
89 static class DummyAssignmentListener extends DummyListener implements AssignmentListener {
90 private AtomicInteger closeCount = new AtomicInteger(0);
91 private AtomicInteger openCount = new AtomicInteger(0);
92
93 public DummyAssignmentListener() {
94 }
95
96 @Override
97 public void regionOpened(final HRegionInfo regionInfo, final ServerName serverName) {
98 LOG.info("Assignment open region=" + regionInfo + " server=" + serverName);
99 openCount.incrementAndGet();
100 modified.incrementAndGet();
101 }
102
103 @Override
104 public void regionClosed(final HRegionInfo regionInfo) {
105 LOG.info("Assignment close region=" + regionInfo);
106 closeCount.incrementAndGet();
107 modified.incrementAndGet();
108 }
109
110 public void reset() {
111 openCount.set(0);
112 closeCount.set(0);
113 }
114
115 public int getLoadCount() {
116 return openCount.get();
117 }
118
119 public int getCloseCount() {
120 return closeCount.get();
121 }
122 }
123
124 static class DummyServerListener extends DummyListener implements ServerListener {
125 private AtomicInteger removedCount = new AtomicInteger(0);
126 private AtomicInteger addedCount = new AtomicInteger(0);
127
128 public DummyServerListener() {
129 }
130
131 @Override
132 public void serverAdded(final ServerName serverName) {
133 LOG.info("Server added " + serverName);
134 addedCount.incrementAndGet();
135 modified.incrementAndGet();
136 }
137
138 @Override
139 public void serverRemoved(final ServerName serverName) {
140 LOG.info("Server removed " + serverName);
141 removedCount.incrementAndGet();
142 modified.incrementAndGet();
143 }
144
145 public void reset() {
146 addedCount.set(0);
147 removedCount.set(0);
148 }
149
150 public int getAddedCount() {
151 return addedCount.get();
152 }
153
154 public int getRemovedCount() {
155 return removedCount.get();
156 }
157
158 @Override
159 public void waiting() {
160
161 }
162 }
163
164 @BeforeClass
165 public static void beforeAllTests() throws Exception {
166 TEST_UTIL.startMiniCluster(2);
167 }
168
169 @AfterClass
170 public static void afterAllTests() throws Exception {
171 TEST_UTIL.shutdownMiniCluster();
172 }
173
174 @Test(timeout=60000)
175 public void testServerListener() throws IOException, InterruptedException {
176 ServerManager serverManager = TEST_UTIL.getHBaseCluster().getMaster().getServerManager();
177
178 DummyServerListener listener = new DummyServerListener();
179 serverManager.registerListener(listener);
180 try {
181 MiniHBaseCluster miniCluster = TEST_UTIL.getMiniHBaseCluster();
182
183
184 miniCluster.startRegionServer();
185 listener.awaitModifications(1);
186 assertEquals(1, listener.getAddedCount());
187 assertEquals(0, listener.getRemovedCount());
188
189
190 listener.reset();
191 miniCluster.startRegionServer();
192 listener.awaitModifications(1);
193 assertEquals(1, listener.getAddedCount());
194 assertEquals(0, listener.getRemovedCount());
195
196 int nrs = miniCluster.getRegionServerThreads().size();
197
198
199 listener.reset();
200 miniCluster.stopRegionServer(nrs - 1);
201 listener.awaitModifications(1);
202 assertEquals(0, listener.getAddedCount());
203 assertEquals(1, listener.getRemovedCount());
204
205
206 listener.reset();
207 miniCluster.stopRegionServer(nrs - 2);
208 listener.awaitModifications(1);
209 assertEquals(0, listener.getAddedCount());
210 assertEquals(1, listener.getRemovedCount());
211 } finally {
212 serverManager.unregisterListener(listener);
213 }
214 }
215
216 @Test(timeout=60000)
217 public void testAssignmentListener() throws IOException, InterruptedException {
218 AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager();
219 Admin admin = TEST_UTIL.getHBaseAdmin();
220
221 DummyAssignmentListener listener = new DummyAssignmentListener();
222 am.registerListener(listener);
223 try {
224 final String TABLE_NAME_STR = "testtb";
225 final TableName TABLE_NAME = TableName.valueOf(TABLE_NAME_STR);
226 final byte[] FAMILY = Bytes.toBytes("cf");
227
228
229 LOG.info("Create Table");
230 TEST_UTIL.createTable(TABLE_NAME, FAMILY);
231 listener.awaitModifications(1);
232 assertEquals(1, listener.getLoadCount());
233 assertEquals(0, listener.getCloseCount());
234
235
236 Table table = new HTable(TEST_UTIL.getConfiguration(), TABLE_NAME);
237 try {
238 for (int i = 0; i < 10; ++i) {
239 byte[] key = Bytes.toBytes("row-" + i);
240 Put put = new Put(key);
241 put.add(FAMILY, null, key);
242 table.put(put);
243 }
244 } finally {
245 table.close();
246 }
247
248
249 LOG.info("Split Table");
250 listener.reset();
251 admin.split(TABLE_NAME, Bytes.toBytes("row-3"));
252 listener.awaitModifications(3);
253 assertEquals(2, listener.getLoadCount());
254 assertEquals(1, listener.getCloseCount());
255
256
257 MiniHBaseCluster miniCluster = TEST_UTIL.getMiniHBaseCluster();
258 int mergeable = 0;
259 while (mergeable < 2) {
260 Thread.sleep(100);
261 admin.majorCompact(TABLE_NAME);
262
263
264 RetryCounter retrier = new RetryCounter(30, 1, TimeUnit.SECONDS);
265 while (CompactionState.NONE != admin.getCompactionState(TABLE_NAME)
266 && retrier.shouldRetry()) {
267 retrier.sleepUntilNextRetry();
268 }
269
270
271
272 for (HRegion region : TEST_UTIL.getHBaseCluster().getRegions(TABLE_NAME)) {
273 region.getStores().get(0).closeAndArchiveCompactedFiles();
274 }
275
276 mergeable = 0;
277 for (JVMClusterUtil.RegionServerThread regionThread: miniCluster.getRegionServerThreads()) {
278 for (Region region: regionThread.getRegionServer().getOnlineRegions(TABLE_NAME)) {
279 mergeable += ((HRegion)region).isMergeable() ? 1 : 0;
280 }
281 }
282 }
283
284
285 LOG.info("Merge Regions");
286 listener.reset();
287 List<HRegionInfo> regions = admin.getTableRegions(TABLE_NAME);
288 assertEquals(2, regions.size());
289 admin.mergeRegions(regions.get(0).getEncodedNameAsBytes(),
290 regions.get(1).getEncodedNameAsBytes(), true);
291 listener.awaitModifications(3);
292 assertEquals(1, admin.getTableRegions(TABLE_NAME).size());
293 assertEquals(1, listener.getLoadCount());
294 assertEquals(2, listener.getCloseCount());
295
296
297 LOG.info("Drop Table");
298 listener.reset();
299 TEST_UTIL.deleteTable(TABLE_NAME);
300 listener.awaitModifications(1);
301 assertEquals(0, listener.getLoadCount());
302 assertEquals(1, listener.getCloseCount());
303 } finally {
304 am.unregisterListener(listener);
305 }
306 }
307
308 @Test
309 public void testAddNewServerThatExistsInDraining() throws Exception {
310
311
312
313
314
315
316 Configuration conf = TEST_UTIL.getConfiguration();
317 ZooKeeperWatcher zooKeeper = new ZooKeeperWatcher(conf,
318 "zkWatcher-NewServerDrainTest", abortable, true);
319 String baseZNode = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT,
320 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT);
321 String drainingZNode = ZKUtil.joinZNode(baseZNode,
322 conf.get("zookeeper.znode.draining.rs", "draining"));
323
324 MasterServices services = Mockito.mock(MasterServices.class);
325 HMaster master = Mockito.mock(HMaster.class);
326 Mockito.when(master.getConfiguration()).thenReturn(conf);
327
328 ServerName SERVERNAME_A = ServerName.valueOf("mockserverbulk_a.org", 1000, 8000);
329 ServerName SERVERNAME_B = ServerName.valueOf("mockserverbulk_b.org", 1001, 8000);
330 ServerName SERVERNAME_C = ServerName.valueOf("mockserverbulk_c.org", 1002, 8000);
331
332
333
334 ArrayList<ServerName> drainingServers = new ArrayList<ServerName>();
335 drainingServers.add(SERVERNAME_A);
336 drainingServers.add(SERVERNAME_B);
337
338
339
340
341 HashMap<ServerName, ServerLoad> onlineServers = new HashMap<ServerName, ServerLoad>();
342 onlineServers.put(SERVERNAME_A, ServerLoad.EMPTY_SERVERLOAD);
343 onlineServers.put(SERVERNAME_C, ServerLoad.EMPTY_SERVERLOAD);
344
345
346
347 for (ServerName sn : drainingServers) {
348 String znode = ZKUtil.joinZNode(drainingZNode, sn.getServerName());
349 ZKUtil.createAndFailSilent(zooKeeper, znode);
350 }
351
352
353
354 ServerManager serverManager = new ServerManager(master, services);
355 RegionServerTracker regionServerTracker = new RegionServerTracker(
356 zooKeeper, master, serverManager);
357 regionServerTracker.start();
358
359 DrainingServerTracker drainingServerTracker = new DrainingServerTracker(
360 zooKeeper, master, serverManager);
361 drainingServerTracker.start();
362
363
364 Assert.assertEquals(serverManager.getOnlineServers(),
365 new HashMap<ServerName, ServerLoad>());
366 Assert.assertEquals(serverManager.getDrainingServersList(),
367 new ArrayList<ServerName>());
368
369
370 ArrayList<ServerName> onlineDrainingServers = new ArrayList<ServerName>();
371 for (ServerName sn : onlineServers.keySet()){
372
373 serverManager.checkAndRecordNewServer(sn, onlineServers.get(sn));
374 if (drainingServers.contains(sn)){
375 onlineDrainingServers.add(sn);
376 }
377 }
378
379
380 Assert.assertEquals(serverManager.getOnlineServers(), onlineServers);
381 Assert.assertEquals(serverManager.getDrainingServersList(),
382 onlineDrainingServers);
383 }
384 }