You are viewing a plain text version of this content. The canonical link for it is here.
Posted to hdfs-commits@hadoop.apache.org by co...@apache.org on 2009/12/01 03:45:59 UTC

svn commit: r885658 - in /hadoop/hdfs/trunk: ./ .eclipse.templates/ src/java/org/apache/hadoop/hdfs/server/namenode/ src/test/unit/ src/test/unit/org/ src/test/unit/org/apache/ src/test/unit/org/apache/hadoop/ src/test/unit/org/apache/hadoop/hdfs/ src/...

Author: cos
Date: Tue Dec  1 02:45:39 2009
New Revision: 885658

URL: http://svn.apache.org/viewvc?rev=885658&view=rev
Log:
HDFS-519. Create new tests for lease recovery. Contributed by Konstantin Boudnik.

Added:
    hadoop/hdfs/trunk/src/test/unit/org/
    hadoop/hdfs/trunk/src/test/unit/org/apache/
    hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/
    hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/
    hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/
    hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/namenode/
    hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/namenode/TestNNLeaseRecovery.java
Removed:
    hadoop/hdfs/trunk/src/test/unit/.gitignore
Modified:
    hadoop/hdfs/trunk/.eclipse.templates/.classpath
    hadoop/hdfs/trunk/CHANGES.txt
    hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java

Modified: hadoop/hdfs/trunk/.eclipse.templates/.classpath
URL: http://svn.apache.org/viewvc/hadoop/hdfs/trunk/.eclipse.templates/.classpath?rev=885658&r1=885657&r2=885658&view=diff
==============================================================================
--- hadoop/hdfs/trunk/.eclipse.templates/.classpath (original)
+++ hadoop/hdfs/trunk/.eclipse.templates/.classpath Tue Dec  1 02:45:39 2009
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src/java"/>
+	<classpathentry kind="src" path="src/test/unit"/>
 	<classpathentry kind="src" path="src/test/hdfs"/>
 	<classpathentry kind="src" path="src/ant"/>
 	<classpathentry kind="src" path="src/contrib/hdfsproxy/src/java"/>

Modified: hadoop/hdfs/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/hdfs/trunk/CHANGES.txt?rev=885658&r1=885657&r2=885658&view=diff
==============================================================================
--- hadoop/hdfs/trunk/CHANGES.txt (original)
+++ hadoop/hdfs/trunk/CHANGES.txt Tue Dec  1 02:45:39 2009
@@ -32,6 +32,8 @@
               exclude specific datanodes when locating the next block
               (Cosmin Lehene via Stack)
 
+    HDFS-519. Create new tests for lease recovery (cos)
+
   OPTIMIZATIONS
 
   BUG FIXES

Modified: hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
URL: http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java?rev=885658&r1=885657&r2=885658&view=diff
==============================================================================
--- hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java (original)
+++ hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java Tue Dec  1 02:45:39 2009
@@ -184,7 +184,7 @@
     return namesystem;
   }
 
-  private static void initMetrics(Configuration conf, NamenodeRole role) {
+  static void initMetrics(Configuration conf, NamenodeRole role) {
     myMetrics = new NameNodeMetrics(conf, role);
   }
 

Added: hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/namenode/TestNNLeaseRecovery.java
URL: http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/namenode/TestNNLeaseRecovery.java?rev=885658&view=auto
==============================================================================
--- hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/namenode/TestNNLeaseRecovery.java (added)
+++ hadoop/hdfs/trunk/src/test/unit/org/apache/hadoop/hdfs/server/namenode/TestNNLeaseRecovery.java Tue Dec  1 02:45:39 2009
@@ -0,0 +1,233 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hdfs.server.namenode;
+
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.Log4JLogger;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.fs.permission.PermissionStatus;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.hdfs.protocol.AlreadyBeingCreatedException;
+import org.apache.hadoop.hdfs.server.common.HdfsConstants;
+import org.apache.hadoop.hdfs.server.common.HdfsConstants.NamenodeRole;
+import org.apache.hadoop.test.GenericTestUtils;
+import org.apache.log4j.Level;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestNNLeaseRecovery {
+  public static final Log LOG = LogFactory.getLog(TestNNLeaseRecovery.class);
+  FSNamesystem fsn;
+  Configuration conf;
+  
+  static {
+    ((Log4JLogger)FSNamesystem.LOG).getLogger().setLevel(Level.ALL);
+    ((Log4JLogger)LOG).getLogger().setLevel(Level.ALL);
+  }
+
+  /**
+   * Initiates and sets a spied on FSNamesystem so tests can hook its methods
+   * @throws IOException if an error occurred
+   */
+  @Before
+  public void startUp() throws IOException {
+    conf = new HdfsConfiguration();
+    // avoid stubbing access control
+    conf.setBoolean(DFSConfigKeys.DFS_PERMISSIONS_ENABLED_KEY, false); 
+    NameNode.initMetrics(conf, NamenodeRole.ACTIVE);
+
+    FileSystem.setDefaultUri(conf, "hdfs://localhost:0");
+    conf.set(DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_KEY, "0.0.0.0:0");
+    NameNode.format(conf);
+    fsn = spy(new FSNamesystem(conf));
+  }
+
+  /**
+   * Cleans the resources and closes the instance of FSNamesystem
+   * @throws IOException if an error occurred
+   */
+  @After
+  public void tearDown() throws IOException {
+    if (fsn != null) {
+      try {
+        if (fsn.getFSImage() != null) fsn.getFSImage().close();
+        fsn.close();
+      } finally {
+        File dir = new File(conf.get("hadoop.tmp.dir"));
+        if (dir != null) deleteDir(dir);
+      }
+    }
+  }
+
+  /**
+   * Mocks FSNamesystem instance, adds an empty file and invokes lease recovery
+   * method. 
+   * @throws IOException in case of an error
+   */
+  @Test
+  public void testInternalReleaseLease_allCOMPLETE () throws IOException {
+    LOG.debug("Running " + GenericTestUtils.getMethodName());    
+    LeaseManager.Lease lm = mock(LeaseManager.Lease.class);
+    Path file = spy(new Path("/test.dat"));
+    DatanodeDescriptor dnd = mock(DatanodeDescriptor.class);
+    PermissionStatus ps =
+      new PermissionStatus("test", "test", new FsPermission((short)0777));
+    
+    fsn.dir.addFile(file.toString(), ps, (short)3, 1l, 
+      "test", "test-machine", dnd, 1001l);
+    assertTrue("True has to be returned in this case",
+      fsn.internalReleaseLease(lm, file.toString(), null));
+  }
+  
+  /**
+   * Mocks FSNamesystem instance, adds an empty file, sets status of last two
+   * blocks to non-defined and UNDER_CONSTRUCTION and invokes lease recovery
+   * method. IOException is expected for releasing a create lock on a 
+   * closed file. 
+   * @throws IOException as the result
+   */
+  @Test(expected=IOException.class)
+  public void testInternalReleaseLease_UNKNOWN_COMM () throws IOException {
+    LOG.debug("Running " + GenericTestUtils.getMethodName());
+    LeaseManager.Lease lm = mock(LeaseManager.Lease.class);
+    Path file = 
+      spy(new Path("/" + GenericTestUtils.getMethodName() + "_test.dat"));    
+    DatanodeDescriptor dnd = mock(DatanodeDescriptor.class);
+    PermissionStatus ps =
+      new PermissionStatus("test", "test", new FsPermission((short)0777));
+    
+    mockFileBlocks(null, 
+      HdfsConstants.BlockUCState.UNDER_CONSTRUCTION, file, dnd, ps);
+    
+    fsn.internalReleaseLease(lm, file.toString(), null);
+    assertTrue("FSNamesystem.internalReleaseLease suppose to throw " +
+      "IOException here", false);
+  }  
+
+  /**
+   * Mocks FSNamesystem instance, adds an empty file, sets status of last two
+   * blocks to COMMITTED and COMMITTED and invokes lease recovery
+   * method. AlreadyBeingCreatedException is expected.
+   * @throws AlreadyBeingCreatedException as the result
+   */
+  @Test(expected=AlreadyBeingCreatedException.class)
+  public void testInternalReleaseLease_COMM_COMM () throws IOException {
+    LOG.debug("Running " + GenericTestUtils.getMethodName());
+    LeaseManager.Lease lm = mock(LeaseManager.Lease.class);
+    Path file = 
+      spy(new Path("/" + GenericTestUtils.getMethodName() + "_test.dat"));
+    DatanodeDescriptor dnd = mock(DatanodeDescriptor.class);
+    PermissionStatus ps =
+      new PermissionStatus("test", "test", new FsPermission((short)0777));
+
+    mockFileBlocks(HdfsConstants.BlockUCState.COMMITTED, 
+      HdfsConstants.BlockUCState.COMMITTED, file, dnd, ps);
+
+    fsn.internalReleaseLease(lm, file.toString(), null);
+    assertTrue("FSNamesystem.internalReleaseLease suppose to throw " +
+      "AlreadyBeingCreatedException here", false);
+  }
+
+  /**
+   * Mocks FSNamesystem instance, adds an empty file, sets status of last two
+   * blocks to COMMITTED and UNDER_CONSTRUCTION and invokes lease recovery
+   * method. <code>false</code> is expected as the result
+   * @throws IOException in case of an error
+   */
+  @Test
+  public void testInternalReleaseLease_COMM_CONSTRUCTION () throws IOException {
+    LOG.debug("Running " + GenericTestUtils.getMethodName());
+    LeaseManager.Lease lm = mock(LeaseManager.Lease.class);
+    Path file = 
+      spy(new Path("/" + GenericTestUtils.getMethodName() + "_test.dat"));
+    DatanodeDescriptor dnd = mock(DatanodeDescriptor.class);
+    PermissionStatus ps =
+      new PermissionStatus("test", "test", new FsPermission((short)0777));
+    
+    mockFileBlocks(HdfsConstants.BlockUCState.COMMITTED, 
+      HdfsConstants.BlockUCState.UNDER_CONSTRUCTION, file, dnd, ps);
+        
+    assertFalse("False is expected in return in this case",
+      fsn.internalReleaseLease(lm, file.toString(), null));
+  }
+
+  private void mockFileBlocks(HdfsConstants.BlockUCState penUltState,
+                           HdfsConstants.BlockUCState lastState,
+                           Path file, DatanodeDescriptor dnd, 
+                           PermissionStatus ps) throws IOException {
+    BlockInfo b = mock(BlockInfo.class);
+    BlockInfoUnderConstruction b1 = mock(BlockInfoUnderConstruction.class);
+    when(b.getBlockUCState()).thenReturn(penUltState);
+    when(b1.getBlockUCState()).thenReturn(lastState);
+    BlockInfo[] blocks = new BlockInfo[]{b, b1};
+
+    FSDirectory fsDir = mock(FSDirectory.class);
+    INodeFileUnderConstruction iNFmock = mock(INodeFileUnderConstruction.class);
+    fsn.dir = fsDir;
+    FSImage fsImage = mock(FSImage.class);
+    FSEditLog editLog = mock(FSEditLog.class);
+                            
+    when(fsn.getFSImage()).thenReturn(fsImage);
+    when(fsn.getFSImage().getEditLog()).thenReturn(editLog);
+    fsn.getFSImage().setFSNamesystem(fsn);
+    
+    when(iNFmock.getBlocks()).thenReturn(blocks);
+    when(iNFmock.numBlocks()).thenReturn(2);
+    when(iNFmock.getPenultimateBlock()).thenReturn(b);
+    when(iNFmock.getLastBlock()).thenReturn(b1);
+    when(iNFmock.isUnderConstruction()).thenReturn(true);
+    fsDir.addFile(file.toString(), ps, (short)3, 1l, "test", 
+      "test-machine", dnd, 1001l);
+
+    when(fsDir.getFileINode(anyString())).thenReturn(iNFmock);
+  }
+
+  private static boolean deleteDir(File dir) {
+    if (dir == null) return false;
+    
+    if (dir.isDirectory()) {
+      String[] children = dir.list();
+      for (String aChildren : children) {
+        boolean success = deleteDir(new File(dir, aChildren));
+        if (!success) {
+          return false;
+        }
+      }
+    }
+
+    // The directory is now empty so delete it
+    return dir.delete();
+  }
+}