diff options
Diffstat (limited to 'src/bin/summain.rs')
-rw-r--r-- | src/bin/summain.rs | 53 |
1 files changed, 44 insertions, 9 deletions
diff --git a/src/bin/summain.rs b/src/bin/summain.rs index a2e2b7a..5031006 100644 --- a/src/bin/summain.rs +++ b/src/bin/summain.rs @@ -1,18 +1,51 @@ use anyhow::Context; -use rayon::prelude::*; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use structopt::StructOpt; use summain::ManifestEntry; -fn main() -> anyhow::Result<()> { +#[tokio::main] +async fn main() -> anyhow::Result<()> { let mut opt = Opt::from_args(); opt.pathnames[..].sort(); - let v: Vec<anyhow::Result<ManifestEntry>> = - opt.pathnames.par_iter().map(|p| manifest(&p)).collect(); - for m in v { - let m = m?; + + // Get metadata about all files, but don't compute checksum yet. + // + // This all runs in async worker threads, since it's theoretically + // I/O heavy and benefits from async task context switching. We + // create a task for each named file, since tasks are very cheap. + // We keep the JoinHandle for each task in a vector: there's not + // going to be so many handles that the vector becomes impossibly + // large: Linux only allows 128 KiB of command line arguments. + + let mut handles = vec![]; + for filename in opt.pathnames.iter().cloned() { + handles.push(tokio::spawn(async move { manifest(filename) })); + } + + // Compute checksums for regular files. + // + // This runs in blocking threads, since it's CPU heavy. We create + // another vector of JoinHandles. Again, it won't become too large. + + let mut sumhandles = vec![]; + for h in handles { + let mut m: ManifestEntry = h.await?.await?; + let h = tokio::task::spawn_blocking(move || match m.compute_checksum() { + Err(e) => Err(e), + Ok(_) => Ok(m), + }); + sumhandles.push(h) + } + + // Wait for checksums to be available and print manifest. + // + // Note how this iterates over the results in the right order. + + for h in sumhandles { + let m: ManifestEntry = h.await??; print!("{}", serde_yaml::to_string(&m)?); } + Ok(()) } @@ -22,6 +55,8 @@ struct Opt { pathnames: Vec<PathBuf>, } -fn manifest(path: &Path) -> anyhow::Result<ManifestEntry> { - ManifestEntry::new(path).with_context(|| format!("{}", path.display())) +async fn manifest(path: PathBuf) -> anyhow::Result<ManifestEntry> { + ManifestEntry::new(&path) + .await + .with_context(|| format!("{}", path.display())) } |