HDFS-15427. Merged ListStatus with Fallback target filesystem and InternalDirViewFS. Contributed by Uma Maheswara Rao G.

(cherry picked from commit 7c02d1889b)
This commit is contained in:
Uma Maheswara Rao G 2020-06-23 01:42:25 -07:00
parent 5f67c3f3ca
commit 29a8ee4be6
4 changed files with 360 additions and 78 deletions

View File

@ -374,7 +374,7 @@ abstract class InodeTree<T> {
throws UnsupportedFileSystemException, URISyntaxException, IOException; throws UnsupportedFileSystemException, URISyntaxException, IOException;
protected abstract T getTargetFileSystem(INodeDir<T> dir) protected abstract T getTargetFileSystem(INodeDir<T> dir)
throws URISyntaxException; throws URISyntaxException, IOException;
protected abstract T getTargetFileSystem(String settings, URI[] mergeFsURIs) protected abstract T getTargetFileSystem(String settings, URI[] mergeFsURIs)
throws UnsupportedFileSystemException, URISyntaxException, IOException; throws UnsupportedFileSystemException, URISyntaxException, IOException;
@ -393,7 +393,7 @@ abstract class InodeTree<T> {
return rootFallbackLink != null; return rootFallbackLink != null;
} }
private INodeLink<T> getRootFallbackLink() { protected INodeLink<T> getRootFallbackLink() {
Preconditions.checkState(root.isInternalDir()); Preconditions.checkState(root.isInternalDir());
return rootFallbackLink; return rootFallbackLink;
} }

View File

