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.regionserver; 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.HBaseTestingUtility; 029import org.apache.hadoop.hbase.ServerName; 030import org.apache.hadoop.hbase.testclassification.MediumTests; 031import org.apache.hadoop.hbase.testclassification.RegionServerTests; 032import org.apache.hadoop.hbase.zookeeper.MasterAddressTracker; 033import org.apache.hadoop.hbase.zookeeper.ZKListener; 034import org.apache.hadoop.hbase.zookeeper.ZKUtil; 035import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 036import org.apache.hadoop.hbase.zookeeper.ZNodePaths; 037import org.junit.After; 038import org.junit.AfterClass; 039import org.junit.BeforeClass; 040import org.junit.ClassRule; 041import org.junit.Rule; 042import org.junit.Test; 043import org.junit.experimental.categories.Category; 044import org.junit.rules.TestName; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048@Category({RegionServerTests.class, MediumTests.class}) 049public class TestMasterAddressTracker { 050 051 @ClassRule 052 public static final HBaseClassTestRule CLASS_RULE = 053 HBaseClassTestRule.forClass(TestMasterAddressTracker.class); 054 055 private static final Logger LOG = LoggerFactory.getLogger(TestMasterAddressTracker.class); 056 057 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 058 // Cleaned up after each unit test. 059 private static ZKWatcher zk; 060 061 @Rule 062 public TestName name = new TestName(); 063 064 @After 065 public void cleanUp() { 066 if (zk != null) { 067 zk.close(); 068 } 069 } 070 071 @BeforeClass 072 public static void setUpBeforeClass() throws Exception { 073 TEST_UTIL.startMiniZKCluster(); 074 } 075 076 @AfterClass 077 public static void tearDownAfterClass() throws Exception { 078 TEST_UTIL.shutdownMiniZKCluster(); 079 } 080 081 @Test 082 public void testDeleteIfEquals() throws Exception { 083 final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis()); 084 final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772); 085 try { 086 assertFalse("shouldn't have deleted wrong master server.", 087 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), "some other string.")); 088 } finally { 089 assertTrue("Couldn't clean up master", 090 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString())); 091 } 092 } 093 094 /** 095 * create an address tracker instance 096 * @param sn if not-null set the active master 097 * @param infoPort if there is an active master, set its info port. 098 */ 099 private MasterAddressTracker setupMasterTracker(final ServerName sn, final int infoPort) 100 throws Exception { 101 zk = new ZKWatcher(TEST_UTIL.getConfiguration(), 102 name.getMethodName(), null); 103 ZKUtil.createAndFailSilent(zk, zk.getZNodePaths().baseZNode); 104 ZKUtil.createAndFailSilent(zk, zk.getZNodePaths().backupMasterAddressesZNode); 105 106 // Should not have a master yet 107 MasterAddressTracker addressTracker = new MasterAddressTracker(zk, null); 108 addressTracker.start(); 109 assertFalse(addressTracker.hasMaster()); 110 zk.registerListener(addressTracker); 111 112 // Use a listener to capture when the node is actually created 113 NodeCreationListener listener = new NodeCreationListener(zk, 114 zk.getZNodePaths().masterAddressZNode); 115 zk.registerListener(listener); 116 117 if (sn != null) { 118 LOG.info("Creating master node"); 119 MasterAddressTracker.setMasterAddress(zk, zk.getZNodePaths().masterAddressZNode, 120 sn, infoPort); 121 122 // Wait for the node to be created 123 LOG.info("Waiting for master address manager to be notified"); 124 listener.waitForCreation(); 125 LOG.info("Master node created"); 126 } 127 return addressTracker; 128 } 129 130 /** 131 * Unit tests that uses ZooKeeper but does not use the master-side methods 132 * but rather acts directly on ZK. 133 * @throws Exception 134 */ 135 @Test 136 public void testMasterAddressTrackerFromZK() throws Exception { 137 // Create the master node with a dummy address 138 final int infoPort = 1235; 139 final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis()); 140 final MasterAddressTracker addressTracker = setupMasterTracker(sn, infoPort); 141 try { 142 assertTrue(addressTracker.hasMaster()); 143 ServerName pulledAddress = addressTracker.getMasterAddress(); 144 assertTrue(pulledAddress.equals(sn)); 145 assertEquals(infoPort, addressTracker.getMasterInfoPort()); 146 } finally { 147 assertTrue("Couldn't clean up master", 148 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString())); 149 } 150 } 151 152 153 @Test 154 public void testParsingNull() throws Exception { 155 assertNull("parse on null data should return null.", MasterAddressTracker.parse(null)); 156 } 157 158 @Test 159 public void testNoBackups() throws Exception { 160 final ServerName sn = ServerName.valueOf("localhost", 1234, System.currentTimeMillis()); 161 final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1772); 162 try { 163 assertEquals("Should receive 0 for backup not found.", 0, 164 addressTracker.getBackupMasterInfoPort( 165 ServerName.valueOf("doesnotexist.example.com", 1234, System.currentTimeMillis()))); 166 } finally { 167 assertTrue("Couldn't clean up master", 168 MasterAddressTracker.deleteIfEquals(addressTracker.getWatcher(), sn.toString())); 169 } 170 } 171 172 @Test 173 public void testNoMaster() throws Exception { 174 final MasterAddressTracker addressTracker = setupMasterTracker(null, 1772); 175 assertFalse(addressTracker.hasMaster()); 176 assertNull("should get null master when none active.", addressTracker.getMasterAddress()); 177 assertEquals("Should receive 0 for backup not found.", 0, addressTracker.getMasterInfoPort()); 178 } 179 180 @Test 181 public void testBackupMasters() throws Exception { 182 final ServerName sn = ServerName.valueOf("localhost", 5678, System.currentTimeMillis()); 183 final MasterAddressTracker addressTracker = setupMasterTracker(sn, 1111); 184 assertTrue(addressTracker.hasMaster()); 185 ServerName activeMaster = addressTracker.getMasterAddress(); 186 assertEquals(activeMaster, sn); 187 // No current backup masters 188 List<ServerName> backupMasters = addressTracker.getBackupMasters(); 189 assertEquals(0, backupMasters.size()); 190 ServerName backupMaster1 = ServerName.valueOf("localhost", 2222, -1); 191 ServerName backupMaster2 = ServerName.valueOf("localhost", 3333, -1); 192 String backupZNode1 = ZNodePaths.joinZNode( 193 zk.getZNodePaths().backupMasterAddressesZNode, backupMaster1.toString()); 194 String backupZNode2 = ZNodePaths.joinZNode( 195 zk.getZNodePaths().backupMasterAddressesZNode, backupMaster2.toString()); 196 // Add a backup master 197 MasterAddressTracker.setMasterAddress(zk, backupZNode1, backupMaster1, 2222); 198 MasterAddressTracker.setMasterAddress(zk, backupZNode2, backupMaster2, 3333); 199 backupMasters = addressTracker.getBackupMasters(); 200 assertEquals(2, backupMasters.size()); 201 assertTrue(backupMasters.contains(backupMaster1)); 202 assertTrue(backupMasters.contains(backupMaster2)); 203 } 204 205 public static class NodeCreationListener extends ZKListener { 206 private static final Logger LOG = LoggerFactory.getLogger(NodeCreationListener.class); 207 208 private Semaphore lock; 209 private String node; 210 211 public NodeCreationListener(ZKWatcher watcher, String node) { 212 super(watcher); 213 lock = new Semaphore(0); 214 this.node = node; 215 } 216 217 @Override 218 public void nodeCreated(String path) { 219 if(path.equals(node)) { 220 LOG.debug("nodeCreated(" + path + ")"); 221 lock.release(); 222 } 223 } 224 225 public void waitForCreation() throws InterruptedException { 226 lock.acquire(); 227 } 228 } 229 230} 231