/** * 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); } } }
private void checkNestedSnapshottable(INodeDirectory dir, String path) throws SnapshotException { if (allowNestedSnapshots) { return; } for(INodeDirectory s : snapshottables.values()) { if (s.isAncestorDirectory(dir)) { throw new SnapshotException( "Nested snapshottable directories not allowed: path=" + path + ", the subdirectory " + s.getFullPathName() + " is already a snapshottable directory."); } if (dir.isAncestorDirectory(s)) { throw new SnapshotException( "Nested snapshottable directories not allowed: path=" + path + ", the ancestor " + s.getFullPathName() + " is already a snapshottable directory."); } } }
/** * Set the given snapshottable directory to non-snapshottable. * * @throws SnapshotException if there are snapshots in the directory. */ public void resetSnapshottable(final String path) throws IOException { final INodesInPath iip = fsdir.getINodesInPath4Write(path); final INodeDirectory d = INodeDirectory.valueOf(iip.getLastINode(), path); DirectorySnapshottableFeature sf = d.getDirectorySnapshottableFeature(); if (sf == null) { // the directory is already non-snapshottable return; } if (sf.getNumSnapshots() > 0) { throw new SnapshotException("The directory " + path + " has snapshot(s). " + "Please redo the operation after removing all the snapshots."); } if (d == fsdir.getRoot()) { d.setSnapshotQuota(0); } else { d.removeSnapshottableFeature(); } removeSnapshottable(d); }
/** * Create a snapshot of the given path. * It is assumed that the caller will perform synchronization. * * @param iip the INodes resolved from the snapshottable directory's path * @param snapshotName * The name of the snapshot. * @throws IOException * Throw IOException when 1) the given path does not lead to an * existing snapshottable directory, and/or 2) there exists a * snapshot with the given name for the directory, and/or 3) * snapshot number exceeds quota */ public String createSnapshot(final INodesInPath iip, String snapshotRoot, String snapshotName) throws IOException { INodeDirectory srcRoot = getSnapshottableRoot(iip); if (snapshotCounter == getMaxSnapshotID()) { // We have reached the maximum allowable snapshot ID and since we don't // handle rollover we will fail all subsequent snapshot creation // requests. // throw new SnapshotException( "Failed to create the snapshot. The FileSystem has run out of " + "snapshot IDs and ID rollover is not supported."); } srcRoot.addSnapshot(snapshotCounter, snapshotName); //create success, update id snapshotCounter++; numSnapshots.getAndIncrement(); return Snapshot.getSnapshotPath(snapshotRoot, snapshotName); }
/** * Create a snapshot of the given path. * It is assumed that the caller will perform synchronization. * * @param iip the INodes resolved from the snapshottable directory's path * @param snapshotName * The name of the snapshot. * @throws IOException * Throw IOException when 1) the given path does not lead to an * existing snapshottable directory, and/or 2) there exists a * snapshot with the given name for the directory, and/or 3) * snapshot number exceeds quota */ public String createSnapshot(final INodesInPath iip, String snapshotRoot, String snapshotName) throws IOException { INodeDirectory srcRoot = getSnapshottableRoot(iip); if (snapshotCounter == getMaxSnapshotID()) { // We have reached the maximum allowable snapshot ID and since we don't // handle rollover we will fail all subsequent snapshot creation // requests. throw new SnapshotException( "Failed to create the snapshot. The FileSystem has run out of " + "snapshot IDs and ID rollover is not supported."); } srcRoot.addSnapshot(snapshotCounter, snapshotName); //create success, update id snapshotCounter++; numSnapshots.getAndIncrement(); return Snapshot.getSnapshotPath(snapshotRoot, snapshotName); }
/** * Remove the snapshot with the given name from {@link #snapshotsByNames}, * and delete all the corresponding DirectoryDiff. * * @param reclaimContext records blocks and inodes that need to be reclaimed * @param snapshotRoot The directory where we take snapshots * @param snapshotName The name of the snapshot to be removed * @return The removed snapshot. Null if no snapshot with the given name * exists. */ public Snapshot removeSnapshot( INode.ReclaimContext reclaimContext, INodeDirectory snapshotRoot, String snapshotName) throws SnapshotException { final int i = searchSnapshot(DFSUtil.string2Bytes(snapshotName)); if (i < 0) { throw new SnapshotException("Cannot delete snapshot " + snapshotName + " from path " + snapshotRoot.getFullPathName() + ": the snapshot does not exist."); } else { final Snapshot snapshot = snapshotsByNames.get(i); int prior = Snapshot.findLatestSnapshot(snapshotRoot, snapshot.getId()); snapshotRoot.cleanSubtree(reclaimContext, snapshot.getId(), prior); // remove from snapshotsByNames after successfully cleaning the subtree snapshotsByNames.remove(i); return snapshot; } }
@Test(timeout = 60000) public void testCreateAndDeleteSnapshot() throws Exception { DFSTestUtil.createFile(dfs, filePath, BLOCKSIZE, REPLICATION, SEED); // disallow snapshot on dir dfs.disallowSnapshot(snapRootPath); try { fileContext.createSnapshot(snapRootPath, "s1"); } catch (SnapshotException e) { GenericTestUtils.assertExceptionContains( "Directory is not a snapshottable directory: " + snapRootPath, e); } // allow snapshot on dir dfs.allowSnapshot(snapRootPath); Path ssPath = fileContext.createSnapshot(snapRootPath, "s1"); assertTrue("Failed to create snapshot", dfs.exists(ssPath)); fileContext.deleteSnapshot(snapRootPath, "s1"); assertFalse("Failed to delete snapshot", dfs.exists(ssPath)); }
/** * 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); } } }
/** * Create a snapshot of the given path. * It is assumed that the caller will perform synchronization. * * @param path * The directory path where the snapshot will be taken. * @param snapshotName * The name of the snapshot. * @throws IOException * Throw IOException when 1) the given path does not lead to an * existing snapshottable directory, and/or 2) there exists a * snapshot with the given name for the directory, and/or 3) * snapshot number exceeds quota */ public String createSnapshot(final String path, String snapshotName ) throws IOException { INodeDirectory srcRoot = getSnapshottableRoot(path); if (snapshotCounter == getMaxSnapshotID()) { // We have reached the maximum allowable snapshot ID and since we don't // handle rollover we will fail all subsequent snapshot creation // requests. // throw new SnapshotException( "Failed to create the snapshot. The FileSystem has run out of " + "snapshot IDs and ID rollover is not supported."); } AuthorizationProvider.get().createSnapshot(srcRoot, snapshotCounter); srcRoot.addSnapshot(snapshotCounter, snapshotName); //create success, update id snapshotCounter++; numSnapshots.getAndIncrement(); return Snapshot.getSnapshotPath(path, snapshotName); }
/** * Concat all the blocks from srcs to trg and delete the srcs files */ void concat(String target, String [] srcs, boolean supportRetryCache) throws UnresolvedLinkException, QuotaExceededException, SnapshotAccessControlException, SnapshotException { writeLock(); try { // actual move waitForReady(); long timestamp = now(); unprotectedConcat(target, srcs, timestamp); // do the commit fsImage.getEditLog().logConcat(target, srcs, timestamp, supportRetryCache); } finally { writeUnlock(); } }
private void checkNestedSnapshottable(INodeDirectory dir, String path) throws SnapshotException { if (allowNestedSnapshots) { return; } for(INodeDirectorySnapshottable s : snapshottables.values()) { if (s.isAncestorDirectory(dir)) { throw new SnapshotException( "Nested snapshottable directories not allowed: path=" + path + ", the subdirectory " + s.getFullPathName() + " is already a snapshottable directory."); } if (dir.isAncestorDirectory(s)) { throw new SnapshotException( "Nested snapshottable directories not allowed: path=" + path + ", the ancestor " + s.getFullPathName() + " is already a snapshottable directory."); } } }
/** * Set the given snapshottable directory to non-snapshottable. * * @throws SnapshotException if there are snapshots in the directory. */ public void resetSnapshottable(final String path) throws IOException { final INodesInPath iip = fsdir.getINodesInPath4Write(path); final INodeDirectory d = INodeDirectory.valueOf(iip.getLastINode(), path); if (!d.isSnapshottable()) { // the directory is already non-snapshottable return; } final INodeDirectorySnapshottable s = (INodeDirectorySnapshottable) d; if (s.getNumSnapshots() > 0) { throw new SnapshotException("The directory " + path + " has snapshot(s). " + "Please redo the operation after removing all the snapshots."); } if (s == fsdir.getRoot()) { s.setSnapshotQuota(0); } else { s.replaceSelf(iip.getLatestSnapshot(), fsdir.getINodeMap()); } removeSnapshottable(s); }
/** * Create a snapshot of the given path. * It is assumed that the caller will perform synchronization. * * @param path * The directory path where the snapshot will be taken. * @param snapshotName * The name of the snapshot. * @throws IOException * Throw IOException when 1) the given path does not lead to an * existing snapshottable directory, and/or 2) there exists a * snapshot with the given name for the directory, and/or 3) * snapshot number exceeds quota */ public String createSnapshot(final String path, String snapshotName ) throws IOException { INodeDirectorySnapshottable srcRoot = getSnapshottableRoot(path); if (snapshotCounter == getMaxSnapshotID()) { // We have reached the maximum allowable snapshot ID and since we don't // handle rollover we will fail all subsequent snapshot creation // requests. // throw new SnapshotException( "Failed to create the snapshot. The FileSystem has run out of " + "snapshot IDs and ID rollover is not supported."); } srcRoot.addSnapshot(snapshotCounter, snapshotName); //create success, update id snapshotCounter++; numSnapshots.getAndIncrement(); return Snapshot.getSnapshotPath(path, snapshotName); }
/** * Create a snapshot of the given path. * It is assumed that the caller will perform synchronization. * * @param path * The directory path where the snapshot will be taken. * @param snapshotName * The name of the snapshot. * @throws IOException * Throw IOException when 1) the given path does not lead to an * existing snapshottable directory, and/or 2) there exists a * snapshot with the given name for the directory, and/or 3) * snapshot number exceeds quota */ public String createSnapshot(final String path, String snapshotName ) throws IOException { INodeDirectory srcRoot = getSnapshottableRoot(path); if (snapshotCounter == getMaxSnapshotID()) { // We have reached the maximum allowable snapshot ID and since we don't // handle rollover we will fail all subsequent snapshot creation // requests. // throw new SnapshotException( "Failed to create the snapshot. The FileSystem has run out of " + "snapshot IDs and ID rollover is not supported."); } srcRoot.addSnapshot(snapshotCounter, snapshotName); //create success, update id snapshotCounter++; numSnapshots.getAndIncrement(); return Snapshot.getSnapshotPath(path, snapshotName); }
/** * Set the given snapshottable directory to non-snapshottable. * * @throws SnapshotException if there are snapshots in the directory. */ public void resetSnapshottable(final String path) throws IOException { final INodesInPath iip = fsdir.getINodesInPath4Write(path); final INodeDirectory d = INodeDirectory.valueOf(iip.getLastINode(), path); if (!d.isSnapshottable()) { // the directory is already non-snapshottable return; } final INodeDirectorySnapshottable s = (INodeDirectorySnapshottable) d; if (s.getNumSnapshots() > 0) { throw new SnapshotException("The directory " + path + " has snapshot(s). " + "Please redo the operation after removing all the snapshots."); } if (s == fsdir.getRoot()) { s.setSnapshotQuota(0); } else { s.replaceSelf(iip.getLatestSnapshotId(), fsdir.getINodeMap()); } removeSnapshottable(s); }
/** * 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); }
/** * Find the source root directory where the snapshot will be taken * for a given path. * * @return Snapshottable directory. * @throws IOException * Throw IOException when the given path does not lead to an * existing snapshottable directory. */ public INodeDirectory getSnapshottableRoot(final INodesInPath iip) throws IOException { final String path = iip.getPath(); final INodeDirectory dir = INodeDirectory.valueOf(iip.getLastINode(), path); if (!dir.isSnapshottable()) { throw new SnapshotException( "Directory is not a snapshottable directory: " + path); } return dir; }