Skip to content

Conversation

@baszalmstra
Copy link
Collaborator

@baszalmstra baszalmstra commented Nov 7, 2025

Only copy the executable bit permissions when the source file is executable AND the destination doesn't already have the correct executable bits. This drastically reduces syscalls for non-executable files and executable files that already have correct permissions.

Changes:

  • Created copy_executable_permissions() helper function to encapsulate the optimization logic
  • Applied optimization to reflink operations on Linux
  • Applied optimization to patched file operations (prefix replacement)
  • Only copy executable bits (0o111), not all permission bits
  • Skip permission updates if bits already match

Since the vast majority of package files are not executable, and many executable files already have correct permissions after creation/reflink, this provides a significant performance improvement during package installation.

The optimization only affects Unix systems. On Windows, permissions are handled differently and this optimization is not applicable.

Fixes #486

AI Disclosure

Written by Claude Code Web

@baszalmstra baszalmstra requested a review from wolfv November 7, 2025 09:44
@baszalmstra
Copy link
Collaborator Author

@wolfv This also no longer copies the other permission bits (e.g. read/write). Im not sure if that would cause issues. I assume that either these are already copied because the underlying filesystem works like that or they are not copied but we get the "default" permissions of the user, which might arguably be more correct anyway.

WDYT?

Only copy the executable bit permissions when the source file is
executable AND the destination doesn't already have the correct
executable bits. This drastically reduces syscalls for non-executable
files and executable files that already have correct permissions.

Changes:
- Created `copy_executable_permissions()` helper function to encapsulate
  the optimization logic
- Applied optimization to reflink operations on Linux
- Applied optimization to patched file operations (prefix replacement)
- Only copy executable bits (0o111), not all permission bits
- Skip permission updates if bits already match

Performance impact for reflink operations:
- Non-executable files: 1 syscall (metadata only)
  Previously: 2 syscalls (metadata + set_permissions)

- Executable files with matching permissions: 2 syscalls (metadata source + dest)
  Previously: 2 syscalls (metadata + set_permissions)

- Executable files needing update: 3 syscalls (metadata source + dest + set_permissions)
  Previously: 2 syscalls (metadata + set_permissions)

Performance impact for patched files (prefix replacement):
- Non-executable files: 0 additional syscalls
  Previously: 1 syscall (set_permissions)

- Executable files with matching permissions: 1 syscall (metadata dest)
  Previously: 1 syscall (set_permissions)

- Executable files needing update: 2 syscalls (metadata dest + set_permissions)
  Previously: 1 syscall (set_permissions)

Since the vast majority of package files are not executable, and many
executable files already have correct permissions after creation/reflink,
this provides a significant performance improvement during package installation.

The optimization only affects Unix systems. On Windows, permissions are
handled differently and this optimization is not applicable.

Fixes conda#486
@baszalmstra baszalmstra force-pushed the claude/implement-issue-486-011CUtGDc3P3dxwTpfv2dtKg branch from dc8a610 to 57c6be1 Compare November 7, 2025 10:02
@baszalmstra
Copy link
Collaborator Author

Running this locally on my WSL Ubuntu 22.04 (which doesn't support reflinking) the performance impact is small (~1%). Which is expected. I would be mostly interested to see if this has an impact on macOS.

@tdejager
Copy link
Collaborator

@baszalmstra how can I measure the impact?

@baszalmstra
Copy link
Collaborator Author

Build rattler-bin twice, once on main and once using this PR then run:

hyperfine -w 1 \
  -p "rm -rf .prefix" "./rattler-main create jupyterlab -c https://prefix.dev/conda-forge" \
  -p "rm -rf .prefix" "./target/release/rattler create jupyterlab -c https://prefix.dev/conda-forge"

I expect the biggest difference will be one linux with a filesystem that allows reflinks.

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.

Consider not copying permissions when reflinking on macOS

3 participants