From b28445c7478036eb9cc8df79083a19bdf22c52ce Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 16 Jan 2025 13:33:44 +0200 Subject: [PATCH] Avoid UUID.randomUUID() in startup code 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 --- .../io/vertx/core/file/FileSystemOptions.java | 24 ++++++++++++++- .../io/vertx/core/file/impl/FileCache.java | 29 +++++++++++++++---- .../core/file/impl/FileResolverImpl.java | 7 ++++- .../deployment/DefaultDeploymentManager.java | 7 ++++- .../tests/file/FileResolverTestBase.java | 6 ++-- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/vertx-core/src/main/java/io/vertx/core/file/FileSystemOptions.java b/vertx-core/src/main/java/io/vertx/core/file/FileSystemOptions.java index 66fb5cfc2b6..8759c80abf5 100644 --- a/vertx-core/src/main/java/io/vertx/core/file/FileSystemOptions.java +++ b/vertx-core/src/main/java/io/vertx/core/file/FileSystemOptions.java @@ -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 @@ -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; @@ -147,6 +148,26 @@ 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() { @@ -154,6 +175,7 @@ public String toString() { "classPathResolvingEnabled=" + classPathResolvingEnabled + ", fileCachingEnabled=" + fileCachingEnabled + ", fileCacheDir=" + fileCacheDir + + ", exactFileCacheDir=" + exactFileCacheDir + '}'; } } diff --git a/vertx-core/src/main/java/io/vertx/core/file/impl/FileCache.java b/vertx-core/src/main/java/io/vertx/core/file/impl/FileCache.java index 5156e9e6f14..041ce44d98f 100644 --- a/vertx-core/src/main/java/io/vertx/core/file/impl/FileCache.java +++ b/vertx-core/src/main/java/io/vertx/core/file/impl/FileCache.java @@ -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; @@ -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; @@ -37,7 +36,7 @@ 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()); @@ -45,8 +44,7 @@ static File setupCacheDir(String fileCacheDir) { // 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()) { @@ -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; diff --git a/vertx-core/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java b/vertx-core/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java index b70931d7241..0dc444c675f 100644 --- a/vertx-core/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java +++ b/vertx-core/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java @@ -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; } diff --git a/vertx-core/src/main/java/io/vertx/core/impl/deployment/DefaultDeploymentManager.java b/vertx-core/src/main/java/io/vertx/core/impl/deployment/DefaultDeploymentManager.java index 089b26894f2..8d84ad734d3 100644 --- a/vertx-core/src/main/java/io/vertx/core/impl/deployment/DefaultDeploymentManager.java +++ b/vertx-core/src/main/java/io/vertx/core/impl/deployment/DefaultDeploymentManager.java @@ -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 undeploy(String deploymentID) { diff --git a/vertx-core/src/test/java/io/vertx/tests/file/FileResolverTestBase.java b/vertx-core/src/test/java/io/vertx/tests/file/FileResolverTestBase.java index 32d87e4c6d3..124b282300e 100644 --- a/vertx-core/src/test/java/io/vertx/tests/file/FileResolverTestBase.java +++ b/vertx-core/src/test/java/io/vertx/tests/file/FileResolverTestBase.java @@ -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"); } } }