< 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,16 +20,17 @@
* 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.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;
@@ -37,58 +38,10 @@
* 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.
*/
@@ -98,68 +51,90 @@
}
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);
+ 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('_');
}
- buf.append(c);
+ }
+ 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 >