Search in sources :

Example 11 with Inode

use of alluxio.master.file.meta.Inode in project alluxio by Alluxio.

the class FileSystemMaster method freeAndJournal.

/**
   * Implements free operation.
   * <p>
   * This may write to the journal as free operation may change the pinned state of inodes.
   *
   * @param inodePath inode of the path to free
   * @param options options to free
   * @param journalContext the journal context
   * @throws FileDoesNotExistException if the file does not exist
   * @throws AccessControlException if permission checking fails
   * @throws InvalidPathException if the given path is invalid
   * @throws UnexpectedAlluxioException if the file or directory can not be freed
   */
private void freeAndJournal(LockedInodePath inodePath, FreeOptions options, JournalContext journalContext) throws FileDoesNotExistException, UnexpectedAlluxioException, AccessControlException, InvalidPathException {
    Inode<?> inode = inodePath.getInode();
    if (inode.isDirectory() && !options.isRecursive() && ((InodeDirectory) inode).getNumberOfChildren() > 0) {
        // inode is nonempty, and we don't free a nonempty directory unless recursive is true
        throw new UnexpectedAlluxioException(ExceptionMessage.CANNOT_FREE_NON_EMPTY_DIR.getMessage(mInodeTree.getPath(inode)));
    }
    long opTimeMs = System.currentTimeMillis();
    List<Inode<?>> freeInodes = new ArrayList<>();
    freeInodes.add(inode);
    try (InodeLockList lockList = mInodeTree.lockDescendants(inodePath, InodeTree.LockMode.WRITE)) {
        freeInodes.addAll(lockList.getInodes());
        TempInodePathForDescendant tempInodePath = new TempInodePathForDescendant(inodePath);
        // We go through each inode.
        for (int i = freeInodes.size() - 1; i >= 0; i--) {
            Inode<?> freeInode = freeInodes.get(i);
            if (freeInode.isFile()) {
                if (freeInode.getPersistenceState() != PersistenceState.PERSISTED) {
                    throw new UnexpectedAlluxioException(ExceptionMessage.CANNOT_FREE_NON_PERSISTED_FILE.getMessage(mInodeTree.getPath(freeInode)));
                }
                if (freeInode.isPinned()) {
                    if (!options.isForced()) {
                        throw new UnexpectedAlluxioException(ExceptionMessage.CANNOT_FREE_PINNED_FILE.getMessage(mInodeTree.getPath(freeInode)));
                    }
                    // the path to inode for getPath should already be locked.
                    tempInodePath.setDescendant(freeInode, mInodeTree.getPath(freeInode));
                    SetAttributeOptions setAttributeOptions = SetAttributeOptions.defaults().setRecursive(false).setPinned(false);
                    setAttributeInternal(tempInodePath, false, opTimeMs, setAttributeOptions);
                    journalSetAttribute(tempInodePath, opTimeMs, setAttributeOptions, journalContext);
                }
                // Remove corresponding blocks from workers.
                mBlockMaster.removeBlocks(((InodeFile) freeInode).getBlockIds(), false);
            }
        }
    }
    Metrics.FILES_FREED.inc(freeInodes.size());
}
Also used : SetAttributeOptions(alluxio.master.file.options.SetAttributeOptions) InodeDirectory(alluxio.master.file.meta.InodeDirectory) Inode(alluxio.master.file.meta.Inode) TempInodePathForDescendant(alluxio.master.file.meta.TempInodePathForDescendant) InodeLockList(alluxio.master.file.meta.InodeLockList) UnexpectedAlluxioException(alluxio.exception.UnexpectedAlluxioException) ArrayList(java.util.ArrayList)

Example 12 with Inode

use of alluxio.master.file.meta.Inode in project alluxio by Alluxio.

the class FileSystemMaster method renameInternal.

/**
   * Implements renaming.
   *
   * @param srcInodePath the path of the rename source
   * @param dstInodePath the path to the rename destination
   * @param replayed whether the operation is a result of replaying the journal
   * @param options method options
   * @throws FileDoesNotExistException if a non-existent file is encountered
   * @throws InvalidPathException if an invalid path is encountered
   * @throws IOException if an I/O error is encountered
   */
