Skip to content

Commit 544602e

Browse files
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 3e70006)
1 parent 7084b27 commit 544602e

File tree

9 files changed

+102
-27
lines changed

9 files changed

+102
-27
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FsConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,6 @@ public interface FsConstants {
4444
public static final String VIEWFS_SCHEME = "viewfs";
4545
String FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN =
4646
"fs.viewfs.overload.scheme.target.%s.impl";
47+
String VIEWFS_TYPE = "viewfs";
48+
String VIEWFSOS_TYPE = "viewfsOverloadScheme";
4749
}

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/InodeTree.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.hadoop.classification.InterfaceStability;
3535
import org.apache.hadoop.conf.Configuration;
3636
import org.apache.hadoop.fs.FileAlreadyExistsException;
37+
import org.apache.hadoop.fs.FileSystem;
3738
import org.apache.hadoop.fs.Path;
3839
import org.apache.hadoop.fs.UnsupportedFileSystemException;
3940
import org.apache.hadoop.security.UserGroupInformation;
@@ -67,7 +68,7 @@ enum ResultKind {
6768
// the root of the mount table
6869
private final INode<T> root;
6970
// the fallback filesystem
70-
private final INodeLink<T> rootFallbackLink;
71+
private INodeLink<T> rootFallbackLink;
7172
// the homedir for this mount table
7273
private final String homedirPrefix;
7374
private List<MountPoint<T>> mountPoints = new ArrayList<MountPoint<T>>();
@@ -460,7 +461,8 @@ Configuration getConfig() {
460461
* @throws FileAlreadyExistsException
461462
* @throws IOException
462463
*/
463-
protected InodeTree(final Configuration config, final String viewName)
464+
protected InodeTree(final Configuration config, final String viewName,
465+
final URI theUri, boolean initingUriAsFallbackOnNoMounts)
464466
throws UnsupportedFileSystemException, URISyntaxException,
465467
FileAlreadyExistsException, IOException {
466468
String mountTableName = viewName;
@@ -596,9 +598,19 @@ protected InodeTree(final Configuration config, final String viewName)
596598
}
597599

598600
if (!gotMountTableEntry) {
599-
throw new IOException(
600-
"ViewFs: Cannot initialize: Empty Mount table in config for " +
601-
"viewfs://" + mountTableName + "/");
601+
if (!initingUriAsFallbackOnNoMounts) {
602+
throw new IOException(
603+
"ViewFs: Cannot initialize: Empty Mount table in config for "
604+
+ "viewfs://" + mountTableName + "/");
605+
}
606+
StringBuilder msg =
607+
new StringBuilder("Empty mount table detected for ").append(theUri)
608+
.append(" and considering itself as a linkFallback.");
609+
FileSystem.LOG.info(msg.toString());
610+
rootFallbackLink =
611+
new INodeLink<T>(mountTableName, ugi, getTargetFileSystem(theUri),
612+
theUri);
613+
getRootDir().addFallbackLink(rootFallbackLink);
602614
}
603615
}
604616

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ public String getScheme() {
256256
return FsConstants.VIEWFS_SCHEME;
257257
}
258258

259+
/**
260+
* Returns the ViewFileSystem type.
261+
* @return <code>viewfs</code>
262+
*/
263+
String getType() {
264+
return FsConstants.VIEWFS_TYPE;
265+
}
266+
259267
/**
260268
* Called after a new FileSystem instance is constructed.
261269
* @param theUri a uri whose authority section names the host, port, etc. for
@@ -282,7 +290,10 @@ public void initialize(final URI theUri, final Configuration conf)
282290
}
283291
try {
284292
myUri = new URI(getScheme(), authority, "/", null, null);
285-
fsState = new InodeTree<FileSystem>(conf, tableName) {
293+
boolean initingUriAsFallbackOnNoMounts =
294+
!FsConstants.VIEWFS_TYPE.equals(getType());
295+
fsState = new InodeTree<FileSystem>(conf, tableName, theUri,
296+
initingUriAsFallbackOnNoMounts) {
286297
@Override
287298
protected FileSystem getTargetFileSystem(final URI uri)
288299
throws URISyntaxException, IOException {

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystemOverloadScheme.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@
9595
* be considered as the mount table name. When the passed uri has hostname:port,
9696
* it will simply ignore the port number and only hostname will be considered as
9797
* the mount table name.
98+
* (3) If there are no mount links configured with the initializing uri's
99+
* hostname as the mount table name, then it will automatically consider the
100+
* current uri as fallback( ex: fs.viewfs.mounttable.<mycluster>.linkFallBack)
101+
* target fs uri.
98102
*****************************************************************************/
99103
@InterfaceAudience.LimitedPrivate({ "MapReduce", "HBase", "Hive" })
100104
@InterfaceStability.Evolving
@@ -109,6 +113,14 @@ public String getScheme() {
109113
return myUri.getScheme();
110114
}
111115

116+
/**
117+
* Returns the ViewFileSystem type.
118+
* @return <code>viewfs</code>
119+
*/
120+
String getType() {
121+
return FsConstants.VIEWFSOS_TYPE;
122+
}
123+
112124
@Override
113125
public void initialize(URI theUri, Configuration conf) throws IOException {
114126
this.myUri = theUri;

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,16 @@ URI[] getTargets() {
196196
return targets;
197197
}
198198
}
199-
199+
200+
/**
201+
* Returns the ViewFileSystem type.
202+
*
203+
* @return <code>viewfs</code>
204+
*/
205+
String getType() {
206+
return FsConstants.VIEWFS_TYPE;
207+
}
208+
200209
public ViewFs(final Configuration conf) throws IOException,
201210
URISyntaxException {
202211
this(FsConstants.VIEWFS_URI, conf);
@@ -222,7 +231,10 @@ public ViewFs(final Configuration conf) throws IOException,
222231
CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS_DEFAULT);
223232
// Now build client side view (i.e. client side mount table) from config.
224233
String authority = theUri.getAuthority();
225-
fsState = new InodeTree<AbstractFileSystem>(conf, authority) {
234+
boolean initingUriAsFallbackOnNoMounts =
235+
!FsConstants.VIEWFS_TYPE.equals(getType());
236+
fsState = new InodeTree<AbstractFileSystem>(conf, authority, theUri,
237+
initingUriAsFallbackOnNoMounts) {
226238

227239
@Override
228240
protected AbstractFileSystem getTargetFileSystem(final URI uri)

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFsConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void testInvalidConfig() throws IOException, URISyntaxException {
3939
class Foo {
4040
}
4141

42-
new InodeTree<Foo>(conf, null) {
42+
new InodeTree<Foo>(conf, null, null, false) {
4343

4444
@Override
4545
protected Foo getTargetFileSystem(final URI uri) {

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFsOverloadSchemeListStatus.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,17 @@ public class TestViewFsOverloadSchemeListStatus {
4646

4747
private static final File TEST_DIR =
4848
GenericTestUtils.getTestDir(TestViewfsFileStatus.class.getSimpleName());
49+
private Configuration conf;
50+
private static final String FILE_NAME = "file";
4951

5052
@Before
5153
public void setUp() {
54+
conf = new Configuration();
55+
conf.set(String.format("fs.%s.impl", FILE_NAME),
56+
ViewFileSystemOverloadScheme.class.getName());
57+
conf.set(String
58+
.format(FsConstants.FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN,
59+
FILE_NAME), LocalFileSystem.class.getName());
5260
FileUtil.fullyDelete(TEST_DIR);
5361
assertTrue(TEST_DIR.mkdirs());
5462
}
@@ -77,15 +85,9 @@ public void testListStatusACL() throws IOException, URISyntaxException {
7785
File childDir = new File(TEST_DIR, childDirectoryName);
7886
childDir.mkdirs();
7987

80-
Configuration conf = new Configuration();
8188
ConfigUtil.addLink(conf, "/file", infile.toURI());
8289
ConfigUtil.addLink(conf, "/dir", childDir.toURI());
83-
String fileScheme = "file";
84-
conf.set(String.format("fs.%s.impl", fileScheme),
85-
ViewFileSystemOverloadScheme.class.getName());
86-
conf.set(String
87-
.format(FsConstants.FS_VIEWFS_OVERLOAD_SCHEME_TARGET_FS_IMPL_PATTERN,
88-
fileScheme), LocalFileSystem.class.getName());
90+
8991
String fileUriStr = "file:///";
9092
try (FileSystem vfs = FileSystem.get(new URI(fileUriStr), conf)) {
9193
assertEquals(ViewFileSystemOverloadScheme.class, vfs.getClass());
@@ -95,9 +97,8 @@ public void testListStatusACL() throws IOException, URISyntaxException {
9597
.getRawFileSystem(new Path(fileUriStr), conf);
9698
FileStatus fileStat = localFs.getFileStatus(new Path(infile.getPath()));
9799
FileStatus dirStat = localFs.getFileStatus(new Path(childDir.getPath()));
98-
99100
for (FileStatus status : statuses) {
100-
if (status.getPath().getName().equals(fileScheme)) {
101+
if (status.getPath().getName().equals(FILE_NAME)) {
101102
assertEquals(fileStat.getPermission(), status.getPermission());
102103
} else {
103104
assertEquals(dirStat.getPermission(), status.getPermission());
@@ -111,7 +112,7 @@ public void testListStatusACL() throws IOException, URISyntaxException {
111112

112113
statuses = vfs.listStatus(new Path("/"));
113114
for (FileStatus status : statuses) {
114-
if (status.getPath().getName().equals(fileScheme)) {
115+
if (status.getPath().getName().equals(FILE_NAME)) {
115116
assertEquals(FsPermission.valueOf("-rwxr--r--"),
116117
status.getPermission());
117118
assertFalse(status.isDirectory());
@@ -124,6 +125,24 @@ public void testListStatusACL() throws IOException, URISyntaxException {
124125
}
125126
}
126127

128+
/**
129+
* Tests that ViewFSOverloadScheme should consider initialized fs as fallback
130+
* if there are no mount links configured.
131+
*/
132+
@Test(timeout = 30000)
133+
public void testViewFSOverloadSchemeWithoutAnyMountLinks() throws Exception {
134+
try (FileSystem fs = FileSystem.get(TEST_DIR.toPath().toUri(), conf)) {
135+
ViewFileSystemOverloadScheme vfs = (ViewFileSystemOverloadScheme) fs;
136+
assertEquals(0, vfs.getMountPoints().length);
137+
Path testFallBack = new Path("test", FILE_NAME);
138+
assertTrue(vfs.mkdirs(testFallBack));
139+
FileStatus[] status = vfs.listStatus(testFallBack.getParent());
140+
assertEquals(FILE_NAME, status[0].getPath().getName());
141+
assertEquals(testFallBack.getName(),
142+
vfs.getFileLinkStatus(testFallBack).getPath().getName());
143+
}
144+
}
145+
127146
@AfterClass
128147
public static void cleanup() throws IOException {
129148
FileUtil.fullyDelete(TEST_DIR);

hadoop-hdfs-project/hadoop-hdfs/src/site/markdown/ViewFsOverloadScheme.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ Mount link configurations key, value formats are same as in [ViewFS Guide](./Vie
3333
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.
3434
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>`.
3535
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.
36+
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.
3637

37-
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.
38+
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.
3839

3940
### Enabling View File System Overload Scheme
4041

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/tools/TestViewFileSystemOverloadSchemeWithDFSAdmin.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,16 +228,22 @@ public void testSafeModeShouldFailOnLocalTargetFS() throws Exception {
228228
}
229229

230230
/**
231-
* Tests safemode with ViewFSOverloadScheme, but without mounttables.
231+
* Tests safemode get with ViewFSOverloadScheme, but without any mount links
232+
* configured. The ViewFSOverloadScheme should consider initialized fs as
233+
* fallback fs automatically.
232234
*/
233235
@Test
234-
public void testSafeModeShouldFailWithoutMountTables() throws Exception {
236+
public void testGetSafemodeWithoutMountLinksConfigured() throws Exception {
235237
final DFSAdmin dfsAdmin = new DFSAdmin(conf);
236-
String uri = defaultFSURI.toString();
237-
redirectStream();
238-
int ret = ToolRunner.run(dfsAdmin,
239-
new String[] {"-fs", uri, "-safemode", "enter" });
240-
assertEquals(-1, ret);
238+
try {
239+
redirectStream();
240+
int ret = ToolRunner.run(dfsAdmin,
241+
new String[] {"-fs", defaultFSURI.toString(), "-safemode", "get"});
242+
assertOutMsg("Safe mode is OFF", 0);
243+
assertEquals(0, ret);
244+
} finally {
245+
dfsAdmin.close();
246+
}
241247
}
242248

243249
/**

0 commit comments

Comments
 (0)