HDFS-15429. mkdirs should work when parent dir is an internalDir and fallback configured. Contributed by Uma Maheswara Rao G.

(cherry picked from commit d5e1bb6155)
This commit is contained in:
Uma Maheswara Rao G 2020-06-26 01:29:38 -07:00
parent 29a8ee4be6
commit 81e33d22a0
4 changed files with 542 additions and 37 deletions

View File

@ -1339,6 +1339,31 @@ public class ViewFileSystem extends FileSystem {
dir.toString().substring(1))) { dir.toString().substring(1))) {
return true; // this is the stupid semantics of FileSystem return true; // this is the stupid semantics of FileSystem
} }
if (this.fsState.getRootFallbackLink() != null) {
FileSystem linkedFallbackFs =
this.fsState.getRootFallbackLink().getTargetFileSystem();
Path parent = Path.getPathWithoutSchemeAndAuthority(
new Path(theInternalDir.fullPath));
String leafChild = (InodeTree.SlashPath.equals(dir)) ?
InodeTree.SlashPath.toString() :
dir.getName();
Path dirToCreate = new Path(parent, leafChild);
try {
return linkedFallbackFs.mkdirs(dirToCreate, permission);
} catch (IOException e) {
if (LOG.isDebugEnabled()) {
StringBuilder msg =
new StringBuilder("Failed to create ").append(dirToCreate)
.append(" at fallback : ")
.append(linkedFallbackFs.getUri());
LOG.debug(msg.toString(), e);
}
return false;
}
}
throw readOnlyMountTable("mkdirs", dir); throw readOnlyMountTable("mkdirs", dir);
} }

View File

