You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ha...@apache.org on 2008/12/17 00:18:42 UTC

svn commit: r727212 - in /hadoop/core/trunk: CHANGES.txt src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java src/test/org/apache/hadoop/hdfs/TestDatanodeBlockScanner.java

Author: hairong
Date: Tue Dec 16 15:18:41 2008
New Revision: 727212

URL: http://svn.apache.org/viewvc?rev=727212&view=rev
Log:
HADOOP-4810. Data lost at cluster startup time. Contributed by Hairong Kuang.

Modified:
    hadoop/core/trunk/CHANGES.txt
    hadoop/core/trunk/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
    hadoop/core/trunk/src/test/org/apache/hadoop/hdfs/TestDatanodeBlockScanner.java

Modified: hadoop/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/CHANGES.txt?rev=727212&r1=727211&r2=727212&view=diff
==============================================================================
--- hadoop/core/trunk/CHANGES.txt (original)
+++ hadoop/core/trunk/CHANGES.txt Tue Dec 16 15:18:41 2008
@@ -1555,6 +1555,8 @@
     HADOOP-4857. Fixes TestUlimit to have exactly 1 map in the jobs spawned.
     (Ravi Gummadi via ddas)
 
+    HADOOP-4810. Data lost at cluster startup time. (hairong)
+
 Release 0.18.2 - 2008-11-03
 
   BUG FIXES

Modified: hadoop/core/trunk/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java?rev=727212&r1=727211&r2=727212&view=diff
==============================================================================
--- hadoop/core/trunk/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java (original)
+++ hadoop/core/trunk/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java Tue Dec 16 15:18:41 2008
@@ -1518,13 +1518,13 @@
     } else {
       INodeFile inode = blocksMap.getINode(blk);
       assert inode!=null : (blk + " in blocksMap must belongs to a file.");
+      // Add this replica to corruptReplicas Map 
+      corruptReplicas.addToCorruptReplicasMap(blk, node);
       if (countNodes(blk).liveReplicas()>inode.getReplication()) {
         // the block is over-replicated so invalidate the replicas immediately
         invalidateBlock(blk, node);
       } else {
-        // Add this replica to corruptReplicas Map and 
         // add the block to neededReplication 
-        corruptReplicas.addToCorruptReplicasMap(blk, node);
         updateNeededReplications(blk, -1, 0);
       }
     }
@@ -1538,9 +1538,6 @@
     NameNode.stateChangeLog.info("DIR* NameSystem.invalidateBlock: " 
                                  + blk + " on " 
                                  + dn.getName());
