blob: e0343a02f5863637240abf4a0e78a75377bf668a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.protocol;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DFSUtil;
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectorySnapshottable.SnapshotDiffInfo;
/**
* This class represents to end users the difference between two snapshots of
* the same directory, or the difference between a snapshot of the directory and
* its current state. Instead of capturing all the details of the diff, which
* is stored in {@link SnapshotDiffInfo}, this class only lists where the
* changes happened and their types.
*/
public class SnapshotDiffReport {
private final static String LINE_SEPARATOR = System.getProperty(
"line.separator", "\n");
/**
* Types of the difference, which include CREATE, MODIFY, DELETE, and RENAME.
* Each type has a label for representation: +/M/-/R represent CREATE, MODIFY,
* DELETE, and RENAME respectively.
*/
public enum DiffType {
CREATE("+"),
MODIFY("M"),
DELETE("-"),
RENAME("R");
private String label;
private DiffType(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public static DiffType getTypeFromLabel(String label) {
if (label.equals(CREATE.getLabel())) {
return CREATE;
} else if (label.equals(MODIFY.getLabel())) {
return MODIFY;
} else if (label.equals(DELETE.getLabel())) {
return DELETE;
} else if (label.equals(RENAME.getLabel())) {
return RENAME;
}
return null;
}
};
/**
* Representing the full path and diff type of a file/directory where changes
* have happened.
*/
public static class DiffReportEntry {
/** The type of the difference. */
private final DiffType type;
/**
* The relative path (related to the snapshot root) of the file/directory
* where changes have happened
*/
private final byte[] relativePath;
public DiffReportEntry(DiffType type, byte[] path) {
this.type = type;
this.relativePath = path;
}
public DiffReportEntry(DiffType type, byte[][] pathComponents) {
this.type = type;
this.relativePath = DFSUtil.byteArray2bytes(pathComponents);
}
@Override
public String toString() {
return type.getLabel() + "\t" + getRelativePathString();
}
public DiffType getType() {
return type;
}
public String getRelativePathString() {
String path = DFSUtil.bytes2String(relativePath);
if (path.isEmpty()) {
return Path.CUR_DIR;
} else {
return Path.CUR_DIR + Path.SEPARATOR + path;
}
}
public byte[] getRelativePath() {
return relativePath;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other != null && other instanceof DiffReportEntry) {
DiffReportEntry entry = (DiffReportEntry) other;
return type.equals(entry.getType())
&& Arrays.equals(relativePath, entry.getRelativePath());
}
return false;
}
@Override
public int hashCode() {
return Arrays.hashCode(relativePath);
}
}
/** snapshot root full path */
private final String snapshotRoot;
/** start point of the diff */
private final String fromSnapshot;
/** end point of the diff */
private final String toSnapshot;
/** list of diff */
private final List<DiffReportEntry> diffList;
public SnapshotDiffReport(String snapshotRoot, String fromSnapshot,
String toSnapshot, List<DiffReportEntry> entryList) {
this.snapshotRoot = snapshotRoot;
this.fromSnapshot = fromSnapshot;
this.toSnapshot = toSnapshot;
this.diffList = entryList != null ? entryList : Collections
.<DiffReportEntry> emptyList();
}
/** @return {@link #snapshotRoot}*/
public String getSnapshotRoot() {
return snapshotRoot;
}
/** @return {@link #fromSnapshot} */
public String getFromSnapshot() {
return fromSnapshot;
}
/** @return {@link #toSnapshot} */
public String getLaterSnapshotName() {
return toSnapshot;
}
/** @return {@link #diffList} */
public List<DiffReportEntry> getDiffList() {
return diffList;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
String from = fromSnapshot == null || fromSnapshot.isEmpty() ?
"current directory" : "snapshot " + fromSnapshot;
String to = toSnapshot == null || toSnapshot.isEmpty() ? "current directory"
: "snapshot " + toSnapshot;
str.append("Difference between " + from + " and " + to
+ " under directory " + snapshotRoot + ":" + LINE_SEPARATOR);
for (DiffReportEntry entry : diffList) {
str.append(entry.toString() + LINE_SEPARATOR);
}
return str.toString();
}
}