/** * Remove a file/directory from the namespace. * <p> * For large directories, deletion is incremental. The blocks under * the directory are collected and deleted a small number at a time holding * the {@link FSNamesystem} lock. * <p> * For small directory or file the deletion is done in one shot. * * @param fsn namespace * @param src path name to be deleted * @param recursive boolean true to apply to all sub-directories recursively * @param logRetryCache whether to record RPC ids in editlog for retry cache * rebuilding * @return blocks collected from the deleted path * @throws IOException */ static BlocksMapUpdateInfo delete( FSNamesystem fsn, String src, boolean recursive, boolean logRetryCache) throws IOException { FSDirectory fsd = fsn.getFSDirectory(); FSPermissionChecker pc = fsd.getPermissionChecker(); byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src); src = fsd.resolvePath(pc, src, pathComponents); final INodesInPath iip = fsd.getINodesInPath4Write(src, false); if (!recursive && fsd.isNonEmptyDirectory(iip)) { throw new PathIsNotEmptyDirectoryException(src + " is non empty"); } if (fsd.isPermissionEnabled()) { fsd.checkPermission(pc, iip, false, null, FsAction.WRITE, null, FsAction.ALL, true); } if (recursive && fsd.isNonEmptyDirectory(iip)) { checkProtectedDescendants(fsd, fsd.normalizePath(src)); } return deleteInternal(fsn, src, iip, logRetryCache); }
@Test public void testChildDeletion() throws Throwable { ServiceRecord app = createRecord("app1", PersistencePolicies.APPLICATION, "app", null); ServiceRecord container = createRecord("container1", PersistencePolicies.CONTAINER, "container", null); operations.bind("/app", app, BindFlags.OVERWRITE); operations.bind("/app/container", container, BindFlags.OVERWRITE); try { int p = purge("/", "app1", PersistencePolicies.APPLICATION, RegistryAdminService.PurgePolicy.FailOnChildren); fail("expected a failure, got a purge count of " + p); } catch (PathIsNotEmptyDirectoryException expected) { // expected } }
/** * Remove a file/directory from the namespace. * <p> * For large directories, deletion is incremental. The blocks under * the directory are collected and deleted a small number at a time holding * the {@link FSNamesystem} lock. * <p> * For small directory or file the deletion is done in one shot. * */ static BlocksMapUpdateInfo delete( FSNamesystem fsn, String src, boolean recursive, boolean logRetryCache) throws IOException { FSDirectory fsd = fsn.getFSDirectory(); FSPermissionChecker pc = fsd.getPermissionChecker(); byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src); src = fsd.resolvePath(pc, src, pathComponents); final INodesInPath iip = fsd.getINodesInPath4Write(src, false); if (!recursive && fsd.isNonEmptyDirectory(iip)) { throw new PathIsNotEmptyDirectoryException(src + " is non empty"); } if (fsd.isPermissionEnabled()) { fsd.checkPermission(pc, iip, false, null, FsAction.WRITE, null, FsAction.ALL, true); } return deleteInternal(fsn, src, iip, logRetryCache); }
/** @throws Exception If failed. */ public void testDeleteFailsIfNonRecursive() throws Exception { Path fsHome = new Path(primaryFsUri); Path someDir3 = new Path(fsHome, "/someDir1/someDir2/someDir3"); FSDataOutputStream os = fs.create(someDir3, EnumSet.noneOf(CreateFlag.class), Options.CreateOpts.perms(FsPermission.getDefault())); os.close(); final Path someDir2 = new Path(fsHome, "/someDir1/someDir2"); GridTestUtils.assertThrows(log, new Callable<Object>() { @Override public Object call() throws Exception { fs.delete(someDir2, false); return null; } }, PathIsNotEmptyDirectoryException.class, null); assertPathExists(fs, someDir2); assertPathExists(fs, someDir3); }
@Override protected void processPath(PathData item) throws IOException { if (!item.stat.isDirectory()) { throw new PathIsNotDirectoryException(item.toString()); } if (item.fs.listStatus(item.path).length == 0) { if (!item.fs.delete(item.path, false)) { throw new PathIOException(item.toString()); } } else if (!ignoreNonEmpty) { throw new PathIsNotEmptyDirectoryException(item.toString()); } }
@Test public void testDeleteNonEmpty() throws Throwable { putExampleServiceEntry(ENTRY_PATH, 0); try { operations.delete(PARENT_PATH, false); fail("Expected a failure"); } catch (PathIsNotEmptyDirectoryException expected) { // expected; ignore } operations.delete(PARENT_PATH, true); }
@Test public void testRMNonRf() throws Throwable { mkPath("/rm", CreateMode.PERSISTENT); mkPath("/rm/child", CreateMode.PERSISTENT); try { curatorService.zkDelete("/rm", false, null); fail("expected a failure"); } catch (PathIsNotEmptyDirectoryException expected) { } }
/** * Cast IO exception to IGFS exception. * * @param msg Error message. * @param e IO exception. * @return IGFS exception. */ public static IgfsException cast(String msg, IOException e) { if (e instanceof FileNotFoundException) return new IgfsPathNotFoundException(e); else if (e instanceof ParentNotDirectoryException) return new IgfsParentNotDirectoryException(msg, e); else if (e instanceof PathIsNotEmptyDirectoryException) return new IgfsDirectoryNotEmptyException(e); else if (e instanceof PathExistsException) return new IgfsPathAlreadyExistsException(msg, e); else return new IgfsException(msg, e); }
/** * Remove a file/directory from the namespace. * <p> * For large directories, deletion is incremental. The blocks under * the directory are collected and deleted a small number at a time holding * the {@link FSNamesystem} lock. * <p> * For small directory or file the deletion is done in one shot. * * @see ClientProtocol#delete(String, boolean) for description of exceptions */ private boolean deleteInternal(String src, boolean recursive, boolean enforcePermission, boolean logRetryCache) throws AccessControlException, SafeModeException, UnresolvedLinkException, IOException { BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo(); List<INode> removedINodes = new ChunkedArrayList<INode>(); FSPermissionChecker pc = getPermissionChecker(); checkOperation(OperationCategory.WRITE); byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src); boolean ret = false; waitForLoadingFSImage(); writeLock(); try { checkOperation(OperationCategory.WRITE); checkNameNodeSafeMode("Cannot delete " + src); src = resolvePath(src, pathComponents); if (!recursive && dir.isNonEmptyDirectory(src)) { throw new PathIsNotEmptyDirectoryException(src + " is non empty"); } if (enforcePermission && isPermissionEnabled) { checkPermission(pc, src, false, null, FsAction.WRITE, null, FsAction.ALL, true, false); } long mtime = now(); // Unlink the target directory from directory tree long filesRemoved = dir.delete(src, collectedBlocks, removedINodes, mtime); if (filesRemoved < 0) { return false; } getEditLog().logDelete(src, mtime, logRetryCache); incrDeletedFileCount(filesRemoved); // Blocks/INodes will be handled later removePathAndBlocks(src, null, removedINodes, true); ret = true; } finally { writeUnlock(); } getEditLog().logSync(); removeBlocks(collectedBlocks); // Incremental deletion of blocks collectedBlocks.clear(); if (NameNode.stateChangeLog.isDebugEnabled()) { NameNode.stateChangeLog.debug("DIR* Namesystem.delete: " + src +" is removed"); } return ret; }
/** * Delete a path. * * If the operation returns without an error then the entry has been * deleted. * @param path path delete recursively * @param recursive recursive flag * @throws PathNotFoundException path is not in the registry. * @throws InvalidPathnameException the path is invalid. * @throws PathIsNotEmptyDirectoryException path has child entries, but * recursive is false. * @throws IOException Any other IO Exception * */ void delete(String path, boolean recursive) throws PathNotFoundException, PathIsNotEmptyDirectoryException, InvalidPathnameException, IOException;