Skip to content

Commit

Permalink
Avoid UUID.randomUUID() in startup code
Browse files Browse the repository at this point in the history
This is done because bootstrapping the plumbing
needed by the JDK to produce a UUID value
is expensive, it thus doesn't make sense to
pay this cost when the property isn't actually
needed
  • Loading branch information
geoand committed Jan 17, 2025
1 parent 35444ab commit b28445c
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class FileSystemOptions {
private boolean classPathResolvingEnabled = DEFAULT_CLASS_PATH_RESOLVING_ENABLED;
private boolean fileCachingEnabled = DEFAULT_FILE_CACHING_ENABLED;
private String fileCacheDir = DEFAULT_FILE_CACHING_DIR;
private String exactFileCacheDir;

/**
* Default constructor
Expand Down Expand Up @@ -128,7 +129,7 @@ public FileSystemOptions setFileCachingEnabled(boolean fileCachingEnabled) {
}

/**
* @return the configured file cache dir
* @return the base name of the configured file cache dir. Vert.x will append a random value to this when determining the effective value
*/
public String getFileCacheDir() {
return this.fileCacheDir;
Expand All @@ -147,13 +148,34 @@ public FileSystemOptions setFileCacheDir(String fileCacheDir) {
return this;
}

/**
* @return the configured exact file cache dir to be used as is
*/
public String getExactFileCacheDir() {
return this.exactFileCacheDir;
}

/**
* When vert.x reads a file that is packaged with the application it gets
* extracted to this directory first and subsequent reads will use the extracted
* file to get better IO performance.
*
* @param exactFileCacheDir the value
* @return a reference to this, so the API can be used fluently
*/
public FileSystemOptions setExactFileCacheDir(String exactFileCacheDir) {
this.exactFileCacheDir = exactFileCacheDir;
return this;
}


@Override
public String toString() {
return "FileSystemOptions{" +
"classPathResolvingEnabled=" + classPathResolvingEnabled +
", fileCachingEnabled=" + fileCachingEnabled +
", fileCacheDir=" + fileCacheDir +
", exactFileCacheDir=" + exactFileCacheDir +
'}';
}
}
29 changes: 23 additions & 6 deletions vertx-core/src/main/java/io/vertx/core/file/impl/FileCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import java.io.InputStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
Expand All @@ -27,8 +26,8 @@

public class FileCache {

static FileCache setupCache(String fileCacheDir) {
FileCache cache = new FileCache(setupCacheDir(fileCacheDir));
static FileCache setupCache(String fileCacheDir, boolean isEffectiveValue) {
FileCache cache = new FileCache(setupCacheDir(fileCacheDir, isEffectiveValue));
// Add shutdown hook to delete on exit
cache.registerShutdownHook();
return cache;
Expand All @@ -37,16 +36,15 @@ static FileCache setupCache(String fileCacheDir) {
/**
* Prepares the cache directory to be used in the application.
*/
static File setupCacheDir(String fileCacheDir) {
static File setupCacheDir(String fileCacheDir, boolean isEffectiveValue) {
// ensure that the argument doesn't end with separator
if (fileCacheDir.endsWith(File.separator)) {
fileCacheDir = fileCacheDir.substring(0, fileCacheDir.length() - File.separator.length());
}

// the cacheDir will be suffixed a unique id to avoid eavesdropping from other processes/users
// also this ensures that if process A deletes cacheDir, it won't affect process B
String cacheDirName = fileCacheDir + "-" + UUID.randomUUID();
File cacheDir = new File(cacheDirName);
File cacheDir = isEffectiveValue ? new File(fileCacheDir) : effectiveCacheDir(fileCacheDir);
// Create the cache directory
try {
if (Utils.isWindows()) {
Expand All @@ -63,6 +61,25 @@ static File setupCacheDir(String fileCacheDir) {
return cacheDir;
}

private static File effectiveCacheDir(String fileCacheDir) {
for(int i = 0; i < 10; i++) {
try {
// attempt to create a file using a really quick random value
String cacheDirName = fileCacheDir + "-" + System.nanoTime();
File file = new File(cacheDirName);
Files.createDirectories(file.toPath());
return file;
} catch(FileAlreadyExistsException ignore) {
} catch (IOException ignore) {
// hope that the fallback will work
break;
}
}

String cacheDirName = fileCacheDir + "-" + UUID.randomUUID();
return new File(cacheDirName);
}

private Thread shutdownHook;
private File cacheDir;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,12 @@ public FileResolverImpl(FileSystemOptions fileSystemOptions) {
enableCPResolving = fileSystemOptions.isClassPathResolvingEnabled();

if (enableCPResolving) {
cache = FileCache.setupCache(fileSystemOptions.getFileCacheDir());
String exactFileCacheDir = fileSystemOptions.getExactFileCacheDir();
if (exactFileCacheDir != null) {
cache = FileCache.setupCache(exactFileCacheDir, true);
} else {
cache = FileCache.setupCache(fileSystemOptions.getFileCacheDir(), false);
}
} else {
cache = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ public DefaultDeploymentManager(VertxImpl vertx) {
}

private String generateDeploymentID() {
return UUID.randomUUID().toString();
if (vertx.isClustered() && vertx.haManager()!=null) {
// in this case we need a globally unique id
return UUID.randomUUID().toString();
}
// in the default case we want to generate the ID as fast as possible
return Long.valueOf(new Random().nextLong()).toString();
}

public Future<Void> undeploy(String deploymentID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,12 @@ public void testGetTheCacheDirWithoutHacks() {
if (cacheDir != null) {
assertTrue(cacheDir.startsWith(cacheBaseDir + "-"));
// strip the remaining
String uuid = cacheDir.substring(cacheBaseDir.length() + 1);
String val = cacheDir.substring(cacheBaseDir.length() + 1);
try {
UUID.fromString(uuid);
Long.parseLong(val);
// OK
} catch (Exception e) {
fail("Expected a UUID");
fail("Expected a Long");
}
}
}
Expand Down

0 comments on commit b28445c

Please sign in to comment.