Repository navigation
refactor: 上下文传播(工程改进第三项)——EntryClock 条目时刻由 ThreadLocal 换 ScopedValue(纯重构、行为零变化) - #19
Merged
Merged
Conversation
…纯重构、行为零变化)
- 改动:服务端 EntryClock.APPLY_NOW 由 ThreadLocal<Long> 改 ScopedValue<Long>(nowMs() 判定 get()!=null → isBound()),新增包内 ApplyOp 函数接口与 withApplyNow(long, ApplyOp)(ScopedValue.where(...).call(...) 的宽 Exception 收窄:InvalidProtocolBufferException/RuntimeException 原样重抛、其余包 IllegalStateException),删除 setApplyNow/clearApplyNow;LockStateMachineCore.apply 的 switch 抽为私有 applyBody(entry, t),入口收敛为 try { return EntryClock.withApplyNow(t, () -> applyBody(entry, t)); } catch (InvalidProtocolBufferException | RuntimeException e) { return error(...); }——catch 面逐字不变,finally clearApplyNow() 与 setApplyNow(0) 冗余死写随转换消失。全仓库唯一真 ThreadLocal 用法就此消灭,"忘清即泄漏陈旧条目时刻"的结构性隐患面随之关闭。
- 定位修正:工程改进"上下文传播"项原措辞"客户端内部会话/追踪上下文传递评估,替代线程本地袋"经评估证伪——客户端会话身份全程显式传递(SessionContext 经 Route 捕获 + Thread.currentThread().threadId() 显式读),无 ambient 需求、不存在"线程本地袋";落点据实收敛为服务端唯一真 ThreadLocal 的机制替换。
- 关键事实(实测双证,决定本项为纯重构):JEP 506 final 版 ScopedValue 绑定仅经 StructuredTaskScope.fork 继承(src.zip 中 java.base/java/lang/ScopedValue.java Inheritance 节原文 + 探针实测:Thread.start/ofPlatform/ofVirtual 与 newVirtualThreadPerTaskExecutor 一律不继承);故传播边界在 ThreadLocal 与 ScopedValue 下逐格相同,不引入语义变宽。据此按 OpenSpec"纯重构"规则设 .openspec.yaml skip_specs: true(无规格 delta,zero-delta 经 validate 接受)。
- 测试:StateMachineDeterminismTest 新增"条目时刻作用域传播边界矩阵"五格——域内同线程可见 / 域外同线程回落系统时钟 / 既有非派生线程回落 / 域内新建子线程不继承 / 并发作用域以不同携带时刻互不串扰且摘要与串行一致;作为常驻回归绊线(两种机制下皆绿)。行为零变化故无可红先锚点,初版"子线程继承"断言为错误前提,已按实测反转为"不继承";陈旧注释("thread-local")与 inApplyScope 辅助同步为有界作用域。
- 验证:mvn -s settings.xml clean verify 全 7 模块 BUILD SUCCESS(0 失败 0 错误;首轮 client 侧 surefire fork 启动瞬时错误经单模块复跑与整轮复跑双证为环境性 flake,非代码缺陷);javadoc:javadoc(server)无缺失;check-source-citations.sh 零命中;openspec validate --archived 本 change ✓;-Pdrill 判不需要(无进程/时序/线程形态变化,判例对齐影子修复),依据记 evidence/drill-decision.md。
- 文档·治理:EntryClock(类级线程模型/成立前提/契约边界,show=private)与 LockStateMachine 类级注释同步;ROADMAP 决策记录补 2026-10-09 评估裁决行 + 工程改进第 52 行描述与状态校正为已落地(附归档链接);change 归档至 openspec/changes/archive/2026-10-09-refactor-entry-clock-scoped-value/。
- 契约面:Clock 接口/CoreEngine/SystemClock 零改动;对外无 API、无 wire、无协议门、无快照格式、无规格变化。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
工程改进第三项「上下文传播」落地:服务端
EntryClock的条目时刻时间源由ThreadLocal换为ScopedValue(JDK 25 / JEP 506 已转正)。纯内部机制替换、行为零变化。为什么
ThreadLocal(EntryClock.APPLY_NOW,apply 期向应用调用路径注入条目携带时刻以保 Raft 回放确定性)以set/try-finally 清值配对,漏清即静默把陈旧条目时刻泄漏给该线程后续读取;ScopedValue 以有界作用域结构性消除该隐患面。SessionContext经Route捕获 +Thread.currentThread().threadId()显式读),无 ambient 需求、不存在「线程本地袋」;落点据实收敛为服务端唯一真 ThreadLocal 的机制替换。关键事实(决定本项为纯重构)
JEP 506 final 版 ScopedValue 绑定仅经
StructuredTaskScope.fork继承——src.zip中java.base/java/lang/ScopedValue.javaInheritance 节原文,加探针实测(Thread.start/ofPlatform/ofVirtual/newVirtualThreadPerTaskExecutor一律不继承)。故传播边界在 ThreadLocal 与 ScopedValue 下逐格相同,不引入语义变宽;按 OpenSpec「纯重构」规则设.openspec.yamlskip_specs: true(无规格 delta)。改动
EntryClock:ThreadLocal<Long>→ScopedValue<Long>;新增包内ApplyOp+withApplyNow(long, ApplyOp)(宽Exception收窄:IPBE/RuntimeException 原样重抛、其余包IllegalStateException);删除setApplyNow/clearApplyNow。LockStateMachineCore.apply:switch抽为applyBody(entry, t),入口收敛为作用域调用;catch 面逐字不变,finally clearApplyNow()与setApplyNow(0)冗余死写消失。Clock/CoreEngine/SystemClock零改动;无对外 API、无 wire、无协议门、无快照格式、无规格变化。测试与验证
StateMachineDeterminismTest新增「条目时刻作用域传播边界矩阵」五格(域内同线程可见 / 域外回落 / 既有非派生线程回落 / 域内新建子线程不继承 / 并发作用域互不串扰)——常驻回归绊线。行为零变化故无可红先锚点;初版「子线程继承」断言为错误前提,已按实测反转为「不继承」。mvn -s settings.xml clean verify全 7/7 模块 BUILD SUCCESS(0 失败 0 错误);javadoc:javadoc无缺失;check-source-citations.sh零命中;openspec validate --archived本 change ✓。-Pdrill判不需要(无进程/时序/线程形态变化,判例对齐影子修复),依据记evidence/drill-decision.md。备注(如实)
首轮
clean verify在 client 侧 surefire fork 启动处出现瞬时错误(无Tests run摘要);client 模块有openlatch-server的 test-scope 依赖,故未假定无关——经单模块复跑(含全部 IT)+ 整轮复跑双证为环境性 flake,非代码缺陷。