Skip to content

Commit 7a3afaf

Browse files
committed
Track FS close
1 parent 840e3eb commit 7a3afaf

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarTreeShakeInput.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,8 @@ public byte[] get() {
712712
return is.readAllBytes();
713713
} catch (IOException e) {
714714
throw new UncheckedIOException("Failed to read bytecode " + path
715-
+ " (fileSystem.isOpen=" + path.getFileSystem().isOpen() + ")", e);
715+
+ " (fileSystem.isOpen=" + path.getFileSystem().isOpen()
716+
+ ", interrupted=" + Thread.currentThread().isInterrupted() + ")", e);
716717
}
717718
}
718719
}

independent-projects/bootstrap/app-model/src/main/java/io/quarkus/paths/ArchivePathTree.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,8 @@ protected class OpenArchivePathTree extends OpenContainerPathTree {
282282

283283
protected OpenArchivePathTree(FileSystem fs) {
284284
super(ArchivePathTree.this.pathFilter, ArchivePathTree.this);
285-
this.fs = fs;
286-
this.rootPath = fs.getPath("/");
285+
this.fs = CloseTrapFileSystem.wrapIfTraced(fs, ArchivePathTree.this.archive);
286+
this.rootPath = this.fs.getPath("/");
287287
}
288288

289289
@Override
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package io.quarkus.paths;
2+
3+
import java.io.IOException;
4+
import java.nio.file.FileStore;
5+
import java.nio.file.FileSystem;
6+
import java.nio.file.Path;
7+
import java.nio.file.PathMatcher;
8+
import java.nio.file.WatchService;
9+
import java.nio.file.attribute.UserPrincipalLookupService;
10+
import java.nio.file.spi.FileSystemProvider;
11+
import java.util.Set;
12+
13+
import org.jboss.logging.Logger;
14+
15+
/**
16+
* Debug wrapper that intercepts {@link FileSystem#close()} to log
17+
* the stack trace of the caller. Used to diagnose unexpected
18+
* {@code ClosedChannelException} on shared ZipFileSystems.
19+
* <p>
20+
* Only wraps archives matching a trace filter (currently jboss-threads)
21+
* to avoid overhead in production.
22+
*/
23+
class CloseTrapFileSystem extends FileSystem {
24+
25+
private static final Logger log = Logger.getLogger(CloseTrapFileSystem.class);
26+
27+
private final FileSystem delegate;
28+
private final Path archive;
29+
30+
static FileSystem wrapIfTraced(FileSystem fs, Path archive) {
31+
if (archive.toString().contains("jboss-threads")) {
32+
return new CloseTrapFileSystem(fs, archive);
33+
}
34+
return fs;
35+
}
36+
37+
private CloseTrapFileSystem(FileSystem delegate, Path archive) {
38+
this.delegate = delegate;
39+
this.archive = archive;
40+
}
41+
42+
@Override
43+
public void close() throws IOException {
44+
log.warnf(new Exception("CloseTrapFileSystem.close() stack trace"),
45+
"ZipFS.close() called for %s on thread %s",
46+
archive, Thread.currentThread().getName());
47+
delegate.close();
48+
}
49+
50+
// --- pure delegation below ---
51+
52+
@Override
53+
public FileSystemProvider provider() {
54+
return delegate.provider();
55+
}
56+
57+
@Override
58+
public boolean isOpen() {
59+
return delegate.isOpen();
60+
}
61+
62+
@Override
63+
public boolean isReadOnly() {
64+
return delegate.isReadOnly();
65+
}
66+
67+
@Override
68+
public String getSeparator() {
69+
return delegate.getSeparator();
70+
}
71+
72+
@Override
73+
public Iterable<Path> getRootDirectories() {
74+
return delegate.getRootDirectories();
75+
}
76+
77+
@Override
78+
public Iterable<FileStore> getFileStores() {
79+
return delegate.getFileStores();
80+
}
81+
82+
@Override
83+
public Set<String> supportedFileAttributeViews() {
84+
return delegate.supportedFileAttributeViews();
85+
}
86+
87+
@Override
88+
public Path getPath(String first, String... more) {
89+
return delegate.getPath(first, more);
90+
}
91+
92+
@Override
93+
public PathMatcher getPathMatcher(String syntaxAndPattern) {
94+
return delegate.getPathMatcher(syntaxAndPattern);
95+
}
96+
97+
@Override
98+
public UserPrincipalLookupService getUserPrincipalLookupService() {
99+
return delegate.getUserPrincipalLookupService();
100+
}
101+
102+
@Override
103+
public WatchService newWatchService() throws IOException {
104+
return delegate.newWatchService();
105+
}
106+
}

0 commit comments

Comments
 (0)