private void renameInternal(LockedInodePath srcInodePath, LockedInodePath dstInodePath, boolean replayed, RenameOptions options) throws FileDoesNotExistException, InvalidPathException, IOException {
    // Rename logic:
    // 1. Change the source inode name to the destination name.
    // 2. Insert the source inode into the destination parent.
    // 3. Do UFS operations if necessary.
    // 4. Remove the source inode (reverting the name) from the source parent.
    // 5. Set the last modification times for both source and destination parent inodes.
    Inode<?> srcInode = srcInodePath.getInode();
    AlluxioURI srcPath = srcInodePath.getUri();
    AlluxioURI dstPath = dstInodePath.getUri();
    InodeDirectory srcParentInode = srcInodePath.getParentInodeDirectory();
    InodeDirectory dstParentInode = dstInodePath.getParentInodeDirectory();
    String srcName = srcPath.getName();
    String dstName = dstPath.getName();
    LOG.debug("Renaming {} to {}", srcPath, dstPath);
    // 1. Change the source inode name to the destination name.
    srcInode.setName(dstName);
    srcInode.setParentId(dstParentInode.getId());
    // 2. Insert the source inode into the destination parent.
    if (!dstParentInode.addChild(srcInode)) {
        // On failure, revert changes and throw exception.
        srcInode.setName(srcName);
        srcInode.setParentId(srcParentInode.getId());
        throw new InvalidPathException("Destination path: " + dstPath + " already exists.");
    }
    // If the source file is persisted, rename it in the UFS.
    try {
        if (!replayed && srcInode.isPersisted()) {
            MountTable.Resolution resolution = mMountTable.resolve(srcPath);
            String ufsSrcPath = resolution.getUri().toString();
            UnderFileSystem ufs = resolution.getUfs();
            String ufsDstUri = mMountTable.resolve(dstPath).getUri().toString();
            // Create ancestor directories from top to the bottom. We cannot use recursive create
            // parents here because the permission for the ancestors can be different.
            List<Inode<?>> dstInodeList = dstInodePath.getInodeList();
            Stack<Pair<String, MkdirsOptions>> ufsDirsToMakeWithOptions = new Stack<>();
            AlluxioURI curUfsDirPath = new AlluxioURI(ufsDstUri).getParent();
            // The dst inode does not exist yet, so the last inode in the list is the existing parent.
            for (int i = dstInodeList.size() - 1; i >= 0; i--) {
                if (ufs.isDirectory(curUfsDirPath.toString())) {
                    break;
                }
                Inode<?> curInode = dstInodeList.get(i);
                MkdirsOptions mkdirsOptions = MkdirsOptions.defaults().setCreateParent(false).setOwner(curInode.getOwner()).setGroup(curInode.getGroup()).setMode(new Mode(curInode.getMode()));
                ufsDirsToMakeWithOptions.push(new Pair<>(curUfsDirPath.toString(), mkdirsOptions));
                curUfsDirPath = curUfsDirPath.getParent();
            }
            while (!ufsDirsToMakeWithOptions.empty()) {
                Pair<String, MkdirsOptions> ufsDirAndPerm = ufsDirsToMakeWithOptions.pop();
                if (!ufs.mkdirs(ufsDirAndPerm.getFirst(), ufsDirAndPerm.getSecond())) {
                    throw new IOException(ExceptionMessage.FAILED_UFS_CREATE.getMessage(ufsDirAndPerm.getFirst()));
                }
            }
            boolean success;
            if (srcInode.isFile()) {
                success = ufs.renameFile(ufsSrcPath, ufsDstUri);
            } else {
                success = ufs.renameDirectory(ufsSrcPath, ufsDstUri);
            }
            if (!success) {
                throw new IOException(ExceptionMessage.FAILED_UFS_RENAME.getMessage(ufsSrcPath, ufsDstUri));
            }
        }
    } catch (Exception e) {
        // On failure, revert changes and throw exception.
        if (!dstParentInode.removeChild(dstName)) {
            LOG.error("Failed to revert rename changes. Alluxio metadata may be inconsistent.");
        }
        srcInode.setName(srcName);
        srcInode.setParentId(srcParentInode.getId());
        throw e;
    }
    // TODO(jiri): A crash between now and the time the rename operation is journaled will result in
    // an inconsistency between Alluxio and UFS.
    // 4. Remove the source inode (reverting the name) from the source parent. The name must be
    // reverted or removeChild will not be able to find the appropriate child entry since it is
    // keyed on the original name.
    srcInode.setName(srcName);
    if (!srcParentInode.removeChild(srcInode)) {
        // This should never happen.
        LOG.error("Failed to rename {} to {} in Alluxio. Alluxio and under storage may be " + "inconsistent.", srcPath, dstPath);
        srcInode.setName(dstName);
        if (!dstParentInode.removeChild(dstName)) {
            LOG.error("Failed to revert changes when renaming {} to {}. Alluxio metadata may be " + "inconsistent.", srcPath, dstPath);
        }
        srcInode.setName(srcName);
        srcInode.setParentId(srcParentInode.getId());
        throw new IOException("Failed to remove source path " + srcPath + " from parent");
    }
    srcInode.setName(dstName);
    // 5. Set the last modification times for both source and destination parent inodes.
    // Note this step relies on setLastModificationTimeMs being thread safe to guarantee the
    // correct behavior when multiple files are being renamed within a directory.
    dstParentInode.setLastModificationTimeMs(options.getOperationTimeMs());
    srcParentInode.setLastModificationTimeMs(options.getOperationTimeMs());
    Metrics.PATHS_RENAMED.inc();
}
Also used : MkdirsOptions(alluxio.underfs.options.MkdirsOptions) Mode(alluxio.security.authorization.Mode) IOException(java.io.IOException) MountTable(alluxio.master.file.meta.MountTable) InvalidPathException(alluxio.exception.InvalidPathException) AlluxioException(alluxio.exception.AlluxioException) BlockInfoException(alluxio.exception.BlockInfoException) FileAlreadyExistsException(alluxio.exception.FileAlreadyExistsException) IOException(java.io.IOException) InvalidPathException(alluxio.exception.InvalidPathException) AccessControlException(alluxio.exception.AccessControlException) InvalidFileSizeException(alluxio.exception.InvalidFileSizeException) FileDoesNotExistException(alluxio.exception.FileDoesNotExistException) FileAlreadyCompletedException(alluxio.exception.FileAlreadyCompletedException) DirectoryNotEmptyException(alluxio.exception.DirectoryNotEmptyException) UnexpectedAlluxioException(alluxio.exception.UnexpectedAlluxioException) Stack(java.util.Stack) InodeDirectory(alluxio.master.file.meta.InodeDirectory) Inode(alluxio.master.file.meta.Inode) UnderFileSystem(alluxio.underfs.UnderFileSystem) AlluxioURI(alluxio.AlluxioURI) InodePathPair(alluxio.master.file.meta.InodePathPair) Pair(alluxio.collections.Pair)

