27
27
import java .nio .file .attribute .PosixFilePermission ;
28
28
import java .nio .file .attribute .PosixFilePermissions ;
29
29
import java .util .Date ;
30
+ import java .util .function .Supplier ;
30
31
import java .util .stream .Collectors ;
31
32
import java .util .stream .Stream ;
32
33
import net .snowflake .client .log .SFLogger ;
@@ -43,7 +44,6 @@ class FileCacheManager {
43
44
private String cacheDirectorySystemProperty ;
44
45
private String cacheDirectoryEnvironmentVariable ;
45
46
private String baseCacheFileName ;
46
- private long cacheExpirationInMilliseconds ;
47
47
private long cacheFileLockExpirationInMilliseconds ;
48
48
49
49
private File cacheFile ;
@@ -74,12 +74,6 @@ FileCacheManager setBaseCacheFileName(String baseCacheFileName) {
74
74
return this ;
75
75
}
76
76
77
- FileCacheManager setCacheExpirationInSeconds (long cacheExpirationInSeconds ) {
78
- // converting from seconds to milliseconds
79
- this .cacheExpirationInMilliseconds = cacheExpirationInSeconds * 1000 ;
80
- return this ;
81
- }
82
-
83
77
FileCacheManager setCacheFileLockExpirationInSeconds (long cacheFileLockExpirationInSeconds ) {
84
78
this .cacheFileLockExpirationInMilliseconds = cacheFileLockExpirationInSeconds * 1000 ;
85
79
return this ;
@@ -90,6 +84,10 @@ FileCacheManager setOnlyOwnerPermissions(boolean onlyOwnerPermissions) {
90
84
return this ;
91
85
}
92
86
87
+ String getCacheFilePath () {
88
+ return cacheFile .getAbsolutePath ();
89
+ }
90
+
93
91
/**
94
92
* Override the cache file.
95
93
*
@@ -100,7 +98,7 @@ void overrideCacheFile(File newCacheFile) {
100
98
logger .debug ("Cache file doesn't exists. File: {}" , newCacheFile );
101
99
}
102
100
if (onlyOwnerPermissions ) {
103
- FileUtil .throwWhenPermiossionDifferentThanReadWriteForOwner (
101
+ FileUtil .throwWhenPermissionsDifferentThanReadWriteForOwner (
104
102
newCacheFile , "Override cache file" );
105
103
} else {
106
104
FileUtil .logFileUsage (cacheFile , "Override cache file" , false );
@@ -199,12 +197,33 @@ FileCacheManager build() {
199
197
return this ;
200
198
}
201
199
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 );
206
207
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
+ }
207
222
}
223
+ }
224
+
225
+ /** Reads the cache file. */
226
+ JsonNode readCacheFile () {
208
227
try {
209
228
if (!cacheFile .exists ()) {
210
229
logger .debug ("Cache file doesn't exists. File: {}" , cacheFile );
@@ -215,7 +234,7 @@ JsonNode readCacheFile() {
215
234
new InputStreamReader (new FileInputStream (cacheFile ), DEFAULT_FILE_ENCODING )) {
216
235
217
236
if (onlyOwnerPermissions ) {
218
- FileUtil .throwWhenPermiossionDifferentThanReadWriteForOwner (cacheFile , "Read cache" );
237
+ FileUtil .throwWhenPermissionsDifferentThanReadWriteForOwner (cacheFile , "Read cache" );
219
238
FileUtil .throwWhenOwnerDifferentThanCurrentUser (cacheFile , "Read cache" );
220
239
} else {
221
240
FileUtil .logFileUsage (cacheFile , "Read cache" , false );
@@ -230,32 +249,21 @@ JsonNode readCacheFile() {
230
249
231
250
void writeCacheFile (JsonNode input ) {
232
251
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
240
252
try {
241
253
if (input == null ) {
242
254
return ;
243
255
}
244
256
try (Writer writer =
245
257
new OutputStreamWriter (new FileOutputStream (cacheFile ), DEFAULT_FILE_ENCODING )) {
246
258
if (onlyOwnerPermissions ) {
247
- FileUtil .throwWhenPermiossionDifferentThanReadWriteForOwner (cacheFile , "Write to cache" );
259
+ FileUtil .throwWhenPermissionsDifferentThanReadWriteForOwner (cacheFile , "Write to cache" );
248
260
} else {
249
261
FileUtil .logFileUsage (cacheFile , "Write to cache" , false );
250
262
}
251
263
writer .write (input .toString ());
252
264
}
253
265
} catch (IOException ex ) {
254
266
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
- }
259
267
}
260
268
}
261
269
@@ -277,10 +285,10 @@ void deleteCacheFile() {
277
285
*
278
286
* @return true if success or false
279
287
*/
280
- private boolean tryLockCacheFile () {
288
+ private boolean tryToLockCacheFile () {
281
289
int cnt = 0 ;
282
290
boolean locked = false ;
283
- while (cnt < 100 && !(locked = lockCacheFile ())) {
291
+ while (cnt < 10 && !(locked = lockCacheFile ())) {
284
292
try {
285
293
Thread .sleep (100 );
286
294
} catch (InterruptedException ex ) {
@@ -289,56 +297,27 @@ private boolean tryLockCacheFile() {
289
297
++cnt ;
290
298
}
291
299
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
+ }
293
304
}
294
305
return locked ;
295
306
}
296
307
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 () {
316
309
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
-
326
310
long lockFileTs = fileCreationTime (cacheLockFile );
327
311
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" );
330
313
}
331
314
if (lockFileTs < currentTime - this .cacheFileLockExpirationInMilliseconds ) {
332
315
// old lock file
333
316
if (!cacheLockFile .delete ()) {
334
317
logger .debug ("Failed to delete the directory. Dir: {}" , cacheLockFile );
335
- return false ;
336
318
}
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 );
339
320
}
340
- logger .debug ("Failed to lock the file. Ignored." , false );
341
- return false ;
342
321
}
343
322
344
323
/**
@@ -361,7 +340,21 @@ private static long fileCreationTime(File targetFile) {
361
340
return -1 ;
362
341
}
363
342
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 ();
366
359
}
367
360
}
0 commit comments