From 9124aeee835a5b892760c3cbce151563374ca402 Mon Sep 17 00:00:00 2001
From: Eli Collins <eli@cloudera.com>
Date: Mon, 1 Mar 2010 17:36:41 -0800
Subject: [PATCH] HDFS-761. Failure to process rename operation from edits log due
 to quota verification.

When processing edits log, quota verification is not done and the
used quota for directories is not updated. The update is done at
the end of processing edits log. This rule is broken by change
introduced in HDFS-677. This causes namenode from handling rename
operation from edits log due to quota verification failure. Once
this happens, namenode does not proceed edits log any
further. This results in check point failure on backup node or
secondary namenode. This also prevents namenode from coming up.
---
 .../hadoop/hdfs/server/namenode/FSDirectory.java   |    4 ++
 src/test/org/apache/hadoop/hdfs/TestDFSRename.java |   41 ++++++++++++++++++-
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java b/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
index 327a781..89be923 100644
--- a/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
+++ b/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
@@ -1009,6 +1009,10 @@ class FSDirectory implements FSConstants, Closeable {
    */
   private void verifyQuota(INode[] inodes, int pos, long nsDelta, long dsDelta,
       INode commonAncestor) throws QuotaExceededException {
+    if (!ready) {
+      // Do not check quota if edits log is still being processed
+      return;
+    }
     if (pos>inodes.length) {
       pos = inodes.length;
     }
diff --git a/src/test/org/apache/hadoop/hdfs/TestDFSRename.java b/src/test/org/apache/hadoop/hdfs/TestDFSRename.java
index 0d76a52..84071c6 100644
--- a/src/test/org/apache/hadoop/hdfs/TestDFSRename.java
+++ b/src/test/org/apache/hadoop/hdfs/TestDFSRename.java
@@ -27,7 +27,8 @@ import org.apache.hadoop.hdfs.protocol.FSConstants;
 import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
 
 public class TestDFSRename extends junit.framework.TestCase {
-  MiniDFSCluster cluster = null;
+  static Configuration CONF = new Configuration();
+  static MiniDFSCluster cluster = null;
   static int countLease(MiniDFSCluster cluster) {
     return cluster.getNameNode().namesystem.leaseManager.countLease();
   }
@@ -36,8 +37,16 @@ public class TestDFSRename extends junit.framework.TestCase {
 
   @Override
   protected void setUp() throws Exception {
-    Configuration conf = new Configuration();
-    cluster = new MiniDFSCluster(conf, 2, true, null);
+    cluster = new MiniDFSCluster(CONF, 2, true, null);
+  }
+  
+  private void restartCluster() throws IOException {
+    if (cluster != null) {
+      cluster.shutdown();
+      cluster = null;
+    }
+    cluster = new MiniDFSCluster(CONF, 1, false, null);
+    cluster.waitClusterUp();
   }
   
   @Override
@@ -156,6 +165,32 @@ public class TestDFSRename extends junit.framework.TestCase {
     rename(dst1, src1, false, true);
   }
   
+  /**
+   * Perform operations such as setting quota, deletion of files, rename and
+   * ensure system can apply edits log during startup.
+   */
+  public void testEditsLog() throws Exception {
+    DistributedFileSystem fs = (DistributedFileSystem) cluster.getFileSystem();
+    Path src1 = new Path(dir, "testEditsLog/srcdir/src1");
+    Path dst1 = new Path(dir, "testEditsLog/dstdir/dst1");
+    createFile(fs, src1);
+    fs.mkdirs(dst1.getParent());
+    createFile(fs, dst1);
+    
+    // Set quota so that dst1 parent cannot allow under it new files/directories 
+    fs.setQuota(dst1.getParent(), 2, FSConstants.QUOTA_DONT_SET);
+    // Free up quota for a subsequent rename
+    fs.delete(dst1, true);
+    rename(src1, dst1, true, false);
+    
+    // Restart the cluster and ensure the above operations can be
+    // loaded from the edits log
+    restartCluster();
+    fs = (DistributedFileSystem)cluster.getFileSystem();
+    assertFalse(fs.exists(src1));   // ensure src1 is already renamed
+    assertTrue(fs.exists(dst1));    // ensure rename dst exists
+  }
+  
   private void rename(Path src, Path dst, boolean renameSucceeds,
       boolean quotaException) throws Exception {
     DistributedFileSystem fs = (DistributedFileSystem) cluster.getFileSystem();
-- 
1.6.0.4

