Skip to content

Commit 13cc58c

Browse files
geoandvietj
authored andcommitted
Introduce option to treat cache dir as exact path
1 parent 4387906 commit 13cc58c

File tree

6 files changed

+156
-7
lines changed

6 files changed

+156
-7
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, FileSys
2727
obj.setFileCacheDir((String)member.getValue());
2828
}
2929
break;
30+
case "fileCacheDirAsExactPath":
31+
if (member.getValue() instanceof Boolean) {
32+
obj.setFileCacheDirAsExactPath((Boolean)member.getValue());
33+
}
34+
break;
3035
}
3136
}
3237
}
@@ -41,5 +46,6 @@ static void toJson(FileSystemOptions obj, java.util.Map<String, Object> json) {
4146
if (obj.getFileCacheDir() != null) {
4247
json.put("fileCacheDir", obj.getFileCacheDir());
4348
}
49+
json.put("fileCacheDirAsExactPath", obj.isFileCacheDirAsExactPath());
4450
}
4551
}

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

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

48+
/**
49+
* The default value for using file cache dir as exact path = {@code false}
50+
*/
51+
public static final boolean DEFAULT_FILE_CACHE_DIR_AS_EXACT_PATH = false;
52+
4853
private boolean classPathResolvingEnabled = DEFAULT_CLASS_PATH_RESOLVING_ENABLED;
4954
private boolean fileCachingEnabled = DEFAULT_FILE_CACHING_ENABLED;
5055
private String fileCacheDir = DEFAULT_FILE_CACHING_DIR;
56+
private boolean fileCacheDirAsExactPath = DEFAULT_FILE_CACHE_DIR_AS_EXACT_PATH;
5157

5258
/**
5359
* Default constructor
@@ -64,6 +70,7 @@ public FileSystemOptions(FileSystemOptions other) {
6470
this.classPathResolvingEnabled = other.isClassPathResolvingEnabled();
6571
this.fileCachingEnabled = other.isFileCachingEnabled();
6672
this.fileCacheDir = other.getFileCacheDir();
73+
this.fileCacheDirAsExactPath = other.isFileCacheDirAsExactPath();
6774
}
6875

6976
/**
@@ -147,13 +154,35 @@ public FileSystemOptions setFileCacheDir(String fileCacheDir) {
147154
return this;
148155
}
149156

157+
/**
158+
* @return whether the file cache dir should be used as an exact path
159+
*/
160+
public boolean isFileCacheDirAsExactPath() {
161+
return this.fileCacheDirAsExactPath;
162+
}
163+
164+
/**
165+
* Set to {@code true} to use the configured file cache dir as an exact path.
166+
* When {@code false} (the default), a unique subdirectory is created under the
167+
* file cache dir. When {@code true} and the directory already exists, a suffix
168+
* like "-2", "-3", etc. is appended to guarantee uniqueness.
169+
*
170+
* @param fileCacheDirAsExactPath the value
171+
* @return a reference to this, so the API can be used fluently
172+
*/
173+
public FileSystemOptions setFileCacheDirAsExactPath(boolean fileCacheDirAsExactPath) {
174+
this.fileCacheDirAsExactPath = fileCacheDirAsExactPath;
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+
", fileCacheDirAsExactPath=" + fileCacheDirAsExactPath +
157186
'}';
158187
}
159188
}

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727