-    if (isInSafeMode()) {
-      throw new SafeModeException("Cannot invalidate block " + blk, safeMode);
-    }
     DatanodeDescriptor node = getDatanode(dn);
     if (node == null) {
       throw new IOException("Cannot invalidate block " + blk +
@@ -2776,7 +2773,7 @@
     assert storedBlock != null : "Block must be stored by now";
 
     if (block != storedBlock) {
-      if (block.getNumBytes() > 0) {
+      if (block.getNumBytes() >= 0) {
         long cursize = storedBlock.getNumBytes();
         if (cursize == 0) {
           storedBlock.setNumBytes(block.getNumBytes());
@@ -2788,12 +2785,13 @@
           try {
             if (cursize > block.getNumBytes()) {
               // new replica is smaller in size than existing block.
-              // Delete new replica.
-              LOG.warn("Deleting block " + block + " from " + node.getName());
-              invalidateBlock(block, node);
+              // Mark the new replica as corrupt.
+              LOG.warn("Mark new replica " + block + " from " + node.getName() + 
+                  "as corrupt because its length is shorter than existing ones");
+              markBlockAsCorrupt(block, node);
             } else {
               // new replica is larger in size than existing block.
-              // Delete pre-existing replicas.
+              // Mark pre-existing replicas as corrupt.
               int numNodes = blocksMap.numNodes(block);
               int count = 0;
               DatanodeDescriptor nodes[] = new DatanodeDescriptor[numNodes];
@@ -2805,9 +2803,9 @@
                 }
               }
               for (int j = 0; j < count; j++) {
-                LOG.warn("Deleting block " + block + " from " + 
-                         nodes[j].getName());
-                invalidateBlock(block, nodes[j]);
+                LOG.warn("Mark existing replica " + block + " from " + node.getName() + 
+                " as corrupt because its length is shorter than the new one");
+                markBlockAsCorrupt(block, nodes[j]);
               }
               //
               // change the size of block in blocksMap

Modified: hadoop/core/trunk/src/test/org/apache/hadoop/hdfs/TestDatanodeBlockScanner.java
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/src/test/org/apache/hadoop/hdfs/TestDatanodeBlockScanner.java?rev=727212&r1=727211&r2=727212&view=diff
==============================================================================
--- hadoop/core/trunk/src/test/org/apache/hadoop/hdfs/TestDatanodeBlockScanner.java (original)
+++ hadoop/core/trunk/src/test/org/apache/hadoop/hdfs/TestDatanodeBlockScanner.java Tue Dec 16 15:18:41 2008
@@ -385,4 +385,67 @@
     assertTrue(blocks.get(0).isCorrupt() == false);
     cluster.shutdown();
   }
+  
+  /** Test if NameNode handles truncated blocks in block report */
+  public void testTruncatedBlockReport() throws Exception {
+    final Configuration conf = new Configuration();
+    final short REPLICATION_FACTOR = (short)2;
+
+    MiniDFSCluster cluster = new MiniDFSCluster(conf, REPLICATION_FACTOR, true, null);
+    cluster.waitActive();
+    FileSystem fs = cluster.getFileSystem();
+    try {
+      final Path fileName = new Path("/file1");
+      DFSTestUtil.createFile(fs, fileName, 1, REPLICATION_FACTOR, 0);
+      DFSTestUtil.waitReplication(fs, fileName, REPLICATION_FACTOR);
+
+      String block = DFSTestUtil.getFirstBlock(fs, fileName).getBlockName();
+
+      // Truncate replica of block
+      truncateReplica(block, 0);
+
+      cluster.shutdown();
+
+      // restart the cluster
+      cluster = new MiniDFSCluster(
+          0, conf, REPLICATION_FACTOR, false, true, null, null, null);
+      cluster.startDataNodes(conf, 1, true, null, null);
+      cluster.waitActive();  // now we have 3 datanodes
+
+      // wait for truncated block be detected and the block to be replicated
+      DFSTestUtil.waitReplication(
+          cluster.getFileSystem(), fileName, REPLICATION_FACTOR);
+      
+      // Make sure that truncated block will be deleted
+      waitForBlockDeleted(block, 0);
+    } finally {
+      cluster.shutdown();
+    }
+  }
+  
+  private void truncateReplica(String blockName, int dnIndex) throws IOException {
+    File baseDir = new File(System.getProperty("test.build.data"), "dfs/data");
+    for (int i=dnIndex*2; i<dnIndex*2+2; i++) {
+      File blockFile = new File(baseDir, "data" + (i+1)+ "/current/" + 
+                               blockName);
+      if (blockFile.exists()) {
+        RandomAccessFile raFile = new RandomAccessFile(blockFile, "rw");
+        raFile.setLength(raFile.length()-1);
+        raFile.close();
+        break;
+      }
+    }
+  }
+  
+  private void waitForBlockDeleted(String blockName, int dnIndex) 
+  throws IOException, InterruptedException {
+    File baseDir = new File(System.getProperty("test.build.data"), "dfs/data");
+    File blockFile1 = new File(baseDir, "data" + (2*dnIndex+1)+ "/current/" + 
+        blockName);
+    File blockFile2 = new File(baseDir, "data" + (2*dnIndex+2)+ "/current/" + 
+        blockName);
+    while (blockFile1.exists() || blockFile2.exists()) {
+      Thread.sleep(100);
+    }
+  }
 }