HDFS-15464: ViewFsOverloadScheme should work when -fs option pointing to remote cluster without mount links (#2132). Contributed by Uma Maheswara Rao G.
(cherry picked from commit 3e70006639
)
This commit is contained in:
parent
10f8010519
commit
ae8261c671
@ -44,4 +44,6 @@ public interface FsConstants {
|
|||||||
public static final String VIEWFS_SCHEME = "viewfs";
|
public static final String VIEWFS_SCHEME = "viewfs";
|
||||||
String FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN =
|
String FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN =
|
||||||
"fs.viewfs.overload.scheme.target.%s.impl";
|
"fs.viewfs.overload.scheme.target.%s.impl";
|
||||||
|
String VIEWFS_TYPE = "viewfs";
|
||||||
|
String VIEWFSOS_TYPE = "viewfsOverloadScheme";
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FileAlreadyExistsException;
|
import org.apache.hadoop.fs.FileAlreadyExistsException;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.UnsupportedFileSystemException;
|
import org.apache.hadoop.fs.UnsupportedFileSystemException;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
@ -67,7 +68,7 @@ enum ResultKind {
|
|||||||
// the root of the mount table
|
// the root of the mount table
|
||||||
private final INode<T> root;
|
private final INode<T> root;
|
||||||
// the fallback filesystem
|
// the fallback filesystem
|
||||||
private final INodeLink<T> rootFallbackLink;
|
private INodeLink<T> rootFallbackLink;
|
||||||
// the homedir for this mount table
|
// the homedir for this mount table
|
||||||
private final String homedirPrefix;
|
private final String homedirPrefix;
|
||||||
private List<MountPoint<T>> mountPoints = new ArrayList<MountPoint<T>>();
|
private List<MountPoint<T>> mountPoints = new ArrayList<MountPoint<T>>();
|
||||||
@ -460,7 +461,8 @@ Configuration getConfig() {
|
|||||||
* @throws FileAlreadyExistsException
|
* @throws FileAlreadyExistsException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected InodeTree(final Configuration config, final String viewName)
|
protected InodeTree(final Configuration config, final String viewName,
|
||||||
|
final URI theUri, boolean initingUriAsFallbackOnNoMounts)
|
||||||
throws UnsupportedFileSystemException, URISyntaxException,
|
throws UnsupportedFileSystemException, URISyntaxException,
|
||||||
FileAlreadyExistsException, IOException {
|
FileAlreadyExistsException, IOException {
|
||||||
String mountTableName = viewName;
|
String mountTableName = viewName;
|
||||||
@ -596,9 +598,19 @@ protected InodeTree(final Configuration config, final String viewName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!gotMountTableEntry) {
|
if (!gotMountTableEntry) {
|
||||||
throw new IOException(
|
if (!initingUriAsFallbackOnNoMounts) {
|
||||||
"ViewFs: Cannot initialize: Empty Mount table in config for " +
|
throw new IOException(
|
||||||
"viewfs://" + mountTableName + "/");
|
"ViewFs: Cannot initialize: Empty Mount table in config for "
|
||||||
|
+ "viewfs://" + mountTableName + "/");
|
||||||
|
}
|
||||||
|
StringBuilder msg =
|
||||||
|
new StringBuilder("Empty mount table detected for ").append(theUri)
|
||||||
|
.append(" and considering itself as a linkFallback.");
|
||||||
|
FileSystem.LOG.info(msg.toString());
|
||||||
|
rootFallbackLink =
|
||||||
|
new INodeLink<T>(mountTableName, ugi, getTargetFileSystem(theUri),
|
||||||
|
theUri);
|
||||||
|
getRootDir().addFallbackLink(rootFallbackLink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +258,14 @@ public String getScheme() {
|
|||||||
return FsConstants.VIEWFS_SCHEME;
|
return FsConstants.VIEWFS_SCHEME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ViewFileSystem type.
|
||||||
|
* @return <code>viewfs</code>
|
||||||
|
*/
|
||||||
|
String getType() {
|
||||||
|
return FsConstants.VIEWFS_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after a new FileSystem instance is constructed.
|
* Called after a new FileSystem instance is constructed.
|
||||||
* @param theUri a uri whose authority section names the host, port, etc. for
|
* @param theUri a uri whose authority section names the host, port, etc. for
|
||||||
@ -284,7 +292,10 @@ public void initialize(final URI theUri, final Configuration conf)
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
myUri = new URI(getScheme(), authority, "/", null, null);
|
myUri = new URI(getScheme(), authority, "/", null, null);
|
||||||
fsState = new InodeTree<FileSystem>(conf, tableName) {
|
boolean initingUriAsFallbackOnNoMounts =
|
||||||
|
!FsConstants.VIEWFS_TYPE.equals(getType());
|
||||||
|
fsState = new InodeTree<FileSystem>(conf, tableName, theUri,
|
||||||
|
initingUriAsFallbackOnNoMounts) {
|
||||||
@Override
|
@Override
|
||||||
protected FileSystem getTargetFileSystem(final URI uri)
|
protected FileSystem getTargetFileSystem(final URI uri)
|
||||||
throws URISyntaxException, IOException {
|
throws URISyntaxException, IOException {
|
||||||
|
@ -95,6 +95,10 @@
|
|||||||
* be considered as the mount table name. When the passed uri has hostname:port,
|
* be considered as the mount table name. When the passed uri has hostname:port,
|
||||||
* it will simply ignore the port number and only hostname will be considered as
|
* it will simply ignore the port number and only hostname will be considered as
|
||||||
* the mount table name.
|
* the mount table name.
|
||||||
|
* (3) If there are no mount links configured with the initializing uri's
|
||||||
|
* hostname as the mount table name, then it will automatically consider the
|
||||||
|
* current uri as fallback( ex: fs.viewfs.mounttable.<mycluster>.linkFallBack)
|
||||||
|
* target fs uri.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@InterfaceAudience.LimitedPrivate({ "MapReduce", "HBase", "Hive" })
|
@InterfaceAudience.LimitedPrivate({ "MapReduce", "HBase", "Hive" })
|
||||||
@InterfaceStability.Evolving
|
@InterfaceStability.Evolving
|
||||||
@ -109,6 +113,14 @@ public String getScheme() {
|
|||||||
return myUri.getScheme();
|
return myUri.getScheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ViewFileSystem type.
|
||||||
|
* @return <code>viewfs</code>
|
||||||
|
*/
|
||||||
|
String getType() {
|
||||||
|
return FsConstants.VIEWFSOS_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URI theUri, Configuration conf) throws IOException {
|
public void initialize(URI theUri, Configuration conf) throws IOException {
|
||||||
this.myUri = theUri;
|
this.myUri = theUri;
|
||||||
|
@ -196,7 +196,16 @@ URI[] getTargets() {
|
|||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ViewFileSystem type.
|
||||||
|
*
|
||||||
|
* @return <code>viewfs</code>
|
||||||
|
*/
|
||||||
|
String getType() {
|
||||||
|
return FsConstants.VIEWFS_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
public ViewFs(final Configuration conf) throws IOException,
|
public ViewFs(final Configuration conf) throws IOException,
|
||||||
URISyntaxException {
|
URISyntaxException {
|
||||||
this(FsConstants.VIEWFS_URI, conf);
|
this(FsConstants.VIEWFS_URI, conf);
|
||||||
@ -222,7 +231,10 @@ public ViewFs(final Configuration conf) throws IOException,
|
|||||||
CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS_DEFAULT);
|
CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS_DEFAULT);
|
||||||
// Now build client side view (i.e. client side mount table) from config.
|
// Now build client side view (i.e. client side mount table) from config.
|
||||||
String authority = theUri.getAuthority();
|
String authority = theUri.getAuthority();
|
||||||
fsState = new InodeTree<AbstractFileSystem>(conf, authority) {
|
boolean initingUriAsFallbackOnNoMounts =
|
||||||
|
!FsConstants.VIEWFS_TYPE.equals(getType());
|
||||||
|
fsState = new InodeTree<AbstractFileSystem>(conf, authority, theUri,
|
||||||
|
initingUriAsFallbackOnNoMounts) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractFileSystem getTargetFileSystem(final URI uri)
|
protected AbstractFileSystem getTargetFileSystem(final URI uri)
|
||||||
|
@ -39,7 +39,7 @@ public void testInvalidConfig() throws IOException, URISyntaxException {
|
|||||||
class Foo {
|
class Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
new InodeTree<Foo>(conf, null) {
|
new InodeTree<Foo>(conf, null, null, false) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Foo getTargetFileSystem(final URI uri) {
|
protected Foo getTargetFileSystem(final URI uri) {
|
||||||
|
@ -46,9 +46,17 @@ public class TestViewFsOverloadSchemeListStatus {
|
|||||||
|
|
||||||
private static final File TEST_DIR =
|
private static final File TEST_DIR =
|
||||||
GenericTestUtils.getTestDir(TestViewfsFileStatus.class.getSimpleName());
|
GenericTestUtils.getTestDir(TestViewfsFileStatus.class.getSimpleName());
|
||||||
|
private Configuration conf;
|
||||||
|
private static final String FILE_NAME = "file";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
conf = new Configuration();
|
||||||
|
conf.set(String.format("fs.%s.impl", FILE_NAME),
|
||||||
|
ViewFileSystemOverloadScheme.class.getName());
|
||||||
|
conf.set(String
|
||||||
|
.format(FsConstants.FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN,
|
||||||
|
FILE_NAME), LocalFileSystem.class.getName());
|
||||||
FileUtil.fullyDelete(TEST_DIR);
|
FileUtil.fullyDelete(TEST_DIR);
|
||||||
assertTrue(TEST_DIR.mkdirs());
|
assertTrue(TEST_DIR.mkdirs());
|
||||||
}
|
}
|
||||||
@ -77,15 +85,9 @@ public void testListStatusACL() throws IOException, URISyntaxException {
|
|||||||
File childDir = new File(TEST_DIR, childDirectoryName);
|
File childDir = new File(TEST_DIR, childDirectoryName);
|
||||||
childDir.mkdirs();
|
childDir.mkdirs();
|
||||||
|
|
||||||
Configuration conf = new Configuration();
|
|
||||||
ConfigUtil.addLink(conf, "/file", infile.toURI());
|
ConfigUtil.addLink(conf, "/file", infile.toURI());
|
||||||
ConfigUtil.addLink(conf, "/dir", childDir.toURI());
|
ConfigUtil.addLink(conf, "/dir", childDir.toURI());
|
||||||
String fileScheme = "file";
|
|
||||||
conf.set(String.format("fs.%s.impl", fileScheme),
|
|
||||||
ViewFileSystemOverloadScheme.class.getName());
|
|
||||||
conf.set(String
|
|
||||||
.format(FsConstants.FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN,
|
|
||||||
fileScheme), LocalFileSystem.class.getName());
|
|
||||||
String fileUriStr = "file:///";
|
String fileUriStr = "file:///";
|
||||||
try (FileSystem vfs = FileSystem.get(new URI(fileUriStr), conf)) {
|
try (FileSystem vfs = FileSystem.get(new URI(fileUriStr), conf)) {
|
||||||
assertEquals(ViewFileSystemOverloadScheme.class, vfs.getClass());
|
assertEquals(ViewFileSystemOverloadScheme.class, vfs.getClass());
|
||||||
@ -95,9 +97,8 @@ public void testListStatusACL() throws IOException, URISyntaxException {
|
|||||||
.getRawFileSystem(new Path(fileUriStr), conf);
|
.getRawFileSystem(new Path(fileUriStr), conf);
|
||||||
FileStatus fileStat = localFs.getFileStatus(new Path(infile.getPath()));
|
FileStatus fileStat = localFs.getFileStatus(new Path(infile.getPath()));
|
||||||
FileStatus dirStat = localFs.getFileStatus(new Path(childDir.getPath()));
|
FileStatus dirStat = localFs.getFileStatus(new Path(childDir.getPath()));
|
||||||
|
|
||||||
for (FileStatus status : statuses) {
|
for (FileStatus status : statuses) {
|
||||||
if (status.getPath().getName().equals(fileScheme)) {
|
if (status.getPath().getName().equals(FILE_NAME)) {
|
||||||
assertEquals(fileStat.getPermission(), status.getPermission());
|
assertEquals(fileStat.getPermission(), status.getPermission());
|
||||||
} else {
|
} else {
|
||||||
assertEquals(dirStat.getPermission(), status.getPermission());
|
assertEquals(dirStat.getPermission(), status.getPermission());
|
||||||
@ -111,7 +112,7 @@ public void testListStatusACL() throws IOException, URISyntaxException {
|
|||||||
|
|
||||||
statuses = vfs.listStatus(new Path("/"));
|
statuses = vfs.listStatus(new Path("/"));
|
||||||
for (FileStatus status : statuses) {
|
for (FileStatus status : statuses) {
|
||||||
if (status.getPath().getName().equals(fileScheme)) {
|
if (status.getPath().getName().equals(FILE_NAME)) {
|
||||||
assertEquals(FsPermission.valueOf("-rwxr--r--"),
|
assertEquals(FsPermission.valueOf("-rwxr--r--"),
|
||||||
status.getPermission());
|
status.getPermission());
|
||||||
assertFalse(status.isDirectory());
|
assertFalse(status.isDirectory());
|
||||||
@ -124,6 +125,24 @@ public void testListStatusACL() throws IOException, URISyntaxException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that ViewFSOverloadScheme should consider initialized fs as fallback
|
||||||
|
* if there are no mount links configured.
|
||||||
|
*/
|
||||||
|
@Test(timeout = 30000)
|
||||||
|
public void testViewFSOverloadSchemeWithoutAnyMountLinks() throws Exception {
|
||||||
|
try (FileSystem fs = FileSystem.get(TEST_DIR.toPath().toUri(), conf)) {
|
||||||
|
ViewFileSystemOverloadScheme vfs = (ViewFileSystemOverloadScheme) fs;
|
||||||
|
assertEquals(0, vfs.getMountPoints().length);
|
||||||
|
Path testFallBack = new Path("test", FILE_NAME);
|
||||||
|
assertTrue(vfs.mkdirs(testFallBack));
|
||||||
|
FileStatus[] status = vfs.listStatus(testFallBack.getParent());
|
||||||
|
assertEquals(FILE_NAME, status[0].getPath().getName());
|
||||||
|
assertEquals(testFallBack.getName(),
|
||||||
|
vfs.getFileLinkStatus(testFallBack).getPath().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void cleanup() throws IOException {
|
public static void cleanup() throws IOException {
|
||||||
FileUtil.fullyDelete(TEST_DIR);
|
FileUtil.fullyDelete(TEST_DIR);
|
||||||
|
@ -33,8 +33,9 @@ Mount link configurations key, value formats are same as in [ViewFS Guide](./Vie
|
|||||||
If a user wants to continue use the same fs.defaultFS and wants to have more mount points, then mount link configurations should have the ViewFileSystemOverloadScheme initialized uri's hostname as the mount table name.
|
If a user wants to continue use the same fs.defaultFS and wants to have more mount points, then mount link configurations should have the ViewFileSystemOverloadScheme initialized uri's hostname as the mount table name.
|
||||||
Example if fs.defaultFS is `hdfs://mycluster`, then the mount link configuration key name should be like in the following format `fs.viewfs.mounttable.*mycluster*.link.<mountLinkPath>`.
|
Example if fs.defaultFS is `hdfs://mycluster`, then the mount link configuration key name should be like in the following format `fs.viewfs.mounttable.*mycluster*.link.<mountLinkPath>`.
|
||||||
Even if the initialized fs uri has hostname:port, it will simply ignore the port number and only consider the hostname as the mount table name. We will discuss more example configurations in following sections.
|
Even if the initialized fs uri has hostname:port, it will simply ignore the port number and only consider the hostname as the mount table name. We will discuss more example configurations in following sections.
|
||||||
|
If there are no mount links configured with the initializing uri's hostname as the mount table name, then it will automatically consider the current uri as fallback(`fs.viewfs.mounttable.*mycluster*.linkFallback`) target fs uri.
|
||||||
|
|
||||||
Another important improvement with the ViewFileSystemOverloadScheme is, administrators need not copy the `mount-table.xml` configuration file to 1000s of client nodes. Instead they can keep the mount-table configuration file in a Hadoop compatible file system. So, keeping the configuration file in a central place makes administrators life easier as they can update mount-table in single place.
|
Another important improvement with the ViewFileSystemOverloadScheme is, administrators need not copy the `mount-table.xml` configuration file to 1000s of client nodes. Instead, they can keep the mount-table configuration file in a Hadoop compatible file system. So, keeping the configuration file in a central place makes administrators life easier as they can update mount-table in single place.
|
||||||
|
|
||||||
### Enabling View File System Overload Scheme
|
### Enabling View File System Overload Scheme
|
||||||
|
|
||||||
|
@ -228,16 +228,22 @@ public void testSafeModeShouldFailOnLocalTargetFS() throws Exception {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests safemode with ViewFSOverloadScheme, but without mounttables.
|
* Tests safemode get with ViewFSOverloadScheme, but without any mount links
|
||||||
|
* configured. The ViewFSOverloadScheme should consider initialized fs as
|
||||||
|
* fallback fs automatically.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSafeModeShouldFailWithoutMountTables() throws Exception {
|
public void testGetSafemodeWithoutMountLinksConfigured() throws Exception {
|
||||||
final DFSAdmin dfsAdmin = new DFSAdmin(conf);
|
final DFSAdmin dfsAdmin = new DFSAdmin(conf);
|
||||||
String uri = defaultFSURI.toString();
|
try {
|
||||||
redirectStream();
|
redirectStream();
|
||||||
int ret = ToolRunner.run(dfsAdmin,
|
int ret = ToolRunner.run(dfsAdmin,
|
||||||
new String[] {"-fs", uri, "-safemode", "enter" });
|
new String[] {"-fs", defaultFSURI.toString(), "-safemode", "get"});
|
||||||
assertEquals(-1, ret);
|
assertOutMsg("Safe mode is OFF", 0);
|
||||||
|
assertEquals(0, ret);
|
||||||
|
} finally {
|
||||||
|
dfsAdmin.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user