HDFS-4447. Refactor INodeDirectoryWithSnapshot for supporting general INode diff lists.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-2802@1440216 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
66ea187228
commit
6f4fe09687
|
@ -133,3 +133,6 @@ Branch-2802 Snapshot (Unreleased)
|
||||||
|
|
||||||
HDFS-4131. Add capability to namenode to get snapshot diff. (Jing Zhao via
|
HDFS-4131. Add capability to namenode to get snapshot diff. (Jing Zhao via
|
||||||
suresh)
|
suresh)
|
||||||
|
|
||||||
|
HDFS-4447. Refactor INodeDirectoryWithSnapshot for support general INode diff
|
||||||
|
lists. (szetszwo)
|
||||||
|
|
|
@ -42,7 +42,6 @@ import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeFileUnderConstructio
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeFileWithSnapshot;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeFileWithSnapshot;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.diff.Diff;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.diff.Diff;
|
||||||
import org.apache.hadoop.hdfs.util.ReadOnlyList;
|
|
||||||
import org.apache.hadoop.util.StringUtils;
|
import org.apache.hadoop.util.StringUtils;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -58,20 +57,6 @@ import com.google.common.primitives.SignedBytes;
|
||||||
public abstract class INode implements Diff.Element<byte[]> {
|
public abstract class INode implements Diff.Element<byte[]> {
|
||||||
public static final Log LOG = LogFactory.getLog(INode.class);
|
public static final Log LOG = LogFactory.getLog(INode.class);
|
||||||
|
|
||||||
static final ReadOnlyList<INode> EMPTY_READ_ONLY_LIST
|
|
||||||
= ReadOnlyList.Util.emptyList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert that the snapshot parameter must be null since this class only take
|
|
||||||
* care current state. Subclasses should override the methods for handling the
|
|
||||||
* snapshot states.
|
|
||||||
*/
|
|
||||||
static void assertNull(Snapshot snapshot) {
|
|
||||||
if (snapshot != null) {
|
|
||||||
throw new AssertionError("snapshot is not null: " + snapshot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A pair of objects. */
|
/** A pair of objects. */
|
||||||
public static class Pair<L, R> {
|
public static class Pair<L, R> {
|
||||||
public final L left;
|
public final L left;
|
||||||
|
|
|
@ -599,7 +599,7 @@ public class INodeDirectory extends INode {
|
||||||
* Note that the returned list is never null.
|
* Note that the returned list is never null.
|
||||||
*/
|
*/
|
||||||
public ReadOnlyList<INode> getChildrenList(final Snapshot snapshot) {
|
public ReadOnlyList<INode> getChildrenList(final Snapshot snapshot) {
|
||||||
return children == null ? EMPTY_READ_ONLY_LIST
|
return children == null ? ReadOnlyList.Util.<INode>emptyList()
|
||||||
: ReadOnlyList.Util.asReadOnlyList(children);
|
: ReadOnlyList.Util.asReadOnlyList(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/**
|
||||||
|
* 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.server.namenode.snapshot;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The difference of an inode between in two snapshots.
|
||||||
|
* {@link AbstractINodeDiff2} maintains a list of snapshot diffs,
|
||||||
|
* <pre>
|
||||||
|
* d_1 -> d_2 -> ... -> d_n -> null,
|
||||||
|
* </pre>
|
||||||
|
* where -> denotes the {@link AbstractINodeDiff#posteriorDiff} reference. The
|
||||||
|
* current directory state is stored in the field of {@link INode}.
|
||||||
|
* The snapshot state can be obtained by applying the diffs one-by-one in
|
||||||
|
* reversed chronological order. Let s_1, s_2, ..., s_n be the corresponding
|
||||||
|
* snapshots. Then,
|
||||||
|
* <pre>
|
||||||
|
* s_n = (current state) - d_n;
|
||||||
|
* s_{n-1} = s_n - d_{n-1} = (current state) - d_n - d_{n-1};
|
||||||
|
* ...
|
||||||
|
* s_k = s_{k+1} - d_k = (current state) - d_n - d_{n-1} - ... - d_k.
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
abstract class AbstractINodeDiff<N extends INode,
|
||||||
|
D extends AbstractINodeDiff<N, D>>
|
||||||
|
implements Comparable<Snapshot> {
|
||||||
|
/** The snapshot will be obtained after this diff is applied. */
|
||||||
|
final Snapshot snapshot;
|
||||||
|
/** The snapshot inode data. It is null when there is no change. */
|
||||||
|
N snapshotINode;
|
||||||
|
/**
|
||||||
|
* Posterior diff is the diff happened after this diff.
|
||||||
|
* The posterior diff should be first applied to obtain the posterior
|
||||||
|
* snapshot and then apply this diff in order to obtain this snapshot.
|
||||||
|
* If the posterior diff is null, the posterior state is the current state.
|
||||||
|
*/
|
||||||
|
private D posteriorDiff;
|
||||||
|
|
||||||
|
AbstractINodeDiff(Snapshot snapshot, N snapshotINode, D posteriorDiff) {
|
||||||
|
Preconditions.checkNotNull(snapshot, "snapshot is null");
|
||||||
|
|
||||||
|
this.snapshot = snapshot;
|
||||||
|
this.snapshotINode = snapshotINode;
|
||||||
|
this.posteriorDiff = posteriorDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compare diffs with snapshot ID. */
|
||||||
|
@Override
|
||||||
|
public final int compareTo(final Snapshot that) {
|
||||||
|
return Snapshot.ID_COMPARATOR.compare(this.snapshot, that);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the snapshot object of this diff. */
|
||||||
|
final Snapshot getSnapshot() {
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the posterior diff. */
|
||||||
|
final D getPosterior() {
|
||||||
|
return posteriorDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the posterior diff. */
|
||||||
|
final void setPosterior(D posterior) {
|
||||||
|
posteriorDiff = posterior;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy the INode state to the snapshot if it is not done already. */
|
||||||
|
void checkAndInitINode(N snapshotCopy) {
|
||||||
|
if (snapshotINode == null) {
|
||||||
|
if (snapshotCopy == null) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final N right = (N)getCurrentINode().createSnapshotCopy().right;
|
||||||
|
snapshotCopy = right;
|
||||||
|
}
|
||||||
|
snapshotINode = snapshotCopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the current inode. */
|
||||||
|
abstract N getCurrentINode();
|
||||||
|
|
||||||
|
/** @return the inode corresponding to the snapshot. */
|
||||||
|
N getSnapshotINode() {
|
||||||
|
// get from this diff, then the posterior diff and then the current inode
|
||||||
|
for(AbstractINodeDiff<N, D> d = this; ; d = d.posteriorDiff) {
|
||||||
|
if (d.snapshotINode != null) {
|
||||||
|
return d.snapshotINode;
|
||||||
|
} else if (d.posteriorDiff == null) {
|
||||||
|
return getCurrentINode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Combine the posterior diff and collect blocks for deletion. */
|
||||||
|
abstract void combinePosteriorAndCollectBlocks(final D posterior,
|
||||||
|
final BlocksMapUpdateInfo collectedBlocks);
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
/**
|
||||||
|
* 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.server.namenode.snapshot;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of snapshot diffs for storing snapshot data.
|
||||||
|
*
|
||||||
|
* @param <N> The {@link INode} type.
|
||||||
|
* @param <D> The diff type, which must extend {@link AbstractINodeDiff}.
|
||||||
|
*/
|
||||||
|
abstract class AbstractINodeDiffList<N extends INode,
|
||||||
|
D extends AbstractINodeDiff<N, D>>
|
||||||
|
implements Iterable<D> {
|
||||||
|
/** Diff list sorted by snapshot IDs, i.e. in chronological order. */
|
||||||
|
private final List<D> diffs = new ArrayList<D>();
|
||||||
|
|
||||||
|
/** @return this list as a unmodifiable {@link List}. */
|
||||||
|
final List<D> asList() {
|
||||||
|
return Collections.unmodifiableList(diffs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the current inode. */
|
||||||
|
abstract N getCurrentINode();
|
||||||
|
|
||||||
|
/** Add a {@link AbstractINodeDiff} for the given snapshot and inode. */
|
||||||
|
abstract D addSnapshotDiff(Snapshot snapshot, N inode, boolean isSnapshotCreation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the snapshot with the given name. The synchronization of the diff
|
||||||
|
* list will be done outside.
|
||||||
|
*
|
||||||
|
* If the diff to remove is not the first one in the diff list, we need to
|
||||||
|
* combine the diff with its previous one:
|
||||||
|
*
|
||||||
|
* @param snapshot The snapshot to be deleted
|
||||||
|
* @param collectedBlocks Used to collect information for blocksMap update
|
||||||
|
* @return The SnapshotDiff containing the deleted snapshot.
|
||||||
|
* Null if the snapshot with the given name does not exist.
|
||||||
|
*/
|
||||||
|
final AbstractINodeDiff<N, D> deleteSnapshotDiff(Snapshot snapshot,
|
||||||
|
final BlocksMapUpdateInfo collectedBlocks) {
|
||||||
|
int snapshotIndex = Collections.binarySearch(diffs, snapshot);
|
||||||
|
if (snapshotIndex < 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
final D removed = diffs.remove(snapshotIndex);
|
||||||
|
if (snapshotIndex > 0) {
|
||||||
|
// combine the to-be-removed diff with its previous diff
|
||||||
|
final AbstractINodeDiff<N, D> previous = diffs.get(snapshotIndex - 1);
|
||||||
|
previous.combinePosteriorAndCollectBlocks(removed, collectedBlocks);
|
||||||
|
previous.setPosterior(removed.getPosterior());
|
||||||
|
}
|
||||||
|
removed.setPosterior(null);
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Append the diff at the end of the list. */
|
||||||
|
final D append(D diff) {
|
||||||
|
final AbstractINodeDiff<N, D> last = getLast();
|
||||||
|
diffs.add(diff);
|
||||||
|
if (last != null) {
|
||||||
|
last.setPosterior(diff);
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert the diff to the beginning of the list. */
|
||||||
|
final void insert(D diff) {
|
||||||
|
diffs.add(0, diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the last diff. */
|
||||||
|
final D getLast() {
|
||||||
|
final int n = diffs.size();
|
||||||
|
return n == 0? null: diffs.get(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the last snapshot. */
|
||||||
|
final Snapshot getLastSnapshot() {
|
||||||
|
final AbstractINodeDiff<N, D> last = getLast();
|
||||||
|
return last == null? null: last.getSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the diff corresponding to the given snapshot.
|
||||||
|
* When the diff is null, it means that the current state and
|
||||||
|
* the corresponding snapshot state are the same.
|
||||||
|
*/
|
||||||
|
final D getDiff(Snapshot snapshot) {
|
||||||
|
if (snapshot == null) {
|
||||||
|
// snapshot == null means the current state, therefore, return null.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final int i = Collections.binarySearch(diffs, snapshot);
|
||||||
|
if (i >= 0) {
|
||||||
|
// exact match
|
||||||
|
return diffs.get(i);
|
||||||
|
} else {
|
||||||
|
// Exact match not found means that there were no changes between
|
||||||
|
// given snapshot and the next state so that the diff for the given
|
||||||
|
// snapshot was not recorded. Thus, return the next state.
|
||||||
|
final int j = -i - 1;
|
||||||
|
return j < diffs.size()? diffs.get(j): null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the latest snapshot diff exists. If not, add it.
|
||||||
|
* @return the latest snapshot diff, which is never null.
|
||||||
|
*/
|
||||||
|
final D checkAndAddLatestSnapshotDiff(Snapshot latest) {
|
||||||
|
final D last = getLast();
|
||||||
|
return last != null && last.snapshot.equals(latest)? last
|
||||||
|
: addSnapshotDiff(latest, getCurrentINode(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<D> iterator() {
|
||||||
|
return diffs.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "diffs=" + diffs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -150,7 +150,7 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
|
|
||||||
public INodeDirectorySnapshottable(INodeDirectory dir) {
|
public INodeDirectorySnapshottable(INodeDirectory dir) {
|
||||||
super(dir, true, dir instanceof INodeDirectoryWithSnapshot ?
|
super(dir, true, dir instanceof INodeDirectoryWithSnapshot ?
|
||||||
((INodeDirectoryWithSnapshot) dir).getSnapshotDiffs() : null);
|
((INodeDirectoryWithSnapshot) dir).getDiffs(): null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the number of existing snapshots. */
|
/** @return the number of existing snapshots. */
|
||||||
|
@ -252,7 +252,7 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
+ "snapshot with the same name \"" + name + "\".");
|
+ "snapshot with the same name \"" + name + "\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
addSnapshotDiff(s, this, true);
|
getDiffs().addSnapshotDiff(s, this, true);
|
||||||
snapshotsByNames.add(-i - 1, s);
|
snapshotsByNames.add(-i - 1, s);
|
||||||
|
|
||||||
//set modification time
|
//set modification time
|
||||||
|
@ -264,7 +264,7 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the snapshot with the given name from {@link #snapshotsByNames},
|
* Remove the snapshot with the given name from {@link #snapshotsByNames},
|
||||||
* and delete all the corresponding SnapshotDiff.
|
* and delete all the corresponding DirectoryDiff.
|
||||||
*
|
*
|
||||||
* @param snapshotName The name of the snapshot to be removed
|
* @param snapshotName The name of the snapshot to be removed
|
||||||
* @param collectedBlocks Used to collect information to update blocksMap
|
* @param collectedBlocks Used to collect information to update blocksMap
|
||||||
|
@ -286,14 +286,14 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively delete SnapshotDiff associated with the given snapshot under a
|
* Recursively delete DirectoryDiff associated with the given snapshot under a
|
||||||
* directory
|
* directory
|
||||||
*/
|
*/
|
||||||
private void deleteDiffsForSnapshot(Snapshot snapshot, INodeDirectory dir,
|
private void deleteDiffsForSnapshot(Snapshot snapshot, INodeDirectory dir,
|
||||||
BlocksMapUpdateInfo collectedBlocks) {
|
BlocksMapUpdateInfo collectedBlocks) {
|
||||||
if (dir instanceof INodeDirectoryWithSnapshot) {
|
if (dir instanceof INodeDirectoryWithSnapshot) {
|
||||||
INodeDirectoryWithSnapshot sdir = (INodeDirectoryWithSnapshot) dir;
|
INodeDirectoryWithSnapshot sdir = (INodeDirectoryWithSnapshot) dir;
|
||||||
sdir.deleteSnapshotDiff(snapshot, collectedBlocks);
|
sdir.getDiffs().deleteSnapshotDiff(snapshot, collectedBlocks);
|
||||||
}
|
}
|
||||||
ReadOnlyList<INode> children = dir.getChildrenList(null);
|
ReadOnlyList<INode> children = dir.getChildrenList(null);
|
||||||
for (INode child : children) {
|
for (INode child : children) {
|
||||||
|
@ -401,7 +401,7 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
out.println();
|
out.println();
|
||||||
out.print(prefix);
|
out.print(prefix);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for(SnapshotDiff diff : getSnapshotDiffs()) {
|
for(DirectoryDiff diff : getDiffs()) {
|
||||||
if (diff.isSnapshotRoot()) {
|
if (diff.isSnapshotRoot()) {
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
@ -415,12 +415,12 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Pair<? extends INode, Snapshot>> iterator() {
|
public Iterator<Pair<? extends INode, Snapshot>> iterator() {
|
||||||
return new Iterator<Pair<? extends INode, Snapshot>>() {
|
return new Iterator<Pair<? extends INode, Snapshot>>() {
|
||||||
final Iterator<SnapshotDiff> i = getSnapshotDiffs().iterator();
|
final Iterator<DirectoryDiff> i = getDiffs().iterator();
|
||||||
private SnapshotDiff next = findNext();
|
private DirectoryDiff next = findNext();
|
||||||
|
|
||||||
private SnapshotDiff findNext() {
|
private DirectoryDiff findNext() {
|
||||||
for(; i.hasNext(); ) {
|
for(; i.hasNext(); ) {
|
||||||
final SnapshotDiff diff = i.next();
|
final DirectoryDiff diff = i.next();
|
||||||
if (diff.isSnapshotRoot()) {
|
if (diff.isSnapshotRoot()) {
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
* The difference between the current state and a previous snapshot
|
* The difference between the current state and a previous snapshot
|
||||||
* of the children list of an INodeDirectory.
|
* of the children list of an INodeDirectory.
|
||||||
*/
|
*/
|
||||||
public static class ChildrenDiff extends Diff<byte[], INode> {
|
static class ChildrenDiff extends Diff<byte[], INode> {
|
||||||
ChildrenDiff() {}
|
ChildrenDiff() {}
|
||||||
|
|
||||||
private ChildrenDiff(final List<INode> created, final List<INode> deleted) {
|
private ChildrenDiff(final List<INode> created, final List<INode> deleted) {
|
||||||
|
@ -173,100 +173,56 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The difference between two snapshots. {@link INodeDirectoryWithSnapshot}
|
* The difference of an {@link INodeDirectory} between two snapshots.
|
||||||
* maintains a list of snapshot diffs,
|
|
||||||
* <pre>
|
|
||||||
* d_1 -> d_2 -> ... -> d_n -> null,
|
|
||||||
* </pre>
|
|
||||||
* where -> denotes the {@link SnapshotDiff#posteriorDiff} reference. The
|
|
||||||
* current directory state is stored in the field of {@link INodeDirectory}.
|
|
||||||
* The snapshot state can be obtained by applying the diffs one-by-one in
|
|
||||||
* reversed chronological order. Let s_1, s_2, ..., s_n be the corresponding
|
|
||||||
* snapshots. Then,
|
|
||||||
* <pre>
|
|
||||||
* s_n = (current state) - d_n;
|
|
||||||
* s_{n-1} = s_n - d_{n-1} = (current state) - d_n - d_{n-1};
|
|
||||||
* ...
|
|
||||||
* s_k = s_{k+1} - d_k = (current state) - d_n - d_{n-1} - ... - d_k.
|
|
||||||
* </pre>
|
|
||||||
*/
|
*/
|
||||||
public class SnapshotDiff implements Comparable<Snapshot> {
|
class DirectoryDiff extends AbstractINodeDiff<INodeDirectory, DirectoryDiff> {
|
||||||
/** The snapshot will be obtained after this diff is applied. */
|
|
||||||
final Snapshot snapshot;
|
|
||||||
/** The size of the children list at snapshot creation time. */
|
/** The size of the children list at snapshot creation time. */
|
||||||
final int childrenSize;
|
private final int childrenSize;
|
||||||
/**
|
|
||||||
* Posterior diff is the diff happened after this diff.
|
|
||||||
* The posterior diff should be first applied to obtain the posterior
|
|
||||||
* snapshot and then apply this diff in order to obtain this snapshot.
|
|
||||||
* If the posterior diff is null, the posterior state is the current state.
|
|
||||||
*/
|
|
||||||
private SnapshotDiff posteriorDiff;
|
|
||||||
/** The children list diff. */
|
/** The children list diff. */
|
||||||
private final ChildrenDiff diff;
|
private final ChildrenDiff diff;
|
||||||
/** The snapshot inode data. It is null when there is no change. */
|
|
||||||
private INodeDirectory snapshotINode = null;
|
|
||||||
|
|
||||||
private SnapshotDiff(Snapshot snapshot, INodeDirectory dir) {
|
private DirectoryDiff(Snapshot snapshot, INodeDirectory dir) {
|
||||||
Preconditions.checkNotNull(snapshot, "snapshot is null");
|
super(snapshot, null, null);
|
||||||
|
|
||||||
this.snapshot = snapshot;
|
|
||||||
this.childrenSize = dir.getChildrenList(null).size();
|
this.childrenSize = dir.getChildrenList(null).size();
|
||||||
this.diff = new ChildrenDiff();
|
this.diff = new ChildrenDiff();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructor used by FSImage loading */
|
/** Constructor used by FSImage loading */
|
||||||
SnapshotDiff(Snapshot snapshot,
|
DirectoryDiff(Snapshot snapshot, INodeDirectory snapshotINode,
|
||||||
int childrenSize, INodeDirectory snapshotINode,
|
DirectoryDiff posteriorDiff, int childrenSize,
|
||||||
SnapshotDiff posteriorDiff, List<INode> createdList,
|
List<INode> createdList, List<INode> deletedList) {
|
||||||
List<INode> deletedList) {
|
super(snapshot, snapshotINode, posteriorDiff);
|
||||||
this.snapshot = snapshot;
|
|
||||||
this.childrenSize = childrenSize;
|
this.childrenSize = childrenSize;
|
||||||
this.snapshotINode = snapshotINode;
|
|
||||||
this.posteriorDiff = posteriorDiff;
|
|
||||||
this.diff = new ChildrenDiff(createdList, deletedList);
|
this.diff = new ChildrenDiff(createdList, deletedList);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChildrenDiff getDiff() {
|
ChildrenDiff getChildrenDiff() {
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compare diffs with snapshot ID. */
|
|
||||||
@Override
|
|
||||||
public int compareTo(final Snapshot that) {
|
|
||||||
return Snapshot.ID_COMPARATOR.compare(this.snapshot, that);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Is the inode the root of the snapshot? */
|
/** Is the inode the root of the snapshot? */
|
||||||
boolean isSnapshotRoot() {
|
boolean isSnapshotRoot() {
|
||||||
return snapshotINode == snapshot.getRoot();
|
return snapshotINode == snapshot.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy the INode state to the snapshot if it is not done already. */
|
@Override
|
||||||
private void checkAndInitINode(INodeDirectory snapshotCopy) {
|
INodeDirectory getCurrentINode() {
|
||||||
if (snapshotINode == null) {
|
return INodeDirectoryWithSnapshot.this;
|
||||||
if (snapshotCopy == null) {
|
|
||||||
snapshotCopy = new INodeDirectory(INodeDirectoryWithSnapshot.this,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
snapshotINode = snapshotCopy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the snapshot object of this diff. */
|
@Override
|
||||||
Snapshot getSnapshot() {
|
void combinePosteriorAndCollectBlocks(final DirectoryDiff posterior,
|
||||||
return snapshot;
|
final BlocksMapUpdateInfo collectedBlocks) {
|
||||||
}
|
diff.combinePosterior(posterior.diff, new Diff.Processor<INode>() {
|
||||||
|
/** Collect blocks for deleted files. */
|
||||||
private INodeDirectory getSnapshotINode() {
|
@Override
|
||||||
// get from this diff, then the posterior diff and then the current inode
|
public void process(INode inode) {
|
||||||
for(SnapshotDiff d = this; ; d = d.posteriorDiff) {
|
if (inode != null && inode instanceof INodeFile) {
|
||||||
if (d.snapshotINode != null) {
|
((INodeFile)inode).collectSubtreeBlocksAndClear(collectedBlocks);
|
||||||
return d.snapshotINode;
|
}
|
||||||
} else if (d.posteriorDiff == null) {
|
|
||||||
return INodeDirectoryWithSnapshot.this;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,11 +237,11 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
private List<INode> initChildren() {
|
private List<INode> initChildren() {
|
||||||
if (children == null) {
|
if (children == null) {
|
||||||
final ChildrenDiff combined = new ChildrenDiff();
|
final ChildrenDiff combined = new ChildrenDiff();
|
||||||
for(SnapshotDiff d = SnapshotDiff.this; d != null; d = d.posteriorDiff) {
|
for(DirectoryDiff d = DirectoryDiff.this; d != null; d = d.getPosterior()) {
|
||||||
combined.combinePosterior(d.diff, null);
|
combined.combinePosterior(d.diff, null);
|
||||||
}
|
}
|
||||||
children = combined.apply2Current(ReadOnlyList.Util.asList(
|
children = combined.apply2Current(ReadOnlyList.Util.asList(
|
||||||
INodeDirectoryWithSnapshot.this.getChildrenList(null)));
|
getCurrentINode().getChildrenList(null)));
|
||||||
}
|
}
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +270,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
|
|
||||||
/** @return the child with the given name. */
|
/** @return the child with the given name. */
|
||||||
INode getChild(byte[] name, boolean checkPosterior) {
|
INode getChild(byte[] name, boolean checkPosterior) {
|
||||||
for(SnapshotDiff d = this; ; d = d.posteriorDiff) {
|
for(DirectoryDiff d = this; ; d = d.getPosterior()) {
|
||||||
final Container<INode> returned = d.diff.accessPrevious(name);
|
final Container<INode> returned = d.diff.accessPrevious(name);
|
||||||
if (returned != null) {
|
if (returned != null) {
|
||||||
// the diff is able to determine the inode
|
// the diff is able to determine the inode
|
||||||
|
@ -322,17 +278,18 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
} else if (!checkPosterior) {
|
} else if (!checkPosterior) {
|
||||||
// Since checkPosterior is false, return null, i.e. not found.
|
// Since checkPosterior is false, return null, i.e. not found.
|
||||||
return null;
|
return null;
|
||||||
} else if (d.posteriorDiff == null) {
|
} else if (d.getPosterior() == null) {
|
||||||
// no more posterior diff, get from current inode.
|
// no more posterior diff, get from current inode.
|
||||||
return INodeDirectoryWithSnapshot.this.getChild(name, null);
|
return getCurrentINode().getChild(name, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
final DirectoryDiff posterior = getPosterior();
|
||||||
return "\n " + snapshot + " (-> "
|
return "\n " + snapshot + " (-> "
|
||||||
+ (posteriorDiff == null? null: posteriorDiff.snapshot)
|
+ (posterior == null? null: posterior.snapshot)
|
||||||
+ ") childrenSize=" + childrenSize + ", " + diff;
|
+ ") childrenSize=" + childrenSize + ", " + diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,9 +318,24 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
// Write diff. Node need to write poseriorDiff, since diffs is a list.
|
// Write diff. Node need to write poseriorDiff, since diffs is a list.
|
||||||
diff.write(out);
|
diff.write(out);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<INodeDirectory> getSnapshotDirectory() {
|
/** A list of directory diffs. */
|
||||||
return diff.getDirsInDeleted();
|
class DirectoryDiffList extends AbstractINodeDiffList<INodeDirectory, DirectoryDiff> {
|
||||||
|
@Override
|
||||||
|
INodeDirectoryWithSnapshot getCurrentINode() {
|
||||||
|
return INodeDirectoryWithSnapshot.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
DirectoryDiff addSnapshotDiff(Snapshot snapshot, INodeDirectory dir,
|
||||||
|
boolean isSnapshotCreation) {
|
||||||
|
final DirectoryDiff d = new DirectoryDiff(snapshot, dir);
|
||||||
|
if (isSnapshotCreation) {
|
||||||
|
//for snapshot creation, snapshotINode is the same as the snapshot root
|
||||||
|
d.snapshotINode = snapshot.getRoot();
|
||||||
|
}
|
||||||
|
return append(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +346,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
= new INodeDirectoryWithSnapshot(dir, true, null);
|
= new INodeDirectoryWithSnapshot(dir, true, null);
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
// add a diff for the latest snapshot
|
// add a diff for the latest snapshot
|
||||||
withSnapshot.addSnapshotDiff(latest, dir, false);
|
withSnapshot.diffs.addSnapshotDiff(latest, dir, false);
|
||||||
}
|
}
|
||||||
return withSnapshot;
|
return withSnapshot;
|
||||||
}
|
}
|
||||||
|
@ -402,15 +374,17 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
laterSnapshot = fromSnapshot;
|
laterSnapshot = fromSnapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
int earlierDiffIndex = Collections.binarySearch(diffs, earlierSnapshot);
|
final List<DirectoryDiff> difflist = diffs.asList();
|
||||||
if (earlierDiffIndex < 0 && (-earlierDiffIndex - 1) == diffs.size()) {
|
final int size = difflist.size();
|
||||||
|
int earlierDiffIndex = Collections.binarySearch(difflist, earlierSnapshot);
|
||||||
|
if (earlierDiffIndex < 0 && (-earlierDiffIndex - 1) == size) {
|
||||||
// if the earlierSnapshot is after the latest SnapshotDiff stored in diffs,
|
// if the earlierSnapshot is after the latest SnapshotDiff stored in diffs,
|
||||||
// no modification happened after the earlierSnapshot
|
// no modification happened after the earlierSnapshot
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int laterDiffIndex = diffs.size();
|
int laterDiffIndex = size;
|
||||||
if (laterSnapshot != null) {
|
if (laterSnapshot != null) {
|
||||||
laterDiffIndex = Collections.binarySearch(diffs, laterSnapshot);
|
laterDiffIndex = Collections.binarySearch(difflist, laterSnapshot);
|
||||||
if (laterDiffIndex == -1 || laterDiffIndex == 0) {
|
if (laterDiffIndex == -1 || laterDiffIndex == 0) {
|
||||||
// if the endSnapshot is the earliest SnapshotDiff stored in
|
// if the endSnapshot is the earliest SnapshotDiff stored in
|
||||||
// diffs, or before it, no modification happened before the endSnapshot
|
// diffs, or before it, no modification happened before the endSnapshot
|
||||||
|
@ -425,7 +399,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
boolean dirMetadataChanged = false;
|
boolean dirMetadataChanged = false;
|
||||||
INodeDirectory dirCopy = null;
|
INodeDirectory dirCopy = null;
|
||||||
for (int i = earlierDiffIndex; i < laterDiffIndex; i++) {
|
for (int i = earlierDiffIndex; i < laterDiffIndex; i++) {
|
||||||
SnapshotDiff sdiff = diffs.get(i);
|
DirectoryDiff sdiff = difflist.get(i);
|
||||||
diff.combinePosterior(sdiff.diff, null);
|
diff.combinePosterior(sdiff.diff, null);
|
||||||
if (dirMetadataChanged == false && sdiff.snapshotINode != null) {
|
if (dirMetadataChanged == false && sdiff.snapshotINode != null) {
|
||||||
if (dirCopy == null) {
|
if (dirCopy == null) {
|
||||||
|
@ -441,9 +415,8 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
if (!diff.isEmpty() || dirMetadataChanged) {
|
if (!diff.isEmpty() || dirMetadataChanged) {
|
||||||
return true;
|
return true;
|
||||||
} else if (dirCopy != null) {
|
} else if (dirCopy != null) {
|
||||||
for (int i = laterDiffIndex; i < diffs.size(); i++) {
|
for (int i = laterDiffIndex; i < size; i++) {
|
||||||
if (diffs.get(i).snapshotINode != null
|
if (!dirCopy.metadataEquals(difflist.get(i).snapshotINode)) {
|
||||||
&& !dirCopy.metadataEquals(diffs.get(i).snapshotINode)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,134 +426,28 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Diff list sorted by snapshot IDs, i.e. in chronological order. */
|
/** Diff list sorted by snapshot IDs, i.e. in chronological order. */
|
||||||
private final List<SnapshotDiff> diffs;
|
private final DirectoryDiffList diffs;
|
||||||
|
|
||||||
INodeDirectoryWithSnapshot(INodeDirectory that, boolean adopt,
|
INodeDirectoryWithSnapshot(INodeDirectory that, boolean adopt,
|
||||||
List<SnapshotDiff> diffs) {
|
DirectoryDiffList diffs) {
|
||||||
super(that, adopt, that.getNsQuota(), that.getDsQuota());
|
super(that, adopt, that.getNsQuota(), that.getDsQuota());
|
||||||
this.diffs = diffs != null? diffs: new ArrayList<SnapshotDiff>();
|
this.diffs = diffs != null? diffs: new DirectoryDiffList();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the snapshot with the given name. The synchronization of the diff
|
|
||||||
* list will be done outside.
|
|
||||||
*
|
|
||||||
* If the diff to remove is not the first one in the diff list, we need to
|
|
||||||
* combine the diff with its previous one:
|
|
||||||
*
|
|
||||||
* @param snapshot The snapshot to be deleted
|
|
||||||
* @param collectedBlocks Used to collect information for blocksMap update
|
|
||||||
* @return The SnapshotDiff containing the deleted snapshot.
|
|
||||||
* Null if the snapshot with the given name does not exist.
|
|
||||||
*/
|
|
||||||
SnapshotDiff deleteSnapshotDiff(Snapshot snapshot,
|
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
|
||||||
int snapshotIndex = Collections.binarySearch(diffs, snapshot);
|
|
||||||
if (snapshotIndex == -1) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
SnapshotDiff diffToRemove = null;
|
|
||||||
diffToRemove = diffs.remove(snapshotIndex);
|
|
||||||
if (snapshotIndex > 0) {
|
|
||||||
// combine the to-be-removed diff with its previous diff
|
|
||||||
SnapshotDiff previousDiff = diffs.get(snapshotIndex - 1);
|
|
||||||
previousDiff.diff.combinePosterior(diffToRemove.diff,
|
|
||||||
new Diff.Processor<INode>() {
|
|
||||||
/** Collect blocks for deleted files. */
|
|
||||||
@Override
|
|
||||||
public void process(INode inode) {
|
|
||||||
if (inode != null && inode instanceof INodeFile) {
|
|
||||||
((INodeFile)inode).collectSubtreeBlocksAndClear(collectedBlocks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
previousDiff.posteriorDiff = diffToRemove.posteriorDiff;
|
|
||||||
diffToRemove.posteriorDiff = null;
|
|
||||||
}
|
|
||||||
return diffToRemove;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Insert a SnapshotDiff to the head of diffs */
|
|
||||||
public void insertDiff(SnapshotDiff diff) {
|
|
||||||
diffs.add(0, diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a {@link SnapshotDiff} for the given snapshot and directory. */
|
|
||||||
SnapshotDiff addSnapshotDiff(Snapshot snapshot, INodeDirectory dir,
|
|
||||||
boolean isSnapshotCreation) {
|
|
||||||
final SnapshotDiff last = getLastSnapshotDiff();
|
|
||||||
final SnapshotDiff d = new SnapshotDiff(snapshot, dir);
|
|
||||||
|
|
||||||
if (isSnapshotCreation) {
|
|
||||||
//for snapshot creation, snapshotINode is the same as the snapshot root
|
|
||||||
d.snapshotINode = snapshot.getRoot();
|
|
||||||
}
|
|
||||||
diffs.add(d);
|
|
||||||
if (last != null) {
|
|
||||||
last.posteriorDiff = d;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
SnapshotDiff getLastSnapshotDiff() {
|
|
||||||
final int n = diffs.size();
|
|
||||||
return n == 0? null: diffs.get(n - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the last snapshot. */
|
/** @return the last snapshot. */
|
||||||
public Snapshot getLastSnapshot() {
|
public Snapshot getLastSnapshot() {
|
||||||
final SnapshotDiff last = getLastSnapshotDiff();
|
return diffs.getLastSnapshot();
|
||||||
return last == null? null: last.getSnapshot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return the snapshot diff list. */
|
||||||
* Check if the latest snapshot diff exists. If not, add it.
|
DirectoryDiffList getDiffs() {
|
||||||
* @return the latest snapshot diff, which is never null.
|
|
||||||
*/
|
|
||||||
private SnapshotDiff checkAndAddLatestSnapshotDiff(Snapshot latest) {
|
|
||||||
final SnapshotDiff last = getLastSnapshotDiff();
|
|
||||||
return last != null && last.snapshot.equals(latest)? last
|
|
||||||
: addSnapshotDiff(latest, this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the latest {@link ChildrenDiff} exists. If not, add it.
|
|
||||||
* @return the latest {@link ChildrenDiff}, which is never null.
|
|
||||||
*/
|
|
||||||
ChildrenDiff checkAndAddLatestDiff(Snapshot latest) {
|
|
||||||
return checkAndAddLatestSnapshotDiff(latest).diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@link #snapshots}
|
|
||||||
*/
|
|
||||||
List<SnapshotDiff> getSnapshotDiffs() {
|
|
||||||
return diffs;
|
return diffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @return the diff corresponding to the given snapshot.
|
public Pair<INodeDirectoryWithSnapshot, INodeDirectory> createSnapshotCopy() {
|
||||||
* When the diff is null, it means that the current state and
|
return new Pair<INodeDirectoryWithSnapshot, INodeDirectory>(this,
|
||||||
* the corresponding snapshot state are the same.
|
new INodeDirectory(this, false));
|
||||||
*/
|
|
||||||
SnapshotDiff getSnapshotDiff(Snapshot snapshot) {
|
|
||||||
if (snapshot == null) {
|
|
||||||
// snapshot == null means the current state, therefore, return null.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final int i = Collections.binarySearch(diffs, snapshot);
|
|
||||||
if (i >= 0) {
|
|
||||||
// exact match
|
|
||||||
return diffs.get(i);
|
|
||||||
} else {
|
|
||||||
// Exact match not found means that there were no changes between
|
|
||||||
// given snapshot and the next state so that the diff for the given
|
|
||||||
// snapshot was not recorded. Thus, return the next state.
|
|
||||||
final int j = -i - 1;
|
|
||||||
return j < diffs.size()? diffs.get(j): null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -592,7 +459,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
/** Save the snapshot copy to the latest snapshot. */
|
/** Save the snapshot copy to the latest snapshot. */
|
||||||
public void saveSelf2Snapshot(Snapshot latest, INodeDirectory snapshotCopy) {
|
public void saveSelf2Snapshot(Snapshot latest, INodeDirectory snapshotCopy) {
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
checkAndAddLatestSnapshotDiff(latest).checkAndInitINode(snapshotCopy);
|
diffs.checkAndAddLatestSnapshotDiff(latest).checkAndInitINode(snapshotCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +471,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
final SnapshotDiff diff = checkAndAddLatestSnapshotDiff(latest);
|
final DirectoryDiff diff = diffs.checkAndAddLatestSnapshotDiff(latest);
|
||||||
if (diff.getChild(child.getLocalNameBytes(), false) != null) {
|
if (diff.getChild(child.getLocalNameBytes(), false) != null) {
|
||||||
// it was already saved in the latest snapshot earlier.
|
// it was already saved in the latest snapshot earlier.
|
||||||
return child;
|
return child;
|
||||||
|
@ -629,7 +496,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
ChildrenDiff diff = null;
|
ChildrenDiff diff = null;
|
||||||
Integer undoInfo = null;
|
Integer undoInfo = null;
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
diff = checkAndAddLatestDiff(latest);
|
diff = diffs.checkAndAddLatestSnapshotDiff(latest).diff;
|
||||||
undoInfo = diff.create(inode);
|
undoInfo = diff.create(inode);
|
||||||
}
|
}
|
||||||
final boolean added = super.addChild(inode, setModTime, null);
|
final boolean added = super.addChild(inode, setModTime, null);
|
||||||
|
@ -644,7 +511,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
ChildrenDiff diff = null;
|
ChildrenDiff diff = null;
|
||||||
UndoInfo<INode> undoInfo = null;
|
UndoInfo<INode> undoInfo = null;
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
diff = checkAndAddLatestDiff(latest);
|
diff = diffs.checkAndAddLatestSnapshotDiff(latest).diff;
|
||||||
undoInfo = diff.delete(child);
|
undoInfo = diff.delete(child);
|
||||||
}
|
}
|
||||||
final INode removed = super.removeChild(child, null);
|
final INode removed = super.removeChild(child, null);
|
||||||
|
@ -665,54 +532,54 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReadOnlyList<INode> getChildrenList(Snapshot snapshot) {
|
public ReadOnlyList<INode> getChildrenList(Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getChildrenList(): super.getChildrenList(null);
|
return diff != null? diff.getChildrenList(): super.getChildrenList(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INode getChild(byte[] name, Snapshot snapshot) {
|
public INode getChild(byte[] name, Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getChild(name, true): super.getChild(name, null);
|
return diff != null? diff.getChild(name, true): super.getChild(name, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUserName(Snapshot snapshot) {
|
public String getUserName(Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getSnapshotINode().getUserName()
|
return diff != null? diff.getSnapshotINode().getUserName()
|
||||||
: super.getUserName(null);
|
: super.getUserName(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getGroupName(Snapshot snapshot) {
|
public String getGroupName(Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getSnapshotINode().getGroupName()
|
return diff != null? diff.getSnapshotINode().getGroupName()
|
||||||
: super.getGroupName(null);
|
: super.getGroupName(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FsPermission getFsPermission(Snapshot snapshot) {
|
public FsPermission getFsPermission(Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getSnapshotINode().getFsPermission()
|
return diff != null? diff.getSnapshotINode().getFsPermission()
|
||||||
: super.getFsPermission(null);
|
: super.getFsPermission(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getAccessTime(Snapshot snapshot) {
|
public long getAccessTime(Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getSnapshotINode().getAccessTime()
|
return diff != null? diff.getSnapshotINode().getAccessTime()
|
||||||
: super.getAccessTime(null);
|
: super.getAccessTime(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getModificationTime(Snapshot snapshot) {
|
public long getModificationTime(Snapshot snapshot) {
|
||||||
final SnapshotDiff diff = getSnapshotDiff(snapshot);
|
final DirectoryDiff diff = diffs.getDiff(snapshot);
|
||||||
return diff != null? diff.getSnapshotINode().getModificationTime()
|
return diff != null? diff.getSnapshotINode().getModificationTime()
|
||||||
: super.getModificationTime(null);
|
: super.getModificationTime(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + ", diffs=" + getSnapshotDiffs();
|
return super.toString() + ", " + diffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -726,8 +593,8 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
public int getSnapshotDirectory(
|
public int getSnapshotDirectory(
|
||||||
Map<Snapshot, List<INodeDirectory>> snapshotDirMap) {
|
Map<Snapshot, List<INodeDirectory>> snapshotDirMap) {
|
||||||
int dirNum = 0;
|
int dirNum = 0;
|
||||||
for (SnapshotDiff sdiff : diffs) {
|
for (DirectoryDiff sdiff : diffs) {
|
||||||
List<INodeDirectory> list = sdiff.getSnapshotDirectory();
|
List<INodeDirectory> list = sdiff.getChildrenDiff().getDirsInDeleted();
|
||||||
if (list.size() > 0) {
|
if (list.size() > 0) {
|
||||||
snapshotDirMap.put(sdiff.snapshot, list);
|
snapshotDirMap.put(sdiff.snapshot, list);
|
||||||
dirNum += list.size();
|
dirNum += list.size();
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectoryWithSnapshot.ChildrenDiff;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectoryWithSnapshot.ChildrenDiff;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectoryWithSnapshot.SnapshotDiff;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectoryWithSnapshot.DirectoryDiff;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot.Root;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot.Root;
|
||||||
import org.apache.hadoop.hdfs.util.ReadOnlyList;
|
import org.apache.hadoop.hdfs.util.ReadOnlyList;
|
||||||
|
|
||||||
|
@ -70,13 +70,13 @@ public class SnapshotFSImageFormat {
|
||||||
public static void saveSnapshotDiffs(INodeDirectoryWithSnapshot sNode,
|
public static void saveSnapshotDiffs(INodeDirectoryWithSnapshot sNode,
|
||||||
DataOutputStream out) throws IOException {
|
DataOutputStream out) throws IOException {
|
||||||
// # of SnapshotDiff
|
// # of SnapshotDiff
|
||||||
List<SnapshotDiff> diffs = sNode.getSnapshotDiffs();
|
List<DirectoryDiff> diffs = sNode.getDiffs().asList();
|
||||||
// Record the SnapshotDiff in reversed order, so that we can find the
|
// Record the SnapshotDiff in reversed order, so that we can find the
|
||||||
// correct reference for INodes in the created list when loading the
|
// correct reference for INodes in the created list when loading the
|
||||||
// FSImage
|
// FSImage
|
||||||
out.writeInt(diffs.size());
|
out.writeInt(diffs.size());
|
||||||
for (int i = diffs.size() - 1; i >= 0; i--) {
|
for (int i = diffs.size() - 1; i >= 0; i--) {
|
||||||
SnapshotDiff sdiff = diffs.get(i);
|
DirectoryDiff sdiff = diffs.get(i);
|
||||||
sdiff.write(out);
|
sdiff.write(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,8 +91,8 @@ public class SnapshotFSImageFormat {
|
||||||
INodeDirectoryWithSnapshot parent) throws IOException {
|
INodeDirectoryWithSnapshot parent) throws IOException {
|
||||||
// the INode in the created list should be a reference to another INode
|
// the INode in the created list should be a reference to another INode
|
||||||
// in posterior SnapshotDiffs or one of the current children
|
// in posterior SnapshotDiffs or one of the current children
|
||||||
for (SnapshotDiff postDiff : parent.getSnapshotDiffs()) {
|
for (DirectoryDiff postDiff : parent.getDiffs()) {
|
||||||
INode created = findCreated(createdNodeName, postDiff.getDiff());
|
INode created = findCreated(createdNodeName, postDiff.getChildrenDiff());
|
||||||
if (created != null) {
|
if (created != null) {
|
||||||
return created;
|
return created;
|
||||||
} // else go to the next SnapshotDiff
|
} // else go to the next SnapshotDiff
|
||||||
|
@ -266,8 +266,8 @@ public class SnapshotFSImageFormat {
|
||||||
DataInputStream in, FSImageFormat.Loader loader)
|
DataInputStream in, FSImageFormat.Loader loader)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
for (int i = 0; i < numSnapshotDiffs; i++) {
|
for (int i = 0; i < numSnapshotDiffs; i++) {
|
||||||
SnapshotDiff diff = loadSnapshotDiff(parentWithSnapshot, in, loader);
|
DirectoryDiff diff = loadSnapshotDiff(parentWithSnapshot, in, loader);
|
||||||
parentWithSnapshot.insertDiff(diff);
|
parentWithSnapshot.getDiffs().insert(diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +321,7 @@ public class SnapshotFSImageFormat {
|
||||||
* using.
|
* using.
|
||||||
* @return A {@link SnapshotDiff}.
|
* @return A {@link SnapshotDiff}.
|
||||||
*/
|
*/
|
||||||
private static SnapshotDiff loadSnapshotDiff(
|
private static DirectoryDiff loadSnapshotDiff(
|
||||||
INodeDirectoryWithSnapshot parent, DataInputStream in,
|
INodeDirectoryWithSnapshot parent, DataInputStream in,
|
||||||
FSImageFormat.Loader loader) throws IOException {
|
FSImageFormat.Loader loader) throws IOException {
|
||||||
// 1. Load SnapshotDiff#childrenSize
|
// 1. Load SnapshotDiff#childrenSize
|
||||||
|
@ -342,9 +342,10 @@ public class SnapshotFSImageFormat {
|
||||||
List<INode> deletedList = loadDeletedList(parent, createdList, in, loader);
|
List<INode> deletedList = loadDeletedList(parent, createdList, in, loader);
|
||||||
|
|
||||||
// 6. Compose the SnapshotDiff
|
// 6. Compose the SnapshotDiff
|
||||||
SnapshotDiff sdiff = parent.new SnapshotDiff(snapshot, childrenSize,
|
List<DirectoryDiff> diffs = parent.getDiffs().asList();
|
||||||
snapshotINode, parent.getSnapshotDiffs().isEmpty() ? null : parent
|
DirectoryDiff sdiff = parent.new DirectoryDiff(snapshot, snapshotINode,
|
||||||
.getSnapshotDiffs().get(0), createdList, deletedList);
|
diffs.isEmpty() ? null : diffs.get(0),
|
||||||
|
childrenSize, createdList, deletedList);
|
||||||
return sdiff;
|
return sdiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -451,23 +451,10 @@ public class Diff<K, E extends Diff.Element<K>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert the element list to a compact string. */
|
|
||||||
static <E> String toString(List<E> elements) {
|
|
||||||
if (elements == null || elements.isEmpty()) {
|
|
||||||
return "<empty>";
|
|
||||||
}
|
|
||||||
final StringBuilder b = new StringBuilder("[")
|
|
||||||
.append(elements.get(0));
|
|
||||||
for(int i = 1; i < elements.size(); i++) {
|
|
||||||
b.append(", ").append(elements.get(i));
|
|
||||||
}
|
|
||||||
return b.append("]").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName()
|
return getClass().getSimpleName()
|
||||||
+ "{created=" + toString(created)
|
+ "{created=" + getCreatedList()
|
||||||
+ ", deleted=" + toString(deleted) + "}";
|
+ ", deleted=" + getDeletedList() + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ public class TestINodeFileUnderConstructionWithSnapshot {
|
||||||
INodeFile fileNode = (INodeFile) fsdir.getINode(file.toString());
|
INodeFile fileNode = (INodeFile) fsdir.getINode(file.toString());
|
||||||
INodeDirectorySnapshottable dirNode = (INodeDirectorySnapshottable) fsdir
|
INodeDirectorySnapshottable dirNode = (INodeDirectorySnapshottable) fsdir
|
||||||
.getINode(dir.toString());
|
.getINode(dir.toString());
|
||||||
ChildrenDiff diff = dirNode.getLastSnapshotDiff().getDiff();
|
ChildrenDiff diff = dirNode.getDiffs().getLast().getChildrenDiff();
|
||||||
INode nodeInCreated = diff.searchCreated(fileNode.getLocalNameBytes());
|
INode nodeInCreated = diff.searchCreated(fileNode.getLocalNameBytes());
|
||||||
assertTrue(fileNode == nodeInCreated);
|
assertTrue(fileNode == nodeInCreated);
|
||||||
INode nodeInDeleted = diff.searchDeleted(fileNode.getLocalNameBytes());
|
INode nodeInDeleted = diff.searchDeleted(fileNode.getLocalNameBytes());
|
||||||
|
@ -120,7 +120,7 @@ public class TestINodeFileUnderConstructionWithSnapshot {
|
||||||
DFSTestUtil.appendFile(hdfs, file, BLOCKSIZE);
|
DFSTestUtil.appendFile(hdfs, file, BLOCKSIZE);
|
||||||
|
|
||||||
// check the circular list and corresponding inodes
|
// check the circular list and corresponding inodes
|
||||||
diff = dirNode.getLastSnapshotDiff().getDiff();
|
diff = dirNode.getDiffs().getLast().getChildrenDiff();
|
||||||
fileNode = (INodeFile) fsdir.getINode(file.toString());
|
fileNode = (INodeFile) fsdir.getINode(file.toString());
|
||||||
nodeInCreated = diff.searchCreated(fileNode.getLocalNameBytes());
|
nodeInCreated = diff.searchCreated(fileNode.getLocalNameBytes());
|
||||||
assertTrue(fileNode == nodeInCreated);
|
assertTrue(fileNode == nodeInCreated);
|
||||||
|
@ -140,7 +140,7 @@ public class TestINodeFileUnderConstructionWithSnapshot {
|
||||||
DFSTestUtil.appendFile(hdfs, file, BLOCKSIZE);
|
DFSTestUtil.appendFile(hdfs, file, BLOCKSIZE);
|
||||||
|
|
||||||
// check the circular list and corresponding inodes
|
// check the circular list and corresponding inodes
|
||||||
diff = dirNode.getLastSnapshotDiff().getDiff();
|
diff = dirNode.getDiffs().getLast().getChildrenDiff();
|
||||||
fileNode = (INodeFile) fsdir.getINode(file.toString());
|
fileNode = (INodeFile) fsdir.getINode(file.toString());
|
||||||
nodeInCreated = diff.searchCreated(fileNode.getLocalNameBytes());
|
nodeInCreated = diff.searchCreated(fileNode.getLocalNameBytes());
|
||||||
assertTrue(fileNode == nodeInCreated);
|
assertTrue(fileNode == nodeInCreated);
|
||||||
|
@ -187,7 +187,7 @@ public class TestINodeFileUnderConstructionWithSnapshot {
|
||||||
assertEquals(BLOCKSIZE * 2, ((INodeFile) fileNode).computeFileSize(true));
|
assertEquals(BLOCKSIZE * 2, ((INodeFile) fileNode).computeFileSize(true));
|
||||||
INodeDirectorySnapshottable dirNode = (INodeDirectorySnapshottable) fsdir
|
INodeDirectorySnapshottable dirNode = (INodeDirectorySnapshottable) fsdir
|
||||||
.getINode(dir.toString());
|
.getINode(dir.toString());
|
||||||
ChildrenDiff diff = dirNode.getLastSnapshotDiff().getDiff();
|
ChildrenDiff diff = dirNode.getDiffs().getLast().getChildrenDiff();
|
||||||
INode nodeInDeleted_S0 = diff.searchDeleted(fileNode.getLocalNameBytes());
|
INode nodeInDeleted_S0 = diff.searchDeleted(fileNode.getLocalNameBytes());
|
||||||
assertTrue(nodeInDeleted_S0 instanceof INodeFileUnderConstructionSnapshot);
|
assertTrue(nodeInDeleted_S0 instanceof INodeFileUnderConstructionSnapshot);
|
||||||
assertEquals(BLOCKSIZE * 2,
|
assertEquals(BLOCKSIZE * 2,
|
||||||
|
@ -199,7 +199,7 @@ public class TestINodeFileUnderConstructionWithSnapshot {
|
||||||
|
|
||||||
// re-check nodeInDeleted_S0
|
// re-check nodeInDeleted_S0
|
||||||
dirNode = (INodeDirectorySnapshottable) fsdir.getINode(dir.toString());
|
dirNode = (INodeDirectorySnapshottable) fsdir.getINode(dir.toString());
|
||||||
diff = dirNode.getLastSnapshotDiff().getDiff();
|
diff = dirNode.getDiffs().getLast().getChildrenDiff();
|
||||||
nodeInDeleted_S0 = diff.searchDeleted(fileNode.getLocalNameBytes());
|
nodeInDeleted_S0 = diff.searchDeleted(fileNode.getLocalNameBytes());
|
||||||
assertTrue(nodeInDeleted_S0 instanceof INodeFileUnderConstructionSnapshot);
|
assertTrue(nodeInDeleted_S0 instanceof INodeFileUnderConstructionSnapshot);
|
||||||
assertEquals(BLOCKSIZE * 2,
|
assertEquals(BLOCKSIZE * 2,
|
||||||
|
@ -213,7 +213,7 @@ public class TestINodeFileUnderConstructionWithSnapshot {
|
||||||
// have been stored in s1's deleted list
|
// have been stored in s1's deleted list
|
||||||
fileNode = (INodeFile) fsdir.getINode(file.toString());
|
fileNode = (INodeFile) fsdir.getINode(file.toString());
|
||||||
dirNode = (INodeDirectorySnapshottable) fsdir.getINode(dir.toString());
|
dirNode = (INodeDirectorySnapshottable) fsdir.getINode(dir.toString());
|
||||||
diff = dirNode.getLastSnapshotDiff().getDiff();
|
diff = dirNode.getDiffs().getLast().getChildrenDiff();
|
||||||
INode nodeInCreated_S1 = diff.searchCreated(fileNode.getLocalNameBytes());
|
INode nodeInCreated_S1 = diff.searchCreated(fileNode.getLocalNameBytes());
|
||||||
assertTrue(fileNode == nodeInCreated_S1);
|
assertTrue(fileNode == nodeInCreated_S1);
|
||||||
assertTrue(fileNode instanceof INodeFileWithSnapshot);
|
assertTrue(fileNode instanceof INodeFileWithSnapshot);
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
|
import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectoryWithSnapshot.SnapshotDiff;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectoryWithSnapshot.DirectoryDiff;
|
||||||
import org.apache.hadoop.hdfs.util.ReadOnlyList;
|
import org.apache.hadoop.hdfs.util.ReadOnlyList;
|
||||||
import org.apache.hadoop.ipc.RemoteException;
|
import org.apache.hadoop.ipc.RemoteException;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -91,7 +91,7 @@ public class TestSnapshotRename {
|
||||||
for (int i = 0; i < listByName.size(); i++) {
|
for (int i = 0; i < listByName.size(); i++) {
|
||||||
assertEquals(sortedNames[i], listByName.get(i).getRoot().getLocalName());
|
assertEquals(sortedNames[i], listByName.get(i).getRoot().getLocalName());
|
||||||
}
|
}
|
||||||
List<SnapshotDiff> listByTime = srcRoot.getSnapshotDiffs();
|
List<DirectoryDiff> listByTime = srcRoot.getDiffs().asList();
|
||||||
assertEquals(names.length, listByTime.size());
|
assertEquals(names.length, listByTime.size());
|
||||||
for (int i = 0; i < listByTime.size(); i++) {
|
for (int i = 0; i < listByTime.size(); i++) {
|
||||||
assertEquals(names[i], listByTime.get(i).getSnapshot().getRoot().getLocalName());
|
assertEquals(names[i], listByTime.get(i).getSnapshot().getRoot().getLocalName());
|
||||||
|
|
|
@ -124,10 +124,10 @@ public class TestDiff {
|
||||||
c = diffs.get(i).apply2Previous(c);
|
c = diffs.get(i).apply2Previous(c);
|
||||||
}
|
}
|
||||||
if (!hasIdenticalElements(current, c)) {
|
if (!hasIdenticalElements(current, c)) {
|
||||||
System.out.println("previous = " + Diff.toString(previous));
|
System.out.println("previous = " + previous);
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("current = " + Diff.toString(current));
|
System.out.println("current = " + current);
|
||||||
System.out.println("c = " + Diff.toString(c));
|
System.out.println("c = " + c);
|
||||||
throw new AssertionError("current and c are not identical.");
|
throw new AssertionError("current and c are not identical.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,10 +137,10 @@ public class TestDiff {
|
||||||
p = diffs.get(i).apply2Current(p);
|
p = diffs.get(i).apply2Current(p);
|
||||||
}
|
}
|
||||||
if (!hasIdenticalElements(previous, p)) {
|
if (!hasIdenticalElements(previous, p)) {
|
||||||
System.out.println("previous = " + Diff.toString(previous));
|
System.out.println("previous = " + previous);
|
||||||
System.out.println("p = " + Diff.toString(p));
|
System.out.println("p = " + p);
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("current = " + Diff.toString(current));
|
System.out.println("current = " + current);
|
||||||
throw new AssertionError("previous and p are not identical.");
|
throw new AssertionError("previous and p are not identical.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,20 +155,20 @@ public class TestDiff {
|
||||||
// check if current == previous + combined
|
// check if current == previous + combined
|
||||||
final List<INode> c = combined.apply2Previous(previous);
|
final List<INode> c = combined.apply2Previous(previous);
|
||||||
if (!hasIdenticalElements(current, c)) {
|
if (!hasIdenticalElements(current, c)) {
|
||||||
System.out.println("previous = " + Diff.toString(previous));
|
System.out.println("previous = " + previous);
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("current = " + Diff.toString(current));
|
System.out.println("current = " + current);
|
||||||
System.out.println("c = " + Diff.toString(c));
|
System.out.println("c = " + c);
|
||||||
throw new AssertionError("current and c are not identical.");
|
throw new AssertionError("current and c are not identical.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if previous == current - combined
|
// check if previous == current - combined
|
||||||
final List<INode> p = combined.apply2Current(current);
|
final List<INode> p = combined.apply2Current(current);
|
||||||
if (!hasIdenticalElements(previous, p)) {
|
if (!hasIdenticalElements(previous, p)) {
|
||||||
System.out.println("previous = " + Diff.toString(previous));
|
System.out.println("previous = " + previous);
|
||||||
System.out.println("p = " + Diff.toString(p));
|
System.out.println("p = " + p);
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("current = " + Diff.toString(current));
|
System.out.println("current = " + current);
|
||||||
throw new AssertionError("previous and p are not identical.");
|
throw new AssertionError("previous and p are not identical.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,10 +228,6 @@ public class TestDiff {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String toString(Diff<byte[], INode> diff) {
|
|
||||||
return diff.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String toString(INode inode) {
|
static String toString(INode inode) {
|
||||||
return inode == null? null
|
return inode == null? null
|
||||||
: inode.getLocalName() + ":" + inode.getModificationTime();
|
: inode.getLocalName() + ":" + inode.getModificationTime();
|
||||||
|
@ -256,13 +252,13 @@ public class TestDiff {
|
||||||
final boolean testUndo = RANDOM.nextInt(UNDO_TEST_P) == 0;
|
final boolean testUndo = RANDOM.nextInt(UNDO_TEST_P) == 0;
|
||||||
String before = null;
|
String before = null;
|
||||||
if (testUndo) {
|
if (testUndo) {
|
||||||
before = toString(diff);
|
before = diff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
final int undoInfo = diff.create(inode);
|
final int undoInfo = diff.create(inode);
|
||||||
|
|
||||||
if (testUndo) {
|
if (testUndo) {
|
||||||
final String after = toString(diff);
|
final String after = diff.toString();
|
||||||
//undo
|
//undo
|
||||||
diff.undoCreate(inode, undoInfo);
|
diff.undoCreate(inode, undoInfo);
|
||||||
assertDiff(before, diff);
|
assertDiff(before, diff);
|
||||||
|
@ -281,13 +277,13 @@ public class TestDiff {
|
||||||
final boolean testUndo = RANDOM.nextInt(UNDO_TEST_P) == 0;
|
final boolean testUndo = RANDOM.nextInt(UNDO_TEST_P) == 0;
|
||||||
String before = null;
|
String before = null;
|
||||||
if (testUndo) {
|
if (testUndo) {
|
||||||
before = toString(diff);
|
before = diff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
final UndoInfo<INode> undoInfo = diff.delete(inode);
|
final UndoInfo<INode> undoInfo = diff.delete(inode);
|
||||||
|
|
||||||
if (testUndo) {
|
if (testUndo) {
|
||||||
final String after = toString(diff);
|
final String after = diff.toString();
|
||||||
//undo
|
//undo
|
||||||
diff.undoDelete(inode, undoInfo);
|
diff.undoDelete(inode, undoInfo);
|
||||||
assertDiff(before, diff);
|
assertDiff(before, diff);
|
||||||
|
@ -311,13 +307,13 @@ public class TestDiff {
|
||||||
final boolean testUndo = RANDOM.nextInt(UNDO_TEST_P) == 0;
|
final boolean testUndo = RANDOM.nextInt(UNDO_TEST_P) == 0;
|
||||||
String before = null;
|
String before = null;
|
||||||
if (testUndo) {
|
if (testUndo) {
|
||||||
before = toString(diff);
|
before = diff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
final UndoInfo<INode> undoInfo = diff.modify(oldinode, newinode);
|
final UndoInfo<INode> undoInfo = diff.modify(oldinode, newinode);
|
||||||
|
|
||||||
if (testUndo) {
|
if (testUndo) {
|
||||||
final String after = toString(diff);
|
final String after = diff.toString();
|
||||||
//undo
|
//undo
|
||||||
diff.undoModify(oldinode, newinode, undoInfo);
|
diff.undoModify(oldinode, newinode, undoInfo);
|
||||||
assertDiff(before, diff);
|
assertDiff(before, diff);
|
||||||
|
@ -329,6 +325,6 @@ public class TestDiff {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assertDiff(String s, Diff<byte[], INode> diff) {
|
static void assertDiff(String s, Diff<byte[], INode> diff) {
|
||||||
Assert.assertEquals(s, toString(diff));
|
Assert.assertEquals(s, diff.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue