Skip to content

Commit 2ba7ec2

Browse files
committed
HDFS-15766. RBF: MockResolver.getMountPoints() breaks the semantic of FileSubclusterResolver. Contributed by Jinglun.
1 parent 87bd4d2 commit 2ba7ec2

File tree

4 files changed

+100
-89
lines changed

4 files changed

+100
-89
lines changed

hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/resolver/FileSubclusterResolver.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@
2020

2121
import java.io.IOException;
2222
import java.util.List;
23+
import java.util.LinkedList;
24+
import java.util.Set;
25+
import java.util.TreeSet;
26+
import java.util.Collection;
2327

2428
import org.apache.hadoop.classification.InterfaceAudience;
2529
import org.apache.hadoop.classification.InterfaceStability;
30+
import org.apache.hadoop.fs.Path;
2631

2732
/**
2833
* Interface to map a file path in the global name space to a specific
@@ -75,4 +80,51 @@ public interface FileSubclusterResolver {
7580
* @return Default namespace identifier.
7681
*/
7782
String getDefaultNamespace();
83+
84+
/**
85+
* Get a list of mount points for a path.
86+
*
87+
* @param path Path to get the mount points under.
88+
* @param mountPoints the mount points to choose.
89+
* @return Return empty list if the path is a mount point but there are no
90+
* mount points under the path. Return null if the path is not a mount
91+
* point and there are no mount points under the path.
92+
*/
93+
static List<String> getMountPoints(String path,
94+
Collection<String> mountPoints) {
95+
Set<String> children = new TreeSet<>();
96+
boolean exists = false;
97+
for (String subPath : mountPoints) {
98+
String child = subPath;
99+
100+
// Special case for /
101+
if (!path.equals(Path.SEPARATOR)) {
102+
// Get the children
103+
int ini = path.length();
104+
child = subPath.substring(ini);
105+
}
106+
107+
if (child.isEmpty()) {
108+
// This is a mount point but without children
109+
exists = true;
110+
} else if (child.startsWith(Path.SEPARATOR)) {
111+
// This is a mount point with children
112+
exists = true;
113+
child = child.substring(1);
114+
115+
// We only return immediate children
116+
int fin = child.indexOf(Path.SEPARATOR);
117+
if (fin > -1) {
118+
child = child.substring(0, fin);
119+
}
120+
if (!child.isEmpty()) {
121+
children.add(child);
122+
}
123+
}
124+
}
125+
if (!exists) {
126+
return null;
127+
}
128+
return new LinkedList<>(children);
129+
}
78130
}

hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/resolver/MountTableResolver.java

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -452,46 +452,12 @@ public List<String> getMountPoints(final String str) throws IOException {
452452
verifyMountTable();
453453
final String path = RouterAdmin.normalizeFileSystemPath(str);
454454

455-
Set<String> children = new TreeSet<>();
456455
readLock.lock();
457456
try {
458457
String from = path;
459458
String to = path + Character.MAX_VALUE;
460459
SortedMap<String, MountTable> subMap = this.tree.subMap(from, to);
461-
462-
boolean exists = false;
463-
for (String subPath : subMap.keySet()) {
464-
String child = subPath;
465-
466-
// Special case for /
467-
if (!path.equals(Path.SEPARATOR)) {
468-
// Get the children
469-
int ini = path.length();
470-
child = subPath.substring(ini);
471-
}
472-
473-
if (child.isEmpty()) {
474-
// This is a mount point but without children
475-
exists = true;
476-
} else if (child.startsWith(Path.SEPARATOR)) {
477-
// This is a mount point with children
478-
exists = true;
479-
child = child.substring(1);
480-
481-
// We only return immediate children
482-
int fin = child.indexOf(Path.SEPARATOR);
483-
if (fin > -1) {
484-
child = child.substring(0, fin);
485-
}
486-
if (!child.isEmpty()) {
487-
children.add(child);
488-
}
489-
}
490-
}
491-
if (!exists) {
492-
return null;
493-
}
494-
return new LinkedList<>(children);
460+
return FileSubclusterResolver.getMountPoints(path, subMap.keySet());
495461
} finally {
496462
readLock.unlock();
497463
}

hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/MockResolver.java

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ public void addLocation(String mount, String nsId, String location) {
9494
}
9595
}
9696

