|
@@ -17,19 +17,23 @@
|
|
|
*/
|
|
|
package org.apache.hadoop.hdfs.server.namenode;
|
|
|
|
|
|
+import static org.apache.hadoop.hdfs.server.common.Util.now;
|
|
|
+
|
|
|
import java.io.File;
|
|
|
import java.io.IOException;
|
|
|
+import java.util.Collection;
|
|
|
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.fs.BlockLocation;
|
|
|
import org.apache.hadoop.fs.FileSystem;
|
|
|
import org.apache.hadoop.fs.Path;
|
|
|
import org.apache.hadoop.hdfs.DFSTestUtil;
|
|
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
|
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
|
|
-import org.apache.hadoop.hdfs.TestDatanodeBlockScanner;
|
|
|
import org.apache.hadoop.hdfs.MiniDFSCluster.DataNodeProperties;
|
|
|
import org.apache.hadoop.hdfs.protocol.Block;
|
|
|
import org.apache.hadoop.hdfs.protocol.DatanodeID;
|
|
|
+import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
|
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
|
|
|
|
|
import junit.framework.TestCase;
|
|
@@ -95,4 +99,74 @@ public class TestOverReplicatedBlocks extends TestCase {
|
|
|
cluster.shutdown();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ static final long SMALL_BLOCK_SIZE =
|
|
|
+ DFSConfigKeys.DFS_BYTES_PER_CHECKSUM_DEFAULT;
|
|
|
+ static final long SMALL_FILE_LENGTH = SMALL_BLOCK_SIZE * 4;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The test verifies that replica for deletion is chosen on a node,
|
|
|
+ * with the oldest heartbeat, when this heartbeat is larger than the
|
|
|
+ * tolerable heartbeat interval.
|
|
|
+ * It creates a file with several blocks and replication 4.
|
|
|
+ * The last DN is configured to send heartbeats rarely.
|
|
|
+ *
|
|
|
+ * Test waits until the tolerable heartbeat interval expires, and reduces
|
|
|
+ * replication of the file. All replica deletions should be scheduled for the
|
|
|
+ * last node. No replicas will actually be deleted, since last DN doesn't
|
|
|
+ * send heartbeats.
|
|
|
+ */
|
|
|
+ public void testChooseReplicaToDelete() throws IOException {
|
|
|
+ MiniDFSCluster cluster = null;
|
|
|
+ FileSystem fs = null;
|
|
|
+ try {
|
|
|
+ Configuration conf = new HdfsConfiguration();
|
|
|
+ conf.setLong(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, SMALL_BLOCK_SIZE);
|
|
|
+ cluster = new MiniDFSCluster.Builder(conf).numDataNodes(3).build();
|
|
|
+ fs = cluster.getFileSystem();
|
|
|
+ final FSNamesystem namesystem = cluster.getNamesystem();
|
|
|
+
|
|
|
+ conf.setLong(DFSConfigKeys.DFS_HEARTBEAT_INTERVAL_KEY, 300);
|
|
|
+ cluster.startDataNodes(conf, 1, true, null, null, null);
|
|
|
+ DataNode lastDN = cluster.getDataNodes().get(3);
|
|
|
+ String lastDNid = lastDN.getDatanodeRegistration().getStorageID();
|
|
|
+
|
|
|
+ final Path fileName = new Path("/foo2");
|
|
|
+ DFSTestUtil.createFile(fs, fileName, SMALL_FILE_LENGTH, (short)4, 0L);
|
|
|
+ DFSTestUtil.waitReplication(fs, fileName, (short)4);
|
|
|
+
|
|
|
+ // Wait for tolerable number of heartbeats plus one
|
|
|
+ DatanodeDescriptor nodeInfo = null;
|
|
|
+ long lastHeartbeat = 0;
|
|
|
+ long waitTime = DFSConfigKeys.DFS_HEARTBEAT_INTERVAL_DEFAULT * 1000 *
|
|
|
+ (DFSConfigKeys.DFS_NAMENODE_TOLERATE_HEARTBEAT_MULTIPLIER_DEFAULT + 1);
|
|
|
+ do {
|
|
|
+ synchronized (namesystem.heartbeats) {
|
|
|
+ synchronized (namesystem.datanodeMap) {
|
|
|
+ nodeInfo = namesystem.getDatanode(lastDN.getDatanodeRegistration());
|
|
|
+ lastHeartbeat = nodeInfo.getLastUpdate();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } while(now() - lastHeartbeat < waitTime);
|
|
|
+ fs.setReplication(fileName, (short)3);
|
|
|
+
|
|
|
+ BlockLocation locs[] = fs.getFileBlockLocations(
|
|
|
+ fs.getFileStatus(fileName), 0, Long.MAX_VALUE);
|
|
|
+
|
|
|
+ // All replicas for deletion should be scheduled on lastDN.
|
|
|
+ // And should not actually be deleted, because lastDN does not heartbeat.
|
|
|
+ namesystem.readLock();
|
|
|
+ Collection<Block> dnBlocks =
|
|
|
+ namesystem.blockManager.excessReplicateMap.get(lastDNid);
|
|
|
+ assertEquals("Replicas on node " + lastDNid + " should have been deleted",
|
|
|
+ SMALL_FILE_LENGTH / SMALL_BLOCK_SIZE, dnBlocks.size());
|
|
|
+ namesystem.readUnlock();
|
|
|
+ for(BlockLocation location : locs)
|
|
|
+ assertEquals("Block should still have 4 replicas",
|
|
|
+ 4, location.getNames().length);
|
|
|
+ } finally {
|
|
|
+ if(fs != null) fs.close();
|
|
|
+ if(cluster != null) cluster.shutdown();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|