HADOOP-15565. Add an inner FS cache to ViewFileSystem, separate from the global cache, to avoid file system leaks. Contributed by Jinglun.
This commit is contained in:
parent
44fdee351d
commit
e5e824bd6f
|
@ -194,6 +194,11 @@ public abstract class FileSystem extends Configured
|
||||||
CACHE.map.put(new Cache.Key(uri, conf), fs);
|
CACHE.map.put(new Cache.Key(uri, conf), fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static int cacheSize() {
|
||||||
|
return CACHE.map.size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a FileSystem instance based on the uri, the passed in
|
* Get a FileSystem instance based on the uri, the passed in
|
||||||
* configuration and the user.
|
* configuration and the user.
|
||||||
|
|
|
@ -96,13 +96,12 @@ class ChRootedFileSystem extends FilterFileSystem {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param uri base file system
|
* @param fs base file system
|
||||||
* @param conf configuration
|
* @param uri base uri
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public ChRootedFileSystem(final URI uri, Configuration conf)
|
ChRootedFileSystem(final FileSystem fs, URI uri) throws IOException {
|
||||||
throws IOException {
|
super(fs);
|
||||||
super(FileSystem.get(uri, conf));
|
|
||||||
String pathString = uri.getPath();
|
String pathString = uri.getPath();
|
||||||
if (pathString.isEmpty()) {
|
if (pathString.isEmpty()) {
|
||||||
pathString = "/";
|
pathString = "/";
|
||||||
|
@ -113,7 +112,18 @@ class ChRootedFileSystem extends FilterFileSystem {
|
||||||
workingDir = getHomeDirectory();
|
workingDir = getHomeDirectory();
|
||||||
// We don't use the wd of the myFs
|
// We don't use the wd of the myFs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param uri base file system
|
||||||
|
* @param conf configuration
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public ChRootedFileSystem(final URI uri, Configuration conf)
|
||||||
|
throws IOException {
|
||||||
|
this(FileSystem.get(uri, conf), uri);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after a new FileSystem instance is constructed.
|
* Called after a new FileSystem instance is constructed.
|
||||||
* @param name a uri whose authority section names the host, port, etc.
|
* @param name a uri whose authority section names the host, port, etc.
|
||||||
|
|
|
@ -78,4 +78,11 @@ public interface Constants {
|
||||||
FsPermission PERMISSION_555 = new FsPermission((short) 0555);
|
FsPermission PERMISSION_555 = new FsPermission((short) 0555);
|
||||||
|
|
||||||
String CONFIG_VIEWFS_RENAME_STRATEGY = "fs.viewfs.rename.strategy";
|
String CONFIG_VIEWFS_RENAME_STRATEGY = "fs.viewfs.rename.strategy";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable ViewFileSystem to cache all children filesystems in inner cache.
|
||||||
|
*/
|
||||||
|
String CONFIG_VIEWFS_ENABLE_INNER_CACHE = "fs.viewfs.enable.inner.cache";
|
||||||
|
|
||||||
|
boolean CONFIG_VIEWFS_ENABLE_INNER_CACHE_DEFAULT = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
package org.apache.hadoop.fs.viewfs;
|
package org.apache.hadoop.fs.viewfs;
|
||||||
|
|
||||||
import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555;
|
import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555;
|
||||||
|
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_ENABLE_INNER_CACHE;
|
||||||
|
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_ENABLE_INNER_CACHE_DEFAULT;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -26,10 +28,13 @@ import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
@ -89,6 +94,72 @@ public class ViewFileSystem extends FileSystem {
|
||||||
return readOnlyMountTable(operation, p.toString());
|
return readOnlyMountTable(operation, p.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caching children filesystems. HADOOP-15565.
|
||||||
|
*/
|
||||||
|
static class InnerCache {
|
||||||
|
private Map<Key, FileSystem> map = new HashMap<>();
|
||||||
|
|
||||||
|
FileSystem get(URI uri, Configuration config) throws IOException {
|
||||||
|
Key key = new Key(uri);
|
||||||
|
if (map.get(key) == null) {
|
||||||
|
FileSystem fs = FileSystem.newInstance(uri, config);
|
||||||
|
map.put(key, fs);
|
||||||
|
return fs;
|
||||||
|
} else {
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeAll() {
|
||||||
|
for (FileSystem fs : map.values()) {
|
||||||
|
try {
|
||||||
|
fs.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.info("Fail closing ViewFileSystem's child filesystem " + fs, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerCache unmodifiableCache() {
|
||||||
|
map = Collections.unmodifiableMap(map);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All the cached instances share the same UGI so there is no need to have a
|
||||||
|
* URI in the Key. Make the Key simple with just the scheme and authority.
|
||||||
|
*/
|
||||||
|
private static class Key {
|
||||||
|
private final String scheme;
|
||||||
|
private final String authority;
|
||||||
|
|
||||||
|
Key(URI uri) {
|
||||||
|
scheme = uri.getScheme() == null ? "" : uri.getScheme().toLowerCase();
|
||||||
|
authority =
|
||||||
|
uri.getAuthority() == null ? "" : uri.getAuthority().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(scheme, authority);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj != null && obj instanceof Key) {
|
||||||
|
Key that = (Key) obj;
|
||||||
|
return this.scheme.equals(that.scheme) && this.authority
|
||||||
|
.equals(that.authority);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MountPoint representation built from the configuration.
|
* MountPoint representation built from the configuration.
|
||||||
*/
|
*/
|
||||||
|
@ -125,6 +196,8 @@ public class ViewFileSystem extends FileSystem {
|
||||||
Configuration config;
|
Configuration config;
|
||||||
InodeTree<FileSystem> fsState; // the fs state; ie the mount table
|
InodeTree<FileSystem> fsState; // the fs state; ie the mount table
|
||||||
Path homeDir = null;
|
Path homeDir = null;
|
||||||
|
private boolean enableInnerCache = false;
|
||||||
|
private InnerCache cache;
|
||||||
// Default to rename within same mountpoint
|
// Default to rename within same mountpoint
|
||||||
private RenameStrategy renameStrategy = RenameStrategy.SAME_MOUNTPOINT;
|
private RenameStrategy renameStrategy = RenameStrategy.SAME_MOUNTPOINT;
|
||||||
/**
|
/**
|
||||||
|
@ -178,6 +251,9 @@ public class ViewFileSystem extends FileSystem {
|
||||||
super.initialize(theUri, conf);
|
super.initialize(theUri, conf);
|
||||||
setConf(conf);
|
setConf(conf);
|
||||||
config = conf;
|
config = conf;
|
||||||
|
enableInnerCache = config.getBoolean(CONFIG_VIEWFS_ENABLE_INNER_CACHE,
|
||||||
|
CONFIG_VIEWFS_ENABLE_INNER_CACHE_DEFAULT);
|
||||||
|
final InnerCache innerCache = new InnerCache();
|
||||||
// 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.
|
||||||
final String authority = theUri.getAuthority();
|
final String authority = theUri.getAuthority();
|
||||||
try {
|
try {
|
||||||
|
@ -187,7 +263,13 @@ public class ViewFileSystem extends FileSystem {
|
||||||
@Override
|
@Override
|
||||||
protected FileSystem getTargetFileSystem(final URI uri)
|
protected FileSystem getTargetFileSystem(final URI uri)
|
||||||
throws URISyntaxException, IOException {
|
throws URISyntaxException, IOException {
|
||||||
return new ChRootedFileSystem(uri, config);
|
FileSystem fs;
|
||||||
|
if (enableInnerCache) {
|
||||||
|
fs = innerCache.get(uri, config);
|
||||||
|
} else {
|
||||||
|
fs = FileSystem.get(uri, config);
|
||||||
|
}
|
||||||
|
return new ChRootedFileSystem(fs, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -210,6 +292,12 @@ public class ViewFileSystem extends FileSystem {
|
||||||
throw new IOException("URISyntax exception: " + theUri);
|
throw new IOException("URISyntax exception: " + theUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enableInnerCache) {
|
||||||
|
// All fs instances are created and cached on startup. The cache is
|
||||||
|
// readonly after the initialize() so the concurrent access of the cache
|
||||||
|
// is safe.
|
||||||
|
cache = innerCache.unmodifiableCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1297,4 +1385,12 @@ public class ViewFileSystem extends FileSystem {
|
||||||
SAME_MOUNTPOINT, SAME_TARGET_URI_ACROSS_MOUNTPOINT,
|
SAME_MOUNTPOINT, SAME_TARGET_URI_ACROSS_MOUNTPOINT,
|
||||||
SAME_FILESYSTEM_ACROSS_MOUNTPOINT
|
SAME_FILESYSTEM_ACROSS_MOUNTPOINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
super.close();
|
||||||
|
if (enableInnerCache && cache != null) {
|
||||||
|
cache.closeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1671,4 +1671,10 @@ public class TestFileUtil {
|
||||||
assertEquals(write, read);
|
assertEquals(write, read);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size of FileSystem cache.
|
||||||
|
*/
|
||||||
|
public static int getCacheSize() {
|
||||||
|
return FileSystem.cacheSize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FileStatus;
|
import org.apache.hadoop.fs.FileStatus;
|
||||||
|
@ -32,7 +33,6 @@ import org.apache.hadoop.fs.FilterFileSystem;
|
||||||
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.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.viewfs.ChRootedFileSystem;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -396,7 +396,7 @@ public class TestChRootedFileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListLocatedFileStatus() throws IOException {
|
public void testListLocatedFileStatus() throws Exception {
|
||||||
final Path mockMount = new Path("mockfs://foo/user");
|
final Path mockMount = new Path("mockfs://foo/user");
|
||||||
final Path mockPath = new Path("/usermock");
|
final Path mockPath = new Path("/usermock");
|
||||||
final Configuration conf = new Configuration();
|
final Configuration conf = new Configuration();
|
||||||
|
@ -404,17 +404,35 @@ public class TestChRootedFileSystem {
|
||||||
ConfigUtil.addLink(conf, mockPath.toString(), mockMount.toUri());
|
ConfigUtil.addLink(conf, mockPath.toString(), mockMount.toUri());
|
||||||
FileSystem vfs = FileSystem.get(URI.create("viewfs:///"), conf);
|
FileSystem vfs = FileSystem.get(URI.create("viewfs:///"), conf);
|
||||||
vfs.listLocatedStatus(mockPath);
|
vfs.listLocatedStatus(mockPath);
|
||||||
final FileSystem mockFs = ((MockFileSystem)mockMount.getFileSystem(conf))
|
final FileSystem mockFs =
|
||||||
.getRawFileSystem();
|
((MockFileSystem) getChildFileSystem((ViewFileSystem) vfs,
|
||||||
|
new URI("mockfs://foo/"))).getRawFileSystem();
|
||||||
verify(mockFs).listLocatedStatus(new Path(mockMount.toUri().getPath()));
|
verify(mockFs).listLocatedStatus(new Path(mockMount.toUri().getPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FileSystem getChildFileSystem(ViewFileSystem viewFs, URI uri) {
|
||||||
|
for (FileSystem fs : viewFs.getChildFileSystems()) {
|
||||||
|
if (Objects.equals(fs.getUri().getScheme(), uri.getScheme()) && Objects
|
||||||
|
.equals(fs.getUri().getAuthority(), uri.getAuthority())) {
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
static class MockFileSystem extends FilterFileSystem {
|
static class MockFileSystem extends FilterFileSystem {
|
||||||
|
private URI uri;
|
||||||
MockFileSystem() {
|
MockFileSystem() {
|
||||||
super(mock(FileSystem.class));
|
super(mock(FileSystem.class));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URI name, Configuration conf) throws IOException {}
|
public URI getUri() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void initialize(URI name, Configuration conf) throws IOException {
|
||||||
|
uri = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 30000)
|
@Test(timeout = 30000)
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.hadoop.fs.viewfs;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -31,6 +32,8 @@ import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.permission.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.MockFileSystem;
|
import org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.MockFileSystem;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.getChildFileSystem;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ -46,12 +49,16 @@ public class TestViewFileSystemDelegation { //extends ViewFileSystemTestSetup {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup() throws Exception {
|
public static void setup() throws Exception {
|
||||||
conf = ViewFileSystemTestSetup.createConfig();
|
conf = ViewFileSystemTestSetup.createConfig();
|
||||||
fs1 = setupFileSystem(new URI("fs1:/"), FakeFileSystem.class);
|
setupFileSystem(new URI("fs1:/"), FakeFileSystem.class);
|
||||||
fs2 = setupFileSystem(new URI("fs2:/"), FakeFileSystem.class);
|
setupFileSystem(new URI("fs2:/"), FakeFileSystem.class);
|
||||||
viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
||||||
|
fs1 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
|
||||||
|
new URI("fs1:/"));
|
||||||
|
fs2 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
|
||||||
|
new URI("fs2:/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static FakeFileSystem setupFileSystem(URI uri, Class clazz)
|
static void setupFileSystem(URI uri, Class clazz)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String scheme = uri.getScheme();
|
String scheme = uri.getScheme();
|
||||||
conf.set("fs."+scheme+".impl", clazz.getName());
|
conf.set("fs."+scheme+".impl", clazz.getName());
|
||||||
|
@ -59,22 +66,21 @@ public class TestViewFileSystemDelegation { //extends ViewFileSystemTestSetup {
|
||||||
assertEquals(uri, fs.getUri());
|
assertEquals(uri, fs.getUri());
|
||||||
Path targetPath = new FileSystemTestHelper().getAbsoluteTestRootPath(fs);
|
Path targetPath = new FileSystemTestHelper().getAbsoluteTestRootPath(fs);
|
||||||
ConfigUtil.addLink(conf, "/mounts/"+scheme, targetPath.toUri());
|
ConfigUtil.addLink(conf, "/mounts/"+scheme, targetPath.toUri());
|
||||||
return fs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FileSystem setupMockFileSystem(Configuration conf, URI uri)
|
private static void setupMockFileSystem(Configuration config, URI uri)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String scheme = uri.getScheme();
|
String scheme = uri.getScheme();
|
||||||
conf.set("fs." + scheme + ".impl", MockFileSystem.class.getName());
|
config.set("fs." + scheme + ".impl", MockFileSystem.class.getName());
|
||||||
FileSystem fs = FileSystem.get(uri, conf);
|
ConfigUtil.addLink(config, "/mounts/" + scheme, uri);
|
||||||
ConfigUtil.addLink(conf, "/mounts/" + scheme, uri);
|
|
||||||
return ((MockFileSystem)fs).getRawFileSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSanity() {
|
public void testSanity() throws URISyntaxException {
|
||||||
assertEquals("fs1:/", fs1.getUri().toString());
|
assertEquals(new URI("fs1:/").getScheme(), fs1.getUri().getScheme());
|
||||||
assertEquals("fs2:/", fs2.getUri().toString());
|
assertEquals(new URI("fs1:/").getAuthority(), fs1.getUri().getAuthority());
|
||||||
|
assertEquals(new URI("fs2:/").getScheme(), fs2.getUri().getScheme());
|
||||||
|
assertEquals(new URI("fs2:/").getAuthority(), fs2.getUri().getAuthority());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -91,9 +97,15 @@ public class TestViewFileSystemDelegation { //extends ViewFileSystemTestSetup {
|
||||||
@Test
|
@Test
|
||||||
public void testAclMethods() throws Exception {
|
public void testAclMethods() throws Exception {
|
||||||
Configuration conf = ViewFileSystemTestSetup.createConfig();
|
Configuration conf = ViewFileSystemTestSetup.createConfig();
|
||||||
FileSystem mockFs1 = setupMockFileSystem(conf, new URI("mockfs1:/"));
|
setupMockFileSystem(conf, new URI("mockfs1:/"));
|
||||||
FileSystem mockFs2 = setupMockFileSystem(conf, new URI("mockfs2:/"));
|
setupMockFileSystem(conf, new URI("mockfs2:/"));
|
||||||
FileSystem viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
FileSystem viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
||||||
|
FileSystem mockFs1 =
|
||||||
|
((MockFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
|
||||||
|
new URI("mockfs1:/"))).getRawFileSystem();
|
||||||
|
FileSystem mockFs2 =
|
||||||
|
((MockFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
|
||||||
|
new URI("mockfs2:/"))).getRawFileSystem();
|
||||||
|
|
||||||
Path viewFsPath1 = new Path("/mounts/mockfs1/a/b/c");
|
Path viewFsPath1 = new Path("/mounts/mockfs1/a/b/c");
|
||||||
Path mockFsPath1 = new Path("/a/b/c");
|
Path mockFsPath1 = new Path("/a/b/c");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.apache.hadoop.fs.viewfs;
|
package org.apache.hadoop.fs.viewfs;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.getChildFileSystem;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -54,12 +55,16 @@ public class TestViewFileSystemDelegationTokenSupport {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup() throws Exception {
|
public static void setup() throws Exception {
|
||||||
conf = ViewFileSystemTestSetup.createConfig();
|
conf = ViewFileSystemTestSetup.createConfig();
|
||||||
fs1 = setupFileSystem(new URI("fs1:///"), FakeFileSystem.class);
|
setupFileSystem(new URI("fs1:///"), FakeFileSystem.class);
|
||||||
fs2 = setupFileSystem(new URI("fs2:///"), FakeFileSystem.class);
|
setupFileSystem(new URI("fs2:///"), FakeFileSystem.class);
|
||||||
viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
||||||
|
fs1 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
|
||||||
|
new URI("fs1:///"));
|
||||||
|
fs2 = (FakeFileSystem) getChildFileSystem((ViewFileSystem) viewFs,
|
||||||
|
new URI("fs2:///"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static FakeFileSystem setupFileSystem(URI uri, Class<? extends FileSystem> clazz)
|
static void setupFileSystem(URI uri, Class<? extends FileSystem> clazz)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String scheme = uri.getScheme();
|
String scheme = uri.getScheme();
|
||||||
conf.set("fs."+scheme+".impl", clazz.getName());
|
conf.set("fs."+scheme+".impl", clazz.getName());
|
||||||
|
@ -67,7 +72,6 @@ public class TestViewFileSystemDelegationTokenSupport {
|
||||||
// mount each fs twice, will later ensure 1 token/fs
|
// mount each fs twice, will later ensure 1 token/fs
|
||||||
ConfigUtil.addLink(conf, "/mounts/"+scheme+"-one", fs.getUri());
|
ConfigUtil.addLink(conf, "/mounts/"+scheme+"-one", fs.getUri());
|
||||||
ConfigUtil.addLink(conf, "/mounts/"+scheme+"-two", fs.getUri());
|
ConfigUtil.addLink(conf, "/mounts/"+scheme+"-two", fs.getUri());
|
||||||
return fs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.BlockLocation;
|
import org.apache.hadoop.fs.BlockLocation;
|
||||||
|
@ -36,9 +37,11 @@ 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.FsStatus;
|
import org.apache.hadoop.fs.FsStatus;
|
||||||
|
import org.apache.hadoop.fs.LocalFileSystem;
|
||||||
import org.apache.hadoop.fs.LocatedFileStatus;
|
import org.apache.hadoop.fs.LocatedFileStatus;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.RemoteIterator;
|
import org.apache.hadoop.fs.RemoteIterator;
|
||||||
|
import org.apache.hadoop.fs.TestFileUtil;
|
||||||
import org.apache.hadoop.fs.Trash;
|
import org.apache.hadoop.fs.Trash;
|
||||||
import org.apache.hadoop.fs.UnsupportedFileSystemException;
|
import org.apache.hadoop.fs.UnsupportedFileSystemException;
|
||||||
import org.apache.hadoop.fs.contract.ContractTestUtils;
|
import org.apache.hadoop.fs.contract.ContractTestUtils;
|
||||||
|
@ -64,6 +67,7 @@ import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@ -1267,4 +1271,96 @@ abstract public class ViewFileSystemBaseTest {
|
||||||
containsString("File does not exist:"));
|
containsString("File does not exist:"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testViewFileSystemInnerCache() throws Exception {
|
||||||
|
ViewFileSystem.InnerCache cache = new ViewFileSystem.InnerCache();
|
||||||
|
FileSystem fs = cache.get(fsTarget.getUri(), conf);
|
||||||
|
|
||||||
|
// InnerCache caches filesystem.
|
||||||
|
assertSame(fs, cache.get(fsTarget.getUri(), conf));
|
||||||
|
|
||||||
|
// InnerCache and FileSystem.CACHE are independent.
|
||||||
|
assertNotSame(fs, FileSystem.get(fsTarget.getUri(), conf));
|
||||||
|
|
||||||
|
// close InnerCache.
|
||||||
|
cache.closeAll();
|
||||||
|
try {
|
||||||
|
fs.exists(new Path("/"));
|
||||||
|
if (!(fs instanceof LocalFileSystem)) {
|
||||||
|
// Ignore LocalFileSystem because it can still be used after close.
|
||||||
|
fail("Expect Filesystem closed exception");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("Filesystem closed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloseChildrenFileSystem() throws Exception {
|
||||||
|
final String clusterName = "cluster" + new Random().nextInt();
|
||||||
|
Configuration config = new Configuration(conf);
|
||||||
|
ConfigUtil.addLink(config, clusterName, "/user",
|
||||||
|
new Path(targetTestRoot, "user").toUri());
|
||||||
|
config.setBoolean("fs.viewfs.impl.disable.cache", false);
|
||||||
|
URI uri = new URI("viewfs://" + clusterName + "/");
|
||||||
|
|
||||||
|
ViewFileSystem viewFs = (ViewFileSystem) FileSystem.get(uri, config);
|
||||||
|
assertTrue("viewfs should have at least one child fs.",
|
||||||
|
viewFs.getChildFileSystems().length > 0);
|
||||||
|
// viewFs is cached in FileSystem.CACHE
|
||||||
|
assertSame(viewFs, FileSystem.get(uri, config));
|
||||||
|
|
||||||
|
// child fs is not cached in FileSystem.CACHE
|
||||||
|
FileSystem child = viewFs.getChildFileSystems()[0];
|
||||||
|
assertNotSame(child, FileSystem.get(child.getUri(), config));
|
||||||
|
|
||||||
|
viewFs.close();
|
||||||
|
for (FileSystem childfs : viewFs.getChildFileSystems()) {
|
||||||
|
try {
|
||||||
|
childfs.exists(new Path("/"));
|
||||||
|
if (!(childfs instanceof LocalFileSystem)) {
|
||||||
|
// Ignore LocalFileSystem because it can still be used after close.
|
||||||
|
fail("Expect Filesystem closed exception");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
assertExceptionContains("Filesystem closed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChildrenFileSystemLeak() throws Exception {
|
||||||
|
final String clusterName = "cluster" + new Random().nextInt();
|
||||||
|
Configuration config = new Configuration(conf);
|
||||||
|
ConfigUtil.addLink(config, clusterName, "/user",
|
||||||
|
new Path(targetTestRoot, "user").toUri());
|
||||||
|
|
||||||
|
final int cacheSize = TestFileUtil.getCacheSize();
|
||||||
|
ViewFileSystem viewFs = (ViewFileSystem) FileSystem
|
||||||
|
.get(new URI("viewfs://" + clusterName + "/"), config);
|
||||||
|
assertEquals(cacheSize + 1, TestFileUtil.getCacheSize());
|
||||||
|
viewFs.close();
|
||||||
|
assertEquals(cacheSize, TestFileUtil.getCacheSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteOnExit() throws Exception {
|
||||||
|
final String clusterName = "cluster" + new Random().nextInt();
|
||||||
|
Configuration config = new Configuration(conf);
|
||||||
|
ConfigUtil.addLink(config, clusterName, "/user",
|
||||||
|
new Path(targetTestRoot, "user").toUri());
|
||||||
|
|
||||||
|
Path testDir = new Path("/user/testDeleteOnExit");
|
||||||
|
Path realTestPath = new Path(targetTestRoot, "user/testDeleteOnExit");
|
||||||
|
ViewFileSystem viewFs = (ViewFileSystem) FileSystem
|
||||||
|
.get(new URI("viewfs://" + clusterName + "/"), config);
|
||||||
|
viewFs.mkdirs(testDir);
|
||||||
|
assertTrue(viewFs.exists(testDir));
|
||||||
|
assertTrue(fsTarget.exists(realTestPath));
|
||||||
|
|
||||||
|
viewFs.deleteOnExit(testDir);
|
||||||
|
viewFs.close();
|
||||||
|
assertFalse(fsTarget.exists(realTestPath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ public class TestViewFsDefaultValue {
|
||||||
fileSystemTestHelper.createFile(fHdfs, testFileName);
|
fileSystemTestHelper.createFile(fHdfs, testFileName);
|
||||||
fileSystemTestHelper.createFile(fHdfs, NOT_IN_MOUNTPOINT_FILENAME);
|
fileSystemTestHelper.createFile(fHdfs, NOT_IN_MOUNTPOINT_FILENAME);
|
||||||
Configuration conf = ViewFileSystemTestSetup.createConfig();
|
Configuration conf = ViewFileSystemTestSetup.createConfig();
|
||||||
|
conf.setInt(DFS_REPLICATION_KEY, DFS_REPLICATION_DEFAULT + 1);
|
||||||
ConfigUtil.addLink(conf, "/tmp", new URI(fHdfs.getUri().toString() +
|
ConfigUtil.addLink(conf, "/tmp", new URI(fHdfs.getUri().toString() +
|
||||||
"/tmp"));
|
"/tmp"));
|
||||||
vfs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
vfs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
|
||||||
|
|
Loading…
Reference in New Issue