Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -17,6 +17,8 @@
*/
package org.apache.hadoop.hdfs;

import org.apache.commons.collections.list.TreeList;
import org.apache.hadoop.ipc.RpcNoSuchMethodException;
import org.apache.hadoop.net.DomainNameResolver;
import org.apache.hadoop.thirdparty.com.google.common.base.Joiner;
import org.apache.hadoop.util.Preconditions;
Expand All @@ -30,6 +32,7 @@
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.client.HdfsClientConfigKeys;
import org.apache.hadoop.hdfs.client.impl.SnapshotDiffReportGenerator;
import org.apache.hadoop.hdfs.net.BasicInetPeer;
import org.apache.hadoop.hdfs.net.NioInetPeer;
import org.apache.hadoop.hdfs.net.Peer;
Expand All @@ -43,8 +46,11 @@
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
import org.apache.hadoop.hdfs.protocol.datatransfer.IOStreamPair;
import org.apache.hadoop.hdfs.protocol.ReconfigurationProtocol;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing;
import org.apache.hadoop.hdfs.protocol.datatransfer.sasl.DataEncryptionKeyFactory;
import org.apache.hadoop.hdfs.protocol.datatransfer.sasl.SaslDataTransferClient;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing.DiffReportListingEntry;
import org.apache.hadoop.hdfs.protocolPB.ClientDatanodeProtocolTranslatorPB;
import org.apache.hadoop.hdfs.protocolPB.ReconfigurationProtocolTranslatorPB;
import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier;
Expand All @@ -55,6 +61,7 @@
import org.apache.hadoop.net.NodeBase;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.util.ChunkedArrayList;
import org.apache.hadoop.util.Daemon;
import org.apache.hadoop.util.StringUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -360,6 +367,13 @@ public static byte[] byteArray2bytes(byte[][] pathComponents) {
return path;
}

/**
* Given a list of path components returns a string.
*/
public static String byteArray2String(byte[][] pathComponents) {
return bytes2String(byteArray2bytes(pathComponents));
}

/**
* Decode a specific range of bytes of the given byte array to a string
* using UTF8.
Expand Down Expand Up @@ -1129,4 +1143,68 @@ public static String getSnapshotTrashRoot(String ssRoot,
return (ssRoot.equals("/") ? ssRoot : ssRoot + Path.SEPARATOR)
+ FileSystem.TRASH_PREFIX + Path.SEPARATOR + ugi.getShortUserName();
}

/**
* Returns true if the name of snapshot is vlaid.
* @param snapshotName name of the snapshot.
* @return true if the name of snapshot is vlaid.
*/
public static boolean isValidSnapshotName(String snapshotName) {
// If any of the snapshots specified in the getSnapshotDiffReport call
// is null or empty, it points to the current tree.
return (snapshotName != null && !snapshotName.isEmpty());
}

public static SnapshotDiffReport getSnapshotDiffReport(
String snapshotDir, String fromSnapshot, String toSnapshot,
SnapshotDiffReportFunction withoutListing,
SnapshotDiffReportListingFunction withListing) throws IOException {
// In case the diff needs to be computed between a snapshot and the current
// tree, we should not do iterative diffReport computation as the iterative
// approach might fail if in between the rpc calls the current tree
// changes in absence of the global fsn lock.
if (!isValidSnapshotName(fromSnapshot) || !isValidSnapshotName(toSnapshot)) {
return withoutListing.apply(snapshotDir, fromSnapshot, toSnapshot);
}
byte[] startPath = EMPTY_BYTES;
int index = -1;
SnapshotDiffReportGenerator snapshotDiffReport;
List<DiffReportListingEntry> modifiedList = new TreeList();
List<DiffReportListingEntry> createdList = new ChunkedArrayList<>();
List<DiffReportListingEntry> deletedList = new ChunkedArrayList<>();
SnapshotDiffReportListing report;
do {
try {
report = withListing.apply(snapshotDir, fromSnapshot, toSnapshot, startPath, index);
} catch (RpcNoSuchMethodException|UnsupportedOperationException e) {
// In case the server doesn't support getSnapshotDiffReportListing,
// fallback to getSnapshotDiffReport.
LOG.warn("Falling back to getSnapshotDiffReport {}", e.getMessage());
return withoutListing.apply(snapshotDir, fromSnapshot, toSnapshot);
}
startPath = report.getLastPath();
index = report.getLastIndex();
modifiedList.addAll(report.getModifyList());
createdList.addAll(report.getCreateList());
deletedList.addAll(report.getDeleteList());
} while (!(Arrays.equals(startPath, EMPTY_BYTES)
&& index == -1));
snapshotDiffReport =
new SnapshotDiffReportGenerator(snapshotDir, fromSnapshot, toSnapshot,
report.getIsFromEarlier(), modifiedList, createdList, deletedList);
return snapshotDiffReport.generateReport();
}

