Repository navigation
[PR] fix(storage): a live second writer no longer blocks startup — sharing a local-disk index.db is a supported topology (rev | fix(storage): 活着的第二写者不再阻止启动——共享一个本地盘 index.db 是受支持拓扑(撤回 #5213 的拒绝策略) - #5294
Merged
Conversation
…decision 2026-10-31) Sharing one local-disk index.db IS the supported topology (#5082/#5091): SQLite WAL is multi-process safe locally, so a peer holding <db>.lock is informational-only now (info log + web/status wire) whatever its lane — inline lanes never register, so 'unknown lane' was routinely mistaken for risky and bricked resumes (the 2026-10-31 `bili pi -r` boot failure, #5213's refuse-to-start withdrawn). Withdrawn call sites: UnifiedStore.open secondWriterPolicy:'degrade' opt-in (option removed; crossLaneSafe math deleted), shadow.ts open-catch refusal + recordSidecarOpenFailure line, runtime-status degradeReason verbatim branch, storage-maintenance gc catch (the full-VACUUM starvation guard in runGc via store.unifiedActiveWriter() is untouched). StorageSecondWriterError stays exported (@deprecated) so external import/catch sites keep compiling. Genuine hazard unchanged: two instances walking the SAME session still alarm via the split-brain contest (#3923). Tests rewritten to the never-block contract incl. regression pins for both formerly-refused shapes (same-lane, unknown-lane fleet). Docs: CONFIGURATION EN/ZH seed + README multi-instance section updated.
ranxianglei
commented
Oct 31, 2026
ranxianglei
left a comment
Owner
Author
There was a problem hiding this comment.
审查结论:代码通过,无阻塞问题。CI 绿后即可人工合并(owner 操作)。
按「政策撤回是否撤干净」逐面核过:
1. 核心机制自洽(src/storage/store.ts)
UnifiedStore.open不再接收secondWriterPolicy,任何 lane 形状(同 lane / 跨 lane / 无 lane 旧标记)下活着的第二写者只产生一行 info 日志 +recordSecondProcessOwner状态线,随后照常开库、照常走 lockfile 纪律——死 pid 仍按 stale lock 接管。这正是 #5082/#5091 确立的受支持拓扑该有的行为。- 与「在任何情况下不降级」(2026-10-30 政策)没有冲突:那条政策管的是环境类打开失败(no-engine/CANTOPEN/readonly/DSN),这些分支在 shadow.ts 里原样保留、仍然拒启;被撤回的只是 second-writer 这一个条件,CONFIGURATION.md 的 QUICK_CHECK 条目(EN/ZH/生成物)也同步把它移出了拒绝清单,口径一致。
2. 悬挂引用清零(全库 grep 验证)
StorageSecondWriterError现在只剩:类定义 + @deprecated 说明(保留导出给外部 import/catch)、测试钉、注释历史引用。仓库内部无 throw、无 catch、无secondWriterPolicy调用点。- runtime-status.ts 删掉的
second-writer:前缀透传分支对应的唯一写入源已不存在,删除正确。
3. full-VACUUM 在线护栏未被误伤
- storage-maintenance.ts 删掉的只是 constructor 抛错时的特判分支;护栏本体在 runGc 内(
store.unifiedActiveWriter(),现 L221),活写者持库时--vacuum full照旧拒执行。定向测试#4612: CLI 'storage gc --vacuum full' exits 1 with actionable refusal while a writer is live本地绿。
4. 测试重写是契约翻转而非放松
- 两个曾经会拒启的形状(同 lane 活持有者、无 lane 字段的混版本标记)各留一条回归钉子,断言从「必须 THROW + 锁不被偷 + 可操作错误」翻转为「必须打开 + info 提示在 + 锁接管行为不变 + 状态线带 peer pid」——把「永不阻断」和「依然响亮」两侧都钉死了。
- multi-instance-live.e2e 恢复了 #394/#405/#2401 的 serve/guard/converge 交织(两个 full-mode 实例共享同一个活 index.db),本地 2.2s 通过。头注释里「证明什么/不证明什么/残留 pin 在哪」的边界写得清楚。
5. 同步状态与本地验证
- 分支落后 master 11 个提交(#5253/#5292 两个 merge),文件零重叠;本地临时合并后 tsc 干净、9 个存储相关套件 54 例全绿(issue5046-second-writer-degrade / multi-instance-live / issue4612-gc-online-guard / storage-maintenance-cli / storage-corpus / storage-review-fixes / split-brain-surface / storage-engine-proofs / corrupt-index 系;其中 storage-engine-proofs 首轮 1 失败为本地 kernel/dist 陈旧的环境坑,重建后 12/12)。
- 无 kernel 改动,不涉及版本门;PR body 里提到的 ~50 文件后台批跑以 CI 为准即可。
一个纯观察(非阻塞):NFS/RWX 共享盘不支持多写的限制在 README 新段落末尾被明确保留了,这是这次改写里容易被顺手丢掉的一句话,值得留。
Contributor
📦 Built Package ArtifactBranch: Latest build — install this exact versionnpm install -g billion-context@0.0.7337-pr.5294.5730e76This exact version is immutable and reproducible. The rolling Recent builds (commit → version)
Download artifact
tar xzf billion-context-pr5294.tgz
npm install -g packageInstall instructions are refreshed on each push. |
This was referenced Oct 31, 2026
Contributor
📦 Merged Build PublishedThis merge to master was published as npm install -g billion-context@0.0.938-master.491ac1d # this exact build
npm install -g billion-context@master # always the newest merged build
|
This was referenced Oct 31, 2026
Closed
Closed
Closed
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.
这是什么问题
2026-10-31,机器上多个 bili 实例(不同 profile / inline 车道)共享同一个默认 sessions 目录时,新起的进程直接拒绝启动(例如
bili pi -r恢复会话),报错 "another bili process already writes index.db … REFUSED TO START until isolated"。机器上已经有十几个常驻 bili 时,这条拒绝等于把「恢复会话 / 重启」这条路整个堵死。该拒绝策略来自 PR #5213 引入的 second-writer refuse-to-start。根本原因
拒绝逻辑的判断是「只有对端 lane ≠ 自己的 lane 才允许共存」。但 inline 车道从不在实例登记簿里注册,旧版本进程写的登记标记里也没有 lane 字段——于是「对端 lane 未知」被一律当成危险双写形状 → 拒启。而事实上:
index.db早已被确立为受支持拓扑(A second process was detected writing to the same index.db — another process (pid 435075) is writing to the database in | 检测到第二个进程在写同一个 index.db 另一个进程(pid 435075)正在写入本会话目录的数据库——两个进程写同一个库会损坏数据(#3923/#3959)。请关闭多余实例:一个会话目录只能由一个实例服务。 #5082/[PR] Second process opening index.db falsely reports "will corrupt data" — change to a shared-mode warning (#5082) | 第二个进程打开 index.db 误报「会损坏数据」——改为共享形态的提示(#5082) #5091);owner 决定(2026-10-31):无论什么 lane 情况,活着的第二写者都不再阻止启动——只提示。
改了什么
src/storage/store.ts:UnifiedStore.open删除secondWriterPolicy:"degrade"选项和 crossLaneSafe 判断。任何活着的对端持有者现在只产生一行 info 日志(写明 lane/instanceId)+ 状态线记录(web/状态面板可见 peer pid),随后照常打开数据库、照常执行 lockfile 纪律(死 pid 依旧按 stale lock 接管)。src/storage/shadow.ts/src/storage/runtime-status.ts/src/storage-maintenance.ts:删除三处拒绝分支及对应 degrade/status 文案。full-VACUUM 的在线护栏原样保留(storage gc --vacuum full在有活进程持库时仍然拒绝,走 runGc 内自己的 guard)。StorageSecondWriterError保留导出并标注 @deprecated(外部代码可能还在 import/catch 它;本仓库内部不再有 throw 路径)。tests/issue5046-second-writer-degrade.test.ts换成 never-block 契约,其中「同 lane 活持有者」「无 lane 字段的旧版标记」这两个曾经会触发拒启的形状各留一条回归钉子;tests/multi-instance-live.test.ts同步更新。测试 / 验证
bili pi -r恢复路径实测可正常启动,日志只多一行 info。能否合并
可以合。性质是策略回退 + 文档/测试跟进:无 schema 变更、无协议变化、唯一的行为差异就是 second-writer 条件从「拒启」降为「提示」,且提示信息比原来更全(web 状态线也带上 peer)。真正的分裂脑防护(#3923 per-session 告警)不受影响。合并等 owner 操作(非人类不合并)。
Relates to #5046, #5082, #5091, #3923, #5213.