97+
public boolean removeLocation(String mount, String nsId, String location) {
98+
List<RemoteLocation> locationsList = this.locations.get(mount);
99+
final RemoteLocation remoteLocation =
100+
new RemoteLocation(nsId, location, mount);
101+
if (locationsList != null) {
102+
return locationsList.remove(remoteLocation);
103+
}
104+
return false;
105+
}
106+
97107
public synchronized void cleanRegistrations() {
98108
this.resolver = new HashMap<>();
99109
this.namespaces = new HashSet<>();
@@ -327,33 +337,13 @@ public PathLocation getDestinationForPath(String path) throws IOException {
327337

328338
@Override
329339
public List<String> getMountPoints(String path) throws IOException {
330-
List<String> mounts = new ArrayList<>();
331-
// for root path search, returning all downstream root level mapping
332-
if (path.equals("/")) {
333-
// Mounts only supported under root level
334-
for (String mount : this.locations.keySet()) {
335-
if (mount.length() > 1) {
336-
// Remove leading slash, this is the behavior of the mount tree,
337-
// return only names.
338-
mounts.add(mount.replace("/", ""));
339-
}
340-
}
341-
} else {
342-
// a simplified version of MountTableResolver implementation
343-
for (String key : this.locations.keySet()) {
344-
if (key.startsWith(path)) {
345-
String child = key.substring(path.length());
346-
if (child.length() > 0) {
347-
// only take children so remove parent path and /
348-
mounts.add(key.substring(path.length()+1));
349-
}
350-
}
351-
}
352-
if (mounts.size() == 0) {
353-
mounts = null;
340+
List<String> mountPoints = new ArrayList<>();
341+
for (String mp : this.locations.keySet()) {
342+
if (mp.startsWith(path)) {
343+
mountPoints.add(mp);
354344
}
355345
}
356-
return mounts;
346+
return FileSubclusterResolver.getMountPoints(path, mountPoints);
357347
}
358348

359349
@Override

hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/router/TestRouterRpc.java

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -885,37 +885,40 @@ public void testManageSnapshot() throws Exception {
885885
resolver.addLocation(mountPoint, ns0, "/");
886886

887887
FsPermission permission = new FsPermission("777");
888-
routerProtocol.mkdirs(mountPoint, permission, false);
889888
routerProtocol.mkdirs(snapshotFolder, permission, false);
890-
for (int i = 1; i <= 9; i++) {
891-
String folderPath = snapshotFolder + "/subfolder" + i;
892-
routerProtocol.mkdirs(folderPath, permission, false);
893-
}
894-
895-
LOG.info("Create the snapshot: {}", snapshotFolder);
896-
routerProtocol.allowSnapshot(snapshotFolder);
897-
String snapshotName = routerProtocol.createSnapshot(
898-
snapshotFolder, "snap");
899-
assertEquals(snapshotFolder + "/.snapshot/snap", snapshotName);
900-
assertTrue(verifyFileExists(routerFS, snapshotFolder + "/.snapshot/snap"));
901-
902-
LOG.info("Rename the snapshot and check it changed");
903-
routerProtocol.renameSnapshot(snapshotFolder, "snap", "newsnap");
904-
assertFalse(
905-
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/snap"));
906-
assertTrue(
907-
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/newsnap"));
908-
LambdaTestUtils.intercept(SnapshotException.class,
909-
"Cannot delete snapshot snap from path " + snapshotFolder + ":",
910-
() -> routerFS.deleteSnapshot(new Path(snapshotFolder), "snap"));
911-
912-
LOG.info("Delete the snapshot and check it is not there");
913-
routerProtocol.deleteSnapshot(snapshotFolder, "newsnap");
914-
assertFalse(
915-
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/newsnap"));
889+
try {
890+
for (int i = 1; i <= 9; i++) {
891+
String folderPath = snapshotFolder + "/subfolder" + i;
892+
routerProtocol.mkdirs(folderPath, permission, false);
893+
}
916894

917-
// Cleanup
918-
routerProtocol.delete(mountPoint, true);
895+
LOG.info("Create the snapshot: {}", snapshotFolder);
896+
routerProtocol.allowSnapshot(snapshotFolder);
897+
String snapshotName =
898+
routerProtocol.createSnapshot(snapshotFolder, "snap");
899+
assertEquals(snapshotFolder + "/.snapshot/snap", snapshotName);
900+
assertTrue(
901+
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/snap"));
902+
903+
LOG.info("Rename the snapshot and check it changed");
904+
routerProtocol.renameSnapshot(snapshotFolder, "snap", "newsnap");
905+
assertFalse(
906+
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/snap"));
907+
assertTrue(
908+
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/newsnap"));
909+
LambdaTestUtils.intercept(SnapshotException.class,
910+
"Cannot delete snapshot snap from path " + snapshotFolder + ":",
911+
() -> routerFS.deleteSnapshot(new Path(snapshotFolder), "snap"));
912+
913+
LOG.info("Delete the snapshot and check it is not there");
914+
routerProtocol.deleteSnapshot(snapshotFolder, "newsnap");
915+
assertFalse(
916+
verifyFileExists(routerFS, snapshotFolder + "/.snapshot/newsnap"));
917+
} finally {
918+
// Cleanup
919+
assertTrue(routerProtocol.delete(snapshotFolder, true));
920+
assertTrue(resolver.removeLocation(mountPoint, ns0, "/"));
921+
}
919922
}
920923

921924
@Test

0 commit comments

Comments
 (0)