Skip to content

feat(dist): stage fresh toolchains before atomic publication - #4965

Open
cachebag wants to merge 4 commits into
rust-lang:mainfrom
cachebag:poc/staged-toolchain-install
Open

feat(dist): stage fresh toolchains before atomic publication#4965
cachebag wants to merge 4 commits into
rust-lang:mainfrom
cachebag:poc/staged-toolchain-install

Conversation

@cachebag

@cachebag cachebag commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

This PR implements the second step of the plan discussed in #4663 (details in my design notes), addressing #4400 and #4724 for fresh installs.

The idea is that a fresh toolchain now builds in its own "staging" directory and is then published to toolchains/<name> with a same-filesystem rename, with the update hash only being written after publication. In the case of an interrupted install, this means no partial toolchain is left behind and a retry always works. The stage itself lives at a deterministic per-toolchain path guarded by an OS-released file lock, so an abandoned stage gets reclaimed by the next install instead of accumulating, and a concurrent install of the same toolchain fails fast instead of racing.

Updates still modify toolchains in place, and blocking instead of failing is deferred to the locking work in #988.

cc @rami3l

@cachebag
cachebag force-pushed the poc/staged-toolchain-install branch 2 times, most recently from 6189268 to 0611f4c Compare July 20, 2026 01:30
@rami3l rami3l self-assigned this Jul 20, 2026
@rami3l
rami3l self-requested a review July 20, 2026 08:46
@cachebag
cachebag marked this pull request as draft July 20, 2026 10:35
@cachebag
cachebag force-pushed the poc/staged-toolchain-install branch 2 times, most recently from 02a3bd7 to 109729d Compare July 29, 2026 17:24
@rustbot

This comment has been minimized.

@cachebag
cachebag force-pushed the poc/staged-toolchain-install branch from 109729d to acc04b6 Compare August 2, 2026 00:14
@cachebag
cachebag marked this pull request as ready for review August 2, 2026 00:16
…g dir

Fresh dist installs now stage under `toolchains/+rustup-staging-<name>`,
so interrupted installs of the same toolchain reuse a single staging
directory instead of accumulating abandoned ones. The stage is guarded
by an exclusive advisory file lock held for its lifetime: a dead owner's
stage is reclaimed on the next attempt, while a live owner makes the
contending install fail fast with a clear error. Blocking instead of
failing, and serializing whole operations, is left to the locking work
tracked in rust-lang#988.

Publication failures are classified: if the destination appeared while
the install was staging, the error now says so instead of surfacing a
bare rename failure.

The staged dispatch moves into `InstallMethod::run`, checkpoint names
become exported constants co-located with their checkpoint sites, and
the stray-hash removal in `install_into` is dropped as unreachable:
staged installs never read the alias-scoped hash and rewrite it after
publication.
Interrupted installs are asserted to reuse one deterministic staging
path; a stale stage left by a dead process is reclaimed without leaking
its contents into the published toolchain; and a stray update hash is
ignored during a staged install and refreshed after publication.
@cachebag
cachebag force-pushed the poc/staged-toolchain-install branch from acc04b6 to 5553723 Compare August 5, 2026 19:12
@rustbot

rustbot commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rami3l rami3l left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

I have a question though: If I understand it correctly, we are performing the final stage of the installation in an isolated path under toolchain/ in this case (so no indirection WRT the actual toolchain), how can this evolve into the A/B partitioning scheme as we have previously discussed?

View changes since this review

Comment thread tests/suite/cli_crash.rs Outdated
assert_nightly_is_complete(&cx).await;
}

const BEFORE_METADATA: &str = "manifestation-update-before-metadata";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: It looks like those constants are not fully reused. Try moving them to the specific module instead of just under ./tests (there is an existing example already).

Comment thread src/install.rs
#[cfg(feature = "test")]
use crate::test::checkpoint;

impl StagedToolchain {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Logically impl blocks should follow the type declaration.

Comment thread src/install.rs
}
}

async fn run_staged_dist(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe inline this into .run()?

Comment thread tests/suite/cli_crash.rs Outdated
assert_nightly_is_complete(&cx).await;
}

const BEFORE_METADATA: &str = "manifestation-update-before-metadata";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prevent back-and-forth in a single PR; reorganize the history so that each new change are as close to the place at the end of this PR as possible.

Comment thread src/install.rs
let name = destination
.file_name()
.and_then(|name| name.to_str())
.expect("toolchain destination must have a UTF-8 base name");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here name being a path segment can safely stay as OsStr[ing], there seems to be no need to convert it to a native string?.

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.

3 participants