HADOOP-18193:Support nested mount points in INodeTree
Fixes #4181 Signed-off-by: Owen O'Malley <oomalley@linkedin.com>
This commit is contained in:
parent
1350539f2d
commit
6a95c3a039
|
@ -247,4 +247,22 @@ public class ConfigUtil {
|
|||
return conf.get(Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE_NAME_KEY,
|
||||
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the bool config whether nested mount point is supported. Default: true
|
||||
* @param conf - from this conf
|
||||
* @return whether nested mount point is supported
|
||||
*/
|
||||
public static boolean isNestedMountPointSupported(final Configuration conf) {
|
||||
return conf.getBoolean(Constants.CONFIG_NESTED_MOUNT_POINT_SUPPORTED, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bool value isNestedMountPointSupported in config.
|
||||
* @param conf - from this conf
|
||||
* @param isNestedMountPointSupported - whether nested mount point is supported
|
||||
*/
|
||||
public static void setIsNestedMountPointSupported(final Configuration conf, boolean isNestedMountPointSupported) {
|
||||
conf.setBoolean(Constants.CONFIG_NESTED_MOUNT_POINT_SUPPORTED, isNestedMountPointSupported);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,11 @@ public interface Constants {
|
|||
*/
|
||||
public static final String CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE = "default";
|
||||
|
||||
/**
|
||||
* Config to enable nested mount point in viewfs
|
||||
*/
|
||||
String CONFIG_NESTED_MOUNT_POINT_SUPPORTED = CONFIG_VIEWFS_PREFIX + ".nested.mount.point.supported";
|
||||
|
||||
/**
|
||||
* Config variable full prefix for the default mount table.
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
*/
|
||||
package org.apache.hadoop.fs.viewfs;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Function;
|
||||
import org.apache.hadoop.util.Preconditions;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -81,6 +85,8 @@ public abstract class InodeTree<T> {
|
|||
private List<RegexMountPoint<T>> regexMountPointList =
|
||||
new ArrayList<RegexMountPoint<T>>();
|
||||
|
||||
private final boolean isNestedMountPointSupported;
|
||||
|
||||
public static class MountPoint<T> {
|
||||
String src;
|
||||
INodeLink<T> target;
|
||||
|
@ -99,7 +105,7 @@ public abstract class InodeTree<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the target link.
|
||||
* Returns the target INode link.
|
||||
* @return The target INode link
|
||||
*/
|
||||
public INodeLink<T> getTarget() {
|
||||
|
@ -138,6 +144,14 @@ public abstract class InodeTree<T> {
|
|||
boolean isLink() {
|
||||
return !isInternalDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the link if isLink.
|
||||
* @return will return null, for non links.
|
||||
*/
|
||||
INodeLink<T> getLink() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,6 +226,51 @@ public abstract class InodeTree<T> {
|
|||
}
|
||||
children.put(pathComponent, link);
|
||||
}
|
||||
|
||||
void addDirLink(final String pathComponent, final INodeDirLink<T> dirLink) {
|
||||
children.put(pathComponent, dirLink);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class to represent an INodeDir which also contains a INodeLink. This is used to support nested mount points
|
||||
* where an INode is internalDir but points to a mount link. The class is a subclass of INodeDir and the semantics are
|
||||
* as follows:
|
||||
* isLink(): true
|
||||
* isInternalDir(): true
|
||||
* @param <T>
|
||||
*/
|
||||
static class INodeDirLink<T> extends INodeDir<T> {
|
||||
/**
|
||||
* INodeLink wrapped in the INodeDir
|
||||
*/
|
||||
private final INodeLink<T> link;
|
||||
|
||||
INodeDirLink(String pathToNode, UserGroupInformation aUgi, INodeLink<T> link) {
|
||||
super(pathToNode, aUgi);
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
@Override
|
||||
INodeLink<T> getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* True because the INodeDirLink also contains a INodeLink
|
||||
*/
|
||||
@Override
|
||||
boolean isLink() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* True because the INodeDirLink is internal node
|
||||
*/
|
||||
@Override
|
||||
boolean isInternalDir() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -320,6 +379,11 @@ public abstract class InodeTree<T> {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
INodeLink<T> getLink() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance of FileSystem to use, creating one if needed.
|
||||
* @return An Initialized instance of T
|
||||
|
@ -376,10 +440,17 @@ public abstract class InodeTree<T> {
|
|||
newDir.setInternalDirFs(getTargetFileSystem(newDir));
|
||||
nextInode = newDir;
|
||||
}
|
||||
if (nextInode.isLink()) {
|
||||
if (!nextInode.isInternalDir()) {
|
||||
if (isNestedMountPointSupported) {
|
||||
// nested mount detected, add a new INodeDirLink that wraps existing INodeLink to INodeTree and override existing INodelink
|
||||
INodeDirLink<T> dirLink = new INodeDirLink<T>(nextInode.fullPath, aUgi, (INodeLink<T>) nextInode);
|
||||
curInode.addDirLink(iPath, dirLink);
|
||||
curInode = dirLink;
|
||||
} else {
|
||||
// Error - expected a dir but got a link
|
||||
throw new FileAlreadyExistsException("Path " + nextInode.fullPath +
|
||||
" already exists as link");
|
||||
}
|
||||
} else {
|
||||
assert(nextInode.isInternalDir());
|
||||
curInode = (INodeDir<T>) nextInode;
|
||||
|
@ -445,7 +516,7 @@ public abstract class InodeTree<T> {
|
|||
}
|
||||
|
||||
private INodeLink<T> getRootLink() {
|
||||
Preconditions.checkState(root.isLink());
|
||||
Preconditions.checkState(!root.isInternalDir());
|
||||
return (INodeLink<T>)root;
|
||||
}
|
||||
|
||||
|
@ -538,6 +609,7 @@ public abstract class InodeTree<T> {
|
|||
mountTableName = ConfigUtil.getDefaultMountTableName(config);
|
||||
}
|
||||
homedirPrefix = ConfigUtil.getHomeDirValue(config, mountTableName);
|
||||
isNestedMountPointSupported = ConfigUtil.isNestedMountPointSupported(config);
|
||||
|
||||
boolean isMergeSlashConfigured = false;
|
||||
String mergeSlashTarget = null;
|
||||
|
@ -642,7 +714,8 @@ public abstract class InodeTree<T> {
|
|||
getRootDir().setInternalDirFs(getTargetFileSystem(getRootDir()));
|
||||
getRootDir().setRoot(true);
|
||||
INodeLink<T> fallbackLink = null;
|
||||
for (LinkEntry le : linkEntries) {
|
||||
|
||||
for (LinkEntry le : getLinkEntries(linkEntries)) {
|
||||
switch (le.getLinkType()) {
|
||||
case SINGLE_FALLBACK:
|
||||
if (fallbackLink != null) {
|
||||
|
@ -682,6 +755,32 @@ public abstract class InodeTree<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection of linkEntry. Sort mount point based on alphabetical order of the src paths.
|
||||
* The purpose is to group nested paths(shortest path always comes first) during INodeTree creation.
|
||||
* E.g. /foo is nested with /foo/bar so an INodeDirLink will be created at /foo.
|
||||
* @param linkEntries input linkEntries
|
||||
* @return sorted linkEntries
|
||||
*/
|
||||
private Collection<LinkEntry> getLinkEntries(List<LinkEntry> linkEntries) {
|
||||
Set<LinkEntry> sortedLinkEntries = new TreeSet<>(new Comparator<LinkEntry>() {
|
||||
@Override
|
||||
public int compare(LinkEntry o1, LinkEntry o2) {
|
||||
if (o1 == null) {
|
||||
return -1;
|
||||
}
|
||||
if (o2 == null) {
|
||||
return 1;
|
||||
}
|
||||
String src1 = o1.getSrc();
|
||||
String src2= o2.getSrc();
|
||||
return src1.compareTo(src2);
|
||||
}
|
||||
});
|
||||
sortedLinkEntries.addAll(linkEntries);
|
||||
return sortedLinkEntries;
|
||||
}
|
||||
|
||||
private void checkMntEntryKeyEqualsTarget(
|
||||
String mntEntryKey, String targetMntEntryKey) throws IOException {
|
||||
if (!mntEntryKey.equals(targetMntEntryKey)) {
|
||||
|
@ -795,7 +894,7 @@ public abstract class InodeTree<T> {
|
|||
* been linked to the root directory of a file system.
|
||||
* The first non-slash path component should be name of the mount table.
|
||||
*/
|
||||
if (root.isLink()) {
|
||||
if (!root.isInternalDir()) {
|
||||
Path remainingPath;
|
||||
StringBuilder remainingPathStr = new StringBuilder();
|
||||
// ignore first slash
|
||||
|
@ -818,10 +917,17 @@ public abstract class InodeTree<T> {
|
|||
}
|
||||
|
||||
int i;
|
||||
INodeDirLink<T> lastResolvedDirLink = null;
|
||||
int lastResolvedDirLinkIndex = -1;
|
||||
// ignore first slash
|
||||
for (i = 1; i < path.length - (resolveLastComponent ? 0 : 1); i++) {
|
||||
INode<T> nextInode = curInode.resolveInternal(path[i]);
|
||||
if (nextInode == null) {
|
||||
// first resolve to dirlink for nested mount point
|
||||
if (isNestedMountPointSupported && lastResolvedDirLink != null) {
|
||||
return new ResolveResult<T>(ResultKind.EXTERNAL_DIR, lastResolvedDirLink.getLink().getTargetFileSystem(),
|
||||
lastResolvedDirLink.fullPath, getRemainingPath(path, i),true);
|
||||
}
|
||||
if (hasFallbackLink()) {
|
||||
resolveResult = new ResolveResult<T>(ResultKind.EXTERNAL_DIR,
|
||||
getRootFallbackLink().getTargetFileSystem(), root.fullPath,
|
||||
|
@ -837,46 +943,54 @@ public abstract class InodeTree<T> {
|
|||
}
|
||||
}
|
||||
|
||||
if (nextInode.isLink()) {
|
||||
if (!nextInode.isInternalDir()) {
|
||||
final INodeLink<T> link = (INodeLink<T>) nextInode;
|
||||
final Path remainingPath;
|
||||
if (i >= path.length - 1) {
|
||||
remainingPath = SlashPath;
|
||||
} else {
|
||||
StringBuilder remainingPathStr =
|
||||
new StringBuilder("/" + path[i + 1]);
|
||||
for (int j = i + 2; j < path.length; ++j) {
|
||||
remainingPathStr.append('/').append(path[j]);
|
||||
}
|
||||
remainingPath = new Path(remainingPathStr.toString());
|
||||
}
|
||||
final Path remainingPath = getRemainingPath(path, i + 1);
|
||||
resolveResult = new ResolveResult<T>(ResultKind.EXTERNAL_DIR,
|
||||
link.getTargetFileSystem(), nextInode.fullPath, remainingPath,
|
||||
true);
|
||||
return resolveResult;
|
||||
} else if (nextInode.isInternalDir()) {
|
||||
} else {
|
||||
curInode = (INodeDir<T>) nextInode;
|
||||
// track last resolved nest mount point.
|
||||
if (isNestedMountPointSupported && nextInode.isLink()) {
|
||||
lastResolvedDirLink = (INodeDirLink<T>) nextInode;
|
||||
lastResolvedDirLinkIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have resolved to an internal dir in mount table.
|
||||
Path remainingPath;
|
||||
if (resolveLastComponent) {
|
||||
if (isNestedMountPointSupported && lastResolvedDirLink != null) {
|
||||
remainingPath = getRemainingPath(path, lastResolvedDirLinkIndex + 1);
|
||||
resolveResult = new ResolveResult<T>(ResultKind.EXTERNAL_DIR, lastResolvedDirLink.getLink().getTargetFileSystem(),
|
||||
lastResolvedDirLink.fullPath, remainingPath,true);
|
||||
} else {
|
||||
remainingPath = resolveLastComponent ? SlashPath : getRemainingPath(path, i);
|
||||
resolveResult = new ResolveResult<T>(ResultKind.INTERNAL_DIR, curInode.getInternalDirFs(),
|
||||
curInode.fullPath, remainingPath, false);
|
||||
}
|
||||
return resolveResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return remaining path from specified index to the end of the path array.
|
||||
* @param path An array of path components split by slash
|
||||
* @param startIndex the specified start index of the path array
|
||||
* @return remaining path.
|
||||
*/
|
||||
private Path getRemainingPath(String[] path, int startIndex) {
|
||||
Path remainingPath;
|
||||
if (startIndex >= path.length) {
|
||||
remainingPath = SlashPath;
|
||||
} else {
|
||||
// note we have taken care of when path is "/" above
|
||||
// for internal dirs rem-path does not start with / since the lookup
|
||||
// that follows will do a children.get(remaningPath) and will have to
|
||||
// strip-out the initial /
|
||||
StringBuilder remainingPathStr = new StringBuilder("/" + path[i]);
|
||||
for (int j = i + 1; j < path.length; ++j) {
|
||||
remainingPathStr.append('/').append(path[j]);
|
||||
StringBuilder remainingPathStr = new StringBuilder();
|
||||
for (int j = startIndex; j < path.length; j++) {
|
||||
remainingPathStr.append("/").append(path[j]);
|
||||
}
|
||||
remainingPath = new Path(remainingPathStr.toString());
|
||||
}
|
||||
resolveResult = new ResolveResult<T>(ResultKind.INTERNAL_DIR,
|
||||
curInode.getInternalDirFs(), curInode.fullPath, remainingPath, false);
|
||||
return resolveResult;
|
||||
return remainingPath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1544,7 +1544,7 @@ public class ViewFileSystem extends FileSystem {
|
|||
INode<FileSystem> inode = iEntry.getValue();
|
||||
Path path = new Path(inode.fullPath).makeQualified(myUri, null);
|
||||
if (inode.isLink()) {
|
||||
INodeLink<FileSystem> link = (INodeLink<FileSystem>) inode;
|
||||
INodeLink<FileSystem> link = inode.getLink();
|
||||
|
||||
if (showMountLinksAsSymlinks) {
|
||||
// To maintain backward compatibility, with default option(showing
|
||||
|
|
|
@ -1098,8 +1098,7 @@ public class ViewFs extends AbstractFileSystem {
|
|||
}
|
||||
FileStatus result;
|
||||
if (inode.isLink()) {
|
||||
INodeLink<AbstractFileSystem> inodelink =
|
||||
(INodeLink<AbstractFileSystem>) inode;
|
||||
INodeLink<AbstractFileSystem> inodelink = inode.getLink();
|
||||
try {
|
||||
String linkedPath = inodelink.getTargetFileSystem()
|
||||
.getUri().getPath();
|
||||
|
@ -1169,8 +1168,7 @@ public class ViewFs extends AbstractFileSystem {
|
|||
INode<AbstractFileSystem> inode = iEntry.getValue();
|
||||
Path path = new Path(inode.fullPath).makeQualified(myUri, null);
|
||||
if (inode.isLink()) {
|
||||
INodeLink<AbstractFileSystem> link =
|
||||
(INodeLink<AbstractFileSystem>) inode;
|
||||
INodeLink<AbstractFileSystem> link = inode.getLink();
|
||||
|
||||
if (showMountLinksAsSymlinks) {
|
||||
// To maintain backward compatibility, with default option(showing
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
/**
|
||||
* 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 java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.FsConstants;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* Unit test of nested mount point support in INodeTree
|
||||
*/
|
||||
public class TestNestedMountPoint {
|
||||
private InodeTree inodeTree;
|
||||
private Configuration conf;
|
||||
private String mtName;
|
||||
private URI fsUri;
|
||||
|
||||
static class TestNestMountPointFileSystem {
|
||||
public URI getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
private URI uri;
|
||||
|
||||
TestNestMountPointFileSystem(URI uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
}
|
||||
|
||||
static class TestNestMountPointInternalFileSystem extends TestNestMountPointFileSystem {
|
||||
TestNestMountPointInternalFileSystem(URI uri) {
|
||||
super(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private static final URI LINKFALLBACK_TARGET = URI.create("hdfs://nn00");
|
||||
private static final URI NN1_TARGET = URI.create("hdfs://nn01/a/b");
|
||||
private static final URI NN2_TARGET = URI.create("hdfs://nn02/a/b/e");
|
||||
private static final URI NN3_TARGET = URI.create("hdfs://nn03/a/b/c/d");
|
||||
private static final URI NN4_TARGET = URI.create("hdfs://nn04/a/b/c/d/e");
|
||||
private static final URI NN5_TARGET = URI.create("hdfs://nn05/b/c/d/e");
|
||||
private static final URI NN6_TARGET = URI.create("hdfs://nn06/b/c/d/e/f");
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
conf = new Configuration();
|
||||
mtName = TestNestedMountPoint.class.getName();
|
||||
ConfigUtil.setIsNestedMountPointSupported(conf, true);
|
||||
ConfigUtil.addLink(conf, mtName, "/a/b", NN1_TARGET);
|
||||
ConfigUtil.addLink(conf, mtName, "/a/b/e", NN2_TARGET);
|
||||
ConfigUtil.addLink(conf, mtName, "/a/b/c/d", NN3_TARGET);
|
||||
ConfigUtil.addLink(conf, mtName, "/a/b/c/d/e", NN4_TARGET);
|
||||
ConfigUtil.addLink(conf, mtName, "/b/c/d/e", NN5_TARGET);
|
||||
ConfigUtil.addLink(conf, mtName, "/b/c/d/e/f", NN6_TARGET);
|
||||
ConfigUtil.addLinkFallback(conf, mtName, LINKFALLBACK_TARGET);
|
||||
|
||||
fsUri = new URI(FsConstants.VIEWFS_SCHEME, mtName, "/", null, null);
|
||||
|
||||
inodeTree = new InodeTree<TestNestedMountPoint.TestNestMountPointFileSystem>(conf,
|
||||
mtName, fsUri, false) {
|
||||
@Override
|
||||
protected Function<URI, TestNestedMountPoint.TestNestMountPointFileSystem> initAndGetTargetFs() {
|
||||
return new Function<URI, TestNestMountPointFileSystem>() {
|
||||
@Override
|
||||
public TestNestedMountPoint.TestNestMountPointFileSystem apply(URI uri) {
|
||||
return new TestNestMountPointFileSystem(uri);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// For intenral dir fs
|
||||
@Override
|
||||
protected TestNestedMountPoint.TestNestMountPointInternalFileSystem getTargetFileSystem(
|
||||
final INodeDir<TestNestedMountPoint.TestNestMountPointFileSystem> dir) {
|
||||
return new TestNestMountPointInternalFileSystem(fsUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestNestedMountPoint.TestNestMountPointInternalFileSystem getTargetFileSystem(
|
||||
final String settings, final URI[] mergeFsURIList) {
|
||||
return new TestNestMountPointInternalFileSystem(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
inodeTree = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToLink() throws Exception {
|
||||
// /a/b/c/d/e/f resolves to /a/b/c/d/e and /f
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/c/d/e/f", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b/c/d/e", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN4_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d/e resolves to /a/b/c/d/e and /
|
||||
InodeTree.ResolveResult resolveResult2 = inodeTree.resolve("/a/b/c/d/e", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult2.kind);
|
||||
Assert.assertEquals("/a/b/c/d/e", resolveResult2.resolvedPath);
|
||||
Assert.assertEquals(new Path("/"), resolveResult2.remainingPath);
|
||||
Assert.assertTrue(resolveResult2.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN4_TARGET, ((TestNestMountPointFileSystem) resolveResult2.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult2.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d/e/f/g/h/i resolves to /a/b/c/d/e and /f/g/h/i
|
||||
InodeTree.ResolveResult resolveResult3 = inodeTree.resolve("/a/b/c/d/e/f/g/h/i", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult3.kind);
|
||||
Assert.assertEquals("/a/b/c/d/e", resolveResult3.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f/g/h/i"), resolveResult3.remainingPath);
|
||||
Assert.assertTrue(resolveResult3.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN4_TARGET, ((TestNestMountPointFileSystem) resolveResult3.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult3.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToLinkNotResolveLastComponent() throws Exception {
|
||||
// /a/b/c/d/e/f resolves to /a/b/c/d/e and /f
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/c/d/e/f", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b/c/d/e", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN4_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d/e resolves to /a/b/c/d and /e
|
||||
InodeTree.ResolveResult resolveResult2 = inodeTree.resolve("/a/b/c/d/e", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult2.kind);
|
||||
Assert.assertEquals("/a/b/c/d", resolveResult2.resolvedPath);
|
||||
Assert.assertEquals(new Path("/e"), resolveResult2.remainingPath);
|
||||
Assert.assertTrue(resolveResult2.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN3_TARGET, ((TestNestMountPointFileSystem) resolveResult2.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult2.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d/e/f/g/h/i resolves to /a/b/c/d/e and /f/g/h/i
|
||||
InodeTree.ResolveResult resolveResult3 = inodeTree.resolve("/a/b/c/d/e/f/g/h/i", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult3.kind);
|
||||
Assert.assertEquals("/a/b/c/d/e", resolveResult3.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f/g/h/i"), resolveResult3.remainingPath);
|
||||
Assert.assertTrue(resolveResult3.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN4_TARGET, ((TestNestMountPointFileSystem) resolveResult3.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult3.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToDirLink() throws Exception {
|
||||
// /a/b/c/d/f resolves to /a/b/c/d, /f
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/c/d/f", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b/c/d", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN3_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d resolves to /a/b/c/d and /
|
||||
InodeTree.ResolveResult resolveResult2 = inodeTree.resolve("/a/b/c/d", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult2.kind);
|
||||
Assert.assertEquals("/a/b/c/d", resolveResult2.resolvedPath);
|
||||
Assert.assertEquals(new Path("/"), resolveResult2.remainingPath);
|
||||
Assert.assertTrue(resolveResult2.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN3_TARGET, ((TestNestMountPointFileSystem) resolveResult2.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult2.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d/f/g/h/i resolves to /a/b/c/d and /f/g/h/i
|
||||
InodeTree.ResolveResult resolveResult3 = inodeTree.resolve("/a/b/c/d/f/g/h/i", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult3.kind);
|
||||
Assert.assertEquals("/a/b/c/d", resolveResult3.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f/g/h/i"), resolveResult3.remainingPath);
|
||||
Assert.assertTrue(resolveResult3.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN3_TARGET, ((TestNestMountPointFileSystem) resolveResult3.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult3.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToDirLinkNotResolveLastComponent() throws Exception {
|
||||
// /a/b/c/d/f resolves to /a/b/c/d, /f
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/c/d/f", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b/c/d", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN3_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d resolves to /a/b and /c/d
|
||||
InodeTree.ResolveResult resolveResult2 = inodeTree.resolve("/a/b/c/d", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult2.kind);
|
||||
Assert.assertEquals("/a/b", resolveResult2.resolvedPath);
|
||||
Assert.assertEquals(new Path("/c/d"), resolveResult2.remainingPath);
|
||||
Assert.assertTrue(resolveResult2.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN1_TARGET, ((TestNestMountPointFileSystem) resolveResult2.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult2.isLastInternalDirLink());
|
||||
|
||||
// /a/b/c/d/f/g/h/i resolves to /a/b/c/d and /f/g/h/i
|
||||
InodeTree.ResolveResult resolveResult3 = inodeTree.resolve("/a/b/c/d/f/g/h/i", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult3.kind);
|
||||
Assert.assertEquals("/a/b/c/d", resolveResult3.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f/g/h/i"), resolveResult3.remainingPath);
|
||||
Assert.assertTrue(resolveResult3.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN3_TARGET, ((TestNestMountPointFileSystem) resolveResult3.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult3.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiNestedMountPointsPathResolveToDirLink() throws Exception {
|
||||
// /a/b/f resolves to /a/b and /f
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/f", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN1_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
|
||||
// /a/b resolves to /a/b and /
|
||||
InodeTree.ResolveResult resolveResult2 = inodeTree.resolve("/a/b", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult2.kind);
|
||||
Assert.assertEquals("/a/b", resolveResult2.resolvedPath);
|
||||
Assert.assertEquals(new Path("/"), resolveResult2.remainingPath);
|
||||
Assert.assertTrue(resolveResult2.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN1_TARGET, ((TestNestMountPointFileSystem) resolveResult2.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult2.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiNestedMountPointsPathResolveToDirLinkNotResolveLastComponent() throws Exception {
|
||||
// /a/b/f resolves to /a/b and /f
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/f", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/f"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN1_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
|
||||
// /a/b resolves to /a and /b
|
||||
InodeTree.ResolveResult resolveResult2 = inodeTree.resolve("/a/b", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.INTERNAL_DIR, resolveResult2.kind);
|
||||
Assert.assertEquals("/a", resolveResult2.resolvedPath);
|
||||
Assert.assertEquals(new Path("/b"), resolveResult2.remainingPath);
|
||||
Assert.assertTrue(resolveResult2.targetFileSystem instanceof TestNestMountPointInternalFileSystem);
|
||||
Assert.assertEquals(fsUri, ((TestNestMountPointInternalFileSystem) resolveResult2.targetFileSystem).getUri());
|
||||
Assert.assertFalse(resolveResult2.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToDirLinkLastComponentInternalDir() throws Exception {
|
||||
// /a/b/c resolves to /a/b and /c
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/c", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/c"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN1_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToDirLinkLastComponentInternalDirNotResolveLastComponent() throws Exception {
|
||||
// /a/b/c resolves to /a/b and /c
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/b/c", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a/b", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/c"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(NN1_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertTrue(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToLinkFallBack() throws Exception {
|
||||
// /a/e resolves to linkfallback
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/e", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.EXTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/a/e"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointFileSystem);
|
||||
Assert.assertEquals(LINKFALLBACK_TARGET, ((TestNestMountPointFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertFalse(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathNotResolveToLinkFallBackNotResolveLastComponent() throws Exception {
|
||||
// /a/e resolves to internalDir instead of linkfallback
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/a/e", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.INTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/a", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/e"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointInternalFileSystem);
|
||||
Assert.assertEquals(fsUri, ((TestNestMountPointInternalFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertFalse(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToInternalDir() throws Exception {
|
||||
// /b/c resolves to internal dir
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/b/c", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.INTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/b/c", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointInternalFileSystem);
|
||||
Assert.assertEquals(fsUri, ((TestNestMountPointInternalFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertFalse(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathResolveToInternalDirNotResolveLastComponent() throws Exception {
|
||||
// /b/c resolves to internal dir
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/b/c", false);
|
||||
Assert.assertEquals(InodeTree.ResultKind.INTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/b", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/c"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointInternalFileSystem);
|
||||
Assert.assertEquals(fsUri, ((TestNestMountPointInternalFileSystem) resolveResult.targetFileSystem).getUri());
|
||||
Assert.assertFalse(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSlashResolveToInternalDir() throws Exception {
|
||||
// / resolves to internal dir
|
||||
InodeTree.ResolveResult resolveResult = inodeTree.resolve("/", true);
|
||||
Assert.assertEquals(InodeTree.ResultKind.INTERNAL_DIR, resolveResult.kind);
|
||||
Assert.assertEquals("/", resolveResult.resolvedPath);
|
||||
Assert.assertEquals(new Path("/"), resolveResult.remainingPath);
|
||||
Assert.assertTrue(resolveResult.targetFileSystem instanceof TestNestMountPointInternalFileSystem);
|
||||
Assert.assertFalse(resolveResult.isLastInternalDirLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInodeTreeMountPoints() throws Exception {
|
||||
List<InodeTree.MountPoint<FileSystem>> mountPoints = inodeTree.getMountPoints();
|
||||
Assert.assertEquals(6, mountPoints.size());
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ public class TestViewFsConfig {
|
|||
@Test(expected = FileAlreadyExistsException.class)
|
||||
public void testInvalidConfig() throws IOException, URISyntaxException {
|
||||
Configuration conf = new Configuration();
|
||||
ConfigUtil.setIsNestedMountPointSupported(conf, false);
|
||||
ConfigUtil.addLink(conf, "/internalDir/linkToDir2",
|
||||
new Path("file:///dir2").toUri());
|
||||
ConfigUtil.addLink(conf, "/internalDir/linkToDir2/linkToDir3",
|
||||
|
|
|
@ -460,6 +460,148 @@ abstract public class ViewFileSystemBaseTest {
|
|||
.assertIsFile(fsTarget, new Path(targetTestRoot, "data/fooBar"));
|
||||
}
|
||||
|
||||
|
||||
// rename across nested mount points that point to same target also fail
|
||||
@Test
|
||||
public void testRenameAcrossNestedMountPointSameTarget() throws IOException {
|
||||
setUpNestedMountPoint();
|
||||
fileSystemTestHelper.createFile(fsView, "/user/foo");
|
||||
try {
|
||||
// Nested mount points point to the same target should fail
|
||||
// /user -> /user
|
||||
// /user/userA -> /user
|
||||
// Rename strategy: SAME_MOUNTPOINT
|
||||
fsView.rename(new Path("/user/foo"), new Path("/user/userA/foo"));
|
||||
ContractTestUtils.fail("IOException is not thrown on rename operation");
|
||||
} catch (IOException e) {
|
||||
GenericTestUtils
|
||||
.assertExceptionContains("Renames across Mount points not supported",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// rename across nested mount points fail if the mount link targets are different
|
||||
// even if the targets are part of the same target FS
|
||||
@Test
|
||||
public void testRenameAcrossMountPointDifferentTarget() throws IOException {
|
||||
setUpNestedMountPoint();
|
||||
fileSystemTestHelper.createFile(fsView, "/data/foo");
|
||||
// /data -> /data
|
||||
// /data/dataA -> /dataA
|
||||
// Rename strategy: SAME_MOUNTPOINT
|
||||
try {
|
||||
fsView.rename(new Path("/data/foo"), new Path("/data/dataA/fooBar"));
|
||||
ContractTestUtils.fail("IOException is not thrown on rename operation");
|
||||
} catch (IOException e) {
|
||||
GenericTestUtils
|
||||
.assertExceptionContains("Renames across Mount points not supported",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
// RenameStrategy SAME_TARGET_URI_ACROSS_MOUNTPOINT enabled
|
||||
// to rename across nested mount points that point to same target URI
|
||||
@Test
|
||||
public void testRenameAcrossNestedMountPointSameTargetUriAcrossMountPoint() throws IOException {
|
||||
setUpNestedMountPoint();
|
||||
// /user/foo -> /user
|
||||
// /user/userA/fooBarBar -> /user
|
||||
// Rename strategy: SAME_TARGET_URI_ACROSS_MOUNTPOINT
|
||||
Configuration conf2 = new Configuration(conf);
|
||||
conf2.set(Constants.CONFIG_VIEWFS_RENAME_STRATEGY,
|
||||
ViewFileSystem.RenameStrategy.SAME_TARGET_URI_ACROSS_MOUNTPOINT
|
||||
.toString());
|
||||
FileSystem fsView2 = FileSystem.newInstance(FsConstants.VIEWFS_URI, conf2);
|
||||
fileSystemTestHelper.createFile(fsView2, "/user/foo");
|
||||
fsView2.rename(new Path("/user/foo"), new Path("/user/userA/fooBarBar"));
|
||||
ContractTestUtils.assertPathDoesNotExist(fsView2, "src should not exist after rename",
|
||||
new Path("/user/foo"));
|
||||
ContractTestUtils.assertPathDoesNotExist(fsTarget, "src should not exist after rename",
|
||||
new Path(targetTestRoot, "user/foo"));
|
||||
ContractTestUtils.assertIsFile(fsView2, fileSystemTestHelper.getTestRootPath(fsView2, "/user/userA/fooBarBar"));
|
||||
ContractTestUtils.assertIsFile(fsTarget, new Path(targetTestRoot, "user/fooBarBar"));
|
||||
}
|
||||
|
||||
// RenameStrategy SAME_FILESYSTEM_ACROSS_MOUNTPOINT enabled
|
||||
// to rename across mount points where the mount link targets are different
|
||||
// but are part of the same target FS
|
||||
@Test
|
||||
public void testRenameAcrossNestedMountPointSameFileSystemAcrossMountPoint() throws IOException {
|
||||
setUpNestedMountPoint();
|
||||
// /data/foo -> /data
|
||||
// /data/dataA/fooBar -> /dataA
|
||||
// Rename strategy: SAME_FILESYSTEM_ACROSS_MOUNTPOINT
|
||||
Configuration conf2 = new Configuration(conf);
|
||||
conf2.set(Constants.CONFIG_VIEWFS_RENAME_STRATEGY,
|
||||
ViewFileSystem.RenameStrategy.SAME_FILESYSTEM_ACROSS_MOUNTPOINT
|
||||
.toString());
|
||||
FileSystem fsView2 = FileSystem.newInstance(FsConstants.VIEWFS_URI, conf2);
|
||||
fileSystemTestHelper.createFile(fsView2, "/data/foo");
|
||||
fsView2.rename(new Path("/data/foo"), new Path("/data/dataB/fooBar"));
|
||||
ContractTestUtils
|
||||
.assertPathDoesNotExist(fsView2, "src should not exist after rename",
|
||||
new Path("/data/foo"));
|
||||
ContractTestUtils
|
||||
.assertPathDoesNotExist(fsTarget, "src should not exist after rename",
|
||||
new Path(targetTestRoot, "data/foo"));
|
||||
ContractTestUtils.assertIsFile(fsView2,
|
||||
fileSystemTestHelper.getTestRootPath(fsView2, "/user/fooBar"));
|
||||
ContractTestUtils
|
||||
.assertIsFile(fsTarget, new Path(targetTestRoot, "user/fooBar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationsThroughNestedMountPointsInternal()
|
||||
throws IOException {
|
||||
setUpNestedMountPoint();
|
||||
// Create file with nested mount point
|
||||
fileSystemTestHelper.createFile(fsView, "/user/userB/foo");
|
||||
Assert.assertTrue("Created file should be type file",
|
||||
fsView.getFileStatus(new Path("/user/userB/foo")).isFile());
|
||||
Assert.assertTrue("Target of created file should be type file",
|
||||
fsTarget.getFileStatus(new Path(targetTestRoot,"userB/foo")).isFile());
|
||||
|
||||
// Delete the created file with nested mount point
|
||||
Assert.assertTrue("Delete should succeed",
|
||||
fsView.delete(new Path("/user/userB/foo"), false));
|
||||
Assert.assertFalse("File should not exist after delete",
|
||||
fsView.exists(new Path("/user/userB/foo")));
|
||||
Assert.assertFalse("Target File should not exist after delete",
|
||||
fsTarget.exists(new Path(targetTestRoot,"userB/foo")));
|
||||
|
||||
// Create file with a 2 component dirs with nested mount point
|
||||
fileSystemTestHelper.createFile(fsView, "/internalDir/linkToDir2/linkToDir2/foo");
|
||||
Assert.assertTrue("Created file should be type file",
|
||||
fsView.getFileStatus(new Path("/internalDir/linkToDir2/linkToDir2/foo")).isFile());
|
||||
Assert.assertTrue("Target of created file should be type file",
|
||||
fsTarget.getFileStatus(new Path(targetTestRoot,"linkToDir2/foo")).isFile());
|
||||
|
||||
// Delete the created file with nested mount point
|
||||
Assert.assertTrue("Delete should succeed",
|
||||
fsView.delete(new Path("/internalDir/linkToDir2/linkToDir2/foo"), false));
|
||||
Assert.assertFalse("File should not exist after delete",
|
||||
fsView.exists(new Path("/internalDir/linkToDir2/linkToDir2/foo")));
|
||||
Assert.assertFalse("Target File should not exist after delete",
|
||||
fsTarget.exists(new Path(targetTestRoot,"linkToDir2/foo")));
|
||||
}
|
||||
|
||||
private void setUpNestedMountPoint() throws IOException {
|
||||
// Enable nested mount point, ViewFilesystem should support both non-nested and nested mount points
|
||||
ConfigUtil.setIsNestedMountPointSupported(conf, true);
|
||||
ConfigUtil.addLink(conf, "/user/userA",
|
||||
new Path(targetTestRoot, "user").toUri());
|
||||
ConfigUtil.addLink(conf, "/user/userB",
|
||||
new Path(targetTestRoot, "userB").toUri());
|
||||
ConfigUtil.addLink(conf, "/data/dataA",
|
||||
new Path(targetTestRoot, "dataA").toUri());
|
||||
ConfigUtil.addLink(conf, "/data/dataB",
|
||||
new Path(targetTestRoot, "user").toUri());
|
||||
ConfigUtil.addLink(conf, "/internalDir/linkToDir2/linkToDir2",
|
||||
new Path(targetTestRoot,"linkToDir2").toUri());
|
||||
fsView = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
||||
}
|
||||
|
||||
static protected boolean SupportsBlocks = false; // local fs use 1 block
|
||||
// override for HDFS
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue