feat(cache): opt-in env var to prefer BSD tar on Windows#2379
feat(cache): opt-in env var to prefer BSD tar on Windows#2379zeitlinger wants to merge 1 commit intoactions:mainfrom
Conversation
Set ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS=true to route cache archive/extract through C:\Windows\System32\tar.exe (libarchive bsdtar) instead of Git-for-Windows' MSYS GNU tar. On hosted windows-latest runners, bsdtar extracts many-small-files payloads ~4x faster than MSYS tar because it makes native Win32 syscalls and has zstd built in (no fork-per-file to zstd.exe). Default behavior is unchanged — this only takes effect when the env var is explicitly set. The existing BSD_TAR_ZSTD two-command path handles the BSD tar case end-to-end. Refs: actions/cache#752 Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
There was a problem hiding this comment.
Pull request overview
Adds an opt-in Windows behavior switch to prefer the built-in libarchive tar.exe (bsdtar) for cache archive/extract selection, aiming to speed up extraction of caches with many small files while keeping the existing default unchanged.
Changes:
- Introduces
ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS=trueto selectSystemTarPathOnWindowsahead of GNU tar onwin32when available. - Adds a Windows unit test ensuring the opt-in env var prefers BSD tar even when GNU tar is present.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/cache/src/internal/tar.ts | Adds Windows tar-selection opt-in env var to prefer system bsdtar when present. |
| packages/cache/tests/tar.test.ts | Adds a Windows test covering the new opt-in tar-selection behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| process.env['ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS'] = 'true' | ||
|
|
There was a problem hiding this comment.
This test deletes ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS in finally, which can clobber an existing value if the env var was already set in the test environment. To keep the test hermetic, capture the prior value before setting it and restore it in finally (set back to the old value or delete only if it was originally undefined).
| const gnuTar = await utils.getGnuTarPathOnWindows() | ||
| const systemTar = SystemTarPathOnWindows | ||
| // Opt-in: prefer BSD tar (libarchive, shipped as | ||
| // C:\Windows\System32\tar.exe on Windows 10+). Benchmarks on hosted | ||
| // runners show ~4x faster extract on many-small-files payloads |
There was a problem hiding this comment.
On Windows, getGnuTarPathOnWindows() is awaited before checking the opt-in env var. If GnuTarPathOnWindows doesn’t exist, that helper runs tar --version, which is unnecessary work when ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS=true and SystemTarPathOnWindows exists. Consider checking the env var + existsSync(systemTar) first, and only probing GNU tar when the opt-in isn’t taking effect (or as a fallback).
| // compared to Git for Windows' MSYS GNU tar, because bsdtar makes | ||
| // native Win32 syscalls and has zstd built in (no external | ||
| // zstd.exe fork-per-file). See actions/cache#752 for context. |
There was a problem hiding this comment.
The added comment attributes the speedup partly to “bsdtar … has zstd built in (no external zstd.exe …)”, but the Windows BSD path in this module still shells out to zstd as a separate command (BSD_TAR_ZSTD). This explanation seems misleading/inaccurate relative to what the code actually does; consider rewriting the comment to focus on the MSYS/GNU tar overhead vs native libarchive behavior, or update the implementation if the intent is to leverage bsdtar’s built-in zstd support.
| // compared to Git for Windows' MSYS GNU tar, because bsdtar makes | |
| // native Win32 syscalls and has zstd built in (no external | |
| // zstd.exe fork-per-file). See actions/cache#752 for context. | |
| // compared to Git for Windows' MSYS GNU tar, likely due to native | |
| // Win32/libarchive behavior and lower MSYS process/path translation | |
| // overhead. See actions/cache#752 for context. |
Summary
Adds an opt-in env var
ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWSthat routescache archive/extract through
C:\Windows\System32\tar.exe(libarchive bsdtar)instead of Git-for-Windows' MSYS GNU tar. Default behavior is unchanged.
Refs actions/cache#752.
Why
On hosted
windows-latestrunners, extract of a many-small-files cache isdominated by MSYS tar's POSIX-shim + fork-per-file overhead. Concrete numbers
from a fresh bench on
windows-2025hosted runner (568 MB mise install dir,~40k files, zstd):
*Measured in production CI (
jdx/mise-actionon flint). Bench harness below.That's ~4× faster extract with no archive-size penalty. bsdtar makes native
Win32 syscalls and has zstd built in (no external
zstd.exefork-per-file).Windows Defender exclusions on the target dir only shave ~12 s off the MSYS
path and near-zero off bsdtar — confirming the bottleneck is tar, not AV scans.
Why opt-in (not default)
slashes, permission mapping). Archives written by one are readable by the
other in all formats this package uses (posix ustar + zstd), but switching
the default deserves its own follow-up once this has soaked.
jdx/mise-actionenable the fast path today.Design
getTarPath()onwin32:ACTIONS_CACHE_PREFER_BSD_TAR_ON_WINDOWS=trueandC:\Windows\System32\tar.exeexists → return BSD.The existing
BSD_TAR_ZSTDtwo-command path (zstd + tar piped via temp file)handles the BSD case end-to-end — no changes needed elsewhere.
Test plan
zstd extract tar prefers BSDtar when opt-in env var set— mirrors the existing BSDtar test but keeps GNU tar available, sets the
env var, asserts BSD path is selected and the two-command extract is
invoked. All 12 tar tests pass.
npx prettier --checkandnpx eslintclean on changed files.actions/cacheconsumer (e.g. a mise-actioncache hit) with the env var set shows the extract-time improvement.
Bench reproducer
Workflow used to produce the numbers above (ran on
windows-2025, populatedmise install dir):
https://github.com/grafana/flint/blob/ci/bench-win-extract/.github/workflows/bench-win-extract.yml