From 8acfa66897dc23138f4b0aa41852f50a44407664 Mon Sep 17 00:00:00 2001 From: Kihwal Lee Date: Tue, 29 Jan 2013 22:44:35 +0000 Subject: [PATCH] HDFS-4288. NN accepts incremental BR as IBR in safemode. contributed by Daryn Sharp. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1440192 13f79535-47bb-0310-9956-ffa450edef68 --- hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt | 2 + .../server/blockmanagement/BlockInfo.java | 6 +- .../server/blockmanagement/BlockManager.java | 6 +- .../blockmanagement/DatanodeDescriptor.java | 1 + .../blockmanagement/DatanodeManager.java | 2 +- .../blockmanagement/TestBlockManager.java | 69 +++++++++++++++++++ 6 files changed, 79 insertions(+), 7 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index c76af537680..b405bc4ba92 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -2233,6 +2233,8 @@ Release 0.23.7 - UNRELEASED BUG FIXES + HDFS-4288. NN accepts incremental BR as IBR in safemode (daryn via kihwal) + Release 0.23.6 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockInfo.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockInfo.java index e08af3dd408..0be6b26308a 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockInfo.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockInfo.java @@ -88,11 +88,7 @@ public class BlockInfo extends Block implements LightWeightGSet.LinkedElement { DatanodeDescriptor getDatanode(int index) { assert this.triplets != null : "BlockInfo is not initialized"; assert index >= 0 && index*3 < triplets.length : "Index is out of bound"; - DatanodeDescriptor node = (DatanodeDescriptor)triplets[index*3]; - assert node == null || - DatanodeDescriptor.class.getName().equals(node.getClass().getName()) : - "DatanodeDescriptor is expected at " + index*3; - return node; + return (DatanodeDescriptor)triplets[index*3]; } private BlockInfo getPrevious(int index) { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManager.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManager.java index c56f353db35..2d08bc4b690 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManager.java @@ -62,6 +62,7 @@ import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.ReplicaState; import org.apache.hadoop.hdfs.server.namenode.FSClusterStats; import org.apache.hadoop.hdfs.server.namenode.NameNode; import org.apache.hadoop.hdfs.server.namenode.Namesystem; +import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics; import org.apache.hadoop.hdfs.server.protocol.BlockCommand; import org.apache.hadoop.hdfs.server.protocol.BlocksWithLocations; import org.apache.hadoop.hdfs.server.protocol.BlocksWithLocations.BlockWithLocations; @@ -1576,7 +1577,10 @@ public class BlockManager { } // Log the block report processing stats from Namenode perspective - NameNode.getNameNodeMetrics().addBlockReport((int) (endTime - startTime)); + final NameNodeMetrics metrics = NameNode.getNameNodeMetrics(); + if (metrics != null) { + metrics.addBlockReport((int) (endTime - startTime)); + } blockLog.info("BLOCK* processReport: from " + nodeID + ", blocks: " + newReport.getNumberOfBlocks() + ", processing time: " + (endTime - startTime) + " msecs"); diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeDescriptor.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeDescriptor.java index a0f445a93b0..c542ae343e1 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeDescriptor.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeDescriptor.java @@ -547,6 +547,7 @@ public class DatanodeDescriptor extends DatanodeInfo { @Override public void updateRegInfo(DatanodeID nodeReg) { super.updateRegInfo(nodeReg); + firstBlockReport = true; // must re-process IBR after re-registration } /** diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java index 93bf5ff0ab8..e0a81e0d407 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/DatanodeManager.java @@ -419,7 +419,7 @@ public class DatanodeManager { } /** Add a datanode. */ - private void addDatanode(final DatanodeDescriptor node) { + void addDatanode(final DatanodeDescriptor node) { // To keep host2DatanodeMap consistent with datanodeMap, // remove from host2DatanodeMap the datanodeDescriptor removed // from datanodeMap before adding node to host2DatanodeMap. diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/TestBlockManager.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/TestBlockManager.java index b9811e7e5e5..e88ec92e39b 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/TestBlockManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/blockmanagement/TestBlockManager.java @@ -34,13 +34,16 @@ import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DFSTestUtil; import org.apache.hadoop.hdfs.HdfsConfiguration; import org.apache.hadoop.hdfs.protocol.Block; +import org.apache.hadoop.hdfs.protocol.BlockListAsLongs; import org.apache.hadoop.hdfs.protocol.HdfsConstants; import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor.BlockTargetPair; import org.apache.hadoop.hdfs.server.namenode.FSNamesystem; +import org.apache.hadoop.hdfs.server.protocol.DatanodeRegistration; import org.apache.hadoop.net.NetworkTopology; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import static org.mockito.Mockito.*; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; @@ -485,4 +488,70 @@ public class TestBlockManager { new NumberReplicas(), UnderReplicatedBlocks.QUEUE_HIGHEST_PRIORITY)); } + + @Test + public void testSafeModeIBR() throws Exception { + DatanodeDescriptor node = spy(nodes.get(0)); + node.setStorageID("dummy-storage"); + node.isAlive = true; + + DatanodeRegistration nodeReg = + new DatanodeRegistration(node, null, null, ""); + + // pretend to be in safemode + doReturn(true).when(fsn).isInStartupSafeMode(); + + // register new node + bm.getDatanodeManager().registerDatanode(nodeReg); + bm.getDatanodeManager().addDatanode(node); // swap in spy + assertEquals(node, bm.getDatanodeManager().getDatanode(node)); + assertTrue(node.isFirstBlockReport()); + // send block report, should be processed + reset(node); + bm.processReport(node, "pool", new BlockListAsLongs(null, null)); + verify(node).receivedBlockReport(); + assertFalse(node.isFirstBlockReport()); + // send block report again, should NOT be processed + reset(node); + bm.processReport(node, "pool", new BlockListAsLongs(null, null)); + verify(node, never()).receivedBlockReport(); + assertFalse(node.isFirstBlockReport()); + + // re-register as if node restarted, should update existing node + bm.getDatanodeManager().removeDatanode(node); + reset(node); + bm.getDatanodeManager().registerDatanode(nodeReg); + verify(node).updateRegInfo(nodeReg); + assertTrue(node.isFirstBlockReport()); // ready for report again + // send block report, should be processed after restart + reset(node); + bm.processReport(node, "pool", new BlockListAsLongs(null, null)); + verify(node).receivedBlockReport(); + assertFalse(node.isFirstBlockReport()); + } + + @Test + public void testSafeModeIBRAfterIncremental() throws Exception { + DatanodeDescriptor node = spy(nodes.get(0)); + node.setStorageID("dummy-storage"); + node.isAlive = true; + + DatanodeRegistration nodeReg = + new DatanodeRegistration(node, null, null, ""); + + // pretend to be in safemode + doReturn(true).when(fsn).isInStartupSafeMode(); + + // register new node + bm.getDatanodeManager().registerDatanode(nodeReg); + bm.getDatanodeManager().addDatanode(node); // swap in spy + assertEquals(node, bm.getDatanodeManager().getDatanode(node)); + assertTrue(node.isFirstBlockReport()); + // send block report while pretending to already have blocks + reset(node); + doReturn(1).when(node).numBlocks(); + bm.processReport(node, "pool", new BlockListAsLongs(null, null)); + verify(node).receivedBlockReport(); + assertFalse(node.isFirstBlockReport()); + } }