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
159 @BeforeClass
160 public static void beforeAllTests() throws Exception {
161 TEST_UTIL.startMiniCluster(2);
162 }
163
164 @AfterClass
165 public static void afterAllTests() throws Exception {
166 TEST_UTIL.shutdownMiniCluster();
167 }
168
169 @Test(timeout=60000)
170 public void testServerListener() throws IOException, InterruptedException {
171 ServerManager serverManager = TEST_UTIL.getHBaseCluster().getMaster().getServerManager();
172
173 DummyServerListener listener = new DummyServerListener();
174 serverManager.registerListener(listener);
175 try {
176 MiniHBaseCluster miniCluster = TEST_UTIL.getMiniHBaseCluster();
177
178
179 miniCluster.startRegionServer();
180 listener.awaitModifications(1);
181 assertEquals(1, listener.getAddedCount());
182 assertEquals(0, listener.getRemovedCount());
183
184
185 listener.reset();
186 miniCluster.startRegionServer();
187 listener.awaitModifications(1);
188 assertEquals(1, listener.getAddedCount());
189 assertEquals(0, listener.getRemovedCount());
190
191 int nrs = miniCluster.getRegionServerThreads().size();
192
193
194 listener.reset();
195 miniCluster.stopRegionServer(nrs - 1);
196 listener.awaitModifications(1);
197 assertEquals(0, listener.getAddedCount());
198 assertEquals(1, listener.getRemovedCount());
199
200
201 listener.reset();
202 miniCluster.stopRegionServer(nrs - 2);
203 listener.awaitModifications(1);
204 assertEquals(0, listener.getAddedCount());
205 assertEquals(1, listener.getRemovedCount());
206 } finally {
207 serverManager.unregisterListener(listener);
208 }
209 }
210
211 @Test(timeout=60000)
212 public void testAssignmentListener() throws IOException, InterruptedException {
213 AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager();
214 Admin admin = TEST_UTIL.getHBaseAdmin();
215
216 DummyAssignmentListener listener = new DummyAssignmentListener();
217 am.registerListener(listener);
218 try {
219 final String TABLE_NAME_STR = "testtb";
220 final TableName TABLE_NAME = TableName.valueOf(TABLE_NAME_STR);
221 final byte[] FAMILY = Bytes.toBytes("cf");
222
223
224 LOG.info("Create Table");
225 TEST_UTIL.createTable(TABLE_NAME, FAMILY);
226 listener.awaitModifications(1);
227 assertEquals(1, listener.getLoadCount());
228 assertEquals(0, listener.getCloseCount());
229
230
231 Table table = new HTable(TEST_UTIL.getConfiguration(), TABLE_NAME);
232 try {
233 for (int i = 0; i < 10; ++i) {
234 byte[] key = Bytes.toBytes("row-" + i);
235 Put put = new Put(key);
236 put.add(FAMILY, null, key);
237 table.put(put);
238 }
239 } finally {
240 table.close();
241 }
242
243
244 LOG.info("Split Table");
245 listener.reset();
246 admin.split(TABLE_NAME, Bytes.toBytes("row-3"));
247 listener.awaitModifications(3);
248 assertEquals(2, listener.getLoadCount());
249 assertEquals(1, listener.getCloseCount());
250
251
252 MiniHBaseCluster miniCluster = TEST_UTIL.getMiniHBaseCluster();
253 int mergeable = 0;
254 while (mergeable < 2) {
255 Thread.sleep(100);
256 admin.majorCompact(TABLE_NAME);
257
258
259 RetryCounter retrier = new RetryCounter(30, 1, TimeUnit.SECONDS);
260 while (CompactionState.NONE != admin.getCompactionState(TABLE_NAME)
261 && retrier.shouldRetry()) {
262 retrier.sleepUntilNextRetry();
263 }
264
265
266
267 for (HRegion region : TEST_UTIL.getHBaseCluster().getRegions(TABLE_NAME)) {
268 region.getStores().get(0).closeAndArchiveCompactedFiles();
269 }
270
271 mergeable = 0;
272 for (JVMClusterUtil.RegionServerThread regionThread: miniCluster.getRegionServerThreads()) {
273 for (Region region: regionThread.getRegionServer().getOnlineRegions(TABLE_NAME)) {
274 mergeable += ((HRegion)region).isMergeable() ? 1 : 0;
275 }
276 }
277 }
278
279
280 LOG.info("Merge Regions");
281 listener.reset();
282 List<HRegionInfo> regions = admin.getTableRegions(TABLE_NAME);
283 assertEquals(2, regions.size());
284 admin.mergeRegions(regions.get(0).getEncodedNameAsBytes(),
285 regions.get(1).getEncodedNameAsBytes(), true);
286 listener.awaitModifications(3);
287 assertEquals(1, admin.getTableRegions(TABLE_NAME).size());
288 assertEquals(1, listener.getLoadCount());
289 assertEquals(2, listener.getCloseCount());
290
291
292 LOG.info("Drop Table");
293 listener.reset();
294 TEST_UTIL.deleteTable(TABLE_NAME);
295 listener.awaitModifications(1);
296 assertEquals(0, listener.getLoadCount());
297 assertEquals(1, listener.getCloseCount());
298 } finally {
299 am.unregisterListener(listener);
300 }
301 }
302
303 @Test
304 public void testAddNewServerThatExistsInDraining() throws Exception {
305
306
307
308
309
310
311 Configuration conf = TEST_UTIL.getConfiguration();
312 ZooKeeperWatcher zooKeeper = new ZooKeeperWatcher(conf,
313 "zkWatcher-NewServerDrainTest", abortable, true);
314 String baseZNode = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT,
315 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT);
316 String drainingZNode = ZKUtil.joinZNode(baseZNode,
317 conf.get("zookeeper.znode.draining.rs", "draining"));
318
319 MasterServices services = Mockito.mock(MasterServices.class);
320 HMaster master = Mockito.mock(HMaster.class);
321 Mockito.when(master.getConfiguration()).thenReturn(conf);
322
323 ServerName SERVERNAME_A = ServerName.valueOf("mockserverbulk_a.org", 1000, 8000);
324 ServerName SERVERNAME_B = ServerName.valueOf("mockserverbulk_b.org", 1001, 8000);
325 ServerName SERVERNAME_C = ServerName.valueOf("mockserverbulk_c.org", 1002, 8000);
326
327
328
329 ArrayList<ServerName> drainingServers = new ArrayList<ServerName>();
330 drainingServers.add(SERVERNAME_A);
331 drainingServers.add(SERVERNAME_B);
332
333
334
335
336 HashMap<ServerName, ServerLoad> onlineServers = new HashMap<ServerName, ServerLoad>();
337 onlineServers.put(SERVERNAME_A, ServerLoad.EMPTY_SERVERLOAD);
338 onlineServers.put(SERVERNAME_C, ServerLoad.EMPTY_SERVERLOAD);
339
340
341
342 for (ServerName sn : drainingServers) {
343 String znode = ZKUtil.joinZNode(drainingZNode, sn.getServerName());
344 ZKUtil.createAndFailSilent(zooKeeper, znode);
345 }
346
347
348
349 ServerManager serverManager = new ServerManager(master, services);
350
351 RegionServerTracker regionServerTracker = new RegionServerTracker(
352 zooKeeper, master, serverManager);
353 regionServerTracker.start();
354
355 DrainingServerTracker drainingServerTracker = new DrainingServerTracker(
356 zooKeeper, master, serverManager);
357 drainingServerTracker.start();
358
359
360 Assert.assertEquals(serverManager.getOnlineServers(),
361 new HashMap<ServerName, ServerLoad>());
362 Assert.assertEquals(serverManager.getDrainingServersList(),
363 new ArrayList<ServerName>());
364
365
366 ArrayList<ServerName> onlineDrainingServers = new ArrayList<ServerName>();
367 for (ServerName sn : onlineServers.keySet()){
368
369 serverManager.checkAndRecordNewServer(sn, onlineServers.get(sn));
370 if (drainingServers.contains(sn)){
371 onlineDrainingServers.add(sn);
372 }
373 }
374
375
376 Assert.assertEquals(serverManager.getOnlineServers(), onlineServers);
377 Assert.assertEquals(serverManager.getDrainingServersList(),
378 onlineDrainingServers);
379 }
380 }