perf(externalfiles): cache related entries - #16696
Conversation
PR Summary by QodoCache related entries during unlinked-file searches
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
Code Review by Qodo
1.
|
| } | ||
|
|
||
| private static Path normalizePath(Path path) { | ||
| return path.toAbsolutePath().normalize(); |
There was a problem hiding this comment.
🤖 Generated with Claude Code
Suggestion carried over from #16695: toAbsolutePath().normalize() is lexical, so when the search directory is a symlink/alias of the configured file directory the crawled path and the path from findIn(...) never match and the file loses its "Select entry to link" dropdown. Using filesystem identity fixes it (used on both sides — here and in getRelatedEntriesForFiles):
private static Path normalizePath(Path path) {
try {
return path.toRealPath();
} catch (IOException e) {
return path.toAbsolutePath().normalize();
}
}Test that fails without it (Linux/macOS): create files/ with author000.pdf, a library with entry author000 whose main file directory is files/, Files.createSymbolicLink(link, files), search in link, then getRelatedEntriesForFiles(link.resolve("author000.pdf")) must return the entry (@DisabledOnOs(OS.WINDOWS)).
| taskActiveProperty.setValue(false); | ||
| }) | ||
| .onSuccess(treeRoot -> treeRootProperty.setValue(Optional.of(treeRoot))); | ||
| .onSuccess(searchResult -> { |
There was a problem hiding this comment.
🤖 Generated with Claude Code
Suggestion carried over from #16695: onEnteringPage calls startSearch() again when the user goes back to page 1 and forward while the first search is still running. The older task then finishes later and overwrites relatedEntriesByFile/treeRootProperty of the newer search (and a cancelled search still does the full entry lookup, which is the expensive part). Two small guards cover both:
if (findUnlinkedFilesTask != null) {
findUnlinkedFilesTask.cancel();
}
UnlinkedFilesCrawler task = new UnlinkedFilesCrawler(...);
findUnlinkedFilesTask = task;
task.onSuccess(searchResult -> {
if (findUnlinkedFilesTask != task) {
return; // superseded by a newer search
}
...
})plus in UnlinkedFilesCrawler.call(): isCancelled() ? Map.of() : findRelatedEntriesByFile() after searchDirectory(...) (the executor drops a cancelled task's result anyway).
Resolve associated files in every configured file directory instead of the first match, key the cache by real path so symlinked search directories still match, stop the entry lookup once the search is cancelled, and ignore results of a superseded search in the dialog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZXuvrbXanmtZnE7kKm9EN
The page only places the preview pane into the scene once a tree root exists, so the test never found the button it tried to click. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZXuvrbXanmtZnE7kKm9EN
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZXuvrbXanmtZnE7kKm9EN
* main: Chore(deps): Bump net.ltgt.nullaway from 3.1.0 to 3.2.0 in /jablib (#16712) Chore(deps): Bump org.jsoup:jsoup from 1.23.1 to 1.23.2 in /versions (#16713) Chore(deps): Bump com.autonomousapps:dependency-analysis-gradle-plugin (#16709) Chore(deps): Bump com.autonomousapps:dependency-analysis-gradle-plugin (#16710) Chore(deps): Bump net.ltgt.errorprone from 5.1.0 to 5.1.1 in /jablib (#16711) Run the CAYW JavaFX picker in the native jabsrv image (#16634) Run PR tests when a submodule pointer changes (#16699) New Crowdin updates (#16701) Chore(deps): Bump jablib/src/main/resources/csl-styles from `0b07219` to `0819c0e` (#16685) First class Theme Support in JabRef (#15798) # Conflicts: # jabgui/src/main/java/org/jabref/gui/externalfiles/FindUnlinkedFilesAction.java
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4rMv9fuZY4fsHzNiuUcNt

Summary
Fix performance issues in the Find unlinked files dialog
Add option to hide pdf sidepane
Steps to test
Related issues and pull requests
Closes _____
AI usage
AI CHECKLIST.md walkthrough
Checklist
CHANGELOG.mddescribing the change from the user's point of view (if the change is visible to the user)