Skip to content

Commit 7e04c3a

Browse files
committed
Avoid UUID.randomUUID() in file system related 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
1 parent 201cdad commit 7e04c3a

File tree

9 files changed

+220
-9
lines changed

9 files changed

+220
-9
lines changed

vertx-core/src/main/generated/io/vertx/core/file/FileSystemOptionsConverter.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, FileSys
2929
obj.setFileCacheDir((String)member.getValue());
3030
}
3131
break;
32+
case "exactFileCacheDir":
33+
if (member.getValue() instanceof String) {
34+
obj.setExactFileCacheDir((String)member.getValue());
35+
}
36+
break;
3237
}
3338
}
3439
}
@@ -43,5 +48,8 @@ static void toJson(FileSystemOptions obj, java.util.Map<String, Object> json) {
4348
if (obj.getFileCacheDir() != null) {
4449
json.put("fileCacheDir", obj.getFileCacheDir());
4550
}
51+
if (obj.getExactFileCacheDir() != null) {
52+
json.put("exactFileCacheDir", obj.getExactFileCacheDir());
53+
}
4654
}
4755
}

vertx-core/src/main/java/io/vertx/core/file/FileSystemOptions.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,17 @@ public class FileSystemOptions {
4545
*/
4646
public static final String DEFAULT_FILE_CACHING_DIR = SysProps.FILE_CACHE_DIR.get();
4747

48+
/**
49+
* The default exact file caching dir, which is {@code null} as {@link FileSystemOptions#setExactFileCacheDir}
50+
* is meant to be used by advanced integrations that can guarantee on their own that the cache dir
51+
* will be unique
52+
*/
53+
public static final String DEFAULT_EXACT_FILE_CACHING_DIR = null;
54+
4855
private boolean classPathResolvingEnabled = DEFAULT_CLASS_PATH_RESOLVING_ENABLED;
4956
private boolean fileCachingEnabled = DEFAULT_FILE_CACHING_ENABLED;
5057
private String fileCacheDir = DEFAULT_FILE_CACHING_DIR;
58+
private String exactFileCacheDir = DEFAULT_EXACT_FILE_CACHING_DIR;
5159

5260
/**
5361
* Default constructor
@@ -128,7 +136,7 @@ public FileSystemOptions setFileCachingEnabled(boolean fileCachingEnabled) {
128136
}
129137

130138
/**
131-
* @return the configured file cache dir
139+
* @return the base name of the configured file cache dir. Vert.x will append a random value to this when determining the effective value
132140
*/
133141
public String getFileCacheDir() {
134142
return this.fileCacheDir;
@@ -147,13 +155,34 @@ public FileSystemOptions setFileCacheDir(String fileCacheDir) {
147155
return this;
148156
}
149157

158+
/**
159+
* @return the configured exact file cache dir to be used as is
160+
*/
161+
public String getExactFileCacheDir() {
162+
return this.exactFileCacheDir;
163+
}
164+
165+
/**
166+
* When vert.x reads a file that is packaged with the application it gets
167+
* extracted to this directory first and subsequent reads will use the extracted
168+
* file to get better IO performance.
169+
*
170+
* @param exactFileCacheDir the value
171+
* @return a reference to this, so the API can be used fluently
172+
*/
173+
public FileSystemOptions setExactFileCacheDir(String exactFileCacheDir) {
174+
this.exactFileCacheDir = exactFileCacheDir;
175+
return this;
176+
}
177+
150178

151179
@Override
152180
public String toString() {
153181
return "FileSystemOptions{" +
154182
"classPathResolvingEnabled=" + classPathResolvingEnabled +
155183
", fileCachingEnabled=" + fileCachingEnabled +
156184
", fileCacheDir=" + fileCacheDir +
185+
", exactFileCacheDir=" + exactFileCacheDir +
157186
'}';
158187
}
159188
}

vertx-core/src/main/java/io/vertx/core/file/impl/FileCache.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import java.io.InputStream;
1919
import java.nio.file.FileAlreadyExistsException;
2020
import java.nio.file.Files;
21-
import java.nio.file.Path;
2221
import java.nio.file.StandardCopyOption;
2322
import java.nio.file.attribute.PosixFilePermission;
2423
import java.nio.file.attribute.PosixFilePermissions;
@@ -27,8 +26,8 @@
2726

2827
public class FileCache {
2928

30-
static FileCache setupCache(String fileCacheDir) {
31-
FileCache cache = new FileCache(setupCacheDir(fileCacheDir));
29+
public static FileCache setupCache(String fileCacheDir, boolean isEffectiveValue) {
30+
FileCache cache = new FileCache(setupCacheDir(fileCacheDir, isEffectiveValue));
3231
// Add shutdown hook to delete on exit
3332
cache.registerShutdownHook();
3433
return cache;
@@ -37,16 +36,15 @@ static FileCache setupCache(String fileCacheDir) {
3736
/**
3837
* Prepares the cache directory to be used in the application.
3938
*/
40-
static File setupCacheDir(String fileCacheDir) {
39+
static File setupCacheDir(String fileCacheDir, boolean isEffectiveValue) {
4140
// ensure that the argument doesn't end with separator
4241
if (fileCacheDir.endsWith(File.separator)) {
4342
fileCacheDir = fileCacheDir.substring(0, fileCacheDir.length() - File.separator.length());
4443
}
4544

4645
// the cacheDir will be suffixed a unique id to avoid eavesdropping from other processes/users
4746
// also this ensures that if process A deletes cacheDir, it won't affect process B
48-
String cacheDirName = fileCacheDir + "-" + UUID.randomUUID();
49-
File cacheDir = new File(cacheDirName);
47+
File cacheDir = isEffectiveValue ? new File(fileCacheDir) : new File(fileCacheDir + "-" + UUID.randomUUID());
5048
// Create the cache directory
5149
try {
5250
if (Utils.isWindows()) {
@@ -220,7 +218,7 @@ private void fileNameCheck(File file) throws IOException {
220218
}
221219
}
222220

223-
private File getCacheDir() {
221+
public File getCacheDir() {
224222
File currentCacheDir = cacheDir;
225223
if (currentCacheDir == null) {
226224
throw new IllegalStateException("cacheDir has been removed. FileResolver is closing?");

vertx-core/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ public FileResolverImpl(FileSystemOptions fileSystemOptions) {
6868
enableCPResolving = fileSystemOptions.isClassPathResolvingEnabled();
6969

7070
if (enableCPResolving) {
71-
cache = FileCache.setupCache(fileSystemOptions.getFileCacheDir());
71+
String exactFileCacheDir = fileSystemOptions.getExactFileCacheDir();
72+
if (exactFileCacheDir != null) {
73+
cache = FileCache.setupCache(exactFileCacheDir, true);
74+
} else {
75+
cache = FileCache.setupCache(fileSystemOptions.getFileCacheDir(), false);
76+
}
7277
} else {
7378
cache = null;
7479
}

vertx-core/src/test/java/io/vertx/tests/file/FileCacheTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
package io.vertx.tests.file;
1212

1313
import io.vertx.core.VertxException;
14+
import io.vertx.core.file.FileSystemOptions;
1415
import io.vertx.core.file.impl.FileCache;
16+
import io.vertx.core.file.impl.FileResolverImpl;
1517
import io.vertx.test.core.VertxTestBase;
1618
import org.junit.Test;
1719

@@ -40,4 +42,20 @@ public void testMutateCacheContentOnly() throws IOException {
4042
assertEquals("protected", new String(Files.readAllBytes(other.toPath())));
4143
}
4244
}
45+
46+
@Test
47+
public void testGetTheExactCacheDirWithoutHacks() throws IOException {
48+
String cacheBaseDir;
49+
try {
50+
cacheBaseDir = new File(System.getProperty("java.io.tmpdir", ".") + File.separator + "vertx-cache").getCanonicalPath();
51+
} catch (IOException e) {
52+
throw new IllegalStateException("Cannot resolve the canonical path to the cache dir", e);
53+
}
54+
55+
String cacheDir = FileCache.setupCache(cacheBaseDir + "-exact", true).getCacheDir().getCanonicalPath();
56+
assertTrue(cacheDir.startsWith(cacheBaseDir + "-"));
57+
// strip the remaining
58+
String remaining = cacheDir.substring(cacheBaseDir.length() + 1);
59+
assertEquals(remaining, "exact");
60+
}
4361
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.vertx.tests.file.cachedir;
2+
3+
import io.vertx.core.VertxOptions;
4+
import io.vertx.core.file.FileSystemOptions;
5+
import io.vertx.core.internal.VertxInternal;
6+
import io.vertx.core.spi.file.FileResolver;
7+
import io.vertx.test.core.VertxTestBase;
8+
import java.io.File;
9+
import java.io.IOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.Paths;
13+
import org.junit.Assert;
14+
import org.junit.Test;
15+
16+
public class ExactDirDoesNotExistTest extends VertxTestBase {
17+
18+
private final Path cacheBaseDir;
19+
20+
public ExactDirDoesNotExistTest() throws IOException {
21+
cacheBaseDir = Files.createTempDirectory("cache-does-not-exist");
22+
Files.deleteIfExists(cacheBaseDir);
23+
Assert.assertFalse(Files.exists(cacheBaseDir));
24+
}
25+
26+
@Override
27+
protected VertxOptions getOptions() {
28+
return new VertxOptions(super.getOptions())
29+
.setFileSystemOptions(new FileSystemOptions().setFileCachingEnabled(true).setExactFileCacheDir(cacheBaseDir.toAbsolutePath().toString()));
30+
}
31+
32+
@Test
33+
public void test() throws IOException {
34+
try (FileResolver fileResolver = ((VertxInternal) vertx).fileResolver()) {
35+
File file = fileResolver.resolveFile("conf.json");
36+
Assert.assertEquals(cacheBaseDir.resolve("conf.json").toFile(), file);
37+
}
38+
}
39+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.vertx.tests.file.cachedir;
2+
3+
import io.vertx.core.Vertx;
4+
import io.vertx.core.VertxOptions;
5+
import io.vertx.core.file.FileSystemOptions;
6+
import io.vertx.core.internal.VertxInternal;
7+
import io.vertx.core.spi.file.FileResolver;
8+
import io.vertx.test.core.VertxTestBase;
9+
import java.io.File;
10+
import java.io.IOException;
11+
import java.nio.file.Files;
12+
import java.nio.file.Path;
13+
import java.nio.file.Paths;
14+
import org.junit.Assert;
15+
import org.junit.Test;
16+
17+
public class ExactDirExistsButIsFileTest {
18+
19+
private final Path cacheBaseDir;
20+
21+
public ExactDirExistsButIsFileTest() throws IOException {
22+
cacheBaseDir = Files.createTempDirectory("cache-exists-but-is-file");
23+
Files.deleteIfExists(cacheBaseDir);
24+
Files.createFile(cacheBaseDir);
25+
Assert.assertTrue(Files.exists(cacheBaseDir));
26+
Assert.assertFalse(Files.isDirectory(cacheBaseDir));
27+
}
28+
29+
@Test
30+
public void test() {
31+
Assert.assertThrows(IllegalStateException.class, () -> {
32+
Vertx.builder().with(new VertxOptions().setFileSystemOptions(new FileSystemOptions().setFileCachingEnabled(true).setExactFileCacheDir(cacheBaseDir.toAbsolutePath().toString()))).build();
33+
});
34+
}
35+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.vertx.tests.file.cachedir;
2+
3+
import io.vertx.core.VertxOptions;
4+
import io.vertx.core.file.FileSystemOptions;
5+
import io.vertx.core.internal.VertxInternal;
6+
import io.vertx.core.spi.file.FileResolver;
7+
import io.vertx.test.core.VertxTestBase;
8+
import java.io.File;
9+
import java.io.IOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.Paths;
13+
import org.junit.Assert;
14+
import org.junit.Test;
15+
16+
public class ExactDirExistsTest extends VertxTestBase {
17+
18+
private final Path cacheBaseDir;
19+
20+
public ExactDirExistsTest() throws IOException {
21+
cacheBaseDir = Paths.get(System.getProperty("java.io.tmpdir", "."), "cache-exists");
22+
Files.deleteIfExists(cacheBaseDir);
23+
Files.createDirectories(cacheBaseDir);
24+
Assert.assertTrue(Files.exists(cacheBaseDir));
25+
Assert.assertTrue(Files.isDirectory(cacheBaseDir));
26+
}
27+
28+
@Override
29+
protected VertxOptions getOptions() {
30+
return new VertxOptions(super.getOptions())
31+
.setFileSystemOptions(new FileSystemOptions().setFileCachingEnabled(true).setExactFileCacheDir(cacheBaseDir.toAbsolutePath().toString()));
32+
}
33+
34+
@Test
35+
public void test() throws IOException {
36+
try (FileResolver fileResolver = ((VertxInternal) vertx).fileResolver()) {
37+
File file = fileResolver.resolveFile("conf.json");
38+
Assert.assertEquals(cacheBaseDir.resolve("conf.json").toFile(), file);
39+
}
40+
}
41+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.vertx.tests.file.cachedir;
2+
3+
import io.vertx.core.Vertx;
4+
import io.vertx.core.VertxOptions;
5+
import io.vertx.core.file.FileSystemOptions;
6+
import io.vertx.core.internal.VertxInternal;
7+
import io.vertx.core.spi.file.FileResolver;
8+
import io.vertx.test.core.VertxTestBase;
9+
import java.io.File;
10+
import java.io.IOException;
11+
import java.nio.file.FileSystemException;
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
import java.nio.file.Paths;
15+
import org.junit.Assert;
16+
import org.junit.Test;
17+
18+
public class ExactDirParentIsAFileTest {
19+
20+
private final Path cacheBaseDir;
21+
22+
public ExactDirParentIsAFileTest() throws IOException {
23+
Path cacheBaseDirParent = Paths.get(System.getProperty("java.io.tmpdir", "."), "cache-parent");
24+
Files.deleteIfExists(cacheBaseDirParent);
25+
Files.createFile(cacheBaseDirParent);
26+
Assert.assertTrue(Files.exists(cacheBaseDirParent));
27+
Assert.assertFalse(Files.isDirectory(cacheBaseDirParent));
28+
this.cacheBaseDir = cacheBaseDirParent.resolve("actual-cache");
29+
Assert.assertFalse(Files.exists(cacheBaseDir));
30+
}
31+
32+
@Test
33+
public void test() {
34+
Assert.assertThrows(IllegalStateException.class, () -> {
35+
Vertx.builder().with(new VertxOptions().setFileSystemOptions(new FileSystemOptions().setFileCachingEnabled(true).setExactFileCacheDir(cacheBaseDir.toAbsolutePath().toString()))).build();
36+
});
37+
}
38+
}

0 commit comments

Comments
 (0)