Upstream deletes from the container are dropped as stale: tombstoneIsStale compares revs from different peers' rev spaces
维护者通常 1 天内回复
@aron-cf 已经在做这个了。
开始于 2026年9月29日。
评估
这个 Issue 还没有评估数据。
描述
Summary
Deletes made inside the container (rm, and therefore mv) are never applied to the Durable Object's VFS once the DO's local revision counter is ahead of computerd's. tombstoneIsStale compares revisions from two unrelated counters.
Environment
@cloudflare/computer0.3.1 withcomputer-computerd-linux-x64:0.3.1.withWorkspaceContainer+CloudflareContainerBackend, standard-1.- Same code on
main(e5e28a7).
What happens
- A workspace has some history. Local writes via
ws.fs.writeFilebumpvfs_meta.rev, and so does every file pulled back from the container, becauselinkStagedChunksSyncstamps it with a fresh local rev. ws.runtime.exec('rm x', { backend: 'linux' }).- The container's
lsno longer showsx, andresult()reportssync.status: 'complete',pulled: 0. xis still in the DO's VFS. It is never re-pushed, because it did not change locally, so the two sides stay diverged. Amv a barrives as "b created, a still present".
Files created in the container do propagate, because alreadyApplied compares manifest hashes, not revs.
Cause
packages/dofs/src/sync/apply.ts:
function tombstoneIsStale(db, entry) {
const live = resolveInode(db, entry.path, { followSymlinks: false });
if (live === null) return false;
const row = db.one("SELECT rev FROM vfs_nodes WHERE inode = ?", live.inode);
return row !== undefined && row.rev > entry.rev;
}
row.revis the local node's rev (localvfs_meta.revspace).- For an upstream entry,
entry.revcomes from the peer's change log (computerd's own counter). packages/rpc/src/server.tsitself describes the push caller as "a sync peer with its own rev space".
computerd starts fresh after every sleep, so its counter is small, while the DO's grows with every write and pull. row.rev > entry.rev therefore holds for practically every path, and every container delete is dropped as "stale".
On main the predicate is also used by applyChangesSync (apply.ts:426), so the RPC server path has the same comparison. The same predicate runs on the computerd side for deletes pushed from the DO. It works today only because the DO's revs are larger, and would drop DO deletes if the container's counter were ever ahead.
Repro without a container
Drive a real Workspace over node:sqlite against a fake SyncRPC/ShellRPC peer whose counter starts at 1:
- Write
/workspace/xa few times so the local rev is well above the peer's. - Make the fake command append
{ kind: 'delete', path: '/workspace/x', rev: <peer rev> }to the peer's change log. - Run
ws.runtime.exec(..., { backend }).
Result: pulled === 0 and /workspace/x still exists.
Workaround we are running
One possible fix, which we applied as a local patch to dist/index.js: decide staleness by whether the peer has seen the local version. A node pushed to this backend (rev <= pushRev) yields to the peer's delete; a local change newer than the last completed push still wins.
function tombstoneIsStale(db, entry, backend) {
const live = resolveInode(db, entry.path, { followSymlinks: false });
if (live === null) return false;
const row = db.one("SELECT rev FROM vfs_nodes WHERE inode = ?", live.inode);
if (row === void 0) return false;
return row.rev > readWatermark(db, "pushRev", backend ?? DEFAULT_BACKEND_ID);
}
// call site in applyChanges: tombstoneIsStale(db, entry, options.backend)
After a watermark divergence (pullOnceImpl resets pushRev to 0), deletes stay conservatively dropped until the next push re-establishes the watermark. We are not sure this is the right fix for the computerd side, or for pack pulls, but the cross-space comparison looks unintended.
- 主要语言
- TypeScript
- 星标
- 9.5k
- 派生
- 552
- 平均合并
- 1 天 21 小时
- 30 天内合并 PR
- 42
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
cloudflare/computer 的其他 Issue
-
Feature: add workspace.inspect() and the workspace_summary tool可能已有人在做 @aron-cf 今天认领。 未关闭enhancement
cloudflare/computer#226 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Sync planning scans the full pending change set before yielding; repeated Durable Object CPU-limit failures可能已有人在做 @aron-cf 于 2 天前认领。 未关闭bug
cloudflare/computer#225 · 已指派 1 人 ·
维护者通常 1 天内回复
-
enhancement
难度 4/5 3-5 天 新手友好度 30/100
cloudflare/computer#224 · 5 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
-
Always run the "next" computerd workflow on push to the `release` branch可能已有人在做 @aron-cf 于 3 天前认领。 未关闭bug
cloudflare/computer#222 · 2 条评论 · 1 个 reaction · 已指派 1 人 ·
维护者通常 1 天内回复
-
Make just-bash and acorn optional peer dependencies, pulled in only by the backend that needs them未关闭enhancement
难度 3/5 1-2 天 新手友好度 45/100
cloudflare/computer#220 · 3 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
查看 cloudflare/computer 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 82/100
openwatersio/slackwater-database#281 ·
维护者通常 1 天内回复
-
accepted bug via-triage
难度 2/5 1-3 小时 新手友好度 76/100
pingdotgg/t3code#18690 · 1 条评论 ·
维护者通常 1 天内回复
-
Bayern feature:Application ready web
难度 2/5 1-3 小时 新手友好度 67/100
digitalfabrik/entitlementcard#3176 ·
维护者通常 7 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
NanmiCoder/cc-haha#1533 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复