< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java

Print this page

        

*** 20,35 **** * or visit www.oracle.com if you need additional information or have any * questions. */ package org.graalvm.compiler.debug; import java.io.IOException; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; - import java.util.HashMap; - import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; --- 20,36 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package org.graalvm.compiler.debug; + import java.io.File; import java.io.IOException; + import java.nio.file.FileAlreadyExistsException; + import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicLong; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues;
*** 37,94 **** * Miscellaneous methods for modifying and generating file system paths. */ public class PathUtilities { private static final AtomicLong globalTimeStamp = new AtomicLong(); - /** - * This generates a per thread persistent id to aid mapping related dump files with each other. - */ - private static final ThreadLocal<PerThreadSequence> threadDumpId = new ThreadLocal<>(); - private static final AtomicInteger dumpId = new AtomicInteger(); - - static class PerThreadSequence { - final int threadID; - HashMap<String, Integer> sequences = new HashMap<>(2); - - PerThreadSequence(int threadID) { - this.threadID = threadID; - } - - String generateID(String extension) { - Integer box = sequences.get(extension); - if (box == null) { - sequences.put(extension, 1); - return Integer.toString(threadID); - } else { - sequences.put(extension, box + 1); - return Integer.toString(threadID) + '-' + box; - } - } - } - - private static String getThreadDumpId(String extension) { - PerThreadSequence id = threadDumpId.get(); - if (id == null) { - id = new PerThreadSequence(dumpId.incrementAndGet()); - threadDumpId.set(id); - } - return id.generateID(extension); - } - - /** - * Prepends a period (i.e., {@code '.'}) to an non-null, non-empty string representation a file - * extension if the string does not already start with a period. - * - * @return {@code ext} unmodified if it is null, empty or already starts with a period other - * {@code "." + ext} - */ - public static String formatExtension(String ext) { - if (ext == null || ext.length() == 0) { - return ""; - } - return "." + ext; - } /** * Gets a time stamp for the current process. This method will always return the same value for * the current VM execution. */ --- 38,47 ----
*** 98,165 **** } return globalTimeStamp.get(); } /** - * Generates a {@link Path} using the format "%s-%d_%d%s" with the {@code baseNameOption}, a - * {@link #getGlobalTimeStamp() global timestamp} , {@link #getThreadDumpId a per thread unique - * id} and an optional {@code extension}. - * - * @return the output file path or null if the flag is null - */ - public static Path getPath(OptionValues options, OptionKey<String> baseNameOption, String extension) throws IOException { - return getPath(options, baseNameOption, extension, true); - } - - /** - * Generate a {@link Path} using the format "%s-%d_%s" with the {@code baseNameOption}, a - * {@link #getGlobalTimeStamp() global timestamp} and an optional {@code extension} . - * - * @return the output file path or null if the flag is null - */ - public static Path getPathGlobal(OptionValues options, OptionKey<String> baseNameOption, String extension) throws IOException { - return getPath(options, baseNameOption, extension, false); - } - - private static Path getPath(OptionValues options, OptionKey<String> baseNameOption, String extension, boolean includeThreadId) throws IOException { - if (baseNameOption.getValue(options) == null) { - return null; - } - String ext = formatExtension(extension); - final String name = includeThreadId - ? String.format("%s-%d_%s%s", baseNameOption.getValue(options), getGlobalTimeStamp(), getThreadDumpId(ext), ext) - : String.format("%s-%d%s", baseNameOption.getValue(options), getGlobalTimeStamp(), ext); - Path result = Paths.get(name); - if (result.isAbsolute()) { - return result; - } - Path dumpDir = DebugOptions.getDumpDirectory(options); - return dumpDir.resolve(name).normalize(); - } - - /** * Gets a value based on {@code name} that can be passed to {@link Paths#get(String, String...)} * without causing an {@link InvalidPathException}. * * @return {@code name} with all characters invalid for the current file system replaced by * {@code '_'} */ public static String sanitizeFileName(String name) { try { ! Paths.get(name); return name; } catch (InvalidPathException e) { // fall through } StringBuilder buf = new StringBuilder(name.length()); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); try { Paths.get(String.valueOf(c)); } catch (InvalidPathException e) { - buf.append('_'); } ! buf.append(c); } return buf.toString(); } } --- 51,140 ---- } return globalTimeStamp.get(); } /** * Gets a value based on {@code name} that can be passed to {@link Paths#get(String, String...)} * without causing an {@link InvalidPathException}. * * @return {@code name} with all characters invalid for the current file system replaced by * {@code '_'} */ public static String sanitizeFileName(String name) { try { ! Path path = Paths.get(name); ! if (path.getNameCount() == 0) { return name; + } } catch (InvalidPathException e) { // fall through } StringBuilder buf = new StringBuilder(name.length()); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); + if (c != File.separatorChar && c != ' ' && !Character.isISOControl(c)) { try { Paths.get(String.valueOf(c)); + buf.append(c); + continue; } catch (InvalidPathException e) { } ! } ! buf.append('_'); } return buf.toString(); } + + /** + * A maximum file name length supported by most file systems. There is no platform independent + * way to get this in Java. + */ + private static final int MAX_FILE_NAME_LENGTH = 255; + + private static final String ELLIPSIS = "..."; + + static Path createUnique(OptionValues options, OptionKey<String> baseNameOption, String id, String label, String ext, boolean createDirectory) throws IOException { + String uniqueTag = ""; + int dumpCounter = 1; + String prefix; + if (id == null) { + prefix = baseNameOption.getValue(options); + int slash = prefix.lastIndexOf(File.separatorChar); + prefix = prefix.substring(slash + 1); + } else { + prefix = id; + } + for (;;) { + int fileNameLengthWithoutLabel = uniqueTag.length() + ext.length() + prefix.length() + "[]".length(); + int labelLengthLimit = MAX_FILE_NAME_LENGTH - fileNameLengthWithoutLabel; + String fileName; + if (labelLengthLimit < ELLIPSIS.length()) { + // This means `id` is very long + String suffix = uniqueTag + ext; + int idLengthLimit = Math.min(MAX_FILE_NAME_LENGTH - suffix.length(), prefix.length()); + fileName = sanitizeFileName(prefix.substring(0, idLengthLimit) + suffix); + } else { + if (label == null) { + fileName = sanitizeFileName(prefix + uniqueTag + ext); + } else { + String adjustedLabel = label; + if (label.length() > labelLengthLimit) { + adjustedLabel = label.substring(0, labelLengthLimit - ELLIPSIS.length()) + ELLIPSIS; + } + fileName = sanitizeFileName(prefix + '[' + adjustedLabel + ']' + uniqueTag + ext); + } + } + Path dumpDir = DebugOptions.getDumpDirectory(options); + Path result = Paths.get(dumpDir.toString(), fileName); + try { + if (createDirectory) { + return Files.createDirectory(result); + } else { + return Files.createFile(result); + } + } catch (FileAlreadyExistsException e) { + uniqueTag = "_" + dumpCounter++; + } + } + } + }
< prev index next >