Skip to content

HADOOP-18144. getTrashRoot/s in ViewFileSystem return a viewFS path #4034

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fea90ca
Change to check for EZ/snapshots
Feb 22, 2022
f9963d2
Change getTrashRoot to return viewFS path, instead of targetFS path
Feb 24, 2022
dc30020
Rename MOUNT_POINT_LOCAL_TRASH macro
Feb 24, 2022
eb7e048
Modified getTrashRoot/s to return hybrid paths.
Feb 25, 2022
12bc904
Minor edits
Feb 26, 2022
d605fed
More minor edits
Feb 26, 2022
26cb868
HADOOP-18144. getTrashRoot/s in ViewFileSystem should return viewFS p…
Feb 26, 2022
62f44d3
check trashRoot from targetFS with mountpoint.targetPath.
Mar 5, 2022
a278cbc
Rename MACRO for our flag
Mar 5, 2022
87f2a5d
Renamed flag to CONFIG_VIEWFS_TRASH_USE_VIEWFS_PATH
Mar 5, 2022
d0ae15e
Alright, renamed flag back to CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_…
Mar 5, 2022
7a8d790
minor fix fo the warning
Mar 5, 2022
36b5e3d
Fixed a unit test function name
Mar 5, 2022
83e6be7
changed CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT_DEFAULT to false
Mar 7, 2022
10f1436
Fixed checkstyle
Mar 7, 2022
28bff6a
Fixed out-of-date flag name in comments
Mar 7, 2022
4d27c75
Addressed Owen's comment and add a check for default trash when mount…
Mar 8, 2022
f77abb0
fixed line break
Mar 8, 2022
af30715
Fixed the path comparison
Mar 8, 2022
808749d
fix spotbugs
Mar 8, 2022
b18af88
Another pass to incorporate Owen's changes.
Mar 11, 2022
78b66f7
checkpoint of use if/else to decide expectedTrash.
Mar 12, 2022
095dacc
Added and overwrite getTrashRootInFallBackFS()
Mar 12, 2022
a78bada
Fix new lines
Mar 12, 2022
485a650
minor fix to comments.
Mar 12, 2022
15a6dcc
GetTrashRoots(): include trash roots in fallback FS as well.
Mar 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ public boolean moveToTrash(Path path) throws IOException {
cause = e;
}
}
throw (IOException)
new IOException("Failed to move to trash: " + path).initCause(cause);
throw new IOException("Failed to move " + path + " to trash " + trashPath,
cause);
}

@SuppressWarnings("deprecation")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,9 @@ public interface Constants {
HCFSMountTableConfigLoader.class;

/**
* Enable ViewFileSystem to return a trashRoot which is local to mount point.
* Force ViewFileSystem to return a trashRoot that is inside a mount point.
*/
String CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH = "fs.viewfs.mount.point.local.trash";
boolean CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH_DEFAULT = false;
String CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT =
"fs.viewfs.trash.force-inside-mount-point";
boolean CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT_DEFAULT = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS;
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_AS_SYMLINKS_DEFAULT;
import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555;
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH;
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH_DEFAULT;
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT;
import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT_DEFAULT;

import java.util.function.Function;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -1132,47 +1132,77 @@ public Collection<? extends BlockStoragePolicySpi> getAllStoragePolicies()
* Get the trash root directory for current user when the path
* specified is deleted.
*
* If CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH is not set, return
* the default trash root from targetFS.
* If FORCE_INSIDE_MOUNT_POINT flag is not set, return the default trash root
* from targetFS.
*
* When CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH is set to true,
* 1) If path p is in fallback FS or from the same mount point as the default
* trash root for targetFS, return the default trash root for targetFS.
* 2) else, return a trash root in the mounted targetFS
* (/mntpoint/.Trash/{user})
* When FORCE_INSIDE_MOUNT_POINT is set to true,
* <ol>
* <li>
* If the trash root for path p is in the same mount point as path p,
* and one of:
* <ol>
* <li>The mount point isn't at the top of the target fs.</li>
* <li>The resolved path of path is root (in fallback FS).</li>
* <li>The trash isn't in user's target fs home directory
* get the corresponding viewFS path for the trash root and return
* it.
* </li>
* </ol>
* </li>
* <li>
* else, return the trash root under the root of the mount point
* (/{mntpoint}/.Trash/{user}).
* </li>
* </ol>
*
* Condition 1 handles several different important cases:
* <ul>
* <li>File systems may need to have more local trash roots, such as
* encryption zones or snapshot roots.</li>
* <li>The fallback mount should use the user's home directory.</li>
* <li>Cloud storage systems should not use the user's home directory,
* if the mount points to the top of the container or bucket.</li>
* </ul>
*
* @param path the trash root of the path to be determined.
* @return the trash root path.
*/
@Override
public Path getTrashRoot(Path path) {
boolean useMountPointLocalTrash =
config.getBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH,
CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH_DEFAULT);

