/// <summary>Add a snapshot.</summary> /// <exception cref="Org.Apache.Hadoop.Hdfs.Protocol.SnapshotException"/> /// <exception cref="Org.Apache.Hadoop.Hdfs.Protocol.QuotaExceededException"/> public virtual Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot AddSnapshot (INodeDirectory snapshotRoot, int id, string name) { //check snapshot quota int n = GetNumSnapshots(); if (n + 1 > snapshotQuota) { throw new SnapshotException("Failed to add snapshot: there are already " + n + " snapshot(s) and the snapshot quota is " + snapshotQuota); } Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot s = new Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot (id, name, snapshotRoot); byte[] nameBytes = s.GetRoot().GetLocalNameBytes(); int i = SearchSnapshot(nameBytes); if (i >= 0) { throw new SnapshotException("Failed to add snapshot: there is already a " + "snapshot with the same name \"" + Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.GetSnapshotName(s) + "\"."); } DirectoryWithSnapshotFeature.DirectoryDiff d = GetDiffs().AddDiff(id, snapshotRoot ); d.SetSnapshotRoot(s.GetRoot()); snapshotsByNames.Add(-i - 1, s); // set modification time long now = Time.Now(); snapshotRoot.UpdateModificationTime(now, Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot .CurrentStateId); s.GetRoot().SetModificationTime(now, Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot .CurrentStateId); return(s); }
public virtual INode GetChild(INodeDirectory currentINode, byte[] name, int snapshotId ) { DirectoryWithSnapshotFeature.DirectoryDiff diff = diffs.GetDiffById(snapshotId); return(diff != null?diff.GetChild(name, true, currentINode) : currentINode.GetChild (name, Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.CurrentStateId)); }
/// <returns> /// If there is no corresponding directory diff for the given /// snapshot, this means that the current children list should be /// returned for the snapshot. Otherwise we calculate the children list /// for the snapshot and return it. /// </returns> public virtual ReadOnlyList <INode> GetChildrenList(INodeDirectory currentINode, int snapshotId) { DirectoryWithSnapshotFeature.DirectoryDiff diff = diffs.GetDiffById(snapshotId); return(diff != null?diff.GetChildrenList(currentINode) : currentINode.GetChildrenList (Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.CurrentStateId)); }
public override INodeDirectory.SnapshotAndINode Next() { INodeDirectory.SnapshotAndINode pair = new INodeDirectory.SnapshotAndINode(this.next .GetSnapshotId(), this._enclosing._enclosing.GetSnapshotById(this.next.GetSnapshotId ()).GetRoot()); this.next = this.FindNext(); return(pair); }
/// <summary>Compute the difference between Snapshots.</summary> /// <param name="fromSnapshot"> /// Start point of the diff computation. Null indicates /// current tree. /// </param> /// <param name="toSnapshot"> /// End point of the diff computation. Null indicates current /// tree. /// </param> /// <param name="diff"> /// Used to capture the changes happening to the children. Note /// that the diff still represents (later_snapshot - earlier_snapshot) /// although toSnapshot can be before fromSnapshot. /// </param> /// <param name="currentINode"> /// The /// <see cref="Org.Apache.Hadoop.Hdfs.Server.Namenode.INodeDirectory"/> /// this feature belongs to. /// </param> /// <returns>Whether changes happened between the startSnapshot and endSnaphsot.</returns> internal virtual bool ComputeDiffBetweenSnapshots(Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot fromSnapshot, Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot toSnapshot , DirectoryWithSnapshotFeature.ChildrenDiff diff, INodeDirectory currentINode) { int[] diffIndexPair = diffs.ChangedBetweenSnapshots(fromSnapshot, toSnapshot); if (diffIndexPair == null) { return(false); } int earlierDiffIndex = diffIndexPair[0]; int laterDiffIndex = diffIndexPair[1]; bool dirMetadataChanged = false; INodeDirectoryAttributes dirCopy = null; IList <DirectoryWithSnapshotFeature.DirectoryDiff> difflist = diffs.AsList(); for (int i = earlierDiffIndex; i < laterDiffIndex; i++) { DirectoryWithSnapshotFeature.DirectoryDiff sdiff = difflist[i]; diff.CombinePosterior(sdiff.diff, null); if (!dirMetadataChanged && sdiff.snapshotINode != null) { if (dirCopy == null) { dirCopy = sdiff.snapshotINode; } else { if (!dirCopy.MetadataEquals(sdiff.snapshotINode)) { dirMetadataChanged = true; } } } } if (!diff.IsEmpty() || dirMetadataChanged) { return(true); } else { if (dirCopy != null) { for (int i_1 = laterDiffIndex; i_1 < difflist.Count; i_1++) { if (!dirCopy.MetadataEquals(difflist[i_1].snapshotINode)) { return(true); } } return(!dirCopy.MetadataEquals(currentINode)); } else { return(false); } } }
private DirectoryWithSnapshotFeature.DirectoryDiff FindNext() { for (; this.i.HasNext();) { DirectoryWithSnapshotFeature.DirectoryDiff diff = this.i.Next(); if (diff.IsSnapshotRoot()) { return(diff); } } return(null); }
/// <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); } } }
private IList <INode> InitChildren() { if (this.children == null) { DirectoryWithSnapshotFeature.ChildrenDiff combined = new DirectoryWithSnapshotFeature.ChildrenDiff (); for (DirectoryWithSnapshotFeature.DirectoryDiff d = this._enclosing; d != null; d = d.GetPosterior()) { combined.CombinePosterior(d.diff, null); } this.children = combined.Apply2Current(ReadOnlyList.Util.AsList(currentDir.GetChildrenList (Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.CurrentStateId))); } return(this.children); }
/// <summary> /// Test snapshot during file appending, before the corresponding /// <see cref="Org.Apache.Hadoop.FS.FSDataOutputStream"/> /// instance closes. /// </summary> /// <exception cref="System.Exception"/> public virtual void TestSnapshotWhileAppending() { Path file = new Path(dir, "file"); DFSTestUtil.CreateFile(hdfs, file, Blocksize, Replication, seed); // 1. append without closing stream --> create snapshot HdfsDataOutputStream @out = AppendFileWithoutClosing(file, Blocksize); @out.Hsync(EnumSet.Of(HdfsDataOutputStream.SyncFlag.UpdateLength)); SnapshotTestHelper.CreateSnapshot(hdfs, dir, "s0"); @out.Close(); // check: an INodeFileUnderConstructionWithSnapshot should be stored into s0's // deleted list, with size BLOCKSIZE*2 INodeFile fileNode = (INodeFile)fsdir.GetINode(file.ToString()); NUnit.Framework.Assert.AreEqual(Blocksize * 2, fileNode.ComputeFileSize()); INodeDirectory dirNode = fsdir.GetINode(dir.ToString()).AsDirectory(); DirectoryWithSnapshotFeature.DirectoryDiff last = dirNode.GetDiffs().GetLast(); // 2. append without closing stream @out = AppendFileWithoutClosing(file, Blocksize); @out.Hsync(EnumSet.Of(HdfsDataOutputStream.SyncFlag.UpdateLength)); // re-check nodeInDeleted_S0 dirNode = fsdir.GetINode(dir.ToString()).AsDirectory(); NUnit.Framework.Assert.AreEqual(Blocksize * 2, fileNode.ComputeFileSize(last.GetSnapshotId ())); // 3. take snapshot --> close stream hdfs.CreateSnapshot(dir, "s1"); @out.Close(); // check: an INodeFileUnderConstructionWithSnapshot with size BLOCKSIZE*3 should // have been stored in s1's deleted list fileNode = (INodeFile)fsdir.GetINode(file.ToString()); dirNode = fsdir.GetINode(dir.ToString()).AsDirectory(); last = dirNode.GetDiffs().GetLast(); NUnit.Framework.Assert.IsTrue(fileNode.IsWithSnapshot()); NUnit.Framework.Assert.AreEqual(Blocksize * 3, fileNode.ComputeFileSize(last.GetSnapshotId ())); // 4. modify file --> append without closing stream --> take snapshot --> // close stream hdfs.SetReplication(file, (short)(Replication - 1)); @out = AppendFileWithoutClosing(file, Blocksize); hdfs.CreateSnapshot(dir, "s2"); @out.Close(); // re-check the size of nodeInDeleted_S1 NUnit.Framework.Assert.AreEqual(Blocksize * 3, fileNode.ComputeFileSize(last.GetSnapshotId ())); }
/// <summary>Used to record the modification of a symlink node</summary> public virtual INode SaveChild2Snapshot(INodeDirectory currentINode, INode child, int latestSnapshotId, INode snapshotCopy) { Preconditions.CheckArgument(!child.IsDirectory(), "child is a directory, child=%s" , child); Preconditions.CheckArgument(latestSnapshotId != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot .CurrentStateId); DirectoryWithSnapshotFeature.DirectoryDiff diff = diffs.CheckAndAddLatestSnapshotDiff (latestSnapshotId, currentINode); if (diff.GetChild(child.GetLocalNameBytes(), false, currentINode) != null) { // it was already saved in the latest snapshot earlier. return(child); } diff.diff.Modify(snapshotCopy, child); return(child); }
/// <summary> /// Load /// <see cref="DirectoryDiff"/> /// from fsimage. /// </summary> /// <param name="parent">The directory that the SnapshotDiff belongs to.</param> /// <param name="in"> /// The /// <see cref="System.IO.DataInput"/> /// instance to read. /// </param> /// <param name="loader"> /// The /// <see cref="Loader"/> /// instance that this loading procedure is /// using. /// </param> /// <returns> /// A /// <see cref="DirectoryDiff"/> /// . /// </returns> /// <exception cref="System.IO.IOException"/> private static DirectoryWithSnapshotFeature.DirectoryDiff LoadDirectoryDiff(INodeDirectory parent, DataInput @in, FSImageFormat.Loader loader) { // 1. Read the full path of the Snapshot root to identify the Snapshot Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot snapshot = loader.GetSnapshot (@in); // 2. Load DirectoryDiff#childrenSize int childrenSize = @in.ReadInt(); // 3. Load DirectoryDiff#snapshotINode INodeDirectoryAttributes snapshotINode = LoadSnapshotINodeInDirectoryDiff(snapshot , @in, loader); // 4. Load the created list in SnapshotDiff#Diff IList <INode> createdList = LoadCreatedList(parent, @in); // 5. Load the deleted list in SnapshotDiff#Diff IList <INode> deletedList = LoadDeletedList(parent, createdList, @in, loader); // 6. Compose the SnapshotDiff IList <DirectoryWithSnapshotFeature.DirectoryDiff> diffs = parent.GetDiffs().AsList (); DirectoryWithSnapshotFeature.DirectoryDiff sdiff = new DirectoryWithSnapshotFeature.DirectoryDiff (snapshot.GetId(), snapshotINode, diffs.IsEmpty() ? null : diffs[0], childrenSize , createdList, deletedList, snapshotINode == snapshot.GetRoot()); return(sdiff); }
/// <summary>Load DirectoryDiff list for a directory with snapshot feature</summary> /// <exception cref="System.IO.IOException"/> private void LoadDirectoryDiffList(InputStream @in, INodeDirectory dir, int size, IList <INodeReference> refList) { if (!dir.IsWithSnapshot()) { dir.AddSnapshotFeature(null); } DirectoryWithSnapshotFeature.DirectoryDiffList diffs = dir.GetDiffs(); FSImageFormatProtobuf.LoaderContext state = parent.GetLoaderContext(); for (int i = 0; i < size; i++) { // load a directory diff FsImageProto.SnapshotDiffSection.DirectoryDiff diffInPb = FsImageProto.SnapshotDiffSection.DirectoryDiff .ParseDelimitedFrom(@in); int snapshotId = diffInPb.GetSnapshotId(); Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot snapshot = snapshotMap[snapshotId ]; int childrenSize = diffInPb.GetChildrenSize(); bool useRoot = diffInPb.GetIsSnapshotRoot(); INodeDirectoryAttributes copy = null; if (useRoot) { copy = snapshot.GetRoot(); } else { if (diffInPb.HasSnapshotCopy()) { FsImageProto.INodeSection.INodeDirectory dirCopyInPb = diffInPb.GetSnapshotCopy(); byte[] name = diffInPb.GetName().ToByteArray(); PermissionStatus permission = FSImageFormatPBINode.Loader.LoadPermission(dirCopyInPb .GetPermission(), state.GetStringTable()); AclFeature acl = null; if (dirCopyInPb.HasAcl()) { int[] entries = AclEntryStatusFormat.ToInt(FSImageFormatPBINode.Loader.LoadAclEntries (dirCopyInPb.GetAcl(), state.GetStringTable())); acl = new AclFeature(entries); } XAttrFeature xAttrs = null; if (dirCopyInPb.HasXAttrs()) { xAttrs = new XAttrFeature(FSImageFormatPBINode.Loader.LoadXAttrs(dirCopyInPb.GetXAttrs (), state.GetStringTable())); } long modTime = dirCopyInPb.GetModificationTime(); bool noQuota = dirCopyInPb.GetNsQuota() == -1 && dirCopyInPb.GetDsQuota() == -1 && (!dirCopyInPb.HasTypeQuotas()); if (noQuota) { copy = new INodeDirectoryAttributes.SnapshotCopy(name, permission, acl, modTime, xAttrs); } else { EnumCounters <StorageType> typeQuotas = null; if (dirCopyInPb.HasTypeQuotas()) { ImmutableList <QuotaByStorageTypeEntry> qes = FSImageFormatPBINode.Loader.LoadQuotaByStorageTypeEntries (dirCopyInPb.GetTypeQuotas()); typeQuotas = new EnumCounters <StorageType>(typeof(StorageType), HdfsConstants.QuotaReset ); foreach (QuotaByStorageTypeEntry qe in qes) { if (qe.GetQuota() >= 0 && qe.GetStorageType() != null && qe.GetStorageType().SupportTypeQuota ()) { typeQuotas.Set(qe.GetStorageType(), qe.GetQuota()); } } } copy = new INodeDirectoryAttributes.CopyWithQuota(name, permission, acl, modTime, dirCopyInPb.GetNsQuota(), dirCopyInPb.GetDsQuota(), typeQuotas, xAttrs); } } } // load created list IList <INode> clist = LoadCreatedList(@in, dir, diffInPb.GetCreatedListSize()); // load deleted list IList <INode> dlist = LoadDeletedList(refList, @in, dir, diffInPb.GetDeletedINodeList (), diffInPb.GetDeletedINodeRefList()); // create the directory diff DirectoryWithSnapshotFeature.DirectoryDiff diff = new DirectoryWithSnapshotFeature.DirectoryDiff (snapshotId, copy, null, childrenSize, clist, dlist, useRoot); diffs.AddFirst(diff); } }
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); }
/// <summary>Destroy a subtree under a DstReference node.</summary> /// <exception cref="Org.Apache.Hadoop.Hdfs.Protocol.QuotaExceededException"/> public static void DestroyDstSubtree(BlockStoragePolicySuite bsps, INode inode, int snapshot, int prior, INode.BlocksMapUpdateInfo collectedBlocks, IList <INode> removedINodes ) { Preconditions.CheckArgument(prior != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot .NoSnapshotId); if (inode.IsReference()) { if (inode is INodeReference.WithName && snapshot != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot .CurrentStateId) { // this inode has been renamed before the deletion of the DstReference // subtree inode.CleanSubtree(bsps, snapshot, prior, collectedBlocks, removedINodes); } else { // for DstReference node, continue this process to its subtree DestroyDstSubtree(bsps, inode.AsReference().GetReferredINode(), snapshot, prior, collectedBlocks, removedINodes); } } else { if (inode.IsFile()) { inode.CleanSubtree(bsps, snapshot, prior, collectedBlocks, removedINodes); } else { if (inode.IsDirectory()) { IDictionary <INode, INode> excludedNodes = null; INodeDirectory dir = inode.AsDirectory(); DirectoryWithSnapshotFeature sf = dir.GetDirectoryWithSnapshotFeature(); if (sf != null) { DirectoryWithSnapshotFeature.DirectoryDiffList diffList = sf.GetDiffs(); DirectoryWithSnapshotFeature.DirectoryDiff priorDiff = diffList.GetDiffById(prior ); if (priorDiff != null && priorDiff.GetSnapshotId() == prior) { IList <INode> dList = priorDiff.diff.GetList(Diff.ListType.Deleted); excludedNodes = CloneDiffList(dList); } if (snapshot != Org.Apache.Hadoop.Hdfs.Server.Namenode.Snapshot.Snapshot.CurrentStateId) { diffList.DeleteSnapshotDiff(bsps, snapshot, prior, dir, collectedBlocks, removedINodes ); } priorDiff = diffList.GetDiffById(prior); if (priorDiff != null && priorDiff.GetSnapshotId() == prior) { priorDiff.diff.DestroyCreatedList(bsps, dir, collectedBlocks, removedINodes); } } foreach (INode child in inode.AsDirectory().GetChildrenList(prior)) { if (excludedNodes != null && excludedNodes.Contains(child)) { continue; } DestroyDstSubtree(bsps, child, snapshot, prior, collectedBlocks, removedINodes); } } } } }