@ -1134,11 +1134,35 @@ public class ViewFs extends AbstractFileSystem {
@Override @Override
public void mkdir(final Path dir, final FsPermission permission, public void mkdir(final Path dir, final FsPermission permission,
final boolean createParent) throws AccessControlException, final boolean createParent) throws IOException {
FileAlreadyExistsException {
if (theInternalDir.isRoot() && dir == null) { if (theInternalDir.isRoot() && dir == null) {
throw new FileAlreadyExistsException("/ already exits"); throw new FileAlreadyExistsException("/ already exits");
} }
if (this.fsState.getRootFallbackLink() != null) {
AbstractFileSystem linkedFallbackFs =
this.fsState.getRootFallbackLink().getTargetFileSystem();
Path parent = Path.getPathWithoutSchemeAndAuthority(
new Path(theInternalDir.fullPath));
String leafChild = (InodeTree.SlashPath.equals(dir)) ?
InodeTree.SlashPath.toString() :
dir.getName();
Path dirToCreate = new Path(parent, leafChild);
try {
// We are here because, the parent dir already exist in the mount
// table internal tree. So, let's create parent always in fallback.
linkedFallbackFs.mkdir(dirToCreate, permission, true);
return;
} catch (IOException e) {
if (LOG.isDebugEnabled()) {
StringBuilder msg = new StringBuilder("Failed to create {}")
.append(" at fallback fs : {}");
LOG.debug(msg.toString(), dirToCreate, linkedFallbackFs.getUri());
}
throw e;
}
}
throw readOnlyMountTable("mkdir", dir); throw readOnlyMountTable("mkdir", dir);
} }

View File

@ -19,6 +19,7 @@ package org.apache.hadoop.fs.viewfs;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -69,7 +70,7 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
"/tmp/TestViewFileSystemLinkFallback"; "/tmp/TestViewFileSystemLinkFallback";
private final static Logger LOG = LoggerFactory.getLogger( private final static Logger LOG = LoggerFactory.getLogger(
TestViewFileSystemLinkFallback.class); TestViewFileSystemLinkFallback.class);
private static URI viewFsDefaultClusterUri;
@Override @Override
protected FileSystemTestHelper createFileSystemHelper() { protected FileSystemTestHelper createFileSystemHelper() {
@ -93,6 +94,8 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
FS_HDFS[i] = cluster.getFileSystem(i); FS_HDFS[i] = cluster.getFileSystem(i);
} }
fsDefault = FS_HDFS[FS_INDEX_DEFAULT]; fsDefault = FS_HDFS[FS_INDEX_DEFAULT];
viewFsDefaultClusterUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
} }
@AfterClass @AfterClass
@ -327,21 +330,20 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
fsTarget.mkdirs(dir1); fsTarget.mkdirs(dir1);
fsTarget.mkdirs(dir2); fsTarget.mkdirs(dir2);
String clusterName = Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE; String clusterName = Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE;
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME, clusterName,
"/", null, null);
HashSet<Path> beforeFallback = new HashSet<>(); HashSet<Path> beforeFallback = new HashSet<>();
try(FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
for (FileStatus stat : vfs.listStatus(new Path(viewFsUri.toString()))) { for (FileStatus stat : vfs
.listStatus(new Path(viewFsDefaultClusterUri.toString()))) {
beforeFallback.add(stat.getPath()); beforeFallback.add(stat.getPath());
} }
} }
ConfigUtil.addLinkFallback(conf, clusterName, ConfigUtil.addLinkFallback(conf, clusterName,
new Path(targetTestRoot, "fallbackDir").toUri()); new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>(); HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs.listStatus(new Path(viewFsUri.toString()))) { for (FileStatus stat : vfs
.listStatus(new Path(viewFsDefaultClusterUri.toString()))) {
afterFallback.add(stat.getPath()); afterFallback.add(stat.getPath());
} }
afterFallback.removeAll(beforeFallback); afterFallback.removeAll(beforeFallback);
@ -349,7 +351,7 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
1, afterFallback.size()); 1, afterFallback.size());
Path[] fallbackArray = new Path[afterFallback.size()]; Path[] fallbackArray = new Path[afterFallback.size()];
// Only user1 should be listed as fallback link // Only user1 should be listed as fallback link
Path expected = new Path(viewFsUri.toString(), "user1"); Path expected = new Path(viewFsDefaultClusterUri.toString(), "user1");
assertEquals("Path did not match", assertEquals("Path did not match",
expected, afterFallback.toArray(fallbackArray)[0]); expected, afterFallback.toArray(fallbackArray)[0]);
@ -401,23 +403,21 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
fsTarget.mkdirs(dir2); fsTarget.mkdirs(dir2);
fsTarget.setPermission(new Path(targetTestRoot, "fallbackDir/user1/hive/"), fsTarget.setPermission(new Path(targetTestRoot, "fallbackDir/user1/hive/"),
FsPermission.valueOf("-rwxr--r--")); FsPermission.valueOf("-rwxr--r--"));
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
HashSet<Path> beforeFallback = new HashSet<>(); HashSet<Path> beforeFallback = new HashSet<>();
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
for (FileStatus stat : vfs for (FileStatus stat : vfs.listStatus(
.listStatus(new Path(viewFsUri.toString(), "/user1/hive/"))) { new Path(viewFsDefaultClusterUri.toString(), "/user1/hive/"))) {
beforeFallback.add(stat.getPath()); beforeFallback.add(stat.getPath());
} }
} }
ConfigUtil ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri()); .addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>(); HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs for (FileStatus stat : vfs.listStatus(
.listStatus(new Path(viewFsUri.toString(), "/user1/hive/"))) { new Path(viewFsDefaultClusterUri.toString(), "/user1/hive/"))) {
afterFallback.add(stat.getPath()); afterFallback.add(stat.getPath());
if (dir1.getName().equals(stat.getPath().getName())) { if (dir1.getName().equals(stat.getPath().getName())) {
// make sure fallback dir listed out with correct permissions, but not // make sure fallback dir listed out with correct permissions, but not
@ -426,7 +426,6 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
stat.getPermission()); stat.getPermission());
} }
} }
//
//viewfs://default/user1/hive/warehouse //viewfs://default/user1/hive/warehouse
afterFallback.removeAll(beforeFallback); afterFallback.removeAll(beforeFallback);
assertEquals("The same directory name in fallback link should be shaded", assertEquals("The same directory name in fallback link should be shaded",
@ -475,23 +474,23 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
"fallbackDir/user1/hive/warehouse/partition-0"), "fallbackDir/user1/hive/warehouse/partition-0"),
FsPermission.valueOf("-rwxr--r--")); FsPermission.valueOf("-rwxr--r--"));
fsTarget.setPermission(targetTestRoot, FsPermission.valueOf("-rwxr--rw-")); fsTarget.setPermission(targetTestRoot, FsPermission.valueOf("-rwxr--rw-"));
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
HashSet<Path> beforeFallback = new HashSet<>(); HashSet<Path> beforeFallback = new HashSet<>();
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
for (FileStatus stat : vfs.listStatus( for (FileStatus stat : vfs.listStatus(
new Path(viewFsUri.toString(), "/user1/hive/warehouse/"))) { new Path(viewFsDefaultClusterUri.toString(),
"/user1/hive/warehouse/"))) {
beforeFallback.add(stat.getPath()); beforeFallback.add(stat.getPath());
} }
} }
ConfigUtil ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri()); .addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>(); HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs.listStatus( for (FileStatus stat : vfs.listStatus(
new Path(viewFsUri.toString(), "/user1/hive/warehouse/"))) { new Path(viewFsDefaultClusterUri.toString(),
"/user1/hive/warehouse/"))) {
afterFallback.add(stat.getPath()); afterFallback.add(stat.getPath());
if (dir1.getName().equals(stat.getPath().getName())) { if (dir1.getName().equals(stat.getPath().getName())) {
// make sure fallback dir listed out with correct permissions, but not // make sure fallback dir listed out with correct permissions, but not
@ -508,7 +507,7 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
/** /**
* Tests ListStatus on root with fallback configured. * Tests ListStatus on root with fallback configured.
* =============================Example.======================================= * =============================Example.======================================
* ===== Fallback path tree =============== Mount Path Tree ================== * ===== Fallback path tree =============== Mount Path Tree ==================
* =========================================================================== * ===========================================================================
* * / / ***** / *** * * / / ***** / ***
@ -536,23 +535,21 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
fsTarget.mkdirs(dir1); fsTarget.mkdirs(dir1);
fsTarget.mkdirs(dir2, FsPermission.valueOf("-rwxr--r--")); fsTarget.mkdirs(dir2, FsPermission.valueOf("-rwxr--r--"));
fsTarget.setPermission(targetTestRoot, FsPermission.valueOf("-rwxr--rw-")); fsTarget.setPermission(targetTestRoot, FsPermission.valueOf("-rwxr--rw-"));
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
HashSet<Path> beforeFallback = new HashSet<>(); HashSet<Path> beforeFallback = new HashSet<>();
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
for (FileStatus stat : vfs for (FileStatus stat : vfs
.listStatus(new Path(viewFsUri.toString(), "/"))) { .listStatus(new Path(viewFsDefaultClusterUri.toString(), "/"))) {
beforeFallback.add(stat.getPath()); beforeFallback.add(stat.getPath());
} }
} }
ConfigUtil ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri()); .addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>(); HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs for (FileStatus stat : vfs
.listStatus(new Path(viewFsUri.toString(), "/"))) { .listStatus(new Path(viewFsDefaultClusterUri.toString(), "/"))) {
afterFallback.add(stat.getPath()); afterFallback.add(stat.getPath());
if (dir1.getName().equals(stat.getPath().getName())) { if (dir1.getName().equals(stat.getPath().getName())) {
// make sure fallback dir listed out with correct permissions, but not // make sure fallback dir listed out with correct permissions, but not
@ -584,15 +581,14 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
fsTarget.createNewFile(file1); fsTarget.createNewFile(file1);
Path dir2 = new Path(targetTestRoot, "fallbackDir/user1/hive/warehouse1"); Path dir2 = new Path(targetTestRoot, "fallbackDir/user1/hive/warehouse1");
fsTarget.mkdirs(dir2); fsTarget.mkdirs(dir2);
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
ConfigUtil ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri()); .addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) { try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
for (FileStatus stat : vfs.listStatus( for (FileStatus stat : vfs.listStatus(
new Path(viewFsUri.toString(), "/user1/hive/warehouse/"))) { new Path(viewFsDefaultClusterUri.toString(),
"/user1/hive/warehouse/"))) {
if (file1.getName().equals(stat.getPath().getName())) { if (file1.getName().equals(stat.getPath().getName())) {
// Link represents as symlink. // Link represents as symlink.
assertFalse(stat.isFile()); assertFalse(stat.isFile());
@ -606,4 +602,167 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
} }
} }
} }
/**
* Tests that directory making should be successful when the parent directory
* is same as the existent fallback directory. The new dir should be created
* in fallback instead failing.
*/
@Test
public void testMkdirsOfLinkParentWithFallbackLinkWithSameMountDirectoryTree()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive/warehouse/partition-0",
new Path(targetTestRoot.toString()).toUri());
Path dir1 = new Path(targetTestRoot,
"fallbackDir/user1/hive/warehouse/partition-0");
fsTarget.mkdirs(dir1);
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
Path p = new Path("/user1/hive/warehouse/test");
Path test = Path.mergePaths(fallbackTarget, p);
assertFalse(fsTarget.exists(test));
assertTrue(vfs.mkdirs(p));
assertTrue(fsTarget.exists(test));
}
}
/**
* Tests that directory making should be successful when attempting to create
* the root directory as it's already exist.
*/
@Test
public void testMkdirsOfRootWithFallbackLinkAndMountWithSameDirTree()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil
.addLink(conf, "/user1", new Path(targetTestRoot.toString()).toUri());
Path dir1 = new Path(targetTestRoot, "fallbackDir/user1");
fsTarget.mkdirs(dir1);
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
Path p = new Path("/");
Path test = Path.mergePaths(fallbackTarget, p);
assertTrue(fsTarget.exists(test));
assertTrue(vfs.mkdirs(p));
assertTrue(fsTarget.exists(test));
}
}
/**
* Tests the making of a new directory which is not matching to any of
* internal directory under the root.
*/
@Test
public void testMkdirsOfNewDirWithOutMatchingToMountOrFallbackDirTree()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive/warehouse/partition-0",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
// user2 does not exist in fallback
Path p = new Path("/user2");
Path test = Path.mergePaths(fallbackTarget, p);
assertFalse(fsTarget.exists(test));
assertTrue(vfs.mkdirs(p));
assertTrue(fsTarget.exists(test));
}
}
/**
* Tests that when the parent dirs does not exist in fallback but the parent
* dir is same as mount internal directory, then we create parent structure
* (mount internal directory tree structure) in fallback.
*/
@Test
public void testMkdirsWithFallbackLinkWithMountPathMatchingDirExist()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
//user1 does not exist in fallback
Path immediateLevelToInternalDir = new Path("/user1/test");
Path test = Path.mergePaths(fallbackTarget, immediateLevelToInternalDir);
assertFalse(fsTarget.exists(test));
assertTrue(vfs.mkdirs(immediateLevelToInternalDir));
assertTrue(fsTarget.exists(test));
}
}
/**
* Tests that when the parent dirs does not exist in fallback but the
* immediate parent dir is not same as mount internal directory, then we
* create parent structure (mount internal directory tree structure) in
* fallback.
*/
@Test
public void testMkdirsOfDeepTreeWithFallbackLinkAndMountPathMatchingDirExist()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
//user1 does not exist in fallback
Path multipleLevelToInternalDir = new Path("/user1/test/test");
Path test = Path.mergePaths(fallbackTarget, multipleLevelToInternalDir);
assertFalse(fsTarget.exists(test));
assertTrue(vfs.mkdirs(multipleLevelToInternalDir));
assertTrue(fsTarget.exists(test));
}
}
/**
* Tests that mkdirs should return false when there is a problem with
* fallbackfs.
*/
@Test
public void testMkdirsShouldReturnFalseWhenFallbackFSNotAvailable()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/test",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
try (FileSystem vfs = FileSystem.get(viewFsDefaultClusterUri, conf)) {
//user1/test1 does not exist in fallback
Path nextLevelToInternalDir = new Path("/user1/test1");
Path test = Path.mergePaths(fallbackTarget, nextLevelToInternalDir);
assertFalse(fsTarget.exists(test));
// user1 exists in viewFS mount.
assertNotNull(vfs.getFileStatus(new Path("/user1")));
// user1 does not exists in fallback.
assertFalse(fsTarget.exists(test.getParent()));
cluster.shutdownNameNodes(); // Stopping fallback server
// /user1/test1 does not exist in mount internal dir tree, it would
// attempt to create in fallback.
assertFalse(vfs.mkdirs(nextLevelToInternalDir));
cluster.restartNameNodes();
// should return true succeed when fallback fs is back to normal.
assertTrue(vfs.mkdirs(nextLevelToInternalDir));
assertTrue(fsTarget.exists(test));
}
}
} }

