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 cn...@apache.org on 2016/02/13 00:57:04 UTC

[3/3] hadoop git commit: HADOOP-12780. During WASB atomic rename handle crash when one directory has been renamed but not file under it. Contributed by Madhumita Chakraborty.

HADOOP-12780. During WASB atomic rename handle crash when one directory has been renamed but not file under it. Contributed by Madhumita Chakraborty.

(cherry picked from commit 91a96eaa534dbb27e81b6c24bbb8138200a80a83)
(cherry picked from commit ac5a7935901255e5fc56b88574e72f875942b906)


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

Branch: refs/heads/branch-2.8
Commit: b8464013074a7dc4c56d6adc1b313cf403934a57
Parents: 8c1cf71
Author: cnauroth <cn...@apache.org>
Authored: Fri Feb 12 15:50:10 2016 -0800
Committer: cnauroth <cn...@apache.org>
Committed: Fri Feb 12 15:50:28 2016 -0800

----------------------------------------------------------------------
 hadoop-common-project/hadoop-common/CHANGES.txt |  3 +
 .../fs/azure/AzureNativeFileSystemStore.java    | 30 +++++++++
 .../hadoop/fs/azure/NativeAzureFileSystem.java  |  8 +--
 .../hadoop/fs/azure/NativeFileSystemStore.java  |  2 +
 .../fs/azure/NativeAzureFileSystemBaseTest.java | 67 ++++++++++++++++++++
 5 files changed, 106 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/b8464013/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 2bd9bdc..8c1c5a4 100644
--- a/hadoop-common-project/hadoop-common/CHANGES.txt
+++ b/hadoop-common-project/hadoop-common/CHANGES.txt
@@ -1003,6 +1003,9 @@ Release 2.8.0 - UNRELEASED
     HADOOP-12795. KMS does not log detailed stack trace for unexpected errors.
     (cnauroth)
 
+    HADOOP-12780. During atomic rename handle crash when one directory has been
+    renamed but not file under it. (Madhumita Chakraborty via cnauroth)
+
 Release 2.7.3 - UNRELEASED
 
   INCOMPATIBLE CHANGES

http://git-wip-us.apache.org/repos/asf/hadoop/blob/b8464013/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/AzureNativeFileSystemStore.java
----------------------------------------------------------------------
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/AzureNativeFileSystemStore.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/AzureNativeFileSystemStore.java
index 0097912..7463bc3 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/AzureNativeFileSystemStore.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/AzureNativeFileSystemStore.java
@@ -2565,6 +2565,36 @@ public class AzureNativeFileSystemStore implements NativeFileSystemStore {
   }
 
   /**
+   * Checks whether an explicit file/folder exists.
+   * This is used by redo of atomic rename.
+   * There was a bug(apache jira HADOOP-12780) during atomic rename if
+   * process crashes after an inner directory has been renamed but still
+   * there are file under that directory to be renamed then after the
+   * process comes again it tries to redo the renames. It checks whether
+   * the directory exists or not by calling filesystem.exist.
+   * But filesystem.Exists will treat that directory as implicit directory
+   * and return true as file exists under that directory. So It will try
+   * try to rename that directory and will fail as the corresponding blob
+   * does not exist. So this method explicitly checks for the blob.
+   */
+  @Override
+  public boolean explicitFileExists(String key) throws AzureException {
+    CloudBlobWrapper blob;
+    try {
+      blob = getBlobReference(key);
+      if (null != blob && blob.exists(getInstrumentedContext())) {
+        return true;
+      }
+
+      return false;
+    } catch (StorageException e) {
+      throw new AzureException(e);
+    } catch (URISyntaxException e) {
+      throw new AzureException(e);
+    }
+  }
+
+  /**
    * Changes the permission status on the given key.
    */
   @Override

