Move the extracted JDK into the tool-cache instead of copying it - #1206
Merged
Conversation
Two wall-clock optimizations on the JDK install path. `tc.cacheDir` recursively copies the extracted tree into RUNNER_TOOL_CACHE, so a 200-600MB JDK is written to disk twice. The extraction directory and the tool-cache normally share a filesystem, so `cacheJdkDir` renames it instead and writes the `.complete` marker itself, mirroring the destination layout `tc.cacheDir` produces. It falls back to the copy when the tool-cache location is unknown, when the source is not a real directory (a symlinked source would otherwise leave a dangling entry once RUNNER_TEMP is cleaned), or when the rename fails - a cross-device tool-cache, or anti-virus holding a handle on Windows. The rename is atomic, so the source is still intact for the fallback. Extraction now uses `pigz` for tarballs when the runner provides it, and Windows zips go through the bundled `tar.exe` rather than `tc.extractZip`, which shells out to PowerShell's much slower `Expand-Archive`. Both fall back to the stock extraction and clean up the abandoned directory first. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b76d8cb0-f629-46e1-bf9a-ffde06948644
Contributor
There was a problem hiding this comment.
Pull request overview
This PR optimizes the JDK installation path in setup-java to reduce redundant disk I/O on cache misses by (1) moving extracted JDK directories into the GitHub Actions tool-cache instead of recursively copying them, and (2) speeding up archive extraction using faster tools when available (pigz for .tar.gz, tar.exe for Windows .zip).
Changes:
- Added
cacheJdkDir()to move (rename) extracted JDKs intoRUNNER_TOOL_CACHEwith a safe fallback totc.cacheDirwhen move isn’t possible. - Updated JDK extraction logic to prefer
pigzfor.tar.gzand Windows’%SystemRoot%\System32\tar.exefor.zip, with cleanup and fallbacks to existing@actions/tool-cacheextraction. - Updated installers across distributions to use
cacheJdkDir, and added a dedicated Jest test suite for the new move/extraction behaviors.
Show a summary per file
| File | Description |
|---|---|
| src/util.ts | Introduces cacheJdkDir (move-based tool-cache) and faster extraction paths for tar.gz/zip with fallbacks. |
| src/distributions/*/installer.ts | Switches distribution installers from tc.cacheDir to cacheJdkDir to avoid copy-based caching. |
| tests/util-install.test.ts | Adds tests covering move semantics, .complete marker behavior, and extraction fast-path fallbacks/cleanup. |
| dist/setup/, dist/cleanup/ | Updates compiled/bundled output to reflect the new util logic and installer wiring. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 17/34 changed files
- Comments generated: 0
- Review effort level: Lite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description:
Installing a JDK writes it to disk twice. Every distribution extracts the archive into
RUNNER_TEMPand then callstc.cacheDir, which recursively copies the whole tree intoRUNNER_TOOL_CACHE. For a 200-600MB JDK that is a few hundred megabytes of pure redundant I/O on every cache miss, and it is the single most expensive step in the install path - considerably more than the vendor metadata requests people usually suspect.This PR addresses that, plus the extraction step next to it.
1. Move instead of copy (
cacheJdkDir)New helper in
src/util.ts, replacingtc.cacheDirat all 15 distribution installers. The extraction directory and the tool-cache normally live on the same filesystem, so the copy can just be afs.renameSync. The helper mirrors the destination layouttc.cacheDirproduces exactly (includingsemver.clean(version) || versionand thearchdefault) and writes the.completemarker itself, sotc.findAllVersions/findInToolcachekeep resolving entries unchanged.It falls back to the original
tc.cacheDircopy when:RUNNER_TOOL_CACHEis unset,lstatis deliberate here: renaming a symlinked source would put the link itself in the tool-cache, leaving a danglingJAVA_HOMEonceRUNNER_TEMPis cleaned, and the.completemarker would make it look healthy forever,EXDEV. A rename is atomic, so a failure leaves the source fully intact for the fallback to copy.2. Faster extraction
extractJdkFilenow hands tarball decompression topigzwhen the runner provides it, and extracts Windows zips with the bundled%SystemRoot%\System32\tar.exeinstead oftc.extractZip, which shells out to PowerShell'sExpand-Archive(typically several times slower for a JDK-sized archive). Both paths fall back to the stock extraction, cleaning up the abandoned directory first so a failure does not double peak temp usage.Worth a careful look:
cacheDir/_createToolPath/_completeToolPathin@actions/tool-cacheto confirm the resulting layout is identical, and the symlink case above is the one place they genuinely differ, which is why it falls back.pigzis skipped if its resolved path contains whitespace, sincetarword-splits--use-compress-program..completemarker and directory layout match,java -versionworks, and a subsequent run resolves from the tool-cache with no network.Related issue:
N/A
Check list:
npm run checklocally (format, lint, build, test) and all checks pass.Tests: 20 new cases in
__tests__/util-install.test.tscovering the move, marker creation, replacing an existing entry, version/arch normalization parity withtc.cacheDir, and each fallback path (missing tool-cache root, symlinked source, rename failure with no stale marker left behind, pigz failure and cleanup, whitespace in the pigz path, Windows tar.exe failure and cleanup). Full suite is 1272 passing.