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 ar...@apache.org on 2016/01/12 05:32:05 UTC

[06/23] hadoop git commit: HADOOP-12678. Handle empty rename pending metadata file during atomic rename in redo path. Contributed by Madhumita Chakraborty.

HADOOP-12678. Handle empty rename pending metadata file during atomic rename in redo path. Contributed by Madhumita Chakraborty.


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/f0fa6d86
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/f0fa6d86
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/f0fa6d86

Branch: refs/heads/HDFS-1312
Commit: f0fa6d869b9abb5a900ea1c9eb4eb19ec9831dc4
Parents: 109e528
Author: cnauroth <cn...@apache.org>
Authored: Fri Jan 8 20:18:54 2016 -0800
Committer: cnauroth <cn...@apache.org>
Committed: Fri Jan 8 20:18:59 2016 -0800

----------------------------------------------------------------------
 hadoop-common-project/hadoop-common/CHANGES.txt |  3 ++
 .../hadoop/fs/azure/NativeAzureFileSystem.java  | 38 +++++++++++--
 .../fs/azure/NativeAzureFileSystemBaseTest.java | 57 ++++++++++++++++++++
 3 files changed, 94 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/f0fa6d86/hadoop-common-project/hadoop-common/CHANGES.txt
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt
index 78cd2dd..a5aebeb 100644
--- a/hadoop-common-project/hadoop-common/CHANGES.txt
+++ b/hadoop-common-project/hadoop-common/CHANGES.txt
@@ -1571,6 +1571,9 @@ Release 2.8.0 - UNRELEASED
     HADOOP-12675. Fix description about retention period in usage of expunge
     command. (Masatake Iwasaki via stevel)
 
+    HADOOP-12678. Handle empty rename pending metadata file during atomic rename
+    in redo path. (Madhumita Chakraborty via cnauroth)
+
 Release 2.7.3 - UNRELEASED
 
   INCOMPATIBLE CHANGES

http://git-wip-us.apache.org/repos/asf/hadoop/blob/f0fa6d86/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java
----------------------------------------------------------------------
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java
index 34791e5..96786aa 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeAzureFileSystem.java
@@ -143,9 +143,15 @@ public class NativeAzureFileSystem extends FileSystem {
       FSDataInputStream input = fs.open(f);
       byte[] bytes = new byte[MAX_RENAME_PENDING_FILE_SIZE];
       int l = input.read(bytes);
-      if (l < 0) {
-        throw new IOException(
-            "Error reading pending rename file contents -- no data available");
+      if (l <= 0) {
+        // Jira HADOOP-12678 -Handle empty rename pending metadata file during
+        // atomic rename in redo path. If during renamepending file is created
+        // but not written yet, then this means that rename operation
+        // has not started yet. So we should delete rename pending metadata file.
+        LOG.error("Deleting empty rename pending file "
+            + redoFile + " -- no data available");
+        deleteRenamePendingFile(fs, redoFile);
+        return;
       }
       if (l == MAX_RENAME_PENDING_FILE_SIZE) {
         throw new IOException(
@@ -178,7 +184,7 @@ public class NativeAzureFileSystem extends FileSystem {
             redoFile, contents);
 
         // delete the -RenamePending.json file
-        fs.delete(redoFile, false);
+        deleteRenamePendingFile(fs, redoFile);
         return;
       }
 
@@ -216,6 +222,30 @@ public class NativeAzureFileSystem extends FileSystem {
     }
 
     /**
+     * Deletes rename pending metadata file
+     * @param fs -- the file system
+     * @param redoFile - rename pending metadata file path
+     * @throws IOException - If deletion fails
+     */
+    @VisibleForTesting
+    void deleteRenamePendingFile(FileSystem fs, Path redoFile)
+        throws IOException {
+      try {
+        fs.delete(redoFile, false);
+      } catch (IOException e) {
+        // If the rename metadata was not found then somebody probably
+        // raced with us and finished the delete first
+        Throwable t = e.getCause();
+        if (t != null && t instanceof StorageException
+            && "BlobNotFound".equals(((StorageException) t).getErrorCode())) {
+          LOG.warn("rename pending file " + redoFile + " is already deleted");
+        } else {
+          throw e;
+        }
+      }
+    }
+
+    /**
      * Write to disk the information needed to redo folder rename,
      * in JSON format. The file name will be
      * {@code wasb://<sourceFolderPrefix>/folderName-RenamePending.json}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/f0fa6d86/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/NativeAzureFileSystemBaseTest.java
----------------------------------------------------------------------
diff --git a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/NativeAzureFileSystemBaseTest.java b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/NativeAzureFileSystemBaseTest.java
index 1f07677..7837098 100644
--- a/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/NativeAzureFileSystemBaseTest.java
+++ b/hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azure/NativeAzureFileSystemBaseTest.java
@@ -846,6 +846,63 @@ public abstract class NativeAzureFileSystemBaseTest {
   }
 
   /**
+   * Test the situation when the rename metadata file is empty
+   * i.e. it is created but not written yet. In that case in next rename
+   * this empty file should be deleted. As zero byte metadata file means
+   * rename has not started yet. This is to emulate the scenario where
+   * the process crashes just after creating rename metadata file.
+   *  We had a bug (HADOOP-12678) that in that case listing used to fail and
+   * hbase master did not use to come up
+   */
+  @Test
+  public void testRedoRenameFolderInFolderListingWithZeroByteRenameMetadata()
+      throws IOException {
+    // create original folder
+    String parent = "parent";
+    Path parentFolder = new Path(parent);
+    assertTrue(fs.mkdirs(parentFolder));
+    Path inner = new Path(parentFolder, "innerFolder");
+    assertTrue(fs.mkdirs(inner));
+    Path inner2 = new Path(parentFolder, "innerFolder2");
+    assertTrue(fs.mkdirs(inner2));
+    Path innerFile = new Path(inner2, "file");
+    assertTrue(fs.createNewFile(innerFile));
+
+    Path inner2renamed = new Path(parentFolder, "innerFolder2Renamed");
+
+    // Create an empty rename-pending file
+    final String renamePendingStr = inner2 + FolderRenamePending.SUFFIX;
+    Path renamePendingFile = new Path(renamePendingStr);
+    FSDataOutputStream out = fs.create(renamePendingFile, true);
+    assertTrue(out != null);
+    out.close();
+
+    // Redo the rename operation based on the contents of the
+    // -RenamePending.json file. Trigger the redo by listing
+    // the parent folder. It should not throw and it should
+    // delete empty rename pending file
+    FileStatus[] listed = fs.listStatus(parentFolder);
+    assertEquals(2, listed.length);
+    assertTrue(listed[0].isDirectory());
+    assertTrue(listed[1].isDirectory());
+    assertFalse(fs.exists(renamePendingFile));
+
+    // Verify that even if rename pending file is deleted,
+    // deletion should handle that
+    Path home = fs.getHomeDirectory();
+    String relativeHomeDir = getRelativePath(home.toString());
+    NativeAzureFileSystem.FolderRenamePending pending =
+            new NativeAzureFileSystem.FolderRenamePending(
+                relativeHomeDir + "/" + inner2,
+                relativeHomeDir + "/" + inner2renamed, null,
+                (NativeAzureFileSystem) fs);
+    pending.deleteRenamePendingFile(fs, renamePendingFile);
+
+    assertTrue(fs.exists(inner2)); // verify original folder is there
+    assertFalse(fs.exists(inner2renamed)); // verify the target is not there
+  }
+
+  /**
    * Test the situation where a rename pending file exists but the rename
    * is really done. This could happen if the rename process died just
    * before deleting the rename pending file. It exercises a non-standard