summaryrefslogtreecommitdiff
path: root/src/bin/summain.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/summain.rs')
-rw-r--r--src/bin/summain.rs52
1 files changed, 44 insertions, 8 deletions
diff --git a/src/bin/summain.rs b/src/bin/summain.rs
index 4336ebd..5031006 100644
--- a/src/bin/summain.rs
+++ b/src/bin/summain.rs
@@ -1,17 +1,51 @@
use anyhow::Context;
-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.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(())
}
@@ -21,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()))
}