http://git-wip-us.apache.org/repos/asf/hadoop/blob/b8464013/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 ed65184..c160af8 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
@@ -558,13 +558,13 @@ public class NativeAzureFileSystem extends FileSystem {
         throws IOException {
       Path srcFile = fullPath(srcKey, fileName);
       Path dstFile = fullPath(dstKey, fileName);
-      boolean srcExists = fs.exists(srcFile);
-      boolean dstExists = fs.exists(dstFile);
+      String srcName = fs.pathToKey(srcFile);
+      String dstName = fs.pathToKey(dstFile);
+      boolean srcExists = fs.getStoreInterface().explicitFileExists(srcName);
+      boolean dstExists = fs.getStoreInterface().explicitFileExists(dstName);
       if(srcExists) {
         // Rename gets exclusive access (via a lease) for HBase write-ahead log
         // (WAL) file processing correctness.  See the rename code for details.
-        String srcName = fs.pathToKey(srcFile);
-        String dstName = fs.pathToKey(dstFile);
         fs.getStoreInterface().rename(srcName, dstName, true, null);
       } else if (!srcExists && dstExists) {
         // The rename already finished, so do nothing.

http://git-wip-us.apache.org/repos/asf/hadoop/blob/b8464013/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeFileSystemStore.java
----------------------------------------------------------------------
diff --git a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeFileSystemStore.java b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeFileSystemStore.java
index f052b7f..acdd3d6 100644
--- a/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeFileSystemStore.java
+++ b/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azure/NativeFileSystemStore.java
@@ -109,4 +109,6 @@ interface NativeFileSystemStore {
   SelfRenewingLease acquireLease(String key) throws AzureException;
 
   DataOutputStream retrieveAppendStream(String key, int bufferSize) throws IOException;
+
+  boolean explicitFileExists(String key) throws AzureException;
 }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/b8464013/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 7837098..60e5ec6 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,73 @@ public abstract class NativeAzureFileSystemBaseTest {
   }
 
   /**
+   * There is a nested folder and file under the folder to be renamed
+   * and the process crashes after the nested folder has been renamed but not the file.
+   * then when you list the parent folder, pending renames should be redone
+   * Apache jira HADOOP-12780
+   */
+  @Test
+  public void testRedoRenameFolderRenameInProgress() throws IOException {
+
+    // create original folder
+    String parent = "parent";
+    Path parentFolder = new Path(parent);
+    assertTrue(fs.mkdirs(parentFolder));
+    Path folderToBeRenamed = new Path(parentFolder, "folderToBeRenamed");
+    assertTrue(fs.mkdirs(folderToBeRenamed));
+    String innerFolderName = "innerFolder";
+    Path inner = new Path(folderToBeRenamed, innerFolderName);
+    assertTrue(fs.mkdirs(inner));
+    String innerFileName = "file";
+    Path innerFile = new Path(inner, innerFileName);
+    assertTrue(fs.createNewFile(innerFile));
+
+    Path renamedFolder = new Path(parentFolder, "renamedFolder");
+
+    // propose (but don't do) the rename of innerFolder2
+    Path home = fs.getHomeDirectory();
+    String relativeHomeDir = getRelativePath(home.toString());
+    NativeAzureFileSystem.FolderRenamePending pending =
+        new NativeAzureFileSystem.FolderRenamePending(
+            relativeHomeDir + "/" + folderToBeRenamed,
+            relativeHomeDir + "/" + renamedFolder, null,
+            (NativeAzureFileSystem) fs);
+
+    // Create a rename-pending file and write rename information to it.
+    final String renamePendingStr = folderToBeRenamed + FolderRenamePending.SUFFIX;
+    Path renamePendingFile = new Path(renamePendingStr);
+    FSDataOutputStream out = fs.create(renamePendingFile, true);
+    assertTrue(out != null);
+    writeString(out, pending.makeRenamePendingFileContents());
+
+    // Rename inner folder to simulate the scenario where rename has started and
+    // only one directory has been renamed but not the files under it
+    ((NativeAzureFileSystem) fs).getStoreInterface().rename(
+        relativeHomeDir + "/" +inner, relativeHomeDir + "/" +renamedFolder + "/" + innerFolderName , true, null);
+
+    // Instead of using fs.exist use store.explicitFileExists because fs.exist will return true
+    // even if directory has been renamed, but there are still file under that directory
+    assertFalse(((NativeAzureFileSystem) fs).getStoreInterface().
+        explicitFileExists(relativeHomeDir + "/" + inner)); // verify the explicit inner folder is gone
+    assertTrue(((NativeAzureFileSystem) fs).getStoreInterface().
+        explicitFileExists(relativeHomeDir + "/" + innerFile)); // verify inner file is present
+
+    // Redo the rename operation based on the contents of the
+    // -RenamePending.json file. Trigger the redo by checking for existence of
+    // the original folder. It must appear to not exist.
+    FileStatus[] listed = fs.listStatus(parentFolder);
+    assertEquals(1, listed.length);
+    assertTrue(listed[0].isDirectory());
+
+    // The rename pending file is not a directory, so at this point we know the
+    // redo has been done.
+    assertFalse(fs.exists(inner)); // verify original folder is gone
+    assertFalse(fs.exists(innerFile)); // verify original file is gone
+    assertTrue(fs.exists(renamedFolder)); // verify the target is there
+    assertTrue(fs.exists(new Path(renamedFolder, innerFolderName + "/" + innerFileName)));
+  }
+
+  /**
    * 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