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:03 UTC
[2/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)
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/ac5a7935
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/ac5a7935
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/ac5a7935
Branch: refs/heads/branch-2
Commit: ac5a7935901255e5fc56b88574e72f875942b906
Parents: 63f5120
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:19 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/ac5a7935/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 0ab6d74..bbb55c7 100644
--- a/hadoop-common-project/hadoop-common/CHANGES.txt
+++ b/hadoop-common-project/hadoop-common/CHANGES.txt
@@ -1065,6 +1065,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/ac5a7935/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/ac5a7935/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/ac5a7935/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/ac5a7935/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