|
@@ -21,8 +21,11 @@ import static org.junit.Assert.assertEquals;
|
|
|
import static org.junit.Assert.assertFalse;
|
|
|
import static org.junit.Assert.assertNotNull;
|
|
|
import static org.junit.Assert.assertTrue;
|
|
|
-
|
|
|
+import static org.mockito.Matchers.any;
|
|
|
+import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.when;
|
|
|
import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.HashMap;
|
|
@@ -31,6 +34,7 @@ import java.util.Map;
|
|
|
import java.util.Random;
|
|
|
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.fs.ContentSummary;
|
|
|
import org.apache.hadoop.fs.FileSystem;
|
|
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
|
|
import org.apache.hadoop.hdfs.DFSTestUtil;
|
|
@@ -40,9 +44,13 @@ import org.apache.hadoop.hdfs.LogVerificationAppender;
|
|
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
|
|
import org.apache.hadoop.hdfs.protocol.Block;
|
|
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
|
|
+import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState;
|
|
|
+import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.ReplicaState;
|
|
|
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
|
|
import org.apache.hadoop.hdfs.server.datanode.DataNodeTestUtils;
|
|
|
+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.net.NetworkTopology;
|
|
|
import org.apache.hadoop.net.Node;
|
|
|
import org.apache.hadoop.util.Time;
|
|
@@ -1004,4 +1012,185 @@ public class TestReplicationPolicy {
|
|
|
exception.expect(IllegalArgumentException.class);
|
|
|
blocksReplWorkMultiplier = DFSUtil.getReplWorkMultiplier(conf);
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ @Test(timeout = 60000)
|
|
|
+ public void testUpdateDoesNotCauseSkippedReplication() {
|
|
|
+ UnderReplicatedBlocks underReplicatedBlocks = new UnderReplicatedBlocks();
|
|
|
+
|
|
|
+ Block block1 = new Block(random.nextLong());
|
|
|
+ Block block2 = new Block(random.nextLong());
|
|
|
+ Block block3 = new Block(random.nextLong());
|
|
|
+
|
|
|
+ // Adding QUEUE_VERY_UNDER_REPLICATED block
|
|
|
+ final int block1CurReplicas = 2;
|
|
|
+ final int block1ExpectedReplicas = 7;
|
|
|
+ underReplicatedBlocks.add(block1, block1CurReplicas, 0,
|
|
|
+ block1ExpectedReplicas);
|
|
|
+
|
|
|
+ // Adding QUEUE_VERY_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block2, 2, 0, 7);
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block3, 2, 0, 6);
|
|
|
+
|
|
|
+ List<List<Block>> chosenBlocks;
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 0, 1, 0, 0, 0);
|
|
|
+
|
|
|
+ // Increasing the replications will move the block down a
|
|
|
+ // priority. This simulates a replica being completed in between checks.
|
|
|
+ underReplicatedBlocks.update(block1, block1CurReplicas+1, 0,
|
|
|
+ block1ExpectedReplicas, 1, 0);
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ // This block was moved up a priority and should not be skipped over.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 0, 1, 0, 0, 0);
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_UNDER_REPLICATED.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 0, 0, 1, 0, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test(timeout = 60000)
|
|
|
+ public void testAddStoredBlockDoesNotCauseSkippedReplication()
|
|
|
+ throws IOException {
|
|
|
+ Namesystem mockNS = mock(Namesystem.class);
|
|
|
+ when(mockNS.isPopulatingReplQueues()).thenReturn(true);
|
|
|
+ when(mockNS.hasWriteLock()).thenReturn(true);
|
|
|
+ FSClusterStats mockStats = mock(FSClusterStats.class);
|
|
|
+ BlockManager bm =
|
|
|
+ new BlockManager(mockNS, mockStats, new HdfsConfiguration());
|
|
|
+ UnderReplicatedBlocks underReplicatedBlocks = bm.neededReplications;
|
|
|
+
|
|
|
+ Block block1 = new Block(random.nextLong());
|
|
|
+ Block block2 = new Block(random.nextLong());
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block1, 0, 1, 1);
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block2, 0, 1, 1);
|
|
|
+
|
|
|
+ List<List<Block>> chosenBlocks;
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 1, 0, 0, 0, 0);
|
|
|
+
|
|
|
+ // Adding this block collection to the BlockManager, so that when we add the
|
|
|
+ // block under construction, the BlockManager will realize the expected
|
|
|
+ // replication has been achieved and remove it from the under-replicated
|
|
|
+ // queue.
|
|
|
+ BlockInfoUnderConstruction info = new BlockInfoUnderConstruction(block1, 1);
|
|
|
+ BlockCollection bc = mock(BlockCollection.class);
|
|
|
+ when(bc.getBlockReplication()).thenReturn((short)1);
|
|
|
+ bm.addBlockCollection(info, bc);
|
|
|
+
|
|
|
+ // Adding this block will increase its current replication, and that will
|
|
|
+ // remove it from the queue.
|
|
|
+ bm.addStoredBlockUnderConstruction(info,
|
|
|
+ TestReplicationPolicy.dataNodes[0], ReplicaState.FINALIZED);
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ // This block remains and should not be skipped over.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 1, 0, 0, 0, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test(timeout = 60000)
|
|
|
+ public void
|
|
|
+ testConvertLastBlockToUnderConstructionDoesNotCauseSkippedReplication()
|
|
|
+ throws IOException {
|
|
|
+ Namesystem mockNS = mock(Namesystem.class);
|
|
|
+ when(mockNS.isPopulatingReplQueues()).thenReturn(true);
|
|
|
+ FSClusterStats mockStats = mock(FSClusterStats.class);
|
|
|
+ BlockManager bm =
|
|
|
+ new BlockManager(mockNS, mockStats, new HdfsConfiguration());
|
|
|
+ UnderReplicatedBlocks underReplicatedBlocks = bm.neededReplications;
|
|
|
+
|
|
|
+ Block block1 = new Block(random.nextLong());
|
|
|
+ Block block2 = new Block(random.nextLong());
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block1, 0, 1, 1);
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block2, 0, 1, 1);
|
|
|
+
|
|
|
+ List<List<Block>> chosenBlocks;
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 1, 0, 0, 0, 0);
|
|
|
+
|
|
|
+ final BlockInfo info = new BlockInfo(block1, 1);
|
|
|
+ final MutableBlockCollection mbc = mock(MutableBlockCollection.class);
|
|
|
+ when(mbc.getLastBlock()).thenReturn(info);
|
|
|
+ when(mbc.getPreferredBlockSize()).thenReturn(block1.getNumBytes() + 1);
|
|
|
+ when(mbc.getBlockReplication()).thenReturn((short)1);
|
|
|
+ ContentSummary cs = mock(ContentSummary.class);
|
|
|
+ when(cs.getLength()).thenReturn((long)1);
|
|
|
+ when(mbc.computeContentSummary()).thenReturn(cs);
|
|
|
+ info.setBlockCollection(mbc);
|
|
|
+ bm.addBlockCollection(info, mbc);
|
|
|
+
|
|
|
+ DatanodeDescriptor[] dnAry = {dataNodes[0]};
|
|
|
+ final BlockInfoUnderConstruction ucBlock =
|
|
|
+ info.convertToBlockUnderConstruction(BlockUCState.UNDER_CONSTRUCTION,
|
|
|
+ dnAry);
|
|
|
+ when(mbc.setLastBlock((BlockInfo) any(), (DatanodeDescriptor[]) any()))
|
|
|
+ .thenReturn(ucBlock);
|
|
|
+
|
|
|
+ bm.convertLastBlockToUnderConstruction(mbc);
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ // This block remains and should not be skipped over.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 1, 0, 0, 0, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test(timeout = 60000)
|
|
|
+ public void testupdateNeededReplicationsDoesNotCauseSkippedReplication()
|
|
|
+ throws IOException {
|
|
|
+ Namesystem mockNS = mock(Namesystem.class);
|
|
|
+ when(mockNS.isPopulatingReplQueues()).thenReturn(true);
|
|
|
+ FSClusterStats mockStats = mock(FSClusterStats.class);
|
|
|
+ BlockManager bm =
|
|
|
+ new BlockManager(mockNS, mockStats, new HdfsConfiguration());
|
|
|
+ UnderReplicatedBlocks underReplicatedBlocks = bm.neededReplications;
|
|
|
+
|
|
|
+ Block block1 = new Block(random.nextLong());
|
|
|
+ Block block2 = new Block(random.nextLong());
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block1, 0, 1, 1);
|
|
|
+
|
|
|
+ // Adding QUEUE_UNDER_REPLICATED block
|
|
|
+ underReplicatedBlocks.add(block2, 0, 1, 1);
|
|
|
+
|
|
|
+ List<List<Block>> chosenBlocks;
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 1, 0, 0, 0, 0);
|
|
|
+
|
|
|
+ bm.setReplication((short)0, (short)1, "", block1);
|
|
|
+
|
|
|
+ // Choose 1 block from UnderReplicatedBlocks. Then it should pick 1 block
|
|
|
+ // from QUEUE_VERY_UNDER_REPLICATED.
|
|
|
+ // This block remains and should not be skipped over.
|
|
|
+ chosenBlocks = underReplicatedBlocks.chooseUnderReplicatedBlocks(1);
|
|
|
+ assertTheChosenBlocks(chosenBlocks, 1, 0, 0, 0, 0);
|
|
|
+ }
|
|
|
+}
|