001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.zookeeper; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNull; 023import static org.junit.Assert.assertTrue; 024 025import java.util.List; 026import java.util.concurrent.Semaphore; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HBaseZKTestingUtil; 029import org.apache.hadoop.hbase.ServerName; 030import org.apache.hadoop.hbase.testclassification.MediumTests; 031import org.apache.hadoop.hbase.testclassification.ZKTests; 032import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 033import org.junit.After; 034import org.junit.AfterClass; 035import org.junit.BeforeClass; 036import org.junit.ClassRule; 037import org.junit.Rule; 038import org.junit.Test; 039import org.junit.experimental.categories.Category; 040import org.junit.rules.TestName; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044@Category({ ZKTests.class, MediumTests.class }) 045public class TestMasterAddressTracker { 046 047 @ClassRule 048 public static final HBaseClassTestRule CLASS_RULE = 049 HBaseClassTestRule.forClass(TestMasterAddressTracker.class); 050 051 private static final Logger LOG = LoggerFactory.getLogger(TestMasterAddressTracker.class); 052 053 private final static HBaseZKTestingUtil TEST_UTIL = new HBaseZKTestingUtil(); 054 055 // Cleaned up after each unit test. 056 private ZKWatcher zk; 057 058 @Rule 059 public TestName name = new TestName(); 060 061 @After 062 public void cleanUp() { 063 if (zk != null) { 064 zk.close(); 065 } 066 } 067 068 @BeforeClass 069 public static void setUpBeforeClass() throws Exception { 070 TEST_UTIL.startMiniZKCluster(); 071 } 072 073 @AfterClass 074 public static void tearDownAfterClass() throws Exception { 075 TEST_UTIL.shutdownMiniZKCluster(); 076 } 077 078 @Test 079 public void testDeleteIfEquals() throws Exception { 080 final ServerName sn = 081 ServerName.valueOf("localhost", 1234, EnvironmentEdgeManager.currentTime()); 082 final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772); 083 try { 084 assertFalse("shouldn't have deleted wrong master server.", 085 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), "some other string.")); 086 } finally { 087 assertTrue("Couldn't clean up master", 088 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString())); 089 } 090 } 091 092 /** 093 * create an address tracker instance 094 * @param sn if not-null set the active master 095 * @param infoPort if there is an active master, set its info port. 096 */ 097 private MasterAddressTracker setupMasterTracker(final ServerName sn, final int infoPort) 098 throws Exception { 099 zk = new ZKWatcher(TEST_UTIL.getConfiguration(), name.getMethodName(), null); 100 ZKUtil.createAndFailSilent(zk, zk.getZNodePaths().baseZNode); 101 ZKUtil.createAndFailSilent(zk, zk.getZNodePaths().backupMasterAddressesZNode); 102 103 // Should not have a master yet 104 MasterAddressTracker addressTracker = new MasterAddressTracker(zk, null); 105 addressTracker.start(); 106 assertFalse(addressTracker.hasMaster()); 107 zk.registerListener(addressTracker); 108 109 // Use a listener to capture when the node is actually created 110 NodeCreationListener listener = 111 new NodeCreationListener(zk, zk.getZNodePaths().masterAddressZNode); 112 zk.registerListener(listener); 113 114 if (sn != null) { 115 LOG.info("Creating master node"); 116 MasterAddressTracker.setMasterAddress(zk, zk.getZNodePaths().masterAddressZNode, sn, 117 infoPort); 118 119 // Wait for the node to be created 120 LOG.info("Waiting for master address manager to be notified"); 121 listener.waitForCreation(); 122 LOG.info("Master node created"); 123 } 124 return addressTracker; 125 } 126 127 /** 128 * Unit tests that uses ZooKeeper but does not use the master-side methods but rather acts 129 * directly on ZK. 130 */ 131 @Test 132 public void testMasterAddressTrackerFromZK() throws Exception { 133 // Create the master node with a dummy address 134 final int infoPort = 1235; 135 final ServerName sn = 136 ServerName.valueOf("localhost", 1234, EnvironmentEdgeManager.currentTime()); 137 final MasterAddressTracker addressTracker = setupMasterTracker(sn, infoPort); 138 try { 139 assertTrue(addressTracker.hasMaster()); 140 ServerName pulledAddress = addressTracker.getMasterAddress(); 141 assertTrue(pulledAddress.equals(sn)); 142 assertEquals(infoPort, addressTracker.getMasterInfoPort()); 143 } finally { 144 assertTrue("Couldn't clean up master", 145 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString())); 146 } 147 } 148 149 @Test 150 public void testParsingNull() throws Exception { 151 assertNull("parse on null data should return null.", MasterAddressTracker.parse(null)); 152 } 153 154 @Test 155 public void testNoBackups() throws Exception { 156 final ServerName sn = 157 ServerName.valueOf("localhost", 1234, EnvironmentEdgeManager.currentTime()); 158 final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772); 159 try { 160 assertEquals("Should receive 0 for backup not found.", 0, 161 addressTracker.getBackupMasterInfoPort(ServerName.valueOf("doesnotexist.example.com", 1234, 162 EnvironmentEdgeManager.currentTime()))); 163 } finally { 164 assertTrue("Couldn't clean up master", 165 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString())); 166 } 167 } 168 169 @Test 170 public void testNoMaster() throws Exception { 171 final MasterAddressTracker addressTracker = setupMasterTracker(null, 1772); 172 assertFalse(addressTracker.hasMaster()); 173 assertNull("should get null master when none active.", addressTracker.getMasterAddress()); 174 assertEquals("Should receive 0 for backup not found.", 0, addressTracker.getMasterInfoPort()); 175 } 176 177 @Test 178 public void testBackupMasters() throws Exception { 179 final ServerName sn = 180 ServerName.valueOf("localhost", 5678, EnvironmentEdgeManager.currentTime()); 181 final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1111); 182 assertTrue(addressTracker.hasMaster()); 183 ServerName activeMaster = addressTracker.getMasterAddress(); 184 assertEquals(activeMaster, sn); 185 // No current backup masters 186 List<ServerName> backupMasters = addressTracker.getBackupMasters(); 187 assertEquals(0, backupMasters.size()); 188 ServerName backupMaster1 = ServerName.valueOf("localhost", 2222, -1); 189 ServerName backupMaster2 = ServerName.valueOf("localhost", 3333, -1); 190 String backupZNode1 = 191 ZNodePaths.joinZNode(zk.getZNodePaths().backupMasterAddressesZNode, backupMaster1.toString()); 192 String backupZNode2 = 193 ZNodePaths.joinZNode(zk.getZNodePaths().backupMasterAddressesZNode, backupMaster2.toString()); 194 // Add backup masters 195 MasterAddressTracker.setMasterAddress(zk, backupZNode1, backupMaster1, 2222); 196 MasterAddressTracker.setMasterAddress(zk, backupZNode2, backupMaster2, 3333); 197 TEST_UTIL.waitFor(30000, () -> addressTracker.getBackupMasters().size() == 2); 198 backupMasters = addressTracker.getBackupMasters(); 199 assertEquals(2, backupMasters.size()); 200 assertTrue(backupMasters.contains(backupMaster1)); 201 assertTrue(backupMasters.contains(backupMaster2)); 202 } 203 204 public static class NodeCreationListener extends ZKListener { 205 private static final Logger LOG = LoggerFactory.getLogger(NodeCreationListener.class); 206 207 private Semaphore lock; 208 private String node; 209 210 public NodeCreationListener(ZKWatcher watcher, String node) { 211 super(watcher); 212 lock = new Semaphore(0); 213 this.node = node; 214 } 215 216 @Override 217 public void nodeCreated(String path) { 218 if (path.equals(node)) { 219 LOG.debug("nodeCreated(" + path + ")"); 220 lock.release(); 221 } 222 } 223 224 public void waitForCreation() throws InterruptedException { 225 lock.acquire(); 226 } 227 } 228}