/// <exception cref="System.IO.IOException"/> private void SerializeDirDiffList(INodeDirectory dir, IList <INodeReference> refList , OutputStream @out) { DirectoryWithSnapshotFeature sf = dir.GetDirectoryWithSnapshotFeature(); if (sf != null) { IList <DirectoryWithSnapshotFeature.DirectoryDiff> diffList = sf.GetDiffs().AsList (); FsImageProto.SnapshotDiffSection.DiffEntry entry = ((FsImageProto.SnapshotDiffSection.DiffEntry )FsImageProto.SnapshotDiffSection.DiffEntry.NewBuilder().SetInodeId(dir.GetId()) .SetType(FsImageProto.SnapshotDiffSection.DiffEntry.Type.Directorydiff).SetNumOfDiff (diffList.Count).Build()); entry.WriteDelimitedTo(@out); for (int i = diffList.Count - 1; i >= 0; i--) { // reverse order! DirectoryWithSnapshotFeature.DirectoryDiff diff = diffList[i]; FsImageProto.SnapshotDiffSection.DirectoryDiff.Builder db = FsImageProto.SnapshotDiffSection.DirectoryDiff .NewBuilder().SetSnapshotId(diff.GetSnapshotId()).SetChildrenSize(diff.GetChildrenSize ()).SetIsSnapshotRoot(diff.IsSnapshotRoot()); INodeDirectoryAttributes copy = diff.snapshotINode; if (!diff.IsSnapshotRoot() && copy != null) { db.SetName(ByteString.CopyFrom(copy.GetLocalNameBytes())).SetSnapshotCopy(FSImageFormatPBINode.Saver.BuildINodeDirectory (copy, parent.GetSaverContext())); } // process created list and deleted list IList <INode> created = diff.GetChildrenDiff().GetList(Diff.ListType.Created); db.SetCreatedListSize(created.Count); IList <INode> deleted = diff.GetChildrenDiff().GetList(Diff.ListType.Deleted); foreach (INode d in deleted) { if (d.IsReference()) { refList.AddItem(d.AsReference()); db.AddDeletedINodeRef(refList.Count - 1); } else { db.AddDeletedINode(d.GetId()); } } ((FsImageProto.SnapshotDiffSection.DirectoryDiff)db.Build()).WriteDelimitedTo(@out ); SaveCreatedList(created, @out); } } }
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); }