View File

@ -0,0 +1,297 @@
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.fs.viewfs;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.AbstractFileSystem;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.MiniDFSNNTopology;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Test for viewfs with LinkFallback mount table entries.
*/
public class TestViewFsLinkFallback {
private static FileSystem fsDefault;
private FileSystem fsTarget;
private static MiniDFSCluster cluster;
private static URI viewFsDefaultClusterUri;
private Path targetTestRoot;
@BeforeClass
public static void clusterSetupAtBeginning()
throws IOException, URISyntaxException {
int nameSpacesCount = 3;
int dataNodesCount = 3;
int fsIndexDefault = 0;
Configuration conf = new Configuration();
FileSystem[] fsHdfs = new FileSystem[nameSpacesCount];
conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_DELEGATION_TOKEN_ALWAYS_USE_KEY,
true);
cluster = new MiniDFSCluster.Builder(conf)
.nnTopology(MiniDFSNNTopology.simpleFederatedTopology(
nameSpacesCount))
.numDataNodes(dataNodesCount)
.build();
cluster.waitClusterUp();
for (int i = 0; i < nameSpacesCount; i++) {
fsHdfs[i] = cluster.getFileSystem(i);
}
fsDefault = fsHdfs[fsIndexDefault];
viewFsDefaultClusterUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
}
@AfterClass
public static void clusterShutdownAtEnd() throws Exception {
if (cluster != null) {
cluster.shutdown();
}
}
@Before
public void setUp() throws Exception {
fsTarget = fsDefault;
initializeTargetTestRoot();
}
private void initializeTargetTestRoot() throws IOException {
targetTestRoot = fsDefault.makeQualified(new Path("/"));
for (FileStatus status : fsDefault.listStatus(targetTestRoot)) {
fsDefault.delete(status.getPath(), true);
}
}
/**
* Tests that directory making should be successful when the parent directory
* is same as the existent fallback directory. The new dir should be created
* in fallback instead failing.
*/
@Test
public void testMkdirOfLinkParentWithFallbackLinkWithSameMountDirectoryTree()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive/warehouse/partition-0",
new Path(targetTestRoot.toString()).toUri());
Path dir1 = new Path(targetTestRoot,
"fallbackDir/user1/hive/warehouse/partition-0");
fsTarget.mkdirs(dir1);
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs =
AbstractFileSystem.get(viewFsDefaultClusterUri, conf);
Path p = new Path("/user1/hive/warehouse/test");
Path test = Path.mergePaths(fallbackTarget, p);
assertFalse(fsTarget.exists(test));
vfs.mkdir(p, null, true);
assertTrue(fsTarget.exists(test));
}
/**
* Tests that directory making should be successful when attempting to create
* the root directory as it's already exist.
*/
@Test
public void testMkdirOfRootWithFallbackLinkAndMountWithSameDirTree()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil
.addLink(conf, "/user1", new Path(targetTestRoot.toString()).toUri());
Path dir1 = new Path(targetTestRoot, "fallbackDir/user1");
fsTarget.mkdirs(dir1);
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs =
AbstractFileSystem.get(viewFsDefaultClusterUri, conf);
Path p = new Path("/");
Path test = Path.mergePaths(fallbackTarget, p);
assertTrue(fsTarget.exists(test));
vfs.mkdir(p, null, true);
assertTrue(fsTarget.exists(test));
}
/**
* Tests the making of a new directory which is not matching to any of
* internal directory under the root.
*/
@Test
public void testMkdirOfNewDirWithOutMatchingToMountOrFallbackDirTree()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive/warehouse/partition-0",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs =
AbstractFileSystem.get(viewFsDefaultClusterUri, conf);
// user2 does not exist in fallback
Path p = new Path("/user2");
Path test = Path.mergePaths(fallbackTarget, p);
assertFalse(fsTarget.exists(test));
vfs.mkdir(p, null, true);
assertTrue(fsTarget.exists(test));
}
/**
* Tests that when the parent dirs does not exist in fallback but the parent
* dir is same as mount internal directory, then we create parent structure
* (mount internal directory tree structure) in fallback.
*/
@Test
public void testMkdirWithFallbackLinkWithMountPathMatchingDirExist()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs =
AbstractFileSystem.get(viewFsDefaultClusterUri, conf);
//user1 does not exist in fallback
Path immediateLevelToInternalDir = new Path("/user1/test");
Path test = Path.mergePaths(fallbackTarget, immediateLevelToInternalDir);
assertFalse(fsTarget.exists(test));
vfs.mkdir(immediateLevelToInternalDir, null, true);
assertTrue(fsTarget.exists(test));
}
/**
* Tests that when the parent dirs does not exist in fallback but the
* immediate parent dir is not same as mount internal directory, then we
* create parent structure (mount internal directory tree structure) in
* fallback.
*/
@Test
public void testMkdirOfDeepTreeWithFallbackLinkAndMountPathMatchingDirExist()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs =
AbstractFileSystem.get(viewFsDefaultClusterUri, conf);
//user1 does not exist in fallback
Path multipleLevelToInternalDir = new Path("/user1/test/test");
Path test = Path.mergePaths(fallbackTarget, multipleLevelToInternalDir);
assertFalse(fsTarget.exists(test));
vfs.mkdir(multipleLevelToInternalDir, null, true);
assertTrue(fsTarget.exists(test));
}
/**
* Tests that mkdir with createParent false should still create parent in
* fallback when the same mount dir exist.
*/
@Test
public void testMkdirShouldCreateParentDirInFallbackWhenMountDirExist()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/hive/test",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs = AbstractFileSystem.get(viewFsDefaultClusterUri,
conf);
//user1/hive/test1 does not exist in fallback
Path multipleLevelToInternalDir = new Path("/user1/hive/test1");
Path test = Path.mergePaths(fallbackTarget, multipleLevelToInternalDir);
assertFalse(fsTarget.exists(test));
// user1/hive exist in viewFS.
assertNotNull(vfs.getFileStatus(new Path("/user1/hive")));
// user1/hive does not exists in fallback.
assertFalse(fsTarget.exists(test.getParent()));
vfs.mkdir(multipleLevelToInternalDir, FsPermission.getDirDefault(), false);
assertTrue(fsTarget.exists(test));
}
/**
* Tests that mkdir should fail with IOE when there is a problem with
* fallbackfs.
*/
@Test
public void testMkdirShouldFailWhenFallbackFSNotAvailable()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, false);
ConfigUtil.addLink(conf, "/user1/test",
new Path(targetTestRoot.toString()).toUri());
Path fallbackTarget = new Path(targetTestRoot, "fallbackDir");
fsTarget.mkdirs(fallbackTarget);
ConfigUtil.addLinkFallback(conf, fallbackTarget.toUri());
AbstractFileSystem vfs = AbstractFileSystem.get(viewFsDefaultClusterUri,
conf);
//user1/test1 does not exist in fallback
Path nextLevelToInternalDir = new Path("/user1/test1");
Path test = Path.mergePaths(fallbackTarget, nextLevelToInternalDir);
assertFalse(fsTarget.exists(test));
// user1 exists in viewFS mount.
assertNotNull(vfs.getFileStatus(new Path("/user1")));
// user1 does not exists in fallback.
assertFalse(fsTarget.exists(test.getParent()));
cluster.shutdownNameNodes();
try {
// /user1/test1 does not exist in mount internal dir tree, it would
// attempt to create in fallback.
vfs.mkdir(nextLevelToInternalDir, FsPermission.getDirDefault(),
false);
Assert.fail("It should throw IOE when fallback fs not available.");
} catch (IOException e) {
cluster.restartNameNodes();
// should succeed when fallback fs is back to normal.
vfs.mkdir(nextLevelToInternalDir, FsPermission.getDirDefault(),
false);
}
assertTrue(fsTarget.exists(test));
}
}