blob: df052f171afa8284e13bdc190b3c4a970c3edb20 [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.server.namenode.snapshot;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INodeAttributes;
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotFSImageFormat.ReferenceMap;
import org.apache.hadoop.thirdparty.com.google.common.base.Preconditions;
/**
* The difference of an inode between in two snapshots.
* {@link AbstractINodeDiffList} 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,
A extends INodeAttributes,
D extends AbstractINodeDiff<N, A, D>>
implements Comparable<Integer> {
/** The id of the corresponding snapshot. */
private int snapshotId;
/** The snapshot inode data. It is null when there is no change. */
A 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(int snapshotId, A snapshotINode, D posteriorDiff) {
this.snapshotId = snapshotId;
this.snapshotINode = snapshotINode;
this.posteriorDiff = posteriorDiff;
}
/** Compare diffs with snapshot ID. */
@Override
public final int compareTo(final Integer that) {
return Snapshot.ID_INTEGER_COMPARATOR.compare(this.snapshotId, that);
}
/** @return the snapshot object of this diff. */
public final int getSnapshotId() {
return snapshotId;
}
final void setSnapshotId(int snapshot) {
this.snapshotId = snapshot;
}
/** @return the posterior diff. */
final D getPosterior() {
return posteriorDiff;
}
final void setPosterior(D posterior) {
posteriorDiff = posterior;
}
/** Save the INode state to the snapshot if it is not done already. */
void saveSnapshotCopy(A snapshotCopy) {
Preconditions.checkState(snapshotINode == null, "Expected snapshotINode to be null");
snapshotINode = snapshotCopy;
}
/** @return the inode corresponding to the snapshot. */
A getSnapshotINode() {
// get from this diff, then the posterior diff
// and then null for the current inode
for(AbstractINodeDiff<N, A, D> d = this; ; d = d.posteriorDiff) {
if (d.snapshotINode != null) {
return d.snapshotINode;
} else if (d.posteriorDiff == null) {
return null;
}
}
}
/** Combine the posterior diff and collect blocks for deletion. */
abstract void combinePosteriorAndCollectBlocks(
INode.ReclaimContext reclaimContext, final N currentINode,
final D posterior);
/**
* Delete and clear self.
* @param reclaimContext blocks and inodes that need to be reclaimed
* @param currentINode The inode where the deletion happens.
*/
abstract void destroyDiffAndCollectBlocks(INode.ReclaimContext reclaimContext,
final N currentINode);
@Override
public String toString() {
return getClass().getSimpleName() + ": " + this.getSnapshotId() + " (post="
+ (posteriorDiff == null? null: posteriorDiff.getSnapshotId()) + ")";
}
void writeSnapshot(DataOutput out) throws IOException {
out.writeInt(snapshotId);
}
abstract void write(DataOutput out, ReferenceMap referenceMap
) throws IOException;
}