SymlinkManifestGeneratorUtils.java

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.nativeworker;

import com.google.common.io.MoreFiles;
import com.google.common.io.RecursiveDeleteOption;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;

/**
 * Utility class for generating and managing symlink manifest tables.
 * This class provides methods to create symlink manifest files, clean up symlink data,
 * and handle TPCH-related table columns and types.
 */
public final class SymlinkManifestGeneratorUtils
{
    private SymlinkManifestGeneratorUtils() {}

    /**
     * Creates a symlink manifest file at the specified directory.
     * This method collects all file paths under the hiveTableLocation and writes them
     * to a symlink manifest file named "symlink_manifest" inside the specified symlinkManifestDir.
     *
     * @param hiveTableLocation the root directory of the Hive table files
     * @param symlinkManifestDir the directory where the symlink manifest should be created
     * @throws IOException if an I/O error occurs while creating the directories or writing the manifest
     */
    public static void createSymlinkManifest(Path hiveTableLocation, Path symlinkManifestDir) throws IOException
    {
        if (Files.notExists(symlinkManifestDir.getParent())) {
            Files.createDirectory(symlinkManifestDir.getParent());
        }

        if (Files.notExists(symlinkManifestDir)) {
            Files.createDirectory(symlinkManifestDir);
        }

        Path manifestFilePath = symlinkManifestDir.resolve("symlink_manifest");
        try (BufferedWriter writer = Files.newBufferedWriter(manifestFilePath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
            List<String> fileList = new ArrayList<>();
            collectDataFiles(hiveTableLocation, fileList);

            for (String filePath : fileList) {
                writer.write(filePath);
                writer.write(System.lineSeparator());
            }
        }
    }

    /**
     * Recursively collects all non-hidden file paths in the source directory.
     * If a directory is encountered, the method is called recursively to collect files in subdirectories.
     *
     * @param sourceDir the directory to start collecting files from
     * @param fileList the list where the collected file paths are stored
     * @throws IOException if an I/O error occurs while accessing the directory or files
     */
    private static void collectDataFiles(Path sourceDir, List<String> fileList) throws IOException
    {
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(sourceDir)) {
            for (Path entry : stream) {
                if (!Files.isHidden(entry)) {
                    if (Files.isDirectory(entry)) {
                        collectDataFiles(entry, fileList);
                    }
                    else {
                        fileList.add(entry.toString());
                    }
                }
            }
        }
    }

    /**
     * Cleans up (deletes) all files and subdirectories inside the specified directory.
     * This method walks through the directory tree and deletes files in reverse order to ensure
     * that directories are deleted after their contents.
     *
     * @param directory the root directory to clean up
     * @throws IOException if an I/O error occurs during file deletion
     */

    public static void cleanupSymlinkData(Path directory) throws IOException
    {
        MoreFiles.deleteRecursively(directory, RecursiveDeleteOption.ALLOW_INSECURE);
    }
}