Skip to content

Commit 522cfe7

Browse files
geoandvietj
authored andcommitted
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 0490f19 commit 522cfe7

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)