/// <summary>Delete a snapshot.</summary> /// <remarks> /// Delete a snapshot. 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. /// </remarks> /// <param name="snapshot">The id of the snapshot to be deleted</param> /// <param name="prior">The id of the snapshot taken before the to-be-deleted snapshot /// </param> /// <param name="collectedBlocks">Used to collect information for blocksMap update</param> /// <returns>delta in namespace.</returns> public QuotaCounts DeleteSnapshotDiff(BlockStoragePolicySuite bsps, int snapshot, int prior, N currentINode, INode.BlocksMapUpdateInfo collectedBlocks, IList <INode > removedINodes) { int snapshotIndex = Sharpen.Collections.BinarySearch(diffs, snapshot); QuotaCounts counts = new QuotaCounts.Builder().Build(); D removed = null; if (snapshotIndex == 0) { if (prior != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.NoSnapshotId) { // there is still snapshot before // set the snapshot to latestBefore diffs[snapshotIndex].SetSnapshotId(prior); } else { // there is no snapshot before removed = diffs.Remove(0); counts.Add(removed.DestroyDiffAndCollectBlocks(bsps, currentINode, collectedBlocks , removedINodes)); } } else { if (snapshotIndex > 0) { AbstractINodeDiff <N, A, D> previous = diffs[snapshotIndex - 1]; if (previous.GetSnapshotId() != prior) { diffs[snapshotIndex].SetSnapshotId(prior); } else { // combine the to-be-removed diff with its previous diff removed = diffs.Remove(snapshotIndex); if (previous.snapshotINode == null) { previous.snapshotINode = removed.snapshotINode; } counts.Add(previous.CombinePosteriorAndCollectBlocks(bsps, currentINode, removed, collectedBlocks, removedINodes)); previous.SetPosterior(removed.GetPosterior()); removed.SetPosterior(null); } } } return(counts); }
internal override QuotaCounts DestroyDiffAndCollectBlocks(BlockStoragePolicySuite bsps, INodeDirectory currentINode, INode.BlocksMapUpdateInfo collectedBlocks, IList <INode> removedINodes) { // this diff has been deleted QuotaCounts counts = new QuotaCounts.Builder().Build(); counts.Add(diff.DestroyDeletedList(bsps, collectedBlocks, removedINodes)); INodeDirectoryAttributes snapshotINode = GetSnapshotINode(); if (snapshotINode != null && snapshotINode.GetAclFeature() != null) { AclStorage.RemoveAclFeature(snapshotINode.GetAclFeature()); } return(counts); }
public virtual QuotaCounts CleanDirectory(BlockStoragePolicySuite bsps, INodeDirectory currentINode, int snapshot, int prior, INode.BlocksMapUpdateInfo collectedBlocks , IList <INode> removedINodes) { QuotaCounts counts = new QuotaCounts.Builder().Build(); IDictionary <INode, INode> priorCreated = null; IDictionary <INode, INode> priorDeleted = null; if (snapshot == Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.CurrentStateId) { // delete the current directory currentINode.RecordModification(prior); // delete everything in created list DirectoryWithSnapshotFeature.DirectoryDiff lastDiff = diffs.GetLast(); if (lastDiff != null) { counts.Add(lastDiff.diff.DestroyCreatedList(bsps, currentINode, collectedBlocks, removedINodes)); } counts.Add(currentINode.CleanSubtreeRecursively(bsps, snapshot, prior, collectedBlocks , removedINodes, priorDeleted)); } else { // update prior prior = GetDiffs().UpdatePrior(snapshot, prior); // if there is a snapshot diff associated with prior, we need to record // its original created and deleted list before deleting post if (prior != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.NoSnapshotId) { DirectoryWithSnapshotFeature.DirectoryDiff priorDiff = this.GetDiffs().GetDiffById (prior); if (priorDiff != null && priorDiff.GetSnapshotId() == prior) { IList <INode> cList = priorDiff.diff.GetList(Diff.ListType.Created); IList <INode> dList = priorDiff.diff.GetList(Diff.ListType.Deleted); priorCreated = CloneDiffList(cList); priorDeleted = CloneDiffList(dList); } } counts.Add(GetDiffs().DeleteSnapshotDiff(bsps, snapshot, prior, currentINode, collectedBlocks , removedINodes)); counts.Add(currentINode.CleanSubtreeRecursively(bsps, snapshot, prior, collectedBlocks , removedINodes, priorDeleted)); // check priorDiff again since it may be created during the diff deletion if (prior != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.NoSnapshotId) { DirectoryWithSnapshotFeature.DirectoryDiff priorDiff = this.GetDiffs().GetDiffById (prior); if (priorDiff != null && priorDiff.GetSnapshotId() == prior) { // For files/directories created between "prior" and "snapshot", // we need to clear snapshot copies for "snapshot". Note that we must // use null as prior in the cleanSubtree call. Files/directories that // were created before "prior" will be covered by the later // cleanSubtreeRecursively call. if (priorCreated != null) { // we only check the node originally in prior's created list foreach (INode cNode in priorDiff.GetChildrenDiff().GetList(Diff.ListType.Created )) { if (priorCreated.Contains(cNode)) { counts.Add(cNode.CleanSubtree(bsps, snapshot, Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot .NoSnapshotId, collectedBlocks, removedINodes)); } } } // When a directory is moved from the deleted list of the posterior // diff to the deleted list of this diff, we need to destroy its // descendants that were 1) created after taking this diff and 2) // deleted after taking posterior diff. // For files moved from posterior's deleted list, we also need to // delete its snapshot copy associated with the posterior snapshot. foreach (INode dNode in priorDiff.GetChildrenDiff().GetList(Diff.ListType.Deleted )) { if (priorDeleted == null || !priorDeleted.Contains(dNode)) { counts.Add(CleanDeletedINode(bsps, dNode, snapshot, prior, collectedBlocks, removedINodes )); } } } } } if (currentINode.IsQuotaSet()) { currentINode.GetDirectoryWithQuotaFeature().AddSpaceConsumed2Cache(counts.Negation ()); } return(counts); }
/// <summary> /// Clean an inode while we move it from the deleted list of post to the /// deleted list of prior. /// </summary> /// <param name="bsps">The block storage policy suite.</param> /// <param name="inode">The inode to clean.</param> /// <param name="post">The post snapshot.</param> /// <param name="prior">The id of the prior snapshot.</param> /// <param name="collectedBlocks">Used to collect blocks for later deletion.</param> /// <returns>Quota usage update.</returns> private static QuotaCounts CleanDeletedINode(BlockStoragePolicySuite bsps, INode inode, int post, int prior, INode.BlocksMapUpdateInfo collectedBlocks, IList <INode > removedINodes) { QuotaCounts counts = new QuotaCounts.Builder().Build(); Deque <INode> queue = new ArrayDeque <INode>(); queue.AddLast(inode); while (!queue.IsEmpty()) { INode topNode = queue.PollFirst(); if (topNode is INodeReference.WithName) { INodeReference.WithName wn = (INodeReference.WithName)topNode; if (wn.GetLastSnapshotId() >= post) { wn.CleanSubtree(bsps, post, prior, collectedBlocks, removedINodes); } } else { // For DstReference node, since the node is not in the created list of // prior, we should treat it as regular file/dir if (topNode.IsFile() && topNode.AsFile().IsWithSnapshot()) { INodeFile file = topNode.AsFile(); counts.Add(file.GetDiffs().DeleteSnapshotDiff(bsps, post, prior, file, collectedBlocks , removedINodes)); } else { if (topNode.IsDirectory()) { INodeDirectory dir = topNode.AsDirectory(); DirectoryWithSnapshotFeature.ChildrenDiff priorChildrenDiff = null; DirectoryWithSnapshotFeature sf = dir.GetDirectoryWithSnapshotFeature(); if (sf != null) { // delete files/dirs created after prior. Note that these // files/dirs, along with inode, were deleted right after post. DirectoryWithSnapshotFeature.DirectoryDiff priorDiff = sf.GetDiffs().GetDiffById( prior); if (priorDiff != null && priorDiff.GetSnapshotId() == prior) { priorChildrenDiff = priorDiff.GetChildrenDiff(); counts.Add(priorChildrenDiff.DestroyCreatedList(bsps, dir, collectedBlocks, removedINodes )); } } foreach (INode child in dir.GetChildrenList(prior)) { if (priorChildrenDiff != null && priorChildrenDiff.Search(Diff.ListType.Deleted, child.GetLocalNameBytes()) != null) { continue; } queue.AddLast(child); } } } } } return(counts); }