| /** |
| * 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 java.util.List; |
| |
| import org.apache.hadoop.hdfs.server.namenode.INode; |
| import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo; |
| import org.apache.hadoop.hdfs.server.namenode.Quota; |
| import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotFSImageFormat.ReferenceMap; |
| |
| import 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, |
| D extends AbstractINodeDiff<N, D>> |
| implements Comparable<Integer> { |
| |
| /** The snapshot will be obtained after this diff is applied. */ |
| 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 Integer that) { |
| return Snapshot.ID_INTEGER_COMPARATOR.compare(this.snapshot.getId(), that); |
| } |
| |
| /** @return the snapshot object of this diff. */ |
| public final Snapshot getSnapshot() { |
| return snapshot; |
| } |
| |
| final void setSnapshot(Snapshot snapshot) { |
| this.snapshot = snapshot; |
| } |
| |
| /** @return the posterior diff. */ |
| final D getPosterior() { |
| return posteriorDiff; |
| } |
| |
| /** @return the posterior diff. */ |
| final void setPosterior(D posterior) { |
| posteriorDiff = posterior; |
| } |
| |
| /** Save the INode state to the snapshot if it is not done already. */ |
| void saveSnapshotCopy(N snapshotCopy, N currentINode) { |
| Preconditions.checkState(snapshotINode == null, "Expected snapshotINode to be null"); |
| snapshotINode = snapshotCopy; |
| } |
| |
| /** @return the inode corresponding to the snapshot. */ |
| N getSnapshotINode() { |
| // get from this diff, then the posterior diff |
| // and then null for 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 null; |
| } |
| } |
| } |
| |
| /** Combine the posterior diff and collect blocks for deletion. */ |
| abstract Quota.Counts combinePosteriorAndCollectBlocks(final N currentINode, |
| final D posterior, final BlocksMapUpdateInfo collectedBlocks, |
| final List<INode> removedINodes); |
| |
| /** |
| * Delete and clear self. |
| * @param currentINode The inode where the deletion happens. |
| * @param collectedBlocks Used to collect blocks for deletion. |
| * @return quota usage delta |
| */ |
| abstract Quota.Counts destroyDiffAndCollectBlocks(final N currentINode, |
| final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes); |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + ": " + snapshot + " (post=" |
| + (posteriorDiff == null? null: posteriorDiff.snapshot) + ")"; |
| } |
| |
| void writeSnapshot(DataOutput out) throws IOException { |
| // Assume the snapshot is recorded before, write id only. |
| out.writeInt(snapshot.getId()); |
| } |
| |
| abstract void write(DataOutput out, ReferenceMap referenceMap |
| ) throws IOException; |
| } |