Skip to content

Commit 6575f5d

Browse files
Refactor cache locks
1 parent 8b7aa40 commit 6575f5d

9 files changed

+122
-124
lines changed

src/main/java/net/snowflake/client/core/FileCacheManager.java

+58-65
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.nio.file.attribute.PosixFilePermission;
2828
import java.nio.file.attribute.PosixFilePermissions;
2929
import java.util.Date;
30+
import java.util.function.Supplier;
3031
import java.util.stream.Collectors;
3132
import java.util.stream.Stream;
3233
import net.snowflake.client.log.SFLogger;
@@ -43,7 +44,6 @@ class FileCacheManager {
4344
private String cacheDirectorySystemProperty;
4445
private String cacheDirectoryEnvironmentVariable;
4546
private String baseCacheFileName;
46-
private long cacheExpirationInMilliseconds;
4747
private long cacheFileLockExpirationInMilliseconds;
4848

4949
private File cacheFile;
@@ -74,12 +74,6 @@ FileCacheManager setBaseCacheFileName(String baseCacheFileName) {
7474
return this;
7575
}
7676

77-
FileCacheManager setCacheExpirationInSeconds(long cacheExpirationInSeconds) {
78-
// converting from seconds to milliseconds
79-
this.cacheExpirationInMilliseconds = cacheExpirationInSeconds * 1000;
80-
return this;
81-
}
82-
8377
FileCacheManager setCacheFileLockExpirationInSeconds(long cacheFileLockExpirationInSeconds) {
8478
this.cacheFileLockExpirationInMilliseconds = cacheFileLockExpirationInSeconds * 1000;
8579
return this;
@@ -90,6 +84,10 @@ FileCacheManager setOnlyOwnerPermissions(boolean onlyOwnerPermissions) {
9084
return this;
9185
}
9286

87+
String getCacheFilePath() {
88+
return cacheFile.getAbsolutePath();
89+
}
90+
9391
/**
9492
* Override the cache file.
9593
*
@@ -100,7 +98,7 @@ void overrideCacheFile(File newCacheFile) {
10098
logger.debug("Cache file doesn't exists. File: {}", newCacheFile);
10199
}
102100
if (onlyOwnerPermissions) {
103-
FileUtil.throwWhenPermiossionDifferentThanReadWriteForOwner(
101+
FileUtil.throwWhenPermissionsDifferentThanReadWriteForOwner(
104102
newCacheFile, "Override cache file");
105103
} else {
106104
FileUtil.logFileUsage(cacheFile, "Override cache file", false);
@@ -199,12 +197,33 @@ FileCacheManager build() {
199197
return this;
200198
}
201199

202-
/** Reads the cache file. */
203-
JsonNode readCacheFile() {
204-
if (cacheFile == null || !this.checkCacheLockFile()) {
205-
// no cache or the cache is not valid.
200+
<T> T withLock(Supplier<T> supplier) {
201+
if (cacheFile == null) {
202+
logger.error("No cache file assigned", false);
203+
return null;
204+
}
205+
if (cacheLockFile == null) {
206+
logger.error("No cache lock file assigned", false);
206207
return null;
208+
} else if (cacheLockFile.exists()) {
209+
deleteCacheLockIfExpired();
210+
}
211+
212+
if (!tryToLockCacheFile()) {
213+
logger.debug("Failed to lock the file. Skipping cache operation", false);
214+
return null;
215+
}
216+
try {
217+
return supplier.get();
218+
} finally {
219+
if (!unlockCacheFile()) {
220+
logger.debug("Failed to unlock cache file", false);
221+
}
207222
}
223+
}
224+
225+
/** Reads the cache file. */
226+
JsonNode readCacheFile() {
208227
try {
209228
if (!cacheFile.exists()) {
210229
logger.debug("Cache file doesn't exists. File: {}", cacheFile);
@@ -215,7 +234,7 @@ JsonNode readCacheFile() {
215234
new InputStreamReader(new FileInputStream(cacheFile), DEFAULT_FILE_ENCODING)) {
216235

217236
if (onlyOwnerPermissions) {
218-
FileUtil.throwWhenPermiossionDifferentThanReadWriteForOwner(cacheFile, "Read cache");
237+
FileUtil.throwWhenPermissionsDifferentThanReadWriteForOwner(cacheFile, "Read cache");
219238
FileUtil.throwWhenOwnerDifferentThanCurrentUser(cacheFile, "Read cache");
220239
} else {
221240
FileUtil.logFileUsage(cacheFile, "Read cache", false);
@@ -230,32 +249,21 @@ JsonNode readCacheFile() {
230249

231250
void writeCacheFile(JsonNode input) {
232251
logger.debug("Writing cache file. File: {}", cacheFile);
233-
if (cacheFile == null || !tryLockCacheFile()) {
234-
// no cache file or it failed to lock file
235-
logger.debug(
236-
"No cache file exists or failed to lock the file. Skipping writing the cache", false);
237-
return;
238-
}
239-
// NOTE: must unlock cache file
240252
try {
241253
if (input == null) {
242254
return;
243255
}
244256
try (Writer writer =
245257
new OutputStreamWriter(new FileOutputStream(cacheFile), DEFAULT_FILE_ENCODING)) {
246258
if (onlyOwnerPermissions) {
247-
FileUtil.throwWhenPermiossionDifferentThanReadWriteForOwner(cacheFile, "Write to cache");
259+
FileUtil.throwWhenPermissionsDifferentThanReadWriteForOwner(cacheFile, "Write to cache");
248260
} else {
249261
FileUtil.logFileUsage(cacheFile, "Write to cache", false);
250262
}
251263
writer.write(input.toString());
252264
}
253265
} catch (IOException ex) {
254266
logger.debug("Failed to write the cache file. File: {}", cacheFile);
255-
} finally {
256-
if (!unlockCacheFile()) {
257-
logger.debug("Failed to unlock cache file", false);
258-
}
259267
}
260268
}
261269

@@ -277,10 +285,10 @@ void deleteCacheFile() {
277285
*
278286
* @return true if success or false
279287
*/
280-
private boolean tryLockCacheFile() {
288+
private boolean tryToLockCacheFile() {
281289
int cnt = 0;
282290
boolean locked = false;
283-
while (cnt < 100 && !(locked = lockCacheFile())) {
291+
while (cnt < 10 && !(locked = lockCacheFile())) {
284292
try {
285293
Thread.sleep(100);
286294
} catch (InterruptedException ex) {
@@ -289,56 +297,27 @@ private boolean tryLockCacheFile() {
289297
++cnt;
290298
}
291299
if (!locked) {
292-
logger.debug("Failed to lock the cache file.", false);
300+
deleteCacheLockIfExpired();
301+
if (!lockCacheFile()) {
302+
logger.debug("Failed to lock the cache file.", false);
303+
}
293304
}
294305
return locked;
295306
}
296307

297-
/**
298-
* Lock cache file by creating a lock directory
299-
*
300-
* @return true if success or false
301-
*/
302-
private boolean lockCacheFile() {
303-
return cacheLockFile.mkdirs();
304-
}
305-
306-
/**
307-
* Unlock cache file by deleting a lock directory
308-
*
309-
* @return true if success or false
310-
*/
311-
private boolean unlockCacheFile() {
312-
return cacheLockFile.delete();
313-
}
314-
315-
private boolean checkCacheLockFile() {
308+
private void deleteCacheLockIfExpired() {
316309
long currentTime = new Date().getTime();
317-
long cacheFileTs = fileCreationTime(cacheFile);
318-
319-
if (!cacheLockFile.exists()
320-
&& cacheFileTs > 0
321-
&& currentTime - this.cacheExpirationInMilliseconds <= cacheFileTs) {
322-
logger.debug("No cache file lock directory exists and cache file is up to date.", false);
323-
return true;
324-
}
325-
326310
long lockFileTs = fileCreationTime(cacheLockFile);
327311
if (lockFileTs < 0) {
328-
// failed to get the timestamp of lock directory
329-
return false;
312+
logger.debug("Failed to get the timestamp of lock directory");
330313
}
331314
if (lockFileTs < currentTime - this.cacheFileLockExpirationInMilliseconds) {
332315
// old lock file
333316
if (!cacheLockFile.delete()) {
334317
logger.debug("Failed to delete the directory. Dir: {}", cacheLockFile);
335-
return false;
336318
}
337-
logger.debug("Deleted the cache lock directory, because it was old.", false);
338-
return currentTime - this.cacheExpirationInMilliseconds <= cacheFileTs;
319+
logger.debug("Deleted expired cache lock directory.", false);
339320
}
340-
logger.debug("Failed to lock the file. Ignored.", false);
341-
return false;
342321
}
343322

344323
/**
@@ -361,7 +340,21 @@ private static long fileCreationTime(File targetFile) {
361340
return -1;
362341
}
363342

364-
String getCacheFilePath() {
365-
return cacheFile.getAbsolutePath();
343+
/**
344+
* Lock cache file by creating a lock directory
345+
*
346+
* @return true if success or false
347+
*/
348+
private boolean lockCacheFile() {
349+
return cacheLockFile.mkdirs();
350+
}
351+
352+
/**
353+
* Unlock cache file by deleting a lock directory
354+
*
355+
* @return true if success or false
356+
*/
357+
private boolean unlockCacheFile() {
358+
return cacheLockFile.delete();
366359
}
367360
}

src/main/java/net/snowflake/client/core/FileUtil.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ public static void logFileUsage(String stringPath, String context, boolean logRe
4141
logFileUsage(path, context, logReadAccess);
4242
}
4343

44-
public static void throwWhenPermiossionDifferentThanReadWriteForOwner(File file, String context) {
45-
throwWhenPermiossionDifferentThanReadWriteForOwner(file.toPath(), context);
44+
public static void throwWhenPermissionsDifferentThanReadWriteForOwner(File file, String context) {
45+
throwWhenPermissionsDifferentThanReadWriteForOwner(file.toPath(), context);
4646
}
4747

48-
public static void throwWhenPermiossionDifferentThanReadWriteForOwner(
48+
public static void throwWhenPermissionsDifferentThanReadWriteForOwner(
4949
Path filePath, String context) {
5050
// we do not check the permissions for Windows
5151
if (isWindows()) {
@@ -62,7 +62,9 @@ public static void throwWhenPermiossionDifferentThanReadWriteForOwner(
6262
logger.debug(
6363
"{}File {} access rights: {}", getContextStr(context), filePath, filePermissions);
6464
throw new SecurityException(
65-
String.format("Access to file %s is wider than allowed only to the owner", filePath));
65+
String.format(
66+
"Access to file %s is wider than allowed only to the owner. Remove cached files and re-run the driver.",
67+
filePath));
6668
}
6769
} catch (IOException e) {
6870
throw new SecurityException(

src/main/java/net/snowflake/client/core/SFTrustManager.java

-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ public class SFTrustManager extends X509ExtendedTrustManager {
225225
.setCacheDirectorySystemProperty(CACHE_DIR_PROP)
226226
.setCacheDirectoryEnvironmentVariable(CACHE_DIR_ENV)
227227
.setBaseCacheFileName(CACHE_FILE_NAME)
228-
.setCacheExpirationInSeconds(CACHE_EXPIRATION_IN_SECONDS)
229228
.setCacheFileLockExpirationInSeconds(CACHE_FILE_LOCK_EXPIRATION_IN_SECONDS)
230229
.setOnlyOwnerPermissions(false)
231230
.build();

0 commit comments

Comments
 (0)