Example 13 with Inode

use of alluxio.master.file.meta.Inode in project alluxio by Alluxio.

the class FileSystemMaster method deleteInternal.

/**
   * Implements file deletion.
   *
   * @param inodePath the file {@link LockedInodePath}
   * @param replayed whether the operation is a result of replaying the journal
   * @param opTimeMs the time of the operation
   * @param deleteOptions the method optitions
   * @throws FileDoesNotExistException if a non-existent file is encountered
   * @throws IOException if an I/O error is encountered
   * @throws InvalidPathException if the specified path is the root
   * @throws DirectoryNotEmptyException if recursive is false and the file is a nonempty directory
   */
private void deleteInternal(LockedInodePath inodePath, boolean replayed, long opTimeMs, DeleteOptions deleteOptions) throws FileDoesNotExistException, IOException, DirectoryNotEmptyException, InvalidPathException {
    // journaled will result in an inconsistency between Alluxio and UFS.
    if (!inodePath.fullPathExists()) {
        return;
    }
    Inode<?> inode = inodePath.getInode();
    if (inode == null) {
        return;
    }
    boolean recursive = deleteOptions.isRecursive();
    boolean alluxioOnly = deleteOptions.isAlluxioOnly();
    if (inode.isDirectory() && !recursive && ((InodeDirectory) inode).getNumberOfChildren() > 0) {
        // true
        throw new DirectoryNotEmptyException(ExceptionMessage.DELETE_NONEMPTY_DIRECTORY_NONRECURSIVE, inode.getName());
    }
    if (mInodeTree.isRootId(inode.getId())) {
        // The root cannot be deleted.
        throw new InvalidPathException(ExceptionMessage.DELETE_ROOT_DIRECTORY.getMessage());
    }
    List<Inode<?>> delInodes = new ArrayList<>();
    delInodes.add(inode);
    try (InodeLockList lockList = mInodeTree.lockDescendants(inodePath, InodeTree.LockMode.WRITE)) {
        delInodes.addAll(lockList.getInodes());
        TempInodePathForDescendant tempInodePath = new TempInodePathForDescendant(inodePath);
        // file, we deal with the checkpoints and blocks as well.
        for (int i = delInodes.size() - 1; i >= 0; i--) {
            Inode<?> delInode = delInodes.get(i);
            // the path to delInode for getPath should already be locked.
            AlluxioURI alluxioUriToDel = mInodeTree.getPath(delInode);
            tempInodePath.setDescendant(delInode, alluxioUriToDel);
            // Currently, it will result in an inconsistency between Alluxio and UFS.
            if (!replayed && delInode.isPersisted()) {
                try {
                    // TODO(calvin): Add tests (ALLUXIO-1831)
                    if (mMountTable.isMountPoint(alluxioUriToDel)) {
                        unmountInternal(alluxioUriToDel);
                    } else {
                        // Delete the file in the under file system.
                        MountTable.Resolution resolution = mMountTable.resolve(alluxioUriToDel);
                        String ufsUri = resolution.getUri().toString();
                        UnderFileSystem ufs = resolution.getUfs();
                        boolean failedToDelete = false;
                        if (!alluxioOnly) {
                            if (delInode.isFile()) {
                                if (!ufs.deleteFile(ufsUri)) {
                                    failedToDelete = ufs.isFile(ufsUri);
                                    if (!failedToDelete) {
                                        LOG.warn("The file to delete does not exist in ufs: {}", ufsUri);
                                    }
                                }
                            } else {
                                if (!ufs.deleteDirectory(ufsUri, alluxio.underfs.options.DeleteOptions.defaults().setRecursive(true))) {
                                    failedToDelete = ufs.isDirectory(ufsUri);
                                    if (!failedToDelete) {
                                        LOG.warn("The directory to delete does not exist in ufs: {}", ufsUri);
                                    }
                                }
                            }
                            if (failedToDelete) {
                                LOG.error("Failed to delete {} from the under filesystem", ufsUri);
                                throw new IOException(ExceptionMessage.DELETE_FAILED_UFS.getMessage(ufsUri));
                            }
                        }
                    }
                } catch (InvalidPathException e) {
                    LOG.warn(e.getMessage());
                }
            }
            if (delInode.isFile()) {
                // Remove corresponding blocks from workers and delete metadata in master.
                mBlockMaster.removeBlocks(((InodeFile) delInode).getBlockIds(), true);
            }
            mInodeTree.deleteInode(tempInodePath, opTimeMs);
        }
    }
    Metrics.PATHS_DELETED.inc(delInodes.size());
}
Also used : InodeLockList(alluxio.master.file.meta.InodeLockList) ArrayList(java.util.ArrayList) DirectoryNotEmptyException(alluxio.exception.DirectoryNotEmptyException) IOException(java.io.IOException) MountTable(alluxio.master.file.meta.MountTable) InvalidPathException(alluxio.exception.InvalidPathException) InodeDirectory(alluxio.master.file.meta.InodeDirectory) Inode(alluxio.master.file.meta.Inode) TempInodePathForDescendant(alluxio.master.file.meta.TempInodePathForDescendant) UnderFileSystem(alluxio.underfs.UnderFileSystem) AlluxioURI(alluxio.AlluxioURI)

Aggregations

Inode (alluxio.master.file.meta.Inode)13 AlluxioURI (alluxio.AlluxioURI)6 ArrayList (java.util.ArrayList)6 AccessControlException (alluxio.exception.AccessControlException)5 InvalidPathException (alluxio.exception.InvalidPathException)4 InodeDirectory (alluxio.master.file.meta.InodeDirectory)4 InodeLockList (alluxio.master.file.meta.InodeLockList)4 IOException (java.io.IOException)4 DirectoryNotEmptyException (alluxio.exception.DirectoryNotEmptyException)3 FileAlreadyExistsException (alluxio.exception.FileAlreadyExistsException)3 FileDoesNotExistException (alluxio.exception.FileDoesNotExistException)3 UnexpectedAlluxioException (alluxio.exception.UnexpectedAlluxioException)3 MountTable (alluxio.master.file.meta.MountTable)3 TempInodePathForDescendant (alluxio.master.file.meta.TempInodePathForDescendant)3 Mode (alluxio.security.authorization.Mode)3 UnderFileSystem (alluxio.underfs.UnderFileSystem)3 AlluxioException (alluxio.exception.AlluxioException)2 BlockInfoException (alluxio.exception.BlockInfoException)2 FileAlreadyCompletedException (alluxio.exception.FileAlreadyCompletedException)2 InvalidFileSizeException (alluxio.exception.InvalidFileSizeException)2