1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27
28 import java.io.IOException;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.util.List;
32 import java.util.Map;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.hadoop.conf.Configuration;
37 import org.apache.hadoop.hbase.client.Admin;
38 import org.apache.hadoop.hbase.client.Get;
39 import org.apache.hadoop.hbase.client.HConnection;
40 import org.apache.hadoop.hbase.client.HConnectionManager;
41 import org.apache.hadoop.hbase.client.HTable;
42 import org.apache.hadoop.hbase.client.Put;
43 import org.apache.hadoop.hbase.client.Result;
44 import org.apache.hadoop.hbase.client.ResultScanner;
45 import org.apache.hadoop.hbase.client.Scan;
46 import org.apache.hadoop.hbase.client.Table;
47 import org.apache.hadoop.hbase.coordination.ZkSplitLogWorkerCoordination;
48 import org.apache.hadoop.hbase.master.HMaster;
49 import org.apache.hadoop.hbase.master.LoadBalancer;
50 import org.apache.hadoop.hbase.master.balancer.SimpleLoadBalancer;
51 import org.apache.hadoop.hbase.testclassification.LargeTests;
52 import org.apache.hadoop.hbase.util.Bytes;
53 import org.apache.hadoop.hbase.util.FSUtils;
54 import org.apache.hadoop.hbase.util.Threads;
55 import org.apache.hadoop.hbase.zookeeper.EmptyWatcher;
56 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
57 import org.apache.hadoop.hbase.zookeeper.ZKConfig;
58 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
59 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
60 import org.apache.zookeeper.CreateMode;
61 import org.apache.zookeeper.KeeperException;
62 import org.apache.zookeeper.ZooDefs;
63 import org.apache.zookeeper.ZooKeeper;
64 import org.apache.zookeeper.ZooKeeper.States;
65 import org.apache.zookeeper.data.ACL;
66 import org.apache.zookeeper.data.Stat;
67 import org.junit.After;
68 import org.junit.AfterClass;
69 import org.junit.Assert;
70 import org.junit.Before;
71 import org.junit.BeforeClass;
72 import org.junit.Ignore;
73 import org.junit.Test;
74 import org.junit.experimental.categories.Category;
75
76
77
78 @Category(LargeTests.class)
79 public class TestZooKeeper {
80 private static final Log LOG = LogFactory.getLog(TestZooKeeper.class);
81
82 private final static HBaseTestingUtility
83 TEST_UTIL = new HBaseTestingUtility();
84
85
86
87
88 @BeforeClass
89 public static void setUpBeforeClass() throws Exception {
90
91 Configuration conf = TEST_UTIL.getConfiguration();
92 TEST_UTIL.startMiniDFSCluster(2);
93 TEST_UTIL.startMiniZKCluster();
94 conf.setBoolean("dfs.support.append", true);
95 conf.setInt(HConstants.ZK_SESSION_TIMEOUT, 1000);
96 conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, MockLoadBalancer.class,
97 LoadBalancer.class);
98 }
99
100
101
102
103 @AfterClass
104 public static void tearDownAfterClass() throws Exception {
105 TEST_UTIL.shutdownMiniCluster();
106 }
107
108
109
110
111 @Before
112 public void setUp() throws Exception {
113 TEST_UTIL.startMiniHBaseCluster(2, 2);
114 }
115
116 @After
117 public void after() throws Exception {
118 try {
119
120
121 TEST_UTIL.getHBaseCluster().killAll();
122
123
124 TEST_UTIL.shutdownMiniHBaseCluster();
125 } finally {
126 TEST_UTIL.getTestFileSystem().delete(FSUtils.getRootDir(TEST_UTIL.getConfiguration()), true);
127 ZKUtil.deleteNodeRecursively(TEST_UTIL.getZooKeeperWatcher(), "/hbase");
128 }
129 }
130
131 private ZooKeeperWatcher getZooKeeperWatcher(HConnection c)
132 throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
133 Method getterZK = c.getClass().getDeclaredMethod("getKeepAliveZooKeeperWatcher");
134 getterZK.setAccessible(true);
135 return (ZooKeeperWatcher) getterZK.invoke(c);
136 }
137
138
139
140
141
142
143
144
145 @Ignore
146 @Test
147 public void testClientSessionExpired() throws Exception {
148 Configuration c = new Configuration(TEST_UTIL.getConfiguration());
149
150
151 c.set(HConstants.HBASE_CLIENT_INSTANCE_ID, "1111");
152
153 HConnection connection = HConnectionManager.getConnection(c);
154
155 ZooKeeperWatcher connectionZK = getZooKeeperWatcher(connection);
156 LOG.info("ZooKeeperWatcher= 0x"+ Integer.toHexString(
157 connectionZK.hashCode()));
158 LOG.info("getRecoverableZooKeeper= 0x"+ Integer.toHexString(
159 connectionZK.getRecoverableZooKeeper().hashCode()));
160 LOG.info("session="+Long.toHexString(
161 connectionZK.getRecoverableZooKeeper().getSessionId()));
162
163 TEST_UTIL.expireSession(connectionZK);
164
165 LOG.info("Before using zkw state=" +
166 connectionZK.getRecoverableZooKeeper().getState());
167
168 try {
169 connectionZK.getRecoverableZooKeeper().getZooKeeper().exists(
170 "/1/1", false);
171 } catch (KeeperException ignored) {
172 }
173
174
175 States state = connectionZK.getRecoverableZooKeeper().getState();
176 LOG.info("After using zkw state=" + state);
177 LOG.info("session="+Long.toHexString(
178 connectionZK.getRecoverableZooKeeper().getSessionId()));
179
180
181 final long limit1 = System.currentTimeMillis() + 3000;
182 while (System.currentTimeMillis() < limit1 && state != States.CLOSED){
183 state = connectionZK.getRecoverableZooKeeper().getState();
184 }
185 LOG.info("After using zkw loop=" + state);
186 LOG.info("ZooKeeper should have timed out");
187 LOG.info("session="+Long.toHexString(
188 connectionZK.getRecoverableZooKeeper().getSessionId()));
189
190
191
192
193
194
195
196 ZooKeeperWatcher newConnectionZK = getZooKeeperWatcher(connection);
197
198 States state2 = newConnectionZK.getRecoverableZooKeeper().getState();
199 LOG.info("After new get state=" +state2);
200
201
202
203 final long limit2 = System.currentTimeMillis() + 3000;
204 while (System.currentTimeMillis() < limit2 &&
205 state2 != States.CONNECTED && state2 != States.CONNECTING) {
206
207 newConnectionZK = getZooKeeperWatcher(connection);
208 state2 = newConnectionZK.getRecoverableZooKeeper().getState();
209 }
210 LOG.info("After new get state loop=" + state2);
211
212 Assert.assertTrue(
213 state2 == States.CONNECTED || state2 == States.CONNECTING);
214
215 connection.close();
216 }
217
218 @Test (timeout = 120000)
219 public void testRegionServerSessionExpired() throws Exception {
220 LOG.info("Starting testRegionServerSessionExpired");
221 TEST_UTIL.expireRegionServerSession(0);
222 testSanity("testRegionServerSessionExpired");
223 }
224
225 @Test(timeout = 300000)
226 public void testMasterSessionExpired() throws Exception {
227 LOG.info("Starting testMasterSessionExpired");
228 TEST_UTIL.expireMasterSession();
229 testSanity("testMasterSessionExpired");
230 }
231
232
233
234
235
236
237 @Test(timeout = 300000)
238 public void testMasterZKSessionRecoveryFailure() throws Exception {
239 LOG.info("Starting testMasterZKSessionRecoveryFailure");
240 MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
241 HMaster m = cluster.getMaster();
242 m.abort("Test recovery from zk session expired",
243 new KeeperException.SessionExpiredException());
244 assertTrue(m.isStopped());
245 testSanity("testMasterZKSessionRecoveryFailure");
246 }
247
248
249
250
251
252 private void testSanity(final String testName) throws Exception{
253 String tableName = testName + "_" + System.currentTimeMillis();
254 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
255 HColumnDescriptor family = new HColumnDescriptor("fam");
256 desc.addFamily(family);
257 LOG.info("Creating table " + tableName);
258 Admin admin = TEST_UTIL.getHBaseAdmin();
259 try {
260 admin.createTable(desc);
261 } finally {
262 admin.close();
263 }
264
265 Table table =
266 new HTable(new Configuration(TEST_UTIL.getConfiguration()), desc.getTableName());
267 Put put = new Put(Bytes.toBytes("testrow"));
268 put.add(Bytes.toBytes("fam"),
269 Bytes.toBytes("col"), Bytes.toBytes("testdata"));
270 LOG.info("Putting table " + tableName);
271 table.put(put);
272 table.close();
273 }
274
275 @Test
276 public void testMultipleZK()
277 throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
278 Table localMeta =
279 new HTable(new Configuration(TEST_UTIL.getConfiguration()), TableName.META_TABLE_NAME);
280 Configuration otherConf = new Configuration(TEST_UTIL.getConfiguration());
281 otherConf.set(HConstants.ZOOKEEPER_QUORUM, "127.0.0.1");
282 Table ipMeta = new HTable(otherConf, TableName.META_TABLE_NAME);
283
284
285 final byte [] row = new byte [] {'r'};
286 localMeta.exists(new Get(row));
287 ipMeta.exists(new Get(row));
288
289
290 ZooKeeperWatcher z1 =
291 getZooKeeperWatcher(HConnectionManager.getConnection(localMeta.getConfiguration()));
292 ZooKeeperWatcher z2 =
293 getZooKeeperWatcher(HConnectionManager.getConnection(otherConf));
294 assertFalse(z1 == z2);
295 assertFalse(z1.getQuorum().equals(z2.getQuorum()));
296
297 localMeta.close();
298 ipMeta.close();
299 }
300
301
302
303
304
305 @Test
306 public void testCreateWithParents() throws Exception {
307 ZooKeeperWatcher zkw =
308 new ZooKeeperWatcher(new Configuration(TEST_UTIL.getConfiguration()),
309 TestZooKeeper.class.getName(), null);
310 byte[] expectedData = new byte[] { 1, 2, 3 };
311 ZKUtil.createWithParents(zkw, "/l1/l2/l3/l4/testCreateWithParents", expectedData);
312 byte[] data = ZKUtil.getData(zkw, "/l1/l2/l3/l4/testCreateWithParents");
313 assertTrue(Bytes.equals(expectedData, data));
314 ZKUtil.deleteNodeRecursively(zkw, "/l1");
315
316 ZKUtil.createWithParents(zkw, "/testCreateWithParents", expectedData);
317 data = ZKUtil.getData(zkw, "/testCreateWithParents");
318 assertTrue(Bytes.equals(expectedData, data));
319 ZKUtil.deleteNodeRecursively(zkw, "/testCreateWithParents");
320 }
321
322
323
324
325
326
327 @Test
328 public void testZNodeDeletes() throws Exception {
329 ZooKeeperWatcher zkw = new ZooKeeperWatcher(
330 new Configuration(TEST_UTIL.getConfiguration()),
331 TestZooKeeper.class.getName(), null);
332 ZKUtil.createWithParents(zkw, "/l1/l2/l3/l4");
333 try {
334 ZKUtil.deleteNode(zkw, "/l1/l2");
335 fail("We should not be able to delete if znode has childs");
336 } catch (KeeperException ex) {
337 assertNotNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2/l3/l4", null));
338 }
339 ZKUtil.deleteNodeRecursively(zkw, "/l1/l2");
340
341 assertNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2/l3/l4", null));
342
343
344 ZKUtil.deleteNodeRecursively(zkw, "/l1/l2");
345
346 ZKUtil.deleteNode(zkw, "/l1");
347 assertNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2", null));
348 }
349
350
351
352
353
354
355
356
357 @Test
358 public void testCreateSilentIsReallySilent() throws InterruptedException,
359 KeeperException, IOException {
360 Configuration c = TEST_UTIL.getConfiguration();
361
362 String aclZnode = "/aclRoot";
363 String quorumServers = ZKConfig.getZKQuorumServersString(c);
364 int sessionTimeout = 5 * 1000;
365 ZooKeeper zk = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance);
366 zk.addAuthInfo("digest", "hbase:rox".getBytes());
367
368
369
370 ZooKeeperWatcher zk2 = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
371 "testCreateSilentIsReallySilent", null);
372
373
374 Stat s = null;
375 List<ACL> oldACL = null;
376 while (true) {
377 try {
378 s = new Stat();
379 oldACL = zk.getACL("/", s);
380 break;
381 } catch (KeeperException e) {
382 switch (e.code()) {
383 case CONNECTIONLOSS:
384 case SESSIONEXPIRED:
385 case OPERATIONTIMEOUT:
386 LOG.warn("Possibly transient ZooKeeper exception", e);
387 Threads.sleep(100);
388 break;
389 default:
390 throw e;
391 }
392 }
393 }
394
395
396
397 while (true) {
398 try {
399 zk.setACL("/", ZooDefs.Ids.CREATOR_ALL_ACL, -1);
400 break;
401 } catch (KeeperException e) {
402 switch (e.code()) {
403 case CONNECTIONLOSS:
404 case SESSIONEXPIRED:
405 case OPERATIONTIMEOUT:
406 LOG.warn("Possibly transient ZooKeeper exception: " + e);
407 Threads.sleep(100);
408 break;
409 default:
410 throw e;
411 }
412 }
413 }
414
415 while (true) {
416 try {
417 zk.create(aclZnode, null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
418 break;
419 } catch (KeeperException e) {
420 switch (e.code()) {
421 case CONNECTIONLOSS:
422 case SESSIONEXPIRED:
423 case OPERATIONTIMEOUT:
424 LOG.warn("Possibly transient ZooKeeper exception: " + e);
425 Threads.sleep(100);
426 break;
427 default:
428 throw e;
429 }
430 }
431 }
432 zk.close();
433 ZKUtil.createAndFailSilent(zk2, aclZnode);
434
435
436 ZooKeeper zk3 = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance);
437 zk3.addAuthInfo("digest", "hbase:rox".getBytes());
438 try {
439 zk3.setACL("/", oldACL, -1);
440 } finally {
441 zk3.close();
442 }
443 }
444
445
446
447
448
449 @Test
450 @SuppressWarnings("deprecation")
451 public void testGetChildDataAndWatchForNewChildrenShouldNotThrowNPE()
452 throws Exception {
453 ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
454 "testGetChildDataAndWatchForNewChildrenShouldNotThrowNPE", null);
455 ZKUtil.getChildDataAndWatchForNewChildren(zkw, "/wrongNode");
456 }
457
458
459
460
461
462
463 @Test(timeout = 300000)
464 public void testRegionAssignmentAfterMasterRecoveryDueToZKExpiry() throws Exception {
465 MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
466 cluster.startRegionServer();
467 cluster.waitForActiveAndReadyMaster(10000);
468 HMaster m = cluster.getMaster();
469 final ZooKeeperWatcher zkw = m.getZooKeeper();
470
471 try (Admin admin = TEST_UTIL.getHBaseAdmin()) {
472 byte[][] SPLIT_KEYS = new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b"),
473 Bytes.toBytes("c"), Bytes.toBytes("d"), Bytes.toBytes("e"), Bytes.toBytes("f"),
474 Bytes.toBytes("g"), Bytes.toBytes("h"), Bytes.toBytes("i"), Bytes.toBytes("j") };
475 String tableName = "testRegionAssignmentAfterMasterRecoveryDueToZKExpiry";
476 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(tableName));
477 htd.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
478 admin.createTable(htd, SPLIT_KEYS);
479 TEST_UTIL.waitUntilNoRegionsInTransition(60000);
480 m.getZooKeeper().close();
481 MockLoadBalancer.retainAssignCalled = false;
482 final int expectedNumOfListeners = countPermanentListeners(zkw);
483 m.abort("Test recovery from zk session expired",
484 new KeeperException.SessionExpiredException());
485 assertTrue(m.isStopped());
486
487
488 assertFalse("Retain assignment should not be called", MockLoadBalancer.retainAssignCalled);
489
490
491 cluster.waitForActiveAndReadyMaster(120000);
492 final HMaster newMaster = cluster.getMasterThread().getMaster();
493 assertEquals(expectedNumOfListeners, countPermanentListeners(newMaster.getZooKeeper()));
494 }
495 }
496
497
498
499
500
501 private int countPermanentListeners(ZooKeeperWatcher watcher) {
502 return countListeners(watcher, ZkSplitLogWorkerCoordination.class);
503 }
504
505
506
507
508 private int countListeners(ZooKeeperWatcher watcher, Class<?>... exclude) {
509 int cnt = 0;
510 for (Object o : watcher.getListeners()) {
511 boolean skip = false;
512 for (Class<?> aClass : exclude) {
513 if (aClass.isAssignableFrom(o.getClass())) {
514 skip = true;
515 break;
516 }
517 }
518 if (!skip) {
519 cnt += 1;
520 }
521 }
522 return cnt;
523 }
524
525
526
527
528
529
530 @Test(timeout = 300000)
531 public void testLogSplittingAfterMasterRecoveryDueToZKExpiry() throws IOException,
532 KeeperException, InterruptedException {
533 MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
534 cluster.startRegionServer();
535 HMaster m = cluster.getMaster();
536
537 Admin admin = TEST_UTIL.getHBaseAdmin();
538 Table table = null;
539 try {
540 byte[][] SPLIT_KEYS = new byte[][] { Bytes.toBytes("1"), Bytes.toBytes("2"),
541 Bytes.toBytes("3"), Bytes.toBytes("4"), Bytes.toBytes("5") };
542
543 String tableName = "testLogSplittingAfterMasterRecoveryDueToZKExpiry";
544 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(tableName));
545 HColumnDescriptor hcd = new HColumnDescriptor("col");
546 htd.addFamily(hcd);
547 admin.createTable(htd, SPLIT_KEYS);
548 ZooKeeperWatcher zooKeeperWatcher = HBaseTestingUtility.getZooKeeperWatcher(TEST_UTIL);
549 ZKAssign.blockUntilNoRIT(zooKeeperWatcher);
550 table = new HTable(TEST_UTIL.getConfiguration(), htd.getTableName());
551 Put p;
552 int numberOfPuts;
553 for (numberOfPuts = 0; numberOfPuts < 6; numberOfPuts++) {
554 p = new Put(Bytes.toBytes(numberOfPuts));
555 p.add(Bytes.toBytes("col"), Bytes.toBytes("ql"), Bytes.toBytes("value" + numberOfPuts));
556 table.put(p);
557 }
558 m.getZooKeeper().close();
559 m.abort("Test recovery from zk session expired",
560 new KeeperException.SessionExpiredException());
561 assertTrue(m.isStopped());
562 cluster.getRegionServer(0).abort("Aborting");
563
564
565 Scan scan = new Scan();
566 int numberOfRows = 0;
567 ResultScanner scanner = table.getScanner(scan);
568 Result[] result = scanner.next(1);
569 while (result != null && result.length > 0) {
570 numberOfRows++;
571 result = scanner.next(1);
572 }
573 assertEquals("Number of rows should be equal to number of puts.", numberOfPuts,
574 numberOfRows);
575 } finally {
576 if (table != null) table.close();
577 admin.close();
578 }
579 }
580
581 static class MockLoadBalancer extends SimpleLoadBalancer {
582 static boolean retainAssignCalled = false;
583
584 @Override
585 public Map<ServerName, List<HRegionInfo>> retainAssignment(
586 Map<HRegionInfo, ServerName> regions, List<ServerName> servers) {
587 retainAssignCalled = true;
588 return super.retainAssignment(regions, servers);
589 }
590 }
591
592 }
593