try {
InodeTree.ResolveResult<FileSystem> res =
fsState.resolve(getUriPath(path), true);
Path targetFSTrashRoot =
res.targetFileSystem.getTrashRoot(res.remainingPath);

Path trashRoot = res.targetFileSystem.getTrashRoot(res.remainingPath);
if (!useMountPointLocalTrash) {
return trashRoot;
} else {
// Path p is either in a mount point or in the fallback FS
// Allow clients to use old behavior of delegating to target fs.
if (!config.getBoolean(CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT,
CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT_DEFAULT)) {
return targetFSTrashRoot;
}

if (ROOT_PATH.equals(new Path(res.resolvedPath))
|| trashRoot.toUri().getPath().startsWith(res.resolvedPath)) {
// Path p is in the fallback FS or targetFileSystem.trashRoot is in
// the same mount point as Path p
return trashRoot;
} else {
// targetFileSystem.trashRoot is in a different mount point from
// Path p. Return the trash root for the mount point.
Path mountPointRoot =
res.targetFileSystem.getFileStatus(new Path("/")).getPath();
return new Path(mountPointRoot,
TRASH_PREFIX + "/" + ugi.getShortUserName());
}
// The trash root path from the target fs
String targetFSTrashRootPath = targetFSTrashRoot.toUri().getPath();
// The mount point path in the target fs
String mountTargetPath = res.targetFileSystem.getUri().getPath();
if (!mountTargetPath.endsWith("/")) {
mountTargetPath = mountTargetPath + "/";
}

Path targetFsUserHome = res.targetFileSystem.getHomeDirectory();
if (targetFSTrashRootPath.startsWith(mountTargetPath) &&
!(mountTargetPath.equals(ROOT_PATH.toString()) &&
!res.resolvedPath.equals(ROOT_PATH.toString()) &&
(targetFsUserHome != null && targetFSTrashRootPath.startsWith(
targetFsUserHome.toUri().getPath())))) {
String relativeTrashRoot =
targetFSTrashRootPath.substring(mountTargetPath.length());
return makeQualified(new Path(res.resolvedPath, relativeTrashRoot));
} else {
// Return the trash root for the mount point.
return makeQualified(new Path(res.resolvedPath,
TRASH_PREFIX + "/" + ugi.getShortUserName()));
}
} catch (IOException | IllegalArgumentException e) {
throw new NotInMountpointException(path, "getTrashRoot");
Expand All @@ -1182,72 +1212,78 @@ public Path getTrashRoot(Path path) {
/**
* Get all the trash roots for current user or all users.
*
* When FORCE_INSIDE_MOUNT_POINT is set to true, we also return trash roots
* under the root of each mount point, with their viewFS paths.
*
* @param allUsers return trash roots for all users if true.
* @return all Trash root directories.
*/
@Override
public Collection<FileStatus> getTrashRoots(boolean allUsers) {
List<FileStatus> trashRoots = new ArrayList<>();
// A map from targetFSPath -> FileStatus.
// FileStatus can be from targetFS or viewFS.
HashMap<Path, FileStatus> trashRoots = new HashMap<>();
for (FileSystem fs : getChildFileSystems()) {
trashRoots.addAll(fs.getTrashRoots(allUsers));
for (FileStatus trash : fs.getTrashRoots(allUsers)) {
trashRoots.put(trash.getPath(), trash);
}
}

// Add trash dirs for each mount point
boolean useMountPointLocalTrash =
config.getBoolean(CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH,
CONFIG_VIEWFS_MOUNT_POINT_LOCAL_TRASH_DEFAULT);
if (useMountPointLocalTrash) {
// Return trashRoots if FORCE_INSIDE_MOUNT_POINT is disabled.
if (!config.getBoolean(CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT,
CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT_DEFAULT)) {
return trashRoots.values();
}

Set<Path> currentTrashPaths = new HashSet<>();
for (FileStatus file : trashRoots) {
currentTrashPaths.add(file.getPath());
}
// Get trash roots in TRASH_PREFIX dir inside mount points and fallback FS.
List<InodeTree.MountPoint<FileSystem>> mountPoints =
fsState.getMountPoints();
// If we have a fallback FS, add a mount point for it as <"", fallback FS>.
// The source path of a mount point shall not end with '/', thus for
// fallback fs, we set its mount point src as "".
if (fsState.getRootFallbackLink() != null) {
mountPoints.add(new InodeTree.MountPoint<>("",
fsState.getRootFallbackLink()));
}

MountPoint[] mountPoints = getMountPoints();
try {
for (int i = 0; i < mountPoints.length; i++) {
Path trashRoot = makeQualified(
new Path(mountPoints[i].mountedOnPath + "/" + TRASH_PREFIX));
try {
for (InodeTree.MountPoint<FileSystem> mountPoint : mountPoints) {

// Continue if trashRoot does not exist for this filesystem
if (!exists(trashRoot)) {
continue;
}
Path trashRoot =
makeQualified(new Path(mountPoint.src + "/" + TRASH_PREFIX));

InodeTree.ResolveResult<FileSystem> res =
fsState.resolve(getUriPath(trashRoot), true);

if (!allUsers) {
Path userTrash =
new Path("/" + TRASH_PREFIX + "/" + ugi.getShortUserName());
try {
FileStatus file = res.targetFileSystem.getFileStatus(userTrash);
if (!currentTrashPaths.contains(file.getPath())) {
trashRoots.add(file);
currentTrashPaths.add(file.getPath());
}
} catch (FileNotFoundException ignored) {
}
} else {
FileStatus[] targetFsTrashRoots =
res.targetFileSystem.listStatus(new Path("/" + TRASH_PREFIX));
for (FileStatus file : targetFsTrashRoots) {
// skip if we already include it in currentTrashPaths
if (currentTrashPaths.contains(file.getPath())) {
continue;
}
// Continue if trashRoot does not exist for this mount point
if (!exists(trashRoot)) {
continue;
}

trashRoots.add(file);
currentTrashPaths.add(file.getPath());
}
FileSystem targetFS = mountPoint.target.getTargetFileSystem();
if (!allUsers) {
Path userTrashRoot = new Path(trashRoot, ugi.getShortUserName());
if (exists(userTrashRoot)) {
Path targetFSUserTrashRoot = targetFS.makeQualified(
new Path(targetFS.getUri().getPath(),
TRASH_PREFIX + "/" + ugi.getShortUserName()));
trashRoots.put(targetFSUserTrashRoot, getFileStatus(userTrashRoot));
}
} else {
FileStatus[] mountPointTrashRoots = listStatus(trashRoot);
for (FileStatus trash : mountPointTrashRoots) {
// Remove the mountPoint and the leading '/' to get the
// relative targetFsTrash path
String targetFsTrash = trash.getPath().toUri().getPath()
.substring(mountPoint.src.length() + 1);
Path targetFsTrashPath = targetFS.makeQualified(
new Path(targetFS.getUri().getPath(), targetFsTrash));
trashRoots.put(targetFsTrashPath, trash);
}
}
} catch (IOException e) {
LOG.warn("Exception in get all trash roots", e);
}
} catch (IOException e) {
LOG.warn("Exception in get all trash roots for mount points", e);
}

return trashRoots;
return trashRoots.values();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import static org.apache.hadoop.fs.FileSystem.TRASH_PREFIX;
import org.apache.hadoop.security.UserGroupInformation;

import org.junit.After;
import org.junit.Before;
Expand Down Expand Up @@ -61,6 +63,13 @@ public void setUp() throws Exception {

}

@Override
Path getTrashRootInFallBackFS() throws IOException {
return new Path(
"/" + TRASH_PREFIX + "/" + UserGroupInformation.getCurrentUser()
.getShortUserName());
}

@Test
public void testNflyWriteSimple() throws IOException {
LOG.info("Starting testNflyWriteSimple");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import org.apache.hadoop.fs.FileSystemTestHelper;
import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.Path;
import static org.apache.hadoop.fs.FileSystem.TRASH_PREFIX;
import org.apache.hadoop.security.UserGroupInformation;
import java.io.IOException;

import org.junit.After;
import org.junit.Assert;
Expand Down Expand Up @@ -63,6 +66,13 @@ public void tearDown() throws Exception {
super.tearDown();
}

@Override
Path getTrashRootInFallBackFS() throws IOException {
return new Path(
"/" + TRASH_PREFIX + "/" + UserGroupInformation.getCurrentUser()
.getShortUserName());
}

@Override
@Test
public void testBasicPaths() {
Expand Down
Loading