From 07e82bd5648bccac42e6d42a67c789780ee531f6 Mon Sep 17 00:00:00 2001 From: lick <2188718831@qq.com> Date: Fri, 13 Nov 2026 20:20:46 -0800 Subject: [PATCH] fix(java): keep completed indexing jobs terminal across notification workers --- README.md | 4 +- backend/src/run.rs | 54 ++++++++++++++- docs/releases/v1.1.3.md | 66 +++++++++++++++++++ io.github.lithe-idea.java-support/plugin.json | 2 +- 4 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 docs/releases/v1.1.3.md diff --git a/README.md b/README.md index e447051..c6800b8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Java Support for Lithe -> **Viva 预览版 Java 支持(1.1.2)**:清单已迁到当前契约 0,后端使用 Core +> **Viva 预览版 Java 支持(1.1.3)**:清单已迁到当前契约 0,后端使用 Core > `65cf82343c5e315aae2e335b2e8f0217b703e89a` 中的 Rust SDK 0.4.0(尚无对应发布标签)。 > 本轮验证含第三方 JAR 依赖的普通 Maven 工程:JDT 补全、Maven 编译、main 运行和断点调试,包含变量读取、继续和退出。 > 需要同时包含 Lithe 客户端的动作注册解码、动作刷新与首次调试加载修复;未修改这些行为的旧 preview 不能直接使用本包。 @@ -24,7 +24,7 @@ > SDK. Maven and Gradle import settings come from the Maven and Gradle plugins through a function interface that > Lithe Core relays between plugins. -1.1.2 面向包含主仓库 [#1884](https://github.com/1lck/Lithe-IDEA/pull/1884) 的配套 Viva preview(客户端修订 `607f00967d70a7017d49805183d0d2e6ffdf1c0d` 或更新版本)。API / 能力与传输版本以 `plugin.json`、`sdk.lock.json` +1.1.3 面向包含主仓库 [#1884](https://github.com/1lck/Lithe-IDEA/pull/1884) 的配套 Viva preview(客户端修订 `607f00967d70a7017d49805183d0d2e6ffdf1c0d` 或更新版本)。API / 能力与传输版本以 `plugin.json`、`sdk.lock.json` 和固定 Core 中的[插件资料](https://github.com/Lithe-IDEA/Lithe-core-rust/tree/65cf82343c5e315aae2e335b2e8f0217b703e89a/shared/plugins)为准。 `MIGRATION.md` 保留迁移历史,不能用其中旧宿主、旧 API 数字推断当前兼容性。 diff --git a/backend/src/run.rs b/backend/src/run.rs index dbe7f68..12ad25a 100644 --- a/backend/src/run.rs +++ b/backend/src/run.rs @@ -56,7 +56,7 @@ use lithe_plugin_sdk::{ WorkspaceContext, }; use serde_json::{json, Map}; -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, HashSet, VecDeque}; use std::io::{BufRead, BufReader, Cursor, Write}; use std::net::TcpListener; use std::path::{Path, PathBuf}; @@ -223,6 +223,9 @@ pub struct RunSession { const MAX_ACTION_QUERY_REFRESHES: u8 = 3; const MAX_ACTION_PROGRESS_JOBS: usize = 128; +/// Remember recent terminal job IDs because SDK notification workers may run +/// out of wire order. This per-server history has the same bound as live jobs. +const MAX_COMPLETED_ACTION_PROGRESS_JOBS: usize = 128; #[derive(Default)] struct ActionQueryRetry { @@ -233,6 +236,7 @@ struct ActionQueryRetry { degraded: bool, exhausted_reported: bool, active_work: HashSet, + completed_jobs: VecDeque, progress_limit: bool, } @@ -254,8 +258,17 @@ impl ActionQueryRetry { } fn progress(&mut self, id: &str, complete: bool) -> bool { + // Completion is terminal for a JDT job ID. A delayed worker must not + // resurrect it, nor may a duplicate end consume another retry budget. + if self.completed_jobs.iter().any(|completed| completed == id) { + return false; + } if complete { self.active_work.remove(id); + if self.completed_jobs.len() == MAX_COMPLETED_ACTION_PROGRESS_JOBS { + self.completed_jobs.pop_front(); + } + self.completed_jobs.push_back(id.to_owned()); if self.active_work.is_empty() && !self.progress_limit { return self.work_completed(); } @@ -1520,6 +1533,45 @@ mod tests { ); } + #[test] + fn completed_progress_cannot_be_resurrected_by_a_late_worker() { + let mut retry = ActionQueryRetry::default(); + // SDK notification workers can acquire the lock in a different order + // from the wire: an earlier running update may follow completion. + assert!(!retry.progress("build", true)); + assert!(!retry.progress("build", false)); + assert!(!retry.progress("index", false)); + assert_eq!(retry.defer(retry.completed_work), (true, false)); + assert!( + retry.progress("index", true), + "late build update must not block recovery" + ); + let completed = retry.completed_work; + assert!(!retry.progress("index", true)); + assert_eq!( + retry.completed_work, completed, + "duplicate completion is not new work" + ); + } + + #[test] + fn terminal_progress_history_is_bounded_and_keeps_recent_jobs() { + let mut retry = ActionQueryRetry::default(); + for id in 0..MAX_COMPLETED_ACTION_PROGRESS_JOBS * 2 { + retry.progress(&id.to_string(), true); + } + assert_eq!( + retry.completed_jobs.len(), + MAX_COMPLETED_ACTION_PROGRESS_JOBS + ); + let recent = (MAX_COMPLETED_ACTION_PROGRESS_JOBS * 2 - 1).to_string(); + let completed = retry.completed_work; + retry.progress(&recent, false); + retry.progress(&recent, true); + assert!(retry.active_work.is_empty()); + assert_eq!(retry.completed_work, completed); + } + #[test] fn progress_bookkeeping_is_bounded_and_malformed_events_do_not_recover() { let mut retry = ActionQueryRetry::default(); diff --git a/docs/releases/v1.1.3.md b/docs/releases/v1.1.3.md new file mode 100644 index 0000000..328594a --- /dev/null +++ b/docs/releases/v1.1.3.md @@ -0,0 +1,66 @@ +## 中文 + +Java Support 1.1.3 为配套 Viva 预览版提供 Java 项目支持。本版本是预发布,插件包不带发布者签名。 + +### 下载与安装 + +下载本页对应系统的 ZIP:macOS Apple Silicon(`darwin-arm64`)、macOS Intel(`darwin-x64`)或 Windows x64(`windows-x64`)。在兼容 Viva 客户端的插件设置中选择从文件安装 ZIP。 + +需要包含 [Lithe #1884](https://github.com/1lck/Lithe-IDEA/pull/1884) 的客户端(修订 `607f00967d70a7017d49805183d0d2e6ffdf1c0d` 或更新版本)及 Core #29。旧版 macOS Lithe 和未包含这些修复的 Viva preview 不受支持。插件使用契约/API/能力版本 0;语言服务器使用随包 Temurin 21,项目运行仍使用用户选择的 JDK。 + +Maven 项目配合 Maven 0.0.1;Gradle 项目配合 Gradle 1.0.0。构建工具由用户安装或由项目 Wrapper 提供。 + +### 更新 + +- 修复并发处理索引进度时,晚到的旧更新重新激活已完成任务、导致运行动作不恢复的问题;终态历史有界且不增加后台轮询。 +- 补齐自身 LICENSE/NOTICE 与 Rust 构建依赖的许可和哈希清单,缺失时阻止打包。 + +- 跑通普通 Maven、Gradle 和普通 Java 目录的补全、编译、运行及断点调试,Java 8 项目保留正确的编译目标。 +- Windows 后端静态链接编译器运行库,发布检查拒绝额外的 VC++/MinGW 运行库依赖。 +- 修复 Windows 可执行路径、中文/UNC 文件 URI、Lombok 加载及过长 classpath;退出后清理临时 classpath JAR。 +- 冷索引暂时无法返回运行动作时,在索引任务完成后有界恢复,不增加后台轮询。 +- 已在 macOS 与 Windows 无头验证断点变量、继续/停止、编译错误阻止运行旧 class、暂停时关闭及插件安装目录只读。 + +### 兼容性与已知限制 + +- 二进制依赖类跳转尚未接通:语言服务器能返回 `jdt:` 目标,但插件未注册对应内容提供者,Viva 无法打开类内容;不保证反编译视图或类间继续跳转。 +- `.jsp` 当前按 HTML 打开,没有 Java 语言服务接管,JSP 内的 Java 补全与跳转不受支持。 + +尚未完整验收原生窗口、全部日志/取消路径、JUnit/TestNG 行内运行器和 Spring/MyBatis。JSP HTTP/Servlet 调试通过不代表 JSP 源码补全或 JSP 断点;Ant 源码布局不代表执行 Ant target。Java 5/7 源码级别、长 module-path、JavaCC 生成模型、多版本 JAR 和部分旧泛型项目仍有限制,详见 README 与主仓库 #1881–1883。 + +实测 JDT 内存与补全延迟没有显著改善,本版本不宣称整体性能提升。Windows 的真实工作流在 ARM Windows 上使用 x64 工具验证,其耗时不代表原生 AMD64 性能。 + +--- + +## English + +Java Support 1.1.3 targets the matching Viva preview. This is a prerelease with unsigned plugin archives. + +### Download and installation + +Choose the ZIP for macOS Apple Silicon (`darwin-arm64`), macOS Intel (`darwin-x64`), or Windows x64 (`windows-x64`), then install it from a file in the compatible Viva client's plugin settings. + +The client must include [Lithe #1884](https://github.com/1lck/Lithe-IDEA/pull/1884), revision `607f00967d70a7017d49805183d0d2e6ffdf1c0d` or newer, and Core #29. Legacy macOS Lithe and earlier Viva previews are unsupported. Contract, API and capability versions are 0. Bundled Temurin 21 runs the language server; project execution uses the selected project JDK. + +Use Maven 0.0.1 for Maven projects and Gradle 1.0.0 for Gradle projects. Supply the build tool yourself or through the project's wrapper. + +### Changes + +- Prevent late progress updates from resurrecting completed indexing jobs and blocking run-action recovery; terminal history is bounded without polling. +- Include project and Rust dependency notices with a hash manifest; missing notices stop packaging. + +- Validated completion, compilation, execution and breakpoint debugging for ordinary Maven, Gradle and plain Java projects, preserving Java 8 compilation targets. +- The Windows backend statically links compiler runtimes; release checks reject extra VC++/MinGW runtime DLL dependencies. +- Fixed Windows executable paths, Unicode/UNC file URIs, Lombok loading and long classpaths; temporary classpath JARs are removed after execution. +- Recover run actions after cold-index jobs finish, with bounded retries and no background polling. +- Headless macOS and Windows workflows cover breakpoint locals, continue/stop, refusal to run stale classes after compilation errors, closing paused sessions and read-only installed packages. + +### Compatibility and known limitations + +- Navigation into binary dependency classes is not wired up: the language server returns `jdt:` targets, but no matching content provider is registered, so Viva cannot open them. Decompiled views and further navigation between classes are not supported. +- `.jsp` files currently open as HTML without a Java language service; Java completion and navigation inside JSP are unsupported. + +Native windows, all logging/cancellation paths, inline JUnit/TestNG and Spring/MyBatis have not been fully accepted. JSP HTTP/Servlet debugging does not cover JSP-source completion or JSP breakpoints; Ant source layouts do not cover Ant targets. Java 5/7 source levels, long module-paths, JavaCC models, multi-release JARs and some older generic code remain limited; see README and Lithe #1881–1883. + +Measurements found no significant JDT memory or completion-latency improvement. Windows workflows used x64 tools on ARM Windows, so their timings do not represent native AMD64 performance. + diff --git a/io.github.lithe-idea.java-support/plugin.json b/io.github.lithe-idea.java-support/plugin.json index d246975..8384dba 100644 --- a/io.github.lithe-idea.java-support/plugin.json +++ b/io.github.lithe-idea.java-support/plugin.json @@ -2,7 +2,7 @@ "schemaVersion": 0, "id": "io.github.lithe-idea.java-support", "displayName": "Java Support", - "version": "1.1.2", + "version": "1.1.3", "pluginAPIVersion": 0, "requires": {"backend": 0, "debugAdapters": 0, "languages": 0, "languageServers": 0, "pluginFunctions": 0, "settings": 0, "projectGenerators": 0, "toolDefinitions": 0}, "requiresTools": ["java"],