1111import java .nio .file .Paths ;
1212import java .nio .file .attribute .BasicFileAttributes ;
1313import java .nio .file .attribute .PosixFilePermissions ;
14+ import java .time .Instant ;
15+ import java .time .temporal .ChronoUnit ;
1416import java .util .Set ;
1517import java .util .concurrent .CompletableFuture ;
1618import org .slf4j .Logger ;
@@ -35,9 +37,11 @@ private class CleanupVisitor implements FileVisitor<Path> {
3537 private final Set <String > pidSet = PidHelper .getJavaPids ();
3638
3739 private final boolean cleanSelf ;
40+ private final Instant cutoff ;
3841
3942 CleanupVisitor (boolean cleanSelf ) {
4043 this .cleanSelf = cleanSelf ;
44+ this .cutoff = Instant .now ().minus (cutoffSeconds , ChronoUnit .SECONDS );
4145 }
4246
4347 @ Override
@@ -59,6 +63,9 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
5963
6064 @ Override
6165 public FileVisitResult visitFile (Path file , BasicFileAttributes attrs ) throws IOException {
66+ if (Files .getLastModifiedTime (file ).toInstant ().isAfter (cutoff )) {
67+ return FileVisitResult .SKIP_SUBTREE ;
68+ }
6269 Files .delete (file );
6370 return FileVisitResult .CONTINUE ;
6471 }
@@ -85,6 +92,7 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx
8592
8693 private final Path baseTempDir ;
8794 private final Path tempDir ;
95+ private final long cutoffSeconds ;
8896
8997 private final CompletableFuture <Void > cleanupTask ;
9098
@@ -117,6 +125,19 @@ private TempLocationManager() {
117125 }
118126
119127 TempLocationManager (ConfigProvider configProvider ) {
128+ // In order to avoid racy attempts to clean up files which are currently being processed in a
129+ // JVM which is being shut down (the JVMs far in the shutdown routine may not be reported by
130+ // 'jps' but still can be eg. processing JFR chunks) we will not clean up any files not older
131+ // than '2 * PROFILING_UPLOAD_PERIOD' seconds.
132+ // The reasoning is that even if the file is created immediately at JVM startup once it is
133+ // 'PROFILING_UPLOAD_PERIOD' seconds old it gets processed to upload the final profile data and
134+ // this processing will not take longer than another `PROFILING_UPLOAD_PERIOD' seconds.
135+ // This is just an assumption but as long as the profiled application is working normally (eg.
136+ // OS is not stalling) this assumption will hold.
137+ cutoffSeconds =
138+ configProvider .getLong (
139+ ProfilingConfig .PROFILING_UPLOAD_PERIOD ,
140+ ProfilingConfig .PROFILING_UPLOAD_PERIOD_DEFAULT );
120141 Path configuredTempDir =
121142 Paths .get (
122143 configProvider .getString (
@@ -140,21 +161,21 @@ private TempLocationManager() {
140161 tempDir = baseTempDir .resolve ("pid_" + pid );
141162 cleanupTask = CompletableFuture .runAsync (() -> cleanup (false ));
142163
143- // Runtime.getRuntime()
144- // .addShutdownHook(
145- // new Thread(
146- // () -> {
147- // try {
148- // cleanupTask.join();
149- // } finally {
150- // cleanup(true);
151- // }
152- // },
153- // "Temp Location Manager Cleanup"));
164+ Runtime .getRuntime ()
165+ .addShutdownHook (
166+ new Thread (
167+ () -> {
168+ try {
169+ cleanupTask .join ();
170+ } finally {
171+ cleanup (true );
172+ }
173+ },
174+ "Temp Location Manager Cleanup" ));
154175 }
155176
156177 /**
157- * Get the temporary directory for the current process.
178+ * Get the temporary directory for the current process. The directory will be removed at JVM exit.
158179 *
159180 * @return the temporary directory for the current process
160181 */
0 commit comments