Skip to content

fix(sandbox): clone the vz instance disk instead of copying it - #293

Merged
quickbeard merged 1 commit into
mainfrom
fix/sandbox-disk-clone
Aug 22, 2026
Merged

quickbeard merged 1 commit into
mainfrom
fix/sandbox-disk-clone

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

Problem

Creating or resetting a macOS sandbox spent ~9s writing 8 GiB to disk, and the sandbox's first boot then crawled — often past the 60s start budget, failing with sandbox server did not become healthy within 60000ms. Every boot after that was fine, which is what made it look intermittent.

provision() intends a copy-on-write clone:

await copyFile(join(dirs.image, VZ_DISK_FILE), dirs.disk, constants.COPYFILE_FICLONE)

On macOS that flag does nothing. libuv's uv_fs_copyfile opens the destination and calls fcopyfile(); only clonefile(2) — which takes paths and requires the destination not to exist — can share extents. So it wrote the whole image out, and because the pristine rootfs.img is sparse (8 GiB long, ~4 GiB allocated), the copy also filled its holes with real zeroes.

Measured on this machine against the real image:

runtime time allocated
Node (what Electron runs) 8585 ms 8.0 G
Bun 0 ms 4.0 G (shared)
cp -c 3 ms 4.0 G (shared)

The knock-on effect is what made it feel slow: the VM boots immediately after provisioning, so the guest competed with gigabytes of outstanding write-back for the very disk it was reading. Not the image size itself — the contention.

Fix

On darwin, shell out to cp -c (clonefile), falling back to copyFile if the clone can't happen; rm the destination first, since clonefile requires it absent. Every other platform keeps the existing call.

Verification

End-to-end on this machine, same VM and same image, only the disk differing:

instance disk first boot
full copy (8.0 G allocated) >60s — start timed out
clone (4.0 G shared) 2.0 s (sandbox starting → sandbox ready)
  • bun test src/vz/provider.test.ts: 10 pass — existing create/reset coverage coincidentally exercises the dest-exists path.
  • bun typecheck clean in packages/codev-sandbox.

No new unit test, deliberately. The suite runs under Bun, whose copyFile does clone — so a sparseness assertion passes with or without this fix. I wrote one, confirmed it passed against the unfixed code, and removed it rather than ship false assurance. Pinning this properly needs the clone command injected like spawnImpl/fetchImpl already are; worth doing if this area changes again.

Fork-only package, so no DIVERGENCES row. CHANGELOG entry under Sandbox.

🤖 Generated with Claude Code

Node's COPYFILE_FICLONE is a no-op on macOS: libuv opens the
destination and calls fcopyfile(), so every provision wrote the full
8 GiB image out and expanded its sparse holes. Shell out to cp -c
(clonefile) on darwin, falling back to copyFile.

Measured on an M-series Mac: 8585ms and 8.0G allocated before, 3ms and
shared extents after; first sandbox boot went from >60s (start timed
out) to 2.0s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@quickbeard
quickbeard merged commit e493f2d into main Aug 22, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the fix/sandbox-disk-clone branch August 22, 2026 08:06
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