@ -291,7 +291,8 @@ public class ViewFileSystem extends FileSystem {
@Override @Override
protected FileSystem getTargetFileSystem(final INodeDir<FileSystem> dir) protected FileSystem getTargetFileSystem(final INodeDir<FileSystem> dir)
throws URISyntaxException { throws URISyntaxException {
return new InternalDirOfViewFs(dir, creationTime, ugi, myUri, config); return new InternalDirOfViewFs(dir, creationTime, ugi, myUri, config,
this);
} }
@Override @Override
@ -518,10 +519,10 @@ public class ViewFileSystem extends FileSystem {
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
* Note: listStatus on root("/") considers listing from fallbackLink if * Note: listStatus considers listing from fallbackLink if available. If the
* available. If the same directory name is present in configured mount path * same directory path is present in configured mount path as well as in
* as well as in fallback link, then only the configured mount path will be * fallback fs, then only the fallback path will be listed in the returned
* listed in the returned result. * result except for link.
* *
* If any of the the immediate children of the given path f is a symlink(mount * If any of the the immediate children of the given path f is a symlink(mount
* link), the returned FileStatus object of that children would be represented * link), the returned FileStatus object of that children would be represented
@ -1125,11 +1126,13 @@ public class ViewFileSystem extends FileSystem {
final UserGroupInformation ugi; // the user/group of user who created mtable final UserGroupInformation ugi; // the user/group of user who created mtable
final URI myUri; final URI myUri;
private final boolean showMountLinksAsSymlinks; private final boolean showMountLinksAsSymlinks;
private InodeTree<FileSystem> fsState;
public InternalDirOfViewFs(final InodeTree.INodeDir<FileSystem> dir, public InternalDirOfViewFs(final InodeTree.INodeDir<FileSystem> dir,
final long cTime, final UserGroupInformation ugi, URI uri, final long cTime, final UserGroupInformation ugi, URI uri,
Configuration config) throws URISyntaxException { Configuration config, InodeTree fsState) throws URISyntaxException {
myUri = uri; myUri = uri;
this.fsState = fsState;
try { try {
initialize(myUri, config); initialize(myUri, config);
} catch (IOException e) { } catch (IOException e) {
@ -1225,7 +1228,8 @@ public class ViewFileSystem extends FileSystem {
FileNotFoundException, IOException { FileNotFoundException, IOException {
checkPathIsSlash(f); checkPathIsSlash(f);
FileStatus[] fallbackStatuses = listStatusForFallbackLink(); FileStatus[] fallbackStatuses = listStatusForFallbackLink();
FileStatus[] result = new FileStatus[theInternalDir.getChildren().size()]; Set<FileStatus> linkStatuses = new HashSet<>();
Set<FileStatus> internalDirStatuses = new HashSet<>();
int i = 0; int i = 0;
for (Entry<String, INode<FileSystem>> iEntry : for (Entry<String, INode<FileSystem>> iEntry :
theInternalDir.getChildren().entrySet()) { theInternalDir.getChildren().entrySet()) {
@ -1238,11 +1242,10 @@ public class ViewFileSystem extends FileSystem {
// To maintain backward compatibility, with default option(showing // To maintain backward compatibility, with default option(showing
// mount links as symlinks), we will represent target link as // mount links as symlinks), we will represent target link as
// symlink and rest other properties are belongs to mount link only. // symlink and rest other properties are belongs to mount link only.
result[i++] = linkStatuses.add(
new FileStatus(0, false, 0, 0, creationTime, creationTime, new FileStatus(0, false, 0, 0, creationTime, creationTime,
PERMISSION_555, ugi.getShortUserName(), PERMISSION_555, ugi.getShortUserName(),
ugi.getPrimaryGroupName(), link.getTargetLink(), ugi.getPrimaryGroupName(), link.getTargetLink(), path));
path);
continue; continue;
} }
@ -1258,11 +1261,12 @@ public class ViewFileSystem extends FileSystem {
FileStatus status = FileStatus status =
((ChRootedFileSystem)link.getTargetFileSystem()) ((ChRootedFileSystem)link.getTargetFileSystem())
.getMyFs().getFileStatus(new Path(linkedPath)); .getMyFs().getFileStatus(new Path(linkedPath));
result[i++] = new FileStatus(status.getLen(), status.isDirectory(), linkStatuses.add(
new FileStatus(status.getLen(), status.isDirectory(),
status.getReplication(), status.getBlockSize(), status.getReplication(), status.getBlockSize(),
status.getModificationTime(), status.getAccessTime(), status.getModificationTime(), status.getAccessTime(),
status.getPermission(), status.getOwner(), status.getGroup(), status.getPermission(), status.getOwner(),
null, path); status.getGroup(), null, path));
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
LOG.warn("Cannot get one of the children's(" + path LOG.warn("Cannot get one of the children's(" + path
+ ") target path(" + link.getTargetFileSystem().getUri() + ") target path(" + link.getTargetFileSystem().getUri()
@ -1270,52 +1274,59 @@ public class ViewFileSystem extends FileSystem {
throw ex; throw ex;
} }
} else { } else {
result[i++] = internalDirStatuses.add(
new FileStatus(0, true, 0, 0, creationTime, creationTime, new FileStatus(0, true, 0, 0, creationTime, creationTime,
PERMISSION_555, ugi.getShortUserName(), PERMISSION_555, ugi.getShortUserName(),
ugi.getPrimaryGroupName(), path); ugi.getPrimaryGroupName(), path));
} }
} }
FileStatus[] internalDirStatusesMergedWithFallBack = internalDirStatuses
.toArray(new FileStatus[internalDirStatuses.size()]);
if (fallbackStatuses.length > 0) { if (fallbackStatuses.length > 0) {
return consolidateFileStatuses(fallbackStatuses, result); internalDirStatusesMergedWithFallBack =
} else { merge(fallbackStatuses, internalDirStatusesMergedWithFallBack);
return result;
} }
// Links will always have precedence than internalDir or fallback paths.
return merge(linkStatuses.toArray(new FileStatus[linkStatuses.size()]),
internalDirStatusesMergedWithFallBack);
} }
private FileStatus[] consolidateFileStatuses(FileStatus[] fallbackStatuses, private FileStatus[] merge(FileStatus[] toStatuses,
FileStatus[] mountPointStatuses) { FileStatus[] fromStatuses) {
ArrayList<FileStatus> result = new ArrayList<>(); ArrayList<FileStatus> result = new ArrayList<>();
Set<String> pathSet = new HashSet<>(); Set<String> pathSet = new HashSet<>();
for (FileStatus status : mountPointStatuses) { for (FileStatus status : toStatuses) {
result.add(status); result.add(status);
pathSet.add(status.getPath().getName()); pathSet.add(status.getPath().getName());
} }
for (FileStatus status : fallbackStatuses) { for (FileStatus status : fromStatuses) {
if (!pathSet.contains(status.getPath().getName())) { if (!pathSet.contains(status.getPath().getName())) {
result.add(status); result.add(status);
} }
} }
return result.toArray(new FileStatus[0]); return result.toArray(new FileStatus[result.size()]);
} }
private FileStatus[] listStatusForFallbackLink() throws IOException { private FileStatus[] listStatusForFallbackLink() throws IOException {
if (theInternalDir.isRoot() && if (this.fsState.getRootFallbackLink() != null) {
theInternalDir.getFallbackLink() != null) { FileSystem linkedFallbackFs =
FileSystem linkedFs = this.fsState.getRootFallbackLink().getTargetFileSystem();
theInternalDir.getFallbackLink().getTargetFileSystem(); Path p = Path.getPathWithoutSchemeAndAuthority(
// Fallback link is only applicable for root new Path(theInternalDir.fullPath));
FileStatus[] statuses = linkedFs.listStatus(new Path("/")); if (theInternalDir.isRoot() || linkedFallbackFs.exists(p)) {
FileStatus[] statuses = linkedFallbackFs.listStatus(p);
for (FileStatus status : statuses) { for (FileStatus status : statuses) {
// Fix the path back to viewfs scheme // Fix the path back to viewfs scheme
Path pathFromConfiguredFallbackRoot =
new Path(p, status.getPath().getName());
status.setPath( status.setPath(
new Path(myUri.toString(), status.getPath().getName())); new Path(myUri.toString(), pathFromConfiguredFallbackRoot));
} }
return statuses; return statuses;
} else {
return new FileStatus[0];
} }
} }
return new FileStatus[0];
}
@Override @Override
public boolean mkdirs(Path dir, FsPermission permission) public boolean mkdirs(Path dir, FsPermission permission)

View File

@ -44,6 +44,7 @@ import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileAlreadyExistsException; import org.apache.hadoop.fs.FileAlreadyExistsException;
import org.apache.hadoop.fs.FileChecksum; import org.apache.hadoop.fs.FileChecksum;
import org.apache.hadoop.fs.FileContext;
import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FsConstants; import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.FsServerDefaults; import org.apache.hadoop.fs.FsServerDefaults;
@ -236,7 +237,8 @@ public class ViewFs extends AbstractFileSystem {
@Override @Override
protected AbstractFileSystem getTargetFileSystem( protected AbstractFileSystem getTargetFileSystem(
final INodeDir<AbstractFileSystem> dir) throws URISyntaxException { final INodeDir<AbstractFileSystem> dir) throws URISyntaxException {
return new InternalDirOfViewFs(dir, creationTime, ugi, getUri()); return new InternalDirOfViewFs(dir, creationTime, ugi, getUri(), this,
config);
} }
@Override @Override
@ -455,6 +457,11 @@ public class ViewFs extends AbstractFileSystem {
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
* Note: listStatus considers listing from fallbackLink if available. If the
* same directory path is present in configured mount path as well as in
* fallback fs, then only the fallback path will be listed in the returned
* result except for link.
*
* If any of the the immediate children of the given path f is a symlink(mount * If any of the the immediate children of the given path f is a symlink(mount
* link), the returned FileStatus object of that children would be represented * link), the returned FileStatus object of that children would be represented
* as a symlink. It will not be resolved to the target path and will not get * as a symlink. It will not be resolved to the target path and will not get
@ -880,15 +887,20 @@ public class ViewFs extends AbstractFileSystem {
final long creationTime; // of the the mount table final long creationTime; // of the the mount table
final UserGroupInformation ugi; // the user/group of user who created mtable final UserGroupInformation ugi; // the user/group of user who created mtable
final URI myUri; // the URI of the outer ViewFs final URI myUri; // the URI of the outer ViewFs
private InodeTree<AbstractFileSystem> fsState;
private Configuration conf;
public InternalDirOfViewFs(final InodeTree.INodeDir<AbstractFileSystem> dir, public InternalDirOfViewFs(final InodeTree.INodeDir<AbstractFileSystem> dir,
final long cTime, final UserGroupInformation ugi, final URI uri) final long cTime, final UserGroupInformation ugi, final URI uri,
InodeTree fsState, Configuration conf)
throws URISyntaxException { throws URISyntaxException {
super(FsConstants.VIEWFS_URI, FsConstants.VIEWFS_SCHEME, false, -1); super(FsConstants.VIEWFS_URI, FsConstants.VIEWFS_SCHEME, false, -1);
theInternalDir = dir; theInternalDir = dir;
creationTime = cTime; creationTime = cTime;
this.ugi = ugi; this.ugi = ugi;
myUri = uri; myUri = uri;
this.fsState = fsState;
this.conf = conf;
} }
static private void checkPathIsSlash(final Path f) throws IOException { static private void checkPathIsSlash(final Path f) throws IOException {
@ -1015,7 +1027,8 @@ public class ViewFs extends AbstractFileSystem {
public FileStatus[] listStatus(final Path f) throws IOException { public FileStatus[] listStatus(final Path f) throws IOException {
checkPathIsSlash(f); checkPathIsSlash(f);
FileStatus[] fallbackStatuses = listStatusForFallbackLink(); FileStatus[] fallbackStatuses = listStatusForFallbackLink();
FileStatus[] result = new FileStatus[theInternalDir.getChildren().size()]; Set<FileStatus> linkStatuses = new HashSet<>();
Set<FileStatus> internalDirStatuses = new HashSet<>();
int i = 0; int i = 0;
for (Entry<String, INode<AbstractFileSystem>> iEntry : for (Entry<String, INode<AbstractFileSystem>> iEntry :
theInternalDir.getChildren().entrySet()) { theInternalDir.getChildren().entrySet()) {
@ -1029,11 +1042,10 @@ public class ViewFs extends AbstractFileSystem {
// To maintain backward compatibility, with default option(showing // To maintain backward compatibility, with default option(showing
// mount links as symlinks), we will represent target link as // mount links as symlinks), we will represent target link as
// symlink and rest other properties are belongs to mount link only. // symlink and rest other properties are belongs to mount link only.
result[i++] = linkStatuses.add(
new FileStatus(0, false, 0, 0, creationTime, creationTime, new FileStatus(0, false, 0, 0, creationTime, creationTime,
PERMISSION_555, ugi.getShortUserName(), PERMISSION_555, ugi.getShortUserName(),
ugi.getPrimaryGroupName(), link.getTargetLink(), ugi.getPrimaryGroupName(), link.getTargetLink(), path));
path);
continue; continue;
} }
@ -1049,11 +1061,12 @@ public class ViewFs extends AbstractFileSystem {
FileStatus status = FileStatus status =
((ChRootedFs) link.getTargetFileSystem()).getMyFs() ((ChRootedFs) link.getTargetFileSystem()).getMyFs()
.getFileStatus(new Path(linkedPath)); .getFileStatus(new Path(linkedPath));
result[i++] = new FileStatus(status.getLen(), status.isDirectory(), linkStatuses.add(
new FileStatus(status.getLen(), status.isDirectory(),
status.getReplication(), status.getBlockSize(), status.getReplication(), status.getBlockSize(),
status.getModificationTime(), status.getAccessTime(), status.getModificationTime(), status.getAccessTime(),
status.getPermission(), status.getOwner(), status.getGroup(), status.getPermission(), status.getOwner(),
null, path); status.getGroup(), null, path));
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
LOG.warn("Cannot get one of the children's(" + path LOG.warn("Cannot get one of the children's(" + path
+ ") target path(" + link.getTargetFileSystem().getUri() + ") target path(" + link.getTargetFileSystem().getUri()
@ -1061,52 +1074,63 @@ public class ViewFs extends AbstractFileSystem {
throw ex; throw ex;
} }
} else { } else {
result[i++] = internalDirStatuses.add(
new FileStatus(0, true, 0, 0, creationTime, creationTime, new FileStatus(0, true, 0, 0, creationTime, creationTime,
PERMISSION_555, ugi.getShortUserName(), PERMISSION_555, ugi.getShortUserName(),
ugi.getGroupNames()[0], path); ugi.getPrimaryGroupName(), path));
}
}
if (fallbackStatuses.length > 0) {
return consolidateFileStatuses(fallbackStatuses, result);
} else {
return result;
} }
} }
private FileStatus[] consolidateFileStatuses(FileStatus[] fallbackStatuses, FileStatus[] internalDirStatusesMergedWithFallBack = internalDirStatuses
FileStatus[] mountPointStatuses) { .toArray(new FileStatus[internalDirStatuses.size()]);
if (fallbackStatuses.length > 0) {
internalDirStatusesMergedWithFallBack =
merge(fallbackStatuses, internalDirStatusesMergedWithFallBack);
}
// Links will always have precedence than internalDir or fallback paths.
return merge(linkStatuses.toArray(new FileStatus[linkStatuses.size()]),
internalDirStatusesMergedWithFallBack);
}
private FileStatus[] merge(FileStatus[] toStatuses,
FileStatus[] fromStatuses) {
ArrayList<FileStatus> result = new ArrayList<>(); ArrayList<FileStatus> result = new ArrayList<>();
Set<String> pathSet = new HashSet<>(); Set<String> pathSet = new HashSet<>();
for (FileStatus status : mountPointStatuses) { for (FileStatus status : toStatuses) {
result.add(status); result.add(status);
pathSet.add(status.getPath().getName()); pathSet.add(status.getPath().getName());
} }
for (FileStatus status : fallbackStatuses) { for (FileStatus status : fromStatuses) {
if (!pathSet.contains(status.getPath().getName())) { if (!pathSet.contains(status.getPath().getName())) {
result.add(status); result.add(status);
} }
} }
return result.toArray(new FileStatus[0]); return result.toArray(new FileStatus[result.size()]);
} }
private FileStatus[] listStatusForFallbackLink() throws IOException { private FileStatus[] listStatusForFallbackLink() throws IOException {
if (theInternalDir.isRoot() && if (fsState.getRootFallbackLink() != null) {
theInternalDir.getFallbackLink() != null) { AbstractFileSystem linkedFallbackFs =
AbstractFileSystem linkedFs = fsState.getRootFallbackLink().getTargetFileSystem();
theInternalDir.getFallbackLink().getTargetFileSystem(); Path p = Path.getPathWithoutSchemeAndAuthority(
new Path(theInternalDir.fullPath));
if (theInternalDir.isRoot() || FileContext
.getFileContext(linkedFallbackFs, conf).util().exists(p)) {
// Fallback link is only applicable for root // Fallback link is only applicable for root
FileStatus[] statuses = linkedFs.listStatus(new Path("/")); FileStatus[] statuses = linkedFallbackFs.listStatus(p);
for (FileStatus status : statuses) { for (FileStatus status : statuses) {
// Fix the path back to viewfs scheme // Fix the path back to viewfs scheme
Path pathFromConfiguredFallbackRoot =
new Path(p, status.getPath().getName());
status.setPath( status.setPath(
new Path(myUri.toString(), status.getPath().getName())); new Path(myUri.toString(), pathFromConfiguredFallbackRoot));
} }
return statuses; return statuses;
} else {
return new FileStatus[0];
} }
} }
return new FileStatus[0];
}
@Override @Override
public void mkdir(final Path dir, final FsPermission permission, public void mkdir(final Path dir, final FsPermission permission,

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.fs.viewfs; 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.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -36,6 +37,7 @@ import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileSystemTestHelper; import org.apache.hadoop.fs.FileSystemTestHelper;
import org.apache.hadoop.fs.FsConstants; import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.MiniDFSCluster; import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.MiniDFSNNTopology; import org.apache.hadoop.hdfs.MiniDFSNNTopology;
@ -343,8 +345,8 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
afterFallback.add(stat.getPath()); afterFallback.add(stat.getPath());
} }
afterFallback.removeAll(beforeFallback); afterFallback.removeAll(beforeFallback);
assertTrue("The same directory name in fallback link should be shaded", assertEquals("The same directory name in fallback link should be shaded",
afterFallback.size() == 1); 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(viewFsUri.toString(), "user1");
@ -359,4 +361,249 @@ public class TestViewFileSystemLinkFallback extends ViewFileSystemBaseTest {
assertTrue(vfs.getFileStatus(childDir).isDirectory()); assertTrue(vfs.getFileStatus(childDir).isDirectory());
} }
} }
/**
* Tests ListStatus on non-link parent with fallback configured.
* =============================Example.======================================
* ===== Fallback path tree =============== Mount Path Tree ==================
* ===========================================================================
* * / ***** / *****************
* * / ***** / *****************
* * user1 ***** user1 *****************
* * / ***** / *****************
* * hive ***** hive *****************
* * / \ ***** / *****************
* * warehouse warehouse1 ***** warehouse *****************
* * (-rwxr--r--) ***** (-r-xr--r--) *****************
* * / ***** / *****************
* * partition-0 ***** partition-0 *****************
* ===========================================================================
* ===========================================================================
* *** ls /user1/hive *********
* *** viewfs://default/user1/hive/warehouse (-rwxr--r--) *********
* *** viewfs://default/user1/hive/warehouse1 *********
* ===========================================================================
*/
@Test
public void testListingWithFallbackLinkWithSameMountDirectoryTree()
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());
// Creating multiple directories path under the fallback directory.
// "/user1/hive/warehouse/partition-0" directory already exists as
// configured mount point.
Path dir1 = new Path(targetTestRoot,
"fallbackDir/user1/hive/warehouse/partition-0");
Path dir2 = new Path(targetTestRoot, "fallbackDir/user1/hive/warehouse1");
fsTarget.mkdirs(dir1);
fsTarget.mkdirs(dir2);
fsTarget.setPermission(new Path(targetTestRoot, "fallbackDir/user1/hive/"),
FsPermission.valueOf("-rwxr--r--"));
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
HashSet<Path> beforeFallback = new HashSet<>();
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
for (FileStatus stat : vfs
.listStatus(new Path(viewFsUri.toString(), "/user1/hive/"))) {
beforeFallback.add(stat.getPath());
}
}
ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs
.listStatus(new Path(viewFsUri.toString(), "/user1/hive/"))) {
afterFallback.add(stat.getPath());
if (dir1.getName().equals(stat.getPath().getName())) {
// make sure fallback dir listed out with correct permissions, but not
// with link permissions.
assertEquals(FsPermission.valueOf("-rwxr--r--"),
stat.getPermission());
}
}
//
//viewfs://default/user1/hive/warehouse
afterFallback.removeAll(beforeFallback);
assertEquals("The same directory name in fallback link should be shaded",
1, afterFallback.size());
}
}
/**
* Tests ListStatus on link parent with fallback configured.
* =============================Example.======================================
* ===== Fallback path tree =============== Mount Path Tree ==================
* ===========================================================================
* * / ***** / **********
* * / ***** / **********
* * user1 ***** user1 **********
* * / ***** / **********
* * hive ***** hive **********
* * / \ ***** / **********
* * warehouse warehouse1 ***** warehouse **********
* * (-rwxr--r--) ***** (-r-xr--r--) **********
* * / ***** / **********
* * partition-0 ***** partition-0 ---> targetTestRoot **********
* * ***** (-r-xr--r--) (-rwxr--rw-) **********
* ===========================================================================
* ===========================================================================
* *** ls /user1/hive/warehouse **
* *** viewfs://default/user1/hive/warehouse/partition-0 (-rwxr--rw-) **
* ===========================================================================
*/
@Test
public void testLSOnLinkParentWithFallbackLinkWithSameMountDirectoryTree()
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());
// Creating multiple directories path under the fallback directory.
// "/user1/hive/warehouse/partition-0" directory already exists as
// configured mount point.
Path dir1 = new Path(targetTestRoot,
"fallbackDir/user1/hive/warehouse/partition-0");
Path dir2 = new Path(targetTestRoot, "fallbackDir/user1/hive/warehouse1");
fsTarget.mkdirs(dir1);
fsTarget.mkdirs(dir2);
fsTarget.setPermission(new Path(targetTestRoot,
"fallbackDir/user1/hive/warehouse/partition-0"),
FsPermission.valueOf("-rwxr--r--"));
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<>();
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
for (FileStatus stat : vfs.listStatus(
new Path(viewFsUri.toString(), "/user1/hive/warehouse/"))) {
beforeFallback.add(stat.getPath());
}
}
ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs.listStatus(
new Path(viewFsUri.toString(), "/user1/hive/warehouse/"))) {
afterFallback.add(stat.getPath());
if (dir1.getName().equals(stat.getPath().getName())) {
// make sure fallback dir listed out with correct permissions, but not
// with link permissions.
assertEquals(FsPermission.valueOf("-rwxr--rw-"),
stat.getPermission());
}
}
afterFallback.removeAll(beforeFallback);
assertEquals("Just to make sure paths are same.", 0,
afterFallback.size());
}
}
/**
* Tests ListStatus on root with fallback configured.
* =============================Example.=======================================
* ===== Fallback path tree =============== Mount Path Tree ==================
* ===========================================================================
* * / / ***** / ***
* * / / ***** / ***
* * user1 user2 ***** user1 ---> targetTestRoot ***
* *(-r-xr--r--) (-r-xr--r--) ***** (-rwxr--rw-) ***
* ===========================================================================
* ===========================================================================
* *** ls /user1/hive/warehouse **
* *** viewfs://default/user1(-rwxr--rw-) **
* *** viewfs://default/user2(-r-xr--r--) **
* ===========================================================================
*/
@Test
public void testLSOnRootWithFallbackLinkWithSameMountDirectories()
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());
// Creating multiple directories path under the fallback directory.
// "/user1" directory already exists as configured mount point.
Path dir1 = new Path(targetTestRoot, "fallbackDir/user1");
Path dir2 = new Path(targetTestRoot, "fallbackDir/user2");
fsTarget.mkdirs(dir1);
fsTarget.mkdirs(dir2, FsPermission.valueOf("-rwxr--r--"));
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<>();
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
for (FileStatus stat : vfs
.listStatus(new Path(viewFsUri.toString(), "/"))) {
beforeFallback.add(stat.getPath());
}
}
ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
HashSet<Path> afterFallback = new HashSet<>();
for (FileStatus stat : vfs
.listStatus(new Path(viewFsUri.toString(), "/"))) {
afterFallback.add(stat.getPath());
if (dir1.getName().equals(stat.getPath().getName())) {
// make sure fallback dir listed out with correct permissions, but not
// with link permissions.
assertEquals(FsPermission.valueOf("-rwxr--rw-"),
stat.getPermission());
} else {
assertEquals("Path is: " + stat.getPath(),
FsPermission.valueOf("-rwxr--r--"), stat.getPermission());
}
}
afterFallback.removeAll(beforeFallback);
assertEquals(1, afterFallback.size());
assertEquals("/user2 dir from fallback should be listed.", "user2",
afterFallback.iterator().next().getName());
}
}
@Test
public void testLSOnLinkParentWhereMountLinkMatchesWithAFileUnderFallback()
throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS, true);
ConfigUtil.addLink(conf, "/user1/hive/warehouse/part-0",
new Path(targetTestRoot.toString()).toUri());
// Create a file path in fallback matching to the path of mount link.
Path file1 =
new Path(targetTestRoot, "fallbackDir/user1/hive/warehouse/part-0");
fsTarget.createNewFile(file1);
Path dir2 = new Path(targetTestRoot, "fallbackDir/user1/hive/warehouse1");
fsTarget.mkdirs(dir2);
URI viewFsUri = new URI(FsConstants.VIEWFS_SCHEME,
Constants.CONFIG_VIEWFS_DEFAULT_MOUNT_TABLE, "/", null, null);
ConfigUtil
.addLinkFallback(conf, new Path(targetTestRoot, "fallbackDir").toUri());
try (FileSystem vfs = FileSystem.get(viewFsUri, conf)) {
for (FileStatus stat : vfs.listStatus(
new Path(viewFsUri.toString(), "/user1/hive/warehouse/"))) {
if (file1.getName().equals(stat.getPath().getName())) {
// Link represents as symlink.
assertFalse(stat.isFile());
assertFalse(stat.isDirectory());
assertTrue(stat.isSymlink());
Path fileUnderDir = new Path(stat.getPath(), "check");
assertTrue(vfs.mkdirs(fileUnderDir)); // Creating dir under target
assertTrue(fsTarget
.exists(new Path(targetTestRoot, fileUnderDir.getName())));
}
}
}
}
} }