@FunctionalInterface
public interface SnapshotDiffReportFunction {
SnapshotDiffReport apply(String snapshotDir, String fromSnapshot, String toSnapshot)
throws IOException;
}

@FunctionalInterface
public interface SnapshotDiffReportListingFunction {
SnapshotDiffReportListing apply(String snapshotDir, String fromSnapshot, String toSnapshot,
byte[] startPath, int index)
throws IOException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@

package org.apache.hadoop.hdfs;


import org.apache.hadoop.ipc.RpcNoSuchMethodException;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.classification.VisibleForTesting;
import org.apache.hadoop.util.Preconditions;
import org.apache.commons.collections.list.TreeList;
import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
Expand Down Expand Up @@ -107,16 +104,13 @@
import org.apache.hadoop.hdfs.protocol.RollingUpgradeInfo;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing.DiffReportListingEntry;
import org.apache.hadoop.hdfs.client.impl.SnapshotDiffReportGenerator;
import org.apache.hadoop.hdfs.protocol.SnapshottableDirectoryStatus;
import org.apache.hadoop.hdfs.protocol.SnapshotStatus;
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.net.NetUtils;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.DelegationTokenIssuer;
import org.apache.hadoop.util.ChunkedArrayList;
import org.apache.hadoop.util.Lists;
import org.apache.hadoop.util.Progressable;
import org.slf4j.Logger;
Expand Down Expand Up @@ -2298,8 +2292,8 @@ <SnapshotDiffReportListing> snapshotDiffReportListingRemoteIterator(
@Override
public RemoteIterator<SnapshotDiffReportListing> doCall(final Path p)
throws IOException {
if (!isValidSnapshotName(fromSnapshot) || !isValidSnapshotName(
toSnapshot)) {
if (!DFSUtilClient.isValidSnapshotName(fromSnapshot) ||
!DFSUtilClient.isValidSnapshotName(toSnapshot)) {
throw new UnsupportedOperationException("Remote Iterator is"
+ "supported for snapshotDiffReport between two snapshots");
}
Expand Down Expand Up @@ -2364,52 +2358,11 @@ public SnapshotDiffReportListing next() throws IOException {
}
}

private boolean isValidSnapshotName(String snapshotName) {
// If any of the snapshots specified in the getSnapshotDiffReport call
// is null or empty, it points to the current tree.
return (snapshotName != null && !snapshotName.isEmpty());
}

private SnapshotDiffReport getSnapshotDiffReportInternal(
final String snapshotDir, final String fromSnapshot,
final String toSnapshot) throws IOException {
// In case the diff needs to be computed between a snapshot and the current
// tree, we should not do iterative diffReport computation as the iterative
// approach might fail if in between the rpc calls the current tree
// changes in absence of the global fsn lock.
if (!isValidSnapshotName(fromSnapshot) || !isValidSnapshotName(
toSnapshot)) {
return dfs.getSnapshotDiffReport(snapshotDir, fromSnapshot, toSnapshot);
}
byte[] startPath = DFSUtilClient.EMPTY_BYTES;
int index = -1;
SnapshotDiffReportGenerator snapshotDiffReport;
List<DiffReportListingEntry> modifiedList = new TreeList();
List<DiffReportListingEntry> createdList = new ChunkedArrayList<>();
List<DiffReportListingEntry> deletedList = new ChunkedArrayList<>();
SnapshotDiffReportListing report;
do {
try {
report = dfs.getSnapshotDiffReportListing(snapshotDir, fromSnapshot,
toSnapshot, startPath, index);
} catch (RpcNoSuchMethodException e) {
// In case the server doesn't support getSnapshotDiffReportListing,
// fallback to getSnapshotDiffReport.
DFSClient.LOG.warn(
"Falling back to getSnapshotDiffReport {}", e.getMessage());
return dfs.getSnapshotDiffReport(snapshotDir, fromSnapshot, toSnapshot);
}
startPath = report.getLastPath();
index = report.getLastIndex();
modifiedList.addAll(report.getModifyList());
createdList.addAll(report.getCreateList());
deletedList.addAll(report.getDeleteList());
} while (!(Arrays.equals(startPath, DFSUtilClient.EMPTY_BYTES)
&& index == -1));
snapshotDiffReport =
new SnapshotDiffReportGenerator(snapshotDir, fromSnapshot, toSnapshot,
report.getIsFromEarlier(), modifiedList, createdList, deletedList);
return snapshotDiffReport.generateReport();
return DFSUtilClient.getSnapshotDiffReport(snapshotDir, fromSnapshot, toSnapshot,
dfs::getSnapshotDiffReport, dfs::getSnapshotDiffReportListing);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
import org.apache.hadoop.hdfs.protocol.ErasureCodingPolicy;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing.DiffReportListingEntry;
import org.apache.hadoop.hdfs.protocol.SnapshottableDirectoryStatus;
import org.apache.hadoop.hdfs.protocol.SnapshotStatus;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo.DatanodeInfoBuilder;
Expand Down Expand Up @@ -245,6 +247,14 @@ static ExtendedBlock toExtendedBlock(final Map<?, ?> m) {
return new ExtendedBlock(blockPoolId, blockId, numBytes, generationStamp);
}

static boolean getBoolean(Map<?, ?> m, String key, final boolean defaultValue) {
Object value = m.get(key);
if (value == null) {
return defaultValue;
}
return ((Boolean) value).booleanValue();
}

static int getInt(Map<?, ?> m, String key, final int defaultValue) {
Object value = m.get(key);
if (value == null) {
Expand Down Expand Up @@ -834,6 +844,53 @@ private static SnapshotDiffReport.DiffReportEntry toDiffReportEntry(
return new SnapshotDiffReport.DiffReportEntry(type, sourcePath, targetPath);
}

public static SnapshotDiffReportListing toSnapshotDiffReportListing(
final Map<?, ?> json) {
if (json == null) {
return null;
}

Map<?, ?> m =
(Map<?, ?>) json.get(SnapshotDiffReportListing.class.getSimpleName());
byte[] lastPath = DFSUtilClient.string2Bytes(getString(m, "lastPath", ""));
int lastIndex = getInt(m, "lastIndex", -1);
boolean isFromEarlier = getBoolean(m, "isFromEarlier", false);
List<DiffReportListingEntry> modifyList =
toDiffListingList(getList(m, "modifyList"));
List<DiffReportListingEntry> createList =
toDiffListingList(getList(m, "createList"));
List<DiffReportListingEntry> deleteList =
toDiffListingList(getList(m, "deleteList"));

return new SnapshotDiffReportListing(
lastPath, modifyList, createList, deleteList, lastIndex, isFromEarlier);
}

public static List<DiffReportListingEntry> toDiffListingList(List<?> objs) {
if (objs == null) {
return null;
}
List<DiffReportListingEntry> diffList = new ChunkedArrayList<>();
for (int i = 0; i < objs.size(); i++) {
diffList.add(toDiffReportListingEntry((Map<?, ?>) objs.get(i)));
}
return diffList;
}

private static DiffReportListingEntry toDiffReportListingEntry(
Map<?, ?> json) {
if (json == null) {
return null;
}
long dirId = getLong(json, "dirId", 0);
long fileId = getLong(json, "fileId", 0);
byte[] sourcePath = toByteArray(getString(json, "sourcePath", null));
byte[] targetPath = toByteArray(getString(json, "targetPath", null));
boolean isReference = getBoolean(json, "isReference", false);
return new DiffReportListingEntry(
dirId, fileId, sourcePath, isReference, targetPath);
}

private static byte[] toByteArray(String str) {
if (str == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand All @@ -63,7 +62,6 @@
import org.apache.hadoop.crypto.key.KeyProviderTokenIssuer;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.fs.CommonPathCapabilities;
import org.apache.hadoop.fs.ContentSummary;
import org.apache.hadoop.fs.CreateFlag;
import org.apache.hadoop.fs.DelegationTokenRenewer;
Expand All @@ -78,7 +76,6 @@
import org.apache.hadoop.fs.GlobalStorageStatistics.StorageStatisticsProvider;
import org.apache.hadoop.fs.MultipartUploaderBuilder;
import org.apache.hadoop.fs.QuotaUsage;
import org.apache.hadoop.fs.PathCapabilities;
import org.apache.hadoop.fs.StorageStatistics;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.fs.impl.FileSystemMultipartUploaderBuilder;
Expand All @@ -105,6 +102,7 @@
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReportListing;
import org.apache.hadoop.hdfs.protocol.SnapshottableDirectoryStatus;
import org.apache.hadoop.hdfs.protocol.SnapshotStatus;
import org.apache.hadoop.hdfs.protocol.proto.HdfsProtos.FileEncryptionInfoProto;
Expand Down Expand Up @@ -1445,19 +1443,45 @@ public void renameSnapshot(final Path path, final String snapshotOldName,
new SnapshotNameParam(snapshotNewName)).run();
}

private SnapshotDiffReport getSnapshotDiffReport(
final String snapshotDir, final String fromSnapshot, final String toSnapshot)
throws IOException {
return new FsPathResponseRunner<SnapshotDiffReport>(
GetOpParam.Op.GETSNAPSHOTDIFF,
new Path(snapshotDir),
new OldSnapshotNameParam(fromSnapshot),
new SnapshotNameParam(toSnapshot)) {
@Override
SnapshotDiffReport decodeResponse(Map<?, ?> json) {
return JsonUtilClient.toSnapshotDiffReport(json);
}
}.run();
}

private SnapshotDiffReportListing getSnapshotDiffReportListing(
String snapshotDir, final String fromSnapshot, final String toSnapshot,
byte[] startPath, int index) throws IOException {
return new FsPathResponseRunner<SnapshotDiffReportListing>(
GetOpParam.Op.GETSNAPSHOTDIFFLISTING,
new Path(snapshotDir),
new OldSnapshotNameParam(fromSnapshot),
new SnapshotNameParam(toSnapshot),
new SnapshotDiffStartPathParam(DFSUtilClient.bytes2String(startPath)),
new SnapshotDiffIndexParam(index)) {
@Override
SnapshotDiffReportListing decodeResponse(Map<?, ?> json) {
return JsonUtilClient.toSnapshotDiffReportListing(json);
}
}.run();
}

public SnapshotDiffReport getSnapshotDiffReport(final Path snapshotDir,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is by and large copied from DistributedFileSystem.getSnapshotDiffReportInternal()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved common logic to DFSUtilClient.

final String fromSnapshot, final String toSnapshot) throws IOException {
statistics.incrementReadOps(1);
storageStatistics.incrementOpCounter(OpType.GET_SNAPSHOT_DIFF);
final HttpOpParam.Op op = GetOpParam.Op.GETSNAPSHOTDIFF;
return new FsPathResponseRunner<SnapshotDiffReport>(op, snapshotDir,
new OldSnapshotNameParam(fromSnapshot),
new SnapshotNameParam(toSnapshot)) {
@Override
SnapshotDiffReport decodeResponse(Map<?, ?> json) {
return JsonUtilClient.toSnapshotDiffReport(json);
}
}.run();
return DFSUtilClient.getSnapshotDiffReport(
snapshotDir.toUri().getPath(), fromSnapshot, toSnapshot,
this::getSnapshotDiffReport, this::getSnapshotDiffReportListing);
}

public SnapshottableDirectoryStatus[] getSnapshottableDirectoryList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public enum Op implements HttpOpParam.Op {
LISTSTATUS_BATCH(false, HttpURLConnection.HTTP_OK),
GETSERVERDEFAULTS(false, HttpURLConnection.HTTP_OK),
GETSNAPSHOTDIFF(false, HttpURLConnection.HTTP_OK),
GETSNAPSHOTDIFFLISTING(false, HttpURLConnection.HTTP_OK),
GETSNAPSHOTTABLEDIRECTORYLIST(false, HttpURLConnection.HTTP_OK),
GETSNAPSHOTLIST(false, HttpURLConnection.HTTP_OK);

Expand Down
Loading