/** * Recursively compute the difference between snapshots under a given directory/file. * * @param node The directory/file under which the diff is computed. * @param parentPath Relative path (corresponding to the snapshot root) of the node's parent. * @param diffReport data structure used to store the diff. */ private void computeDiffRecursively( INode node, List<byte[]> parentPath, SnapshotDiffInfo diffReport) { ChildrenDiff diff = new ChildrenDiff(); byte[][] relativePath = parentPath.toArray(new byte[parentPath.size()][]); if (node.isDirectory()) { INodeDirectory dir = node.asDirectory(); if (dir instanceof INodeDirectoryWithSnapshot) { INodeDirectoryWithSnapshot sdir = (INodeDirectoryWithSnapshot) dir; boolean change = sdir.computeDiffBetweenSnapshots(diffReport.from, diffReport.to, diff); if (change) { diffReport.addDirDiff(sdir, relativePath, diff); } } ReadOnlyList<INode> children = dir.getChildrenList(diffReport.isFromEarlier() ? diffReport.to : diffReport.from); for (INode child : children) { final byte[] name = child.getLocalNameBytes(); if (diff.searchIndex(ListType.CREATED, name) < 0 && diff.searchIndex(ListType.DELETED, name) < 0) { parentPath.add(name); computeDiffRecursively(child, parentPath, diffReport); parentPath.remove(parentPath.size() - 1); } } } else if (node.isFile() && node.asFile() instanceof FileWithSnapshot) { FileWithSnapshot file = (FileWithSnapshot) node.asFile(); Snapshot earlierSnapshot = diffReport.isFromEarlier() ? diffReport.from : diffReport.to; Snapshot laterSnapshot = diffReport.isFromEarlier() ? diffReport.to : diffReport.from; boolean change = file.getDiffs().changedBetweenSnapshots(earlierSnapshot, laterSnapshot); if (change) { diffReport.addFileDiff(file.asINodeFile(), relativePath); } } }
@Override public ContentSummaryComputationContext computeContentSummary( final ContentSummaryComputationContext summary) { super.computeContentSummary(summary); summary.getCounts().add(Content.SNAPSHOT, snapshotsByNames.size()); summary.getCounts().add(Content.SNAPSHOTTABLE_DIRECTORY, 1); return summary; }
@Override public void dumpTreeRecursively(PrintWriter out, StringBuilder prefix, Snapshot snapshot) { super.dumpTreeRecursively(out, prefix, snapshot); if (snapshot == null) { out.println(); out.print(prefix); out.print("Snapshot of "); final String name = getLocalName(); out.print(name.isEmpty() ? "/" : name); out.print(": quota="); out.print(getSnapshotQuota()); int n = 0; for (DirectoryDiff diff : getDiffs()) { if (diff.isSnapshotRoot()) { n++; } } Preconditions.checkState(n == snapshotsByNames.size()); out.print(", #snapshot="); out.println(n); dumpTreeRecursively( out, prefix, new Iterable<SnapshotAndINode>() { @Override public Iterator<SnapshotAndINode> iterator() { return new Iterator<SnapshotAndINode>() { final Iterator<DirectoryDiff> i = getDiffs().iterator(); private DirectoryDiff next = findNext(); private DirectoryDiff findNext() { for (; i.hasNext(); ) { final DirectoryDiff diff = i.next(); if (diff.isSnapshotRoot()) { return diff; } } return null; } @Override public boolean hasNext() { return next != null; } @Override public SnapshotAndINode next() { final Snapshot s = next.snapshot; final SnapshotAndINode pair = new SnapshotAndINode(s); next = findNext(); return pair; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }); } }