2828
public class FileCache {
2929

30-
static FileCache setupCache(String fileCacheDir) {
31-
FileCache cache = new FileCache(setupCacheDir(fileCacheDir));
30+
static FileCache setupCache(String fileCacheDir, boolean useExactPath) {
31+
FileCache cache = new FileCache(setupCacheDir(fileCacheDir, useExactPath));
3232
// Add shutdown hook to delete on exit
3333
cache.registerShutdownHook();
3434
return cache;
@@ -37,15 +37,21 @@ static FileCache setupCache(String fileCacheDir) {
3737
/**
3838
* Prepares the cache directory to be used in the application.
3939
*/
40-
static File setupCacheDir(String fileCacheDir) {
40+
static File setupCacheDir(String fileCacheDir, boolean useExactPath) {
4141
// ensure that the argument doesn't end with separator
4242
if (fileCacheDir.endsWith(File.separator)) {
4343
fileCacheDir = fileCacheDir.substring(0, fileCacheDir.length() - File.separator.length());
4444
}
4545

46-
// the cacheDir will be suffixed a unique id to avoid eavesdropping from other processes/users
47-
// also this ensures that if process A deletes cacheDir, it won't affect process B
48-
String cacheDirName = fileCacheDir + "-" + UUID.randomUUID();
46+
String cacheDirName;
47+
if (useExactPath) {
48+
// Use the path as-is, but if it exists, append a suffix to guarantee uniqueness
49+
cacheDirName = findUniqueDir(fileCacheDir);
50+
} else {
51+
// the cacheDir will be suffixed a unique id to avoid eavesdropping from other processes/users
52+
// also this ensures that if process A deletes cacheDir, it won't affect process B
53+
cacheDirName = fileCacheDir + "-" + UUID.randomUUID();
54+
}
4955
File cacheDir = new File(cacheDirName);
5056
// Create the cache directory
5157
try {
@@ -63,6 +69,27 @@ static File setupCacheDir(String fileCacheDir) {
6369
return cacheDir;
6470
}
6571

72+
/**
73+
* Find a unique directory path. If the base path doesn't exist, return it.
74+
* If it exists, append "-2", "-3", etc. until a non-existing path is found.
75+
*/
76+
private static String findUniqueDir(String basePath) {
77+
File baseDir = new File(basePath);
78+
if (!baseDir.exists()) {
79+
return basePath;
80+
}
81+
// Directory exists, find a unique suffix
82+
int suffix = 2;
83+
while (true) {
84+
String candidatePath = basePath + "-" + suffix;
85+
File candidate = new File(candidatePath);
86+
if (!candidate.exists()) {
87+
return candidatePath;
88+
}
89+
suffix++;
90+
}
91+
}
92+
6693
private Thread shutdownHook;
6794
private File cacheDir;
6895

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

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

7070
if (enableCPResolving) {
71-
cache = FileCache.setupCache(fileSystemOptions.getFileCacheDir());
71+
cache = FileCache.setupCache(fileSystemOptions.getFileCacheDir(), fileSystemOptions.isFileCacheDirAsExactPath());
7272
} else {
7373
cache = null;
7474
}
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 org.junit.Assert;
13+
import org.junit.Test;
14+
15+
public class ExactDirDoesNotExistTest extends VertxTestBase {
16+
17+
private final Path cacheBaseDir;
18+
19+
public ExactDirDoesNotExistTest() throws IOException {
20+
cacheBaseDir = Files.createTempDirectory("cache-does-not-exist");
21+
Files.deleteIfExists(cacheBaseDir);
22+
Assert.assertFalse(Files.exists(cacheBaseDir));
23+
}
24+
25+
@Override
26+
protected VertxOptions getOptions() {
27+
return new VertxOptions(super.getOptions())
28+
.setFileSystemOptions(new FileSystemOptions()
29+
.setFileCachingEnabled(true)
30+
.setFileCacheDir(cacheBaseDir.toAbsolutePath().toString())
31+
.setFileCacheDirAsExactPath(true));
32+
}
33+
34+
@Test
35+
public void test() throws IOException {
36+
try (FileResolver fileResolver = ((VertxInternal) vertx).fileResolver()) {
37+
File file = fileResolver.resolve("conf.json");
38+
Assert.assertEquals(cacheBaseDir.resolve("conf.json").toFile().getCanonicalPath(), file.getCanonicalPath());
39+
}
40+
}
41+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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()
32+
.setFileCachingEnabled(true)
33+
.setFileCacheDir(cacheBaseDir.toAbsolutePath().toString())
34+
.setFileCacheDirAsExactPath(true));
35+
}
36+
37+
@Test
38+
public void test() throws IOException {
39+
try (FileResolver fileResolver = ((VertxInternal) vertx).fileResolver()) {
40+
File file = fileResolver.resolve("conf.json");
41+
// When exact path is used and dir exists, a suffix is appended
42+
String resolvedDir = file.getCanonicalFile().getParent();
43+
Assert.assertTrue(resolvedDir.startsWith(cacheBaseDir.toFile().getCanonicalPath()));
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)