Skip to content

Use macOS clonefile(2) for copy-on-write file cloning in Copy task#13671

Draft
jankratochvilcz wants to merge 1 commit into
mainfrom
feature/clonefile-copy-optimization
Draft

Use macOS clonefile(2) for copy-on-write file cloning in Copy task#13671
jankratochvilcz wants to merge 1 commit into
mainfrom
feature/clonefile-copy-optimization

Conversation

@jankratochvilcz
Copy link
Copy Markdown
Contributor

Summary

Add an experimental optimization that uses macOS clonefile(2) syscall for O(1) copy-on-write file cloning on APFS, gated behind the MSBUILD_EXPERIMENTAL_COPY=1 environment variable.

What is clonefile(2)?

clonefile(2) is a macOS syscall (Sierra 10.12+) that creates a copy-on-write clone of a file on APFS. It only copies metadata; data blocks are shared until either side is modified, then diverge transparently. Cost is O(1) — typically 50–200 µs regardless of file size.

Why not hardlinks?

Hardlinks share an inode: chmod/chown on the destination affects the source, and any tool that opens the destination for writing without O_TRUNC mutates the source. Build outputs that get post-processed (codesign, ilrepack) can't safely use hardlinks. Clonefile gives the speed of a hardlink with the semantics of a copy.

Changes

  • src/Tasks/NativeMethods.cs: Added clonefile(2) P/Invoke and TryCloneFile() helper
  • src/Tasks/Copy.cs: Integrated clone attempt before File.Copy fallback, gated behind MSBUILD_EXPERIMENTAL_COPY=1 env var
  • src/Tasks.UnitTests/Copy_Tests.cs: 6 macOS-only tests ([MacOSOnlyFact])

Performance (macOS APFS, Apple Silicon)

Scenario File.Copy clonefile Speedup
200 × 1 MB uniform files 255ms 25ms 10.2×
1000 files, 1 KB → 1 MB gradual 238ms 93ms 2.6×

Design decisions

  • Gated behind MSBUILD_EXPERIMENTAL_COPY=1 — no behavioral change without opt-in
  • Silent fallback to File.Copy on any clonefile error (non-APFS, cross-device, Docker, etc.)
  • Skips clone attempt when CopyWithoutDelete escape hatch is active and dest exists
  • No new task parameter — internal optimization only
  • clonefile preserves mtime/attributes → incremental builds work correctly

Add an experimental optimization that uses macOS clonefile(2) syscall
for O(1) copy-on-write file cloning on APFS, gated behind the
MSBUILD_EXPERIMENTAL_COPY=1 environment variable.

- Add clonefile P/Invoke to Tasks/NativeMethods.cs
- Integrate TryCloneFile into Copy.cs with silent fallback to File.Copy
- Skip clone attempt when CopyWithoutDelete escape hatch is active
- Add 6 macOS-only unit tests: happy path, copy-on-write divergence,
  read-only handling, env var fallback, incremental build invariant,
  and performance load test (1000 files, 1KB-1MB: ~2.6x speedup)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@baronfel
Copy link
Copy Markdown
Member

baronfel commented May 4, 2026

Does this have any impact? The BCL tries to clone files already on Unix, and on macOS this immediately tries to use clonefile.

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.

2 participants