HDFS-15535. RBF: Fix Namespace path to snapshot path resolution for snapshot API. Contributed by Ayush Saxena.
This commit is contained in:
parent
9b9f7ea16a
commit
4813a37023
|
@ -849,6 +849,45 @@ public class RouterRpcClient {
|
|||
final List<? extends RemoteLocationContext> locations,
|
||||
final RemoteMethod remoteMethod, Class<T> expectedResultClass,
|
||||
Object expectedResultValue) throws IOException {
|
||||
return (T) invokeSequential(remoteMethod, locations, expectedResultClass,
|
||||
expectedResultValue).getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes sequential proxy calls to different locations. Continues to invoke
|
||||
* calls until the success condition is met, or until all locations have been
|
||||
* attempted.
|
||||
*
|
||||
* The success condition may be specified by:
|
||||
* <ul>
|
||||
* <li>An expected result class
|
||||
* <li>An expected result value
|
||||
* </ul>
|
||||
*
|
||||
* If no expected result class/values are specified, the success condition is
|
||||
* a call that does not throw a remote exception.
|
||||
*
|
||||
* This returns RemoteResult, which contains the invoked location as well
|
||||
* as the result.
|
||||
*
|
||||
* @param <R> The type of the remote location.
|
||||
* @param <T> The type of the remote method return.
|
||||
* @param remoteMethod The remote method and parameters to invoke.
|
||||
* @param locations List of locations/nameservices to call concurrently.
|
||||
* @param expectedResultClass In order to be considered a positive result, the
|
||||
* return type must be of this class.
|
||||
* @param expectedResultValue In order to be considered a positive result, the
|
||||
* return value must equal the value of this object.
|
||||
* @return The result of the first successful call, or if no calls are
|
||||
* successful, the result of the first RPC call executed, along with
|
||||
* the invoked location in form of RemoteResult.
|
||||
* @throws IOException if the success condition is not met, return the first
|
||||
* remote exception generated.
|
||||
*/
|
||||
public <R extends RemoteLocationContext, T> RemoteResult invokeSequential(
|
||||
final RemoteMethod remoteMethod, final List<R> locations,
|
||||
Class<T> expectedResultClass, Object expectedResultValue)
|
||||
throws IOException {
|
||||
|
||||
final UserGroupInformation ugi = RouterRpcServer.getRemoteUser();
|
||||
final Method m = remoteMethod.getMethod();
|
||||
|
@ -867,9 +906,9 @@ public class RouterRpcClient {
|
|||
if (isExpectedClass(expectedResultClass, result) &&
|
||||
isExpectedValue(expectedResultValue, result)) {
|
||||
// Valid result, stop here
|
||||
@SuppressWarnings("unchecked")
|
||||
T ret = (T)result;
|
||||
return ret;
|
||||
@SuppressWarnings("unchecked") R location = (R) loc;
|
||||
@SuppressWarnings("unchecked") T ret = (T) result;
|
||||
return new RemoteResult<>(location, ret);
|
||||
}
|
||||
if (firstResult == null) {
|
||||
firstResult = result;
|
||||
|
@ -907,9 +946,8 @@ public class RouterRpcClient {
|
|||
throw thrownExceptions.get(0);
|
||||
}
|
||||
// Return the first result, whether it is the value or not
|
||||
@SuppressWarnings("unchecked")
|
||||
T ret = (T)firstResult;
|
||||
return ret;
|
||||
@SuppressWarnings("unchecked") T ret = (T) firstResult;
|
||||
return new RemoteResult<>(locations.get(0), ret);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -104,10 +104,12 @@ public class RouterSnapshot {
|
|||
result = firstelement.getValue();
|
||||
result = result.replaceFirst(loc.getDest(), loc.getSrc());
|
||||
} else {
|
||||
result = rpcClient.invokeSequential(
|
||||
locations, method, String.class, null);
|
||||
RemoteLocation loc = locations.get(0);
|
||||
result = result.replaceFirst(loc.getDest(), loc.getSrc());
|
||||
RemoteResult<RemoteLocation, String> response =
|
||||
rpcClient.invokeSequential(method, locations, String.class, null);
|
||||
RemoteLocation loc = response.getLocation();
|
||||
String invokedResult = response.getResult();
|
||||
result = invokedResult
|
||||
.replaceFirst(loc.getDest(), loc.getSrc());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -180,9 +182,11 @@ public class RouterSnapshot {
|
|||
s.setParentFullPath(DFSUtil.string2Bytes(mountPath));
|
||||
}
|
||||
} else {
|
||||
response = rpcClient.invokeSequential(
|
||||
locations, remoteMethod, SnapshotStatus[].class, null);
|
||||
RemoteLocation loc = locations.get(0);
|
||||
RemoteResult<RemoteLocation, SnapshotStatus[]> invokedResponse = rpcClient
|
||||
.invokeSequential(remoteMethod, locations, SnapshotStatus[].class,
|
||||
null);
|
||||
RemoteLocation loc = invokedResponse.getLocation();
|
||||
response = invokedResponse.getResult();
|
||||
for (SnapshotStatus s : response) {
|
||||
String mountPath = DFSUtil.bytes2String(s.getParentFullPath()).
|
||||
replaceFirst(loc.getDest(), loc.getSrc());
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.apache.hadoop.fs.permission.FsPermission;
|
|||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||
import org.apache.hadoop.hdfs.DFSTestUtil;
|
||||
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||
import org.apache.hadoop.hdfs.protocol.SnapshotStatus;
|
||||
import org.apache.hadoop.hdfs.server.federation.MiniRouterDFSCluster.RouterContext;
|
||||
import org.apache.hadoop.hdfs.server.federation.RouterConfigBuilder;
|
||||
import org.apache.hadoop.hdfs.server.federation.StateStoreDFSCluster;
|
||||
|
@ -492,6 +493,38 @@ public class TestRouterRPCMultipleDestinationMountTableResolver {
|
|||
assertFalse(client.isMultiDestDirectory("/mount/dir"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the snapshot location returned after snapshot operations is in
|
||||
* accordance to the mount path.
|
||||
*/
|
||||
@Test
|
||||
public void testSnapshotPathResolution() throws Exception {
|
||||
// Create a mount entry with non isPathAll order, so as to call
|
||||
// invokeSequential.
|
||||
Map<String, String> destMap = new HashMap<>();
|
||||
destMap.put("ns0", "/tmp_ns0");
|
||||
destMap.put("ns1", "/tmp_ns1");
|
||||
nnFs0.mkdirs(new Path("/tmp_ns0"));
|
||||
nnFs1.mkdirs(new Path("/tmp_ns1"));
|
||||
MountTable addEntry = MountTable.newInstance("/mountSnap", destMap);
|
||||
addEntry.setDestOrder(DestinationOrder.HASH);
|
||||
assertTrue(addMountTable(addEntry));
|
||||
// Create the actual directory in the destination second in sequence of
|
||||
// invokeSequential.
|
||||
nnFs0.mkdirs(new Path("/tmp_ns0/snapDir"));
|
||||
Path snapDir = new Path("/mountSnap/snapDir");
|
||||
Path snapshotPath = new Path("/mountSnap/snapDir/.snapshot/snap");
|
||||
routerFs.allowSnapshot(snapDir);
|
||||
// Verify the snapshot path returned after createSnapshot is as per mount
|
||||
// path.
|
||||
Path snapshot = routerFs.createSnapshot(snapDir, "snap");
|
||||
assertEquals(snapshotPath, snapshot);
|
||||
// Verify the snapshot path returned as part of snapshotListing is as per
|
||||
// mount path.
|
||||
SnapshotStatus[] snapshots = routerFs.getSnapshotListing(snapDir);
|
||||
assertEquals(snapshotPath, snapshots[0].getFullPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenameMultipleDestDirectories() throws Exception {
|
||||
// Test renaming directories using rename API.
|
||||
|
|
Loading…
Reference in New Issue