Skip to content

fix(fs): fs.write 改用每请求唯一临时文件,避免并发保存互相损坏 - #764

Open
nanami-0713 wants to merge 1 commit into
omdsh-dev:mainfrom
nanami-0713:fix/fs-write-unique-temp
Open

nanami-0713 wants to merge 1 commit into
omdsh-dev:mainfrom
nanami-0713:fix/fs-write-unique-temp

Conversation

@nanami-0713

Copy link
Copy Markdown

问题

fs.write(src/index.ts)的临时文件名是 ${path}.dsh-sidebar-tmp-${process.pid}——同一进程内唯一,与请求无关。对同一路径的两次并发保存共享同一个 tmp:

  • 两个 writeFile 交错/相互截断,最终 rename 进目标的是两份草稿的字节混合,而两端编辑器都显示"已保存"
  • 先完成者 rename 走 tmp 后,另一方的 rename 必然 ENOENT 报错
  • 失败路径的 rm(tmp, {force:true}) 还可能删掉另一方正在写的 tmp

触发窗口真实存在:"open to the side"会为同一路径铸造第二个编辑器 tab(EditorHost.tsx),两个 tab 的保存只在各自组件实例内用 savingRef 串行化,同一进程内对同一路径的两次保存可以在 writeFile→rename 窗口内重叠。

仓库里其实已有正确方案:writeWorkspaceUpload(src/fs-operations.ts:70)用「隐藏文件 + randomUUID + .tmp」并注释了"The unique temp name keeps concurrent uploads to the same target independent"——fs.write 没有得到同样处理。

修复

对齐 upload 方案:.${basename(path)}.dsh-sidebar-tmp-${randomUUID()}.tmp,另加 wx 标志(随机名碰撞时快速失败)。名字唯一后,失败路径的 rm 也不可能再误删他人正在写的 tmp。

测试

新增契约测试:同一路径并发两次 fs.write,断言两次调用全部成功且最终文件内容必为其中一份完整草稿(非字节混合、无 rename 失败)。竞态命中本身依赖 OS 调度,测试作为契约守卫;核心论据是共享 tmp 名的代码事实。

…ve corruption

fs.write 的临时文件名只含 pid,同进程内对同一路径的并发保存共享同
一个 tmp:两个 writeFile 会交错/相互截断,先完成者 rename 走 tmp
后,另一个 rename 必然 ENOENT 报错,或目标文件最终是两份草稿的字
节混合,而编辑器仍显示"已保存"。"open to the side"会为同一路径
开第二个编辑器 tab,窗口期真实存在。

对齐 writeWorkspaceUpload 的既有方案(fs-operations.ts):隐藏文件
+ randomUUID + .tmp 后缀,并给 writeFile 加 wx 标志。失败路径的
rm 也因名字唯一不再可能误删他人正在写的 tmp。

新增契约测试:同路径并发 fs.write 全部成功且文件内容必为其中一份
完整草稿。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant