- Commit
- 791bf7edf2bb285bc126af9baa3bfdde1a147479
- Parent
- f026aae21c05709ab539143b1ac34f6b9987da78
- Author
- Pablo <pablo-escobar@riseup.net>
- Date
Parallelized the rendering of the WebP thumbnails
Yet another static page generator for photo galleries
Parallelized the rendering of the WebP thumbnails
4 files changed, 73 insertions, 15 deletions
Status | File Name | N° Changes | Insertions | Deletions |
Modified | Cargo.lock | 27 | 27 | 0 |
Modified | Cargo.toml | 2 | 2 | 0 |
Modified | src/main.rs | 28 | 25 | 3 |
Modified | src/picture.rs | 31 | 19 | 12 |
diff --git a/Cargo.lock b/Cargo.lock @@ -196,6 +196,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] name = "image" version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -330,6 +336,16 @@ dependencies = [ ] [[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] name = "png" version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -460,8 +476,10 @@ name = "stapix" version = "0.1.0" dependencies = [ "image", + "num_cpus", "serde", "serde_yaml", + "threadpool", "webp", ] @@ -477,6 +495,15 @@ dependencies = [ ] [[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] name = "tiff" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml @@ -11,3 +11,5 @@ serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" webp = "0.2" image = "0.24.7" +threadpool = "1.8.1" +num_cpus = "1.16.0"
diff --git a/src/main.rs b/src/main.rs @@ -4,7 +4,9 @@ use std::fs::{self, File}; use std::io::{self, Write}; use std::path::PathBuf; use std::process::exit; +use std::sync::mpsc; use picture::Picture; +use threadpool::ThreadPool; mod picture; @@ -76,7 +78,7 @@ fn render_gallery(pics: Vec<Picture>) -> io::Result<()> { } } - // Warn the user if a particular path doesn't have an associated alt string + // ======================================================================== for pic in &pics { if pic.alt.is_empty() { println!( @@ -86,13 +88,33 @@ fn render_gallery(pics: Vec<Picture>) -> io::Result<()> { } } - // TODO: Parallelize this + // ======================================================================== let mut thumb_path = PathBuf::from(TARGET_PATH); thumb_path.push(THUMBS_PATH); + + let rendering_pool = ThreadPool::with_name( + String::from("thumbnails renderer"), + num_cpus::get() + 1 + ); + let (sender, reciever) = mpsc::channel(); + for pic in &pics { - pic.render_thumbnail(&thumb_path)?; + let sender = sender.clone(); + let pic = pic.clone(); + let thumb_path = thumb_path.clone(); + rendering_pool.execute(move || { + sender.send(pic.render_thumbnail(&thumb_path)) + .expect("channel should still be alive awaiting for the completion of this task"); + }); + } + + for msg in reciever.iter().take(pics.len()) { + if !msg { + exit(1); + } } + // ======================================================================== render_index(&pics)?; for pic in pics {
diff --git a/src/picture.rs b/src/picture.rs @@ -5,9 +5,8 @@ use serde::{ Deserialize, }; use std::fs::{self, File}; -use std::io::{self, Write}; +use std::io::Write; use std::path::{PathBuf, Path}; -use std::process::exit; /// WebP image quality const IMAGE_QUALITY: f32 = 50.0; @@ -26,15 +25,23 @@ pub struct Picture { impl Picture { // TODO: Render GIF files as mp4 instead - pub fn render_thumbnail(&self, target_dir: &Path) -> io::Result<()> { + /// Returns `true` if rendering succeded (or was skipped) and `false` + /// otherwise. All warinings and error messages should be logged in here. + pub fn render_thumbnail(&self, target_dir: &Path) -> bool { let thumb_path = target_dir.join(self.file_name.clone() + ".webp"); // Only try to render thumbnail in case the thumbnail file in the machine // is older than the source file if let (Ok(thumb_meta), Ok(img_meta)) = (fs::metadata(&thumb_path), fs::metadata(&self.path)) { - if thumb_meta.modified()? > img_meta.modified()? { - // TODO: Report a warning to the user - return Ok(()); + let thumb_mod_date = thumb_meta.modified() + .expect("os should support file modification date"); + let img_mod_date = img_meta.modified() + .expect("os should support file modification date"); + + if thumb_mod_date > img_mod_date { + println!("WARNING: Skipped rendering the WebP thumbnail for {name:?}.\nUpdate {path:?} to overwrite this behaviour", + name = self.file_name, path = self.path); + return true; } } @@ -42,7 +49,7 @@ impl Picture { Ok(f) => f, Err(err) => { eprintln!("ERROR: Couldn't open WebP thumbnail file {thumb_path:?}: {err}"); - exit(1); + return false; } }; @@ -53,7 +60,7 @@ impl Picture { "ERROR: Couldn't open file {path:?} to render WebP thumbnail: {err}", path = self.file_name ); - exit(1); + return false; } }; @@ -61,10 +68,10 @@ impl Picture { Ok(img) => img, Err(err) => { eprintln!( - "ERROR: Failed to decode image file {name:?}: {err}", + "ERROR: Faileded to decode image file {name:?}: {err}", name = self.file_name ); - exit(1); + return false; } }; @@ -84,10 +91,10 @@ impl Picture { if let Err(err) = thumb_file.write_all(&mem) { eprintln!("ERROR: Couldn't write WebP thumnail to file {thumb_path:?}: {err}"); - exit(1); + return false; } - Ok(()) + true } }