feat: protect mod payloads with main-thread ownership in 1.1.17

This commit is contained in:
Disy committed 2026-10-06 17:36:00 +08:00
1 parent 691e949691
commit 763c015103
29 files changed
+1552 -53

No files matched your search

+27 -1
View File
@@ -2,6 +2,32 @@
Dimensional Ripper 是一个基于 **NeoForge 1.21.1** 的多线程维度并行优化模组。它通过独立维度 tick 循环与细粒度并行调度,充分利用多核 CPU 提升服务端性能,同时保持稳定的 20 TPS。
## 1.1.17:公共收包线程归属候选修复
服务端游戏阶段经 NeoForge `ServerPayloadContext.enqueueWork` 明确提交到主线程的工作,现在统一进入有界队列,并在维度更新归还执行权后,由真正的服务器主线程调用原处理器。Create/航空学旧组装入口复用同一安全阶段;采用这条公共入口的模组不需要主动适配。登录、配置阶段、客户端及纯网络计算不改派,也不代表任意模组的任意线程访问已自动安全。
队列上限为服务器 4096 项、单连接 256 项,每批最多 64 项或 2 ms(不强行中断已经开始的处理器)。保留观察到的入队顺序;执行前取消的工作不再修改世界,换世界/换玩家/停服后的旧工作明确失效。超载通过原断线流程处理;业务处理器自己抛出的拒绝异常不会被误判为超载踢人。新循环继承菜单暂停,仍在退出的循环也必须归还执行权。等待期间继续服务 Sable 主线程交接,拒绝会产生锁反转的同步重入。
真实本地模组回归:Sable 物理子世界内创建了真实把手约束,复现原路径松手后约束仍有效;经新入口处理同一松手包后约束失效。Create 调速包及 Jade 查询通过,原距离拒绝仍有效。另有队列、取消、暂停、停止和真实 CC 回归。详细环境、日志标记及未覆盖项见 [1.1.17 验证报告](docs/payload-ownership-1.1.17-validation.md)。这些是隔离服务器测试,不等于用户完整整合包、客户端飞行或多人压力验收。
阶段之外维度并行仍保留;有交互时会等待最慢维度收口,不承诺零开销。没有待处理交互时不建立收包屏障。`/dimensionalripper status` 与归属崩溃快照包含队列积压、最老等待、最近批次等待/执行时间;仅凭 Carpet 的低 MSPT 不能判断所有维度正常。记录最多 128 个具名包 ID 加 other、最近 32 条结果,失败警告全局 30 秒限频,不记录包正文。
**仍为测试候选,不要直接替换正式服务器:ServerWarashi(坐服童子)启动分析崩溃、C2ME 冲突、任意后台世界访问及既有停服超时不在这次修复范围内。** 工作线程提交后同步等待公共队列 future 仍不受支持;不能把它宣传为所有模组免适配。
## 1.1.16:CC 调度线程归属候选修复
针对 CC:Tweaked 1.118.0 `TickScheduler` 主线程读取正在被维度线程更新的世界、导致显示器身份检查得到 `null` 的问题:有待处理 token 时,先暂停维度续排并等待在途更新归还所有权,在服务器主线程执行原调度检查,最后恢复原先运行的循环。等待期间继续处理主线程回调,允许 Sable 交接完成;不绕过身份检查,不吞掉真实异常,不强加载未加载区块。CC 的全局延迟队列表对应的区块回调也做串行保护。未安装 CC 时不启用此补丁。
这不是零开销修复:CC 有任务时,安全阶段会等待当前最慢的维度收口,可能暂时影响主线程 TPS;没有任务时不建立屏障,阶段结束后维度与细粒度并行继续运行。不能保证所有维度在这一兼容阶段完全互不影响。`/dimensionalripper status` 增加最近一次交接等待/执行耗时。
线程诊断记录维度、Level/ChunkSource 所属线程、调用线程、位置、阶段和 Sable 交接状态。每维度最多保留 16 条最近事件;入口归属不匹配警告每维度最多 30 秒一次,抑制期间累计计数,慢安全阶段全局最多 30 秒一次。入口快照不等于原子世界快照,也不据此单独判定死锁。崩溃报告新增 `DimensionalRipper Thread Ownership`。
隔离测试:`gradlew runServer -PownershipRegression -PccTestJar=<本机CC的jar绝对路径>`。使用 `runs/server` 下的专用测试世界(运行前确认 `level-name=interaction-regression`、`server-ip=127.0.0.1`、`server-port=25579`),不要指向正式存档。测试源码和 CC jar 不加入常规发布包。已在修复前用真实 CC 显示器复现 `Expected MonitorBlockEntity ... got null`;修复后运行任务会检查日志中的 `OWNERSHIP REGRESSION PASS`、`OWNERSHIP EDGE PASS`、`OWNERSHIP CALLBACK PASS` 和 `OWNERSHIP RESUME PASS`。Minecraft 崩溃有时仍以零退出码结束,不能只检查 Java 退出码。
覆盖:真实显示器身份检查、实际主线程交接桥的回调执行、嵌套/异常后的暂停恢复、拆除与真实身份不匹配、未加载 token、80 个延迟 token 的双维度并发 ticket/unload 回调,以及崩溃诊断。1001 次入口归属不匹配在测试日志中仅输出 1 条警告。另用 1 TPS 的空闲预算复现暂停后仍等待整秒的问题,修正为世界工作完成后立即退出已请求暂停的空闲轮询;保留在途工作的收尾。一次本机测试的 CC 等待/执行为约 7.4/0.12 ms,仅是隔离样本,不是整合包性能承诺。测试调用实际交接桥,但没有加载 Sable 原生物理引擎。
本修复限定于 CC 调度路径,不是对所有模组跨线程访问的通用放行。仍需在完整整合包的存档副本验证,尤其 CC 显示器随 Sable 结构移动的情况;不要据此认为所有航空学、区块发送、停服问题均已解决。
## 优化范围(均为服务端运算,不影响客户端画面/渲染)
### 🗺️ 维度
@@ -44,7 +70,7 @@ Dimensional Ripper 是一个基于 **NeoForge 1.21.1** 的多线程维度并行
## ⚠️ 兼容性说明
**已知未修复问题(1.1.15)**:与 C2ME 的 `c2me_fixes_worldgen_threading_issues` 同时加载时,双方对 `Level` 构造器内随机源初始化的 `@Redirect` 冲突,可能导致启动失败。日志已确认 C2ME 优先级 1100 的重定向覆盖本模组优先级 1000 的 `modzuozhi_threadSafeRandom`,继而触发注入检查失败。当前源码尚未包含此兼容修复,不能视为可直接部署的稳定版。
**已知未修复问题(1.1.15 / 1.1.16)**:与 C2ME 的 `c2me_fixes_worldgen_threading_issues` 同时加载时,双方对 `Level` 构造器内随机源初始化的 `@Redirect` 冲突,可能导致启动失败。日志已确认 C2ME 优先级 1100 的重定向覆盖本模组优先级 1000 的 `modzuozhi_threadSafeRandom`,继而触发注入检查失败。当前源码尚未包含此兼容修复,不能视为可直接部署的稳定版。
1.1.15 针对 Sable 碰撞查询期间反复创建实心占位区块的问题: