-
Notifications
You must be signed in to change notification settings - Fork 976
Interleave downloads with installations when downloading a toolchain #4471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Interleave downloads with installations when downloading a toolchain #4471
Conversation
c4b68b2
to
c2954ba
Compare
c2954ba
to
1d7e5f5
Compare
src/dist/notifications.rs
Outdated
} | ||
} | ||
ComponentInstalled(c, h, t) => { | ||
if Some(h) == t.as_ref() || t.is_none() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Now that we are at it, I would probably give an extra commit to avoid the t.unwrap()
here by flipping the if
and writing something like:
if let Some(t) = t && t != h { ... } else { ... }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this based on how other Notifications were being handled.
Should I refactor all of them now, leave that for another PR, or just change this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@FranciscoTGouveia It should be worthwhile to refactor them all in a separate commit (before your addition) lest we forget about it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you agree, I would like to leave this for a follow-up PR, right after this one is merged.
So I suggest leaving this as unresolved for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, let's do #4471 (comment) for the particular change in this PR, and then move the rest to that style in a subsequent PR.
0ea9162
to
a2a2c20
Compare
947b8da
to
9e5d0e0
Compare
9e5d0e0
to
dd68c17
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modulo the previously requested changes and the two extra nits, I think this PR is quite ready. Thanks a lot, @FranciscoTGouveia!
d149360
to
1b88c36
Compare
Even though downloads are done concurrently, the installations are done sequentially. This means that, as downloads complete, they are in a queue (an mpsc channel) waiting to be consumed by the future responsible for the (sequential) installations. There was a need to relax some test cases to allow for uninstall to happen before the downloads.
…ation with a download
…how a component was installed
…hread installations Co-authored-by: rami3l <[email protected]>
…nue during installations Co-authored-by: rami3l <[email protected]>
1b88c36
to
5b8e05a
Compare
src/dist/manifestation.rs
Outdated
component: Component, | ||
format: CompressionKind, | ||
installer_file: File, | ||
tmp_cx: &temp::Context, | ||
download_cfg: &DownloadCfg<'_>, | ||
new_manifest: &Manifest, | ||
tx: Transaction<'a>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the number of arguments is here too large, and this should be rethought to have a named field struct
that can hold all/most of the arguments.
I think the pre-existing code here could benefit from some refactoring as well, for example by packaging together the arguments passed into the compression wrappers. The uninitialized variables structure also sounds out as pretty unidiomatic.
src/dist/manifestation.rs
Outdated
let download_tx_cloned = download_tx.clone(); | ||
async move { | ||
let _permit = sem.acquire().await.unwrap(); | ||
self.download_component( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pre-existing, but this argument list is also just too long, and I think we should find a different way to express this before layering on more complexity.
src/dist/manifestation.rs
Outdated
|
||
let semaphore = Arc::new(Semaphore::new(concurrent_downloads)); | ||
let component_stream = | ||
tokio_stream::iter(components.into_iter()).map(|(component, format, url, hash)| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest writing this closure as a named function.
|
||
let mut stream = component_stream.buffered(components_len); | ||
let download_handle = async { | ||
let mut hashes = Vec::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest writing this as a named function.
src/dist/manifestation.rs
Outdated
} | ||
hashes | ||
}; | ||
let install_handle = async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest writing this as a named function.
.keys() | ||
.find(|comp| comp.contains(component)) | ||
.cloned(); | ||
if let Some(key) = key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: invert these for early returns.
} | ||
|
||
/// Notifies self that the component has been installed. | ||
pub(crate) fn component_installed(&mut self, component: &str) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we share the duplicate code?
if let Some(t) = t | ||
&& t != h | ||
{ | ||
write!(f, "installing component '{c}' for '{t}'") | ||
} else { | ||
write!(f, "installing component '{c}'") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think this would look better as a match
:
match t {
Some(t) if != h => write!(f, ..),
_ => write!(f, ..),
}
ProgressStyle::with_template(if pb.position() != 0 { | ||
"{msg:>12.bold} downloaded {total_bytes} in {elapsed}" | ||
} else { | ||
"{msg:>12.bold} component already downloaded" | ||
}) | ||
.unwrap(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again there's a lot of duplication here, suggest adding a little abstraction to make it more obvious what happens here.
tmp_cx: &'a temp::Context, | ||
notify_handler: &'a dyn Fn(Notification<'_>), | ||
changes: Vec<ChangedItem>, | ||
tmp_cx: Arc<temp::Context>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to me that tmp_cx
, notify_handler
and process
should be bundled up together.
Very excited about these performance improvements! Personally I don't really feel comfortable with the added complexity in the current changes -- I think there should be some more refactoring before this can be cleanly added. |
Continuation of #4436.
This change aims to speed up the overall performance of the
rustup [toolchain] install
command by allowing the installation of a component to start immediately after its download completes.This approach is particularly beneficial for slower connections, as it enables installations to progress in parallel with ongoing downloads -- so by the time all downloads are finished, all installations should be completed as well.
NB: This PR is not yet ready for review. I believe this change should be backed by benchmarks and user feedback before moving forward. I’ll share those here in the next couple of days.