/** * Check if the given INode (or one of its descendants) is snapshottable and * already has snapshots. * * @param target The given INode * @param snapshottableDirs The list of directories that are snapshottable * but do not have snapshots yet */ static void checkSnapshot( INode target, List<INodeDirectory> snapshottableDirs) throws SnapshotException { if (target.isDirectory()) { INodeDirectory targetDir = target.asDirectory(); DirectorySnapshottableFeature sf = targetDir .getDirectorySnapshottableFeature(); if (sf != null) { if (sf.getNumSnapshots() > 0) { String fullPath = targetDir.getFullPathName(); throw new SnapshotException("The directory " + fullPath + " cannot be deleted since " + fullPath + " is snapshottable and already has snapshots"); } else { if (snapshottableDirs != null) { snapshottableDirs.add(targetDir); } } } for (INode child : targetDir.getChildrenList(Snapshot.CURRENT_STATE_ID)) { checkSnapshot(child, snapshottableDirs); } } }
/** * Check if the given INode (or one of its descendants) is snapshottable and * already has snapshots. * * @param target The given INode * @param snapshottableDirs The list of directories that are snapshottable * but do not have snapshots yet */ private static void checkSnapshot(INode target, List<INodeDirectory> snapshottableDirs) throws SnapshotException { if (target.isDirectory()) { INodeDirectory targetDir = target.asDirectory(); DirectorySnapshottableFeature sf = targetDir .getDirectorySnapshottableFeature(); if (sf != null) { if (sf.getNumSnapshots() > 0) { String fullPath = targetDir.getFullPathName(); throw new SnapshotException("The directory " + fullPath + " cannot be deleted since " + fullPath + " is snapshottable and already has snapshots"); } else { if (snapshottableDirs != null) { snapshottableDirs.add(targetDir); } } } for (INode child : targetDir.getChildrenList(Snapshot.CURRENT_STATE_ID)) { checkSnapshot(child, snapshottableDirs); } } }
/** * Get a listing of all the snapshots of a snapshottable directory */ private static DirectoryListing getSnapshotsListing( FSDirectory fsd, String src, byte[] startAfter) throws IOException { Preconditions.checkState(fsd.hasReadLock()); Preconditions.checkArgument( src.endsWith(HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR), "%s does not end with %s", src, HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR); final String dirPath = FSDirectory.normalizePath(src.substring(0, src.length() - HdfsConstants.DOT_SNAPSHOT_DIR.length())); final INode node = fsd.getINode(dirPath); final INodeDirectory dirNode = INodeDirectory.valueOf(node, dirPath); final DirectorySnapshottableFeature sf = dirNode.getDirectorySnapshottableFeature(); if (sf == null) { throw new SnapshotException( "Directory is not a snapshottable directory: " + dirPath); } final ReadOnlyList<Snapshot> snapshots = sf.getSnapshotList(); int skipSize = ReadOnlyList.Util.binarySearch(snapshots, startAfter); skipSize = skipSize < 0 ? -skipSize - 1 : skipSize + 1; int numOfListing = Math.min(snapshots.size() - skipSize, fsd.getLsLimit()); final HdfsFileStatus listing[] = new HdfsFileStatus[numOfListing]; for (int i = 0; i < numOfListing; i++) { Snapshot.Root sRoot = snapshots.get(i + skipSize).getRoot(); listing[i] = createFileStatus(fsd, src, sRoot.getLocalNameBytes(), sRoot, BlockStoragePolicySuite.ID_UNSPECIFIED, Snapshot.CURRENT_STATE_ID, false, INodesInPath.fromINode(sRoot)); } return new DirectoryListing( listing, snapshots.size() - skipSize - numOfListing); }
/** add DirectorySnapshottableFeature */ public void addSnapshottableFeature() { Preconditions.checkState(!isSnapshottable(), "this is already snapshottable, this=%s", this); DirectoryWithSnapshotFeature s = this.getDirectoryWithSnapshotFeature(); final DirectorySnapshottableFeature snapshottable = new DirectorySnapshottableFeature(s); if (s != null) { this.removeFeature(s); } this.addFeature(snapshottable); }
/** remove DirectorySnapshottableFeature */ public void removeSnapshottableFeature() { DirectorySnapshottableFeature s = getDirectorySnapshottableFeature(); Preconditions.checkState(s != null, "The dir does not have snapshottable feature: this=%s", this); this.removeFeature(s); if (s.getDiffs().asList().size() > 0) { // add a DirectoryWithSnapshotFeature back DirectoryWithSnapshotFeature sf = new DirectoryWithSnapshotFeature( s.getDiffs()); addFeature(sf); } }
/** * Get a listing of all the snapshots of a snapshottable directory */ private static DirectoryListing getSnapshotsListing( FSDirectory fsd, String src, byte[] startAfter) throws IOException { Preconditions.checkState(fsd.hasReadLock()); Preconditions.checkArgument( src.endsWith(HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR), "%s does not end with %s", src, HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR); final String dirPath = FSDirectory.normalizePath(src.substring(0, src.length() - HdfsConstants.DOT_SNAPSHOT_DIR.length())); final INode node = fsd.getINode(dirPath); final INodeDirectory dirNode = INodeDirectory.valueOf(node, dirPath); final DirectorySnapshottableFeature sf = dirNode.getDirectorySnapshottableFeature(); if (sf == null) { throw new SnapshotException( "Directory is not a snapshottable directory: " + dirPath); } final ReadOnlyList<Snapshot> snapshots = sf.getSnapshotList(); int skipSize = ReadOnlyList.Util.binarySearch(snapshots, startAfter); skipSize = skipSize < 0 ? -skipSize - 1 : skipSize + 1; int numOfListing = Math.min(snapshots.size() - skipSize, fsd.getLsLimit()); final HdfsFileStatus listing[] = new HdfsFileStatus[numOfListing]; for (int i = 0; i < numOfListing; i++) { Snapshot.Root sRoot = snapshots.get(i + skipSize).getRoot(); INodeAttributes nodeAttrs = getINodeAttributes( fsd, src, sRoot.getLocalNameBytes(), node, Snapshot.CURRENT_STATE_ID); listing[i] = createFileStatus( fsd, sRoot.getLocalNameBytes(), sRoot, nodeAttrs, HdfsConstants.BLOCK_STORAGE_POLICY_ID_UNSPECIFIED, Snapshot.CURRENT_STATE_ID, false, INodesInPath.fromINode(sRoot)); } return new DirectoryListing( listing, snapshots.size() - skipSize - numOfListing); }
/** Get a collection of full snapshot paths given file and snapshot dir. * @param lsf a list of snapshottable features * @param file full path of the file * @return collection of full paths of snapshot of the file */ static Collection<String> getSnapshotFiles(FSDirectory fsd, List<DirectorySnapshottableFeature> lsf, String file) throws IOException { ArrayList<String> snaps = new ArrayList<>(); for (DirectorySnapshottableFeature sf : lsf) { // for each snapshottable dir e.g. /dir1, /dir2 final ReadOnlyList<Snapshot> lsnap = sf.getSnapshotList(); for (Snapshot s : lsnap) { // for each snapshot name under snapshottable dir // e.g. /dir1/.snapshot/s1, /dir1/.snapshot/s2 final String dirName = s.getRoot().getRootFullPathName(); if (!file.startsWith(dirName)) { // file not in current snapshot root dir, no need to check other snaps break; } String snapname = s.getRoot().getFullPathName(); if (dirName.equals(Path.SEPARATOR)) { // handle rootDir snapname += Path.SEPARATOR; } snapname += file.substring(file.indexOf(dirName) + dirName.length()); if (fsd.getFSNamesystem().getFileInfo(snapname, true) != null) { snaps.add(snapname); } } } return snaps; }
/** * Get a listing of all the snapshots of a snapshottable directory */ private DirectoryListing getSnapshotsListing(String src, byte[] startAfter) throws UnresolvedLinkException, IOException { Preconditions.checkState(hasReadLock()); Preconditions.checkArgument( src.endsWith(HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR), "%s does not end with %s", src, HdfsConstants.SEPARATOR_DOT_SNAPSHOT_DIR); final String dirPath = normalizePath(src.substring(0, src.length() - HdfsConstants.DOT_SNAPSHOT_DIR.length())); final INode node = this.getINode(dirPath); final INodeDirectory dirNode = INodeDirectory.valueOf(node, dirPath); final DirectorySnapshottableFeature sf = dirNode.getDirectorySnapshottableFeature(); if (sf == null) { throw new SnapshotException( "Directory is not a snapshottable directory: " + dirPath); } final ReadOnlyList<Snapshot> snapshots = sf.getSnapshotList(); int skipSize = ReadOnlyList.Util.binarySearch(snapshots, startAfter); skipSize = skipSize < 0 ? -skipSize - 1 : skipSize + 1; int numOfListing = Math.min(snapshots.size() - skipSize, this.lsLimit); final HdfsFileStatus listing[] = new HdfsFileStatus[numOfListing]; for (int i = 0; i < numOfListing; i++) { Root sRoot = snapshots.get(i + skipSize).getRoot(); listing[i] = createFileStatus(sRoot.getLocalNameBytes(), sRoot, BlockStoragePolicySuite.ID_UNSPECIFIED, Snapshot.CURRENT_STATE_ID, false, null); } return new DirectoryListing( listing, snapshots.size() - skipSize - numOfListing); }
public DirectorySnapshottableFeature getDirectorySnapshottableFeature() { return getFeature(DirectorySnapshottableFeature.class); }
@VisibleForTesting @Override public void dumpTreeRecursively(PrintWriter out, StringBuilder prefix, final int snapshot) { super.dumpTreeRecursively(out, prefix, snapshot); out.print(", childrenSize=" + getChildrenList(snapshot).size()); final DirectoryWithQuotaFeature q = getDirectoryWithQuotaFeature(); if (q != null) { out.print(", " + q); } if (this instanceof Snapshot.Root) { out.print(", snapshotId=" + snapshot); } out.println(); if (prefix.length() >= 2) { prefix.setLength(prefix.length() - 2); prefix.append(" "); } dumpTreeRecursively(out, prefix, new Iterable<SnapshotAndINode>() { final Iterator<INode> i = getChildrenList(snapshot).iterator(); @Override public Iterator<SnapshotAndINode> iterator() { return new Iterator<SnapshotAndINode>() { @Override public boolean hasNext() { return i.hasNext(); } @Override public SnapshotAndINode next() { return new SnapshotAndINode(snapshot, i.next()); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }); final DirectorySnapshottableFeature s = getDirectorySnapshottableFeature(); if (s != null) { s.dumpTreeRecursively(this, out, prefix, snapshot); } }