Optimize Fetcher::find and fix quickinstall reporting (#579)

* Optimize `Fetcher::find`: Make it non-async to avoid boxing
   and return `AutoAbortJoinHandle<...>` instead.
   
   Since spawning a new task in tokio box the future anyway, boxing the
   returned future again in `Fetcher::find` merely adds unnecessary
   overheads.
* Optimize `QuickInstall::report`: Make it async fn instead of ret `JoinHandle`
   
   This provides several benefits:
    - On debug build, no task will be spawned
    - The calls to `self.stats_url()` can be evaluated in parallel.
    - The task now returns `()` so that the task spawned is smaller.
* Fix `QuickInstall::find`: `warn!` if quickinstall report fails

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2022-11-30 14:15:22 +11:00 committed by GitHub
parent ff737730f4
commit ab3e47c42b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 84 deletions

View file

@ -6,7 +6,7 @@ pub use quickinstall::*;
use crate::{ use crate::{
errors::BinstallError, errors::BinstallError,
helpers::remote::Client, helpers::{remote::Client, tasks::AutoAbortJoinHandle},
manifests::cargo_toml_binstall::{PkgFmt, PkgMeta}, manifests::cargo_toml_binstall::{PkgFmt, PkgMeta},
}; };
@ -32,7 +32,7 @@ pub trait Fetcher: Send + Sync {
/// ///
/// Must return `true` if a package is available, `false` if none is, and reserve errors to /// Must return `true` if a package is available, `false` if none is, and reserve errors to
/// fatal conditions only. /// fatal conditions only.
async fn find(&self) -> Result<bool, BinstallError>; fn find(self: Arc<Self>) -> AutoAbortJoinHandle<Result<bool, BinstallError>>;
/// Return the package format /// Return the package format
fn pkg_fmt(&self) -> PkgFmt; fn pkg_fmt(&self) -> PkgFmt;

View file

@ -16,6 +16,7 @@ use crate::{
download::Download, download::Download,
remote::{Client, Method}, remote::{Client, Method},
signal::wait_on_cancellation_signal, signal::wait_on_cancellation_signal,
tasks::AutoAbortJoinHandle,
}, },
manifests::cargo_toml_binstall::{PkgFmt, PkgMeta}, manifests::cargo_toml_binstall::{PkgFmt, PkgMeta},
}; };
@ -83,7 +84,8 @@ impl super::Fetcher for GhCrateMeta {
}) })
} }
async fn find(&self) -> Result<bool, BinstallError> { fn find(self: Arc<Self>) -> AutoAbortJoinHandle<Result<bool, BinstallError>> {
AutoAbortJoinHandle::spawn(async move {
let repo = if let Some(repo) = self.data.repo.as_deref() { let repo = if let Some(repo) = self.data.repo.as_deref() {
Some( Some(
self.client self.client
@ -128,16 +130,20 @@ impl super::Fetcher for GhCrateMeta {
let repo = repo.map(String::from); let repo = repo.map(String::from);
let repo = repo.as_deref().map(|u| u.trim_end_matches('/')); let repo = repo.as_deref().map(|u| u.trim_end_matches('/'));
// Use reference to self to fix error of closure
// launch_baseline_find_tasks which moves `this`
let this = &self;
let launch_baseline_find_tasks = |pkg_fmt| { let launch_baseline_find_tasks = |pkg_fmt| {
match &pkg_urls { match &pkg_urls {
Either::Left(pkg_url) => Either::Left(iter::once(*pkg_url)), Either::Left(pkg_url) => Either::Left(iter::once(*pkg_url)),
Either::Right(pkg_urls) => Either::Right(pkg_urls.iter().map(Deref::deref)), Either::Right(pkg_urls) => Either::Right(pkg_urls.iter().map(Deref::deref)),
} }
.flat_map(move |pkg_url| self.launch_baseline_find_tasks(pkg_fmt, pkg_url, repo)) .flat_map(move |pkg_url| this.launch_baseline_find_tasks(pkg_fmt, pkg_url, repo))
}; };
let mut handles: FuturesUnordered<_> = if let Some(pkg_fmt) = self.target_data.meta.pkg_fmt let mut handles: FuturesUnordered<_> =
{ if let Some(pkg_fmt) = self.target_data.meta.pkg_fmt {
launch_baseline_find_tasks(pkg_fmt).collect() launch_baseline_find_tasks(pkg_fmt).collect()
} else { } else {
PkgFmt::iter() PkgFmt::iter()
@ -154,6 +160,7 @@ impl super::Fetcher for GhCrateMeta {
} }
Ok(false) Ok(false)
})
} }
async fn fetch_and_extract(&self, dst: &Path) -> Result<(), BinstallError> { async fn fetch_and_extract(&self, dst: &Path) -> Result<(), BinstallError> {

View file

@ -1,8 +1,7 @@
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use compact_str::CompactString; use compact_str::CompactString;
use tokio::task::JoinHandle; use tracing::{debug, warn};
use tracing::debug;
use url::Url; use url::Url;
use crate::{ use crate::{
@ -11,6 +10,7 @@ use crate::{
download::Download, download::Download,
remote::{Client, Method}, remote::{Client, Method},
signal::wait_on_cancellation_signal, signal::wait_on_cancellation_signal,
tasks::AutoAbortJoinHandle,
}, },
manifests::cargo_toml_binstall::{PkgFmt, PkgMeta}, manifests::cargo_toml_binstall::{PkgFmt, PkgMeta},
}; };
@ -43,14 +43,29 @@ impl super::Fetcher for QuickInstall {
}) })
} }
async fn find(&self) -> Result<bool, BinstallError> { fn find(self: Arc<Self>) -> AutoAbortJoinHandle<Result<bool, BinstallError>> {
AutoAbortJoinHandle::spawn(async move {
if cfg!(debug_assertions) {
debug!("Not sending quickinstall report in debug mode");
} else {
let this = self.clone();
tokio::spawn(async move {
if let Err(err) = this.report().await {
warn!(
"Failed to send quickinstall report for package {}: {err}",
this.package
)
}
});
}
let url = self.package_url(); let url = self.package_url();
self.report();
debug!("Checking for package at: '{url}'"); debug!("Checking for package at: '{url}'");
Ok(self Ok(self
.client .client
.remote_exists(Url::parse(&url)?, Method::HEAD) .remote_exists(Url::parse(&url)?, Method::HEAD)
.await?) .await?)
})
} }
async fn fetch_and_extract(&self, dst: &Path) -> Result<(), BinstallError> { async fn fetch_and_extract(&self, dst: &Path) -> Result<(), BinstallError> {
@ -110,22 +125,12 @@ impl QuickInstall {
) )
} }
pub fn report(&self) -> JoinHandle<Result<(), BinstallError>> { pub async fn report(&self) -> Result<(), BinstallError> {
let stats_url = self.stats_url(); let url = Url::parse(&self.stats_url())?;
let client = self.client.clone();
tokio::spawn(async move {
if cfg!(debug_assertions) {
debug!("Not sending quickinstall report in debug mode");
return Ok(());
}
let url = Url::parse(&stats_url)?;
debug!("Sending installation report to quickinstall ({url})"); debug!("Sending installation report to quickinstall ({url})");
client.remote_exists(url, Method::HEAD).await?; self.client.remote_exists(url, Method::HEAD).await?;
Ok(()) Ok(())
})
} }
} }

View file

@ -20,7 +20,7 @@ use crate::{
drivers::fetch_crate_cratesio, drivers::fetch_crate_cratesio,
errors::BinstallError, errors::BinstallError,
fetchers::{Data, Fetcher, TargetData}, fetchers::{Data, Fetcher, TargetData},
helpers::{remote::Client, tasks::AutoAbortJoinHandle}, helpers::remote::Client,
manifests::cargo_toml_binstall::{Meta, PkgMeta, PkgOverride}, manifests::cargo_toml_binstall::{Meta, PkgMeta, PkgOverride},
}; };
@ -162,10 +162,7 @@ async fn resolve_inner(
.cartesian_product(resolvers) .cartesian_product(resolvers)
.map(|(target_data, f)| { .map(|(target_data, f)| {
let fetcher = f(opts.client.clone(), data.clone(), target_data); let fetcher = f(opts.client.clone(), data.clone(), target_data);
( (fetcher.clone(), fetcher.find())
fetcher.clone(),
AutoAbortJoinHandle::spawn(async move { fetcher.find().await }),
)
}), }),
); );