package org.apache.hadoop.hdfs.server.namenode; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hdfs.protocol.DatanodeID; import org.apache.hadoop.hdfs.server.namenode.StandbySafeMode.SafeModeState; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class TestStandbySafeModeImpl { private static StandbySafeMode safeMode; private static Configuration conf; private static MyNamesystem namesystem; private static final Random random = new Random(); private static Log LOG = LogFactory .getLog(TestStandbySafeModeImpl.class); private class MyNamesystem extends FSNamesystem { public long totalBlocks = 0; @Override public long getBlocksTotal() { return totalBlocks; } } @Before public void setUp() throws Exception { conf = new Configuration(); namesystem = new MyNamesystem(); safeMode = new StandbySafeMode(conf, namesystem); } private DatanodeID generateRandomDatanodeID() { String nodeName = "" + random.nextLong(); return new DatanodeID(nodeName); } @Test public void testBlocks() throws Exception { assertTrue(safeMode.isOn()); assertFalse(safeMode.canLeave()); namesystem.totalBlocks = 100; namesystem.blocksSafe = 100; assertFalse(safeMode.canLeave()); safeMode.setSafeModeStateForTesting(SafeModeState.FAILOVER_IN_PROGRESS); assertTrue(safeMode.canLeave()); } @Test public void testReports() throws Exception { assertTrue(safeMode.isOn()); assertFalse(safeMode.canLeave()); int totalNodes = 100; List <DatanodeID> datanodes = new ArrayList<DatanodeID>(); for (int i = 0; i < totalNodes; i++) { DatanodeID node = generateRandomDatanodeID(); datanodes.add(node); safeMode.reportHeartBeat(node); } for (DatanodeID node : datanodes) { safeMode.reportPrimaryCleared(node); } assertFalse(safeMode.canLeave()); safeMode.setSafeModeStateForTesting(SafeModeState.FAILOVER_IN_PROGRESS); assertTrue(safeMode.canLeave()); } @Test public void testEarlyExit() throws Exception { namesystem.totalBlocks = 100; namesystem.blocksSafe = 100; try { safeMode.leave(false); } catch (RuntimeException e) { LOG.info("Expected exception", e); return; } fail("Did not throw " + SafeModeException.class); } @Test public void testRandomReports() throws Exception { int totalNodes = 10; List <DatanodeID> datanodes = new ArrayList<DatanodeID>(); for (int i = 0; i < totalNodes; i++) { DatanodeID node = generateRandomDatanodeID(); datanodes.add(node); } assertFalse(safeMode.canLeave()); safeMode.setSafeModeStateForTesting(SafeModeState.FAILOVER_IN_PROGRESS); Set<DatanodeID> expectedR = new HashSet<DatanodeID>(); Set<DatanodeID> expectedH = new HashSet<DatanodeID>(); for (DatanodeID node : datanodes) { // Add live node. if (random.nextBoolean()) { safeMode.addLiveNodeForTesting(node); expectedH.add(node); } // Report heartbeat. if (random.nextBoolean()) { int times = 1; // random.nextInt(3); for (int i = 0; i < times; i++) { safeMode.reportHeartBeat(node); expectedR.add(node); expectedH.remove(node); } } // Report primaryClear. if (random.nextBoolean()) { int times = 1;// random.nextInt(3); for (int i = 0; i < times; i++) { safeMode.reportPrimaryCleared(node); expectedR.remove(node); } } } LOG.info("expected : " + expectedR.size() + " actual : " + safeMode.getOutStandingReports().size()); LOG.info("expected : " + expectedH.size() + " actual : " + safeMode.getOutStandingHeartbeats().size()); assertTrue(expectedR.equals(safeMode.getOutStandingReports())); assertTrue(expectedH.equals(safeMode.getOutStandingHeartbeats())); if (expectedR.size() == 0 && expectedH.size() == 0) { assertTrue(safeMode.canLeave()); } else { assertFalse(safeMode.canLeave()); } } @Test public void testBlocksNotSufficient() { namesystem.totalBlocks = 100; namesystem.blocksSafe = 50; int totalNodes = 100; List<DatanodeID> datanodes = new ArrayList<DatanodeID>(); for (int i = 0; i < totalNodes; i++) { DatanodeID node = generateRandomDatanodeID(); datanodes.add(node); safeMode.reportHeartBeat(node); safeMode.reportPrimaryCleared(node); } assertFalse(safeMode.canLeave()); safeMode.setSafeModeStateForTesting(SafeModeState.FAILOVER_IN_PROGRESS); assertFalse(safeMode.canLeave()); } @Test public void testReportsNotSufficient() { namesystem.totalBlocks = 100; namesystem.blocksSafe = 100; assertFalse(safeMode.canLeave()); safeMode.setSafeModeStateForTesting(SafeModeState.FAILOVER_IN_PROGRESS); int totalNodes = 100; List<DatanodeID> datanodes = new ArrayList<DatanodeID>(); for (int i = 0; i < totalNodes; i++) { DatanodeID node = generateRandomDatanodeID(); datanodes.add(node); safeMode.reportHeartBeat(node); if (random.nextBoolean()) { safeMode.reportPrimaryCleared(node); } } assertFalse(safeMode.canLeave()); } @Test public void testAllSufficient() { namesystem.totalBlocks = 100; namesystem.blocksSafe = 100; assertFalse(safeMode.canLeave()); safeMode.setSafeModeStateForTesting(SafeModeState.FAILOVER_IN_PROGRESS); int totalNodes = 100; List<DatanodeID> datanodes = new ArrayList<DatanodeID>(); for (int i = 0; i < totalNodes; i++) { DatanodeID node = generateRandomDatanodeID(); datanodes.add(node); safeMode.reportHeartBeat(node); safeMode.reportPrimaryCleared(node); } assertTrue(safeMode.canLeave()); } }