From b20f2ee8a782e301d3293c8a3cc4777886fdbd27 Mon Sep 17 00:00:00 2001 From: Alexander Weiss Date: Sun, 25 Jun 2023 08:26:24 +0200 Subject: [PATCH] move warm_up into rustic_core --- crates/rustic_core/src/commands/prune.rs | 2 + crates/rustic_core/src/error.rs | 2 + crates/rustic_core/src/lib.rs | 2 +- crates/rustic_core/src/repository.rs | 13 ++- crates/rustic_core/src/repository/warm_up.rs | 93 ++++++++++++++++++++ src/commands/prune.rs | 16 +--- src/commands/repair.rs | 9 +- src/commands/restore.rs | 15 ++-- src/helpers.rs | 92 ++----------------- 9 files changed, 125 insertions(+), 119 deletions(-) create mode 100644 crates/rustic_core/src/repository/warm_up.rs diff --git a/crates/rustic_core/src/commands/prune.rs b/crates/rustic_core/src/commands/prune.rs index dd4e0c18b..21f0ce124 100644 --- a/crates/rustic_core/src/commands/prune.rs +++ b/crates/rustic_core/src/commands/prune.rs @@ -715,6 +715,8 @@ impl PrunePlan { repo: &OpenRepository

, opts: &PruneOpts, ) -> RusticResult<()> { + repo.warm_up_wait(self.repack_packs().into_iter())?; + let be = &repo.dbe; let pb = &repo.pb; diff --git a/crates/rustic_core/src/error.rs b/crates/rustic_core/src/error.rs index 713abeb6a..38dea4a97 100644 --- a/crates/rustic_core/src/error.rs +++ b/crates/rustic_core/src/error.rs @@ -235,6 +235,8 @@ pub enum RepositoryErrorKind { AccessToConfigFileFailed, /// {0:?} FromNomError(nom::Err<()>), + /// {0:?} + FromThreadPoolbilderError(rayon::ThreadPoolBuildError), /// reading Password failed: `{0:?}` ReadingPasswordFromReaderFailed(std::io::Error), /// reading Password from prompt failed: `{0:?}` diff --git a/crates/rustic_core/src/lib.rs b/crates/rustic_core/src/lib.rs index 601b5344b..0a9213086 100644 --- a/crates/rustic_core/src/lib.rs +++ b/crates/rustic_core/src/lib.rs @@ -146,5 +146,5 @@ pub use crate::{ }, RepoFile, }, - repository::{parse_command, OpenRepository, Repository, RepositoryOptions}, + repository::{OpenRepository, Repository, RepositoryOptions}, }; diff --git a/crates/rustic_core/src/repository.rs b/crates/rustic_core/src/repository.rs index 7f530d05e..fc6ee8a20 100644 --- a/crates/rustic_core/src/repository.rs +++ b/crates/rustic_core/src/repository.rs @@ -36,7 +36,7 @@ use crate::{ crypto::aespoly1305::Key, error::RepositoryErrorKind, repofile::{configfile::ConfigFile, keyfile::find_key_in_backend}, - BlobType, IndexBackend, NoProgressBars, ProgressBars, PruneOpts, PrunePlan, RusticResult, + BlobType, Id, IndexBackend, NoProgressBars, ProgressBars, PruneOpts, PrunePlan, RusticResult, SnapshotFile, SnapshotGroup, SnapshotGroupCriterion, }; @@ -44,6 +44,9 @@ pub(super) mod constants { pub(super) const MAX_PASSWORD_RETRIES: usize = 5; } +mod warm_up; +use warm_up::{warm_up, warm_up_wait}; + #[serde_as] #[cfg_attr(feature = "clap", derive(clap::Parser))] #[cfg_attr(feature = "merge", derive(merge::Merge))] @@ -402,6 +405,14 @@ impl OpenRepository

{ pub fn infos_index(&self) -> RusticResult { commands::repoinfo::collect_index_infos(self) } + + pub fn warm_up(&self, packs: impl ExactSizeIterator) -> RusticResult<()> { + warm_up(self, packs) + } + + pub fn warm_up_wait(&self, packs: impl ExactSizeIterator) -> RusticResult<()> { + warm_up_wait(self, packs) + } } #[derive(Debug)] diff --git a/crates/rustic_core/src/repository/warm_up.rs b/crates/rustic_core/src/repository/warm_up.rs new file mode 100644 index 000000000..433005cd0 --- /dev/null +++ b/crates/rustic_core/src/repository/warm_up.rs @@ -0,0 +1,93 @@ +use std::process::Command; +use std::thread::sleep; + +use log::{debug, warn}; +use rayon::ThreadPoolBuilder; + +use super::parse_command; +use crate::{ + error::RepositoryErrorKind, FileType, Id, OpenRepository, Progress, ProgressBars, ReadBackend, + RusticResult, +}; + +pub(super) mod constants { + pub(super) const MAX_READER_THREADS_NUM: usize = 20; +} + +pub(crate) fn warm_up_wait( + repo: &OpenRepository

, + packs: impl ExactSizeIterator, +) -> RusticResult<()> { + warm_up(repo, packs)?; + if let Some(wait) = repo.opts.warm_up_wait { + let p = repo.pb.progress_spinner(format!("waiting {wait}...")); + sleep(*wait); + p.finish(); + } + Ok(()) +} + +pub(crate) fn warm_up( + repo: &OpenRepository

, + packs: impl ExactSizeIterator, +) -> RusticResult<()> { + if let Some(command) = &repo.opts.warm_up_command { + warm_up_command(packs, command, &repo.pb)?; + } else if repo.opts.warm_up { + warm_up_access(repo, packs)?; + } + Ok(()) +} + +fn warm_up_command( + packs: impl ExactSizeIterator, + command: &str, + pb: &P, +) -> RusticResult<()> { + let p = pb.progress_counter("warming up packs..."); + p.set_length(packs.len() as u64); + for pack in packs { + let actual_command = command.replace("%id", &pack.to_hex()); + debug!("calling {actual_command}..."); + let commands = parse_command::<()>(&actual_command) + .map_err(RepositoryErrorKind::FromNomError)? + .1; + let status = Command::new(commands[0]).args(&commands[1..]).status()?; + if !status.success() { + warn!("warm-up command was not successful for pack {pack:?}. {status}"); + } + } + p.finish(); + Ok(()) +} + +fn warm_up_access( + repo: &OpenRepository

, + packs: impl ExactSizeIterator, +) -> RusticResult<()> { + let mut be = repo.be.clone(); + be.set_option("retry", "false")?; + + let p = repo.pb.progress_counter("warming up packs..."); + p.set_length(packs.len() as u64); + + let pool = ThreadPoolBuilder::new() + .num_threads(constants::MAX_READER_THREADS_NUM) + .build() + .map_err(RepositoryErrorKind::FromThreadPoolbilderError)?; + let p = &p; + let be = &be; + pool.in_place_scope(|s| { + for pack in packs { + s.spawn(move |_| { + // ignore errors as they are expected from the warm-up + _ = be.read_partial(FileType::Pack, &pack, false, 0, 1); + p.inc(1); + }); + } + }); + + p.finish(); + + Ok(()) +} diff --git a/src/commands/prune.rs b/src/commands/prune.rs index dc0e5ef73..c58a6592c 100644 --- a/src/commands/prune.rs +++ b/src/commands/prune.rs @@ -12,8 +12,6 @@ use log::debug; use anyhow::Result; -use crate::helpers::warm_up_wait; - use rustic_core::{PruneOpts, PruneStats, Sum}; /// `prune` subcommand @@ -37,23 +35,15 @@ impl Runnable for PruneCmd { impl PruneCmd { fn inner_run(&self) -> Result<()> { let config = RUSTIC_APP.config(); - let progress_options = &config.global.progress_options; - let repo = open_repository(get_repository(&config)); let pruner = repo.prune_plan(&self.opts)?; print_stats(&pruner.stats); - let dry_run = config.global.dry_run; - warm_up_wait( - &repo, - pruner.repack_packs().into_iter(), - !dry_run, - progress_options, - )?; - - if !dry_run { + if config.global.dry_run { + repo.warm_up(pruner.repack_packs().into_iter())?; + } else { pruner.do_prune(&repo, &self.opts)?; } diff --git a/src/commands/repair.rs b/src/commands/repair.rs index 30604ac4f..5ebfa85e5 100644 --- a/src/commands/repair.rs +++ b/src/commands/repair.rs @@ -19,8 +19,6 @@ use rustic_core::{ ProgressBars, ReadBackend, ReadIndex, SnapshotFile, StringList, Tree, WriteBackend, }; -use crate::helpers::warm_up_wait; - /// `repair` subcommand #[derive(clap::Parser, Command, Debug)] pub(crate) struct RepairCmd { @@ -185,12 +183,7 @@ impl IndexSubCmd { // process packs which are listed but not contained in the index pack_read_header.extend(packs.into_iter().map(|(id, size)| (id, false, None, size))); - warm_up_wait( - &repo, - pack_read_header.iter().map(|(id, _, _, _)| *id), - true, - progress_options, - )?; + repo.warm_up_wait(pack_read_header.iter().map(|(id, _, _, _)| *id))?; let indexer = Indexer::new(be.clone()).into_shared(); let p = progress_options.progress_counter("reading pack headers"); diff --git a/src/commands/restore.rs b/src/commands/restore.rs index e93ed4364..568771b86 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -33,7 +33,7 @@ use rustic_core::{ TreeStreamerOptions, }; -use crate::{filtering::SnapshotFilter, helpers::warm_up_wait}; +use crate::filtering::SnapshotFilter; pub(crate) mod constants { pub(crate) const MAX_READER_THREADS_NUM: usize = 20; @@ -134,16 +134,11 @@ impl RestoreCmd { if file_infos.restore_size == 0 { info!("all file contents are fine."); + } else if config.global.dry_run { + repo.warm_up(file_infos.to_packs().into_iter())?; } else { - warm_up_wait( - &repo, - file_infos.to_packs().into_iter(), - !config.global.dry_run, - progress_options, - )?; - if !config.global.dry_run { - restore_contents(be, &dest, file_infos)?; - } + repo.warm_up_wait(file_infos.to_packs().into_iter())?; + restore_contents(be, &dest, file_infos)?; } if !config.global.dry_run { diff --git a/src/helpers.rs b/src/helpers.rs index 82676fe61..8375cb6e1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeSet, process::Command}; +use std::collections::BTreeSet; use abscissa_core::Application; use anyhow::Result; @@ -7,95 +7,15 @@ use comfy_table::{ presets::ASCII_MARKDOWN, Attribute, Cell, CellAlignment, ContentArrangement, Table, }; -use log::{debug, info, trace, warn}; -use rayon::{ - prelude::{IntoParallelRefIterator, ParallelBridge, ParallelIterator}, - ThreadPoolBuilder, -}; +use log::{info, trace}; +use rayon::prelude::{IntoParallelRefIterator, ParallelBridge, ParallelIterator}; use rustic_core::{ - parse_command, BlobType, DecryptWriteBackend, FileType, Id, IndexBackend, IndexedBackend, - Indexer, NodeType, OpenRepository, Packer, Progress, ProgressBars, ReadBackend, ReadIndex, - SnapshotFile, TreeStreamerOnce, + BlobType, DecryptWriteBackend, IndexBackend, IndexedBackend, Indexer, NodeType, OpenRepository, + Packer, Progress, ProgressBars, ReadIndex, SnapshotFile, TreeStreamerOnce, }; -use crate::{application::RUSTIC_APP, config::progress_options::ProgressOptions}; - -pub(super) mod constants { - pub(super) const MAX_READER_THREADS_NUM: usize = 20; -} - -pub(crate) fn warm_up_wait

( - repo: &OpenRepository

, - packs: impl ExactSizeIterator, - wait: bool, - progress_options: &ProgressOptions, -) -> Result<()> { - if let Some(command) = &repo.opts.warm_up_command { - warm_up_command(packs, command, progress_options)?; - } else if repo.opts.warm_up { - warm_up(&repo.be, packs, progress_options)?; - } - if wait { - if let Some(wait) = repo.opts.warm_up_wait { - let p = progress_options.progress_spinner(format!("waiting {wait}...")); - std::thread::sleep(*wait); - p.finish(); - } - } - Ok(()) -} - -pub(crate) fn warm_up_command( - packs: impl ExactSizeIterator, - command: &str, - progress_options: &ProgressOptions, -) -> Result<()> { - let p = progress_options.progress_counter("warming up packs..."); - p.set_length(packs.len() as u64); - for pack in packs { - let actual_command = command.replace("%id", &pack.to_hex()); - debug!("calling {actual_command}..."); - let commands = parse_command::<()>(&actual_command)?.1; - let status = Command::new(commands[0]).args(&commands[1..]).status()?; - if !status.success() { - warn!("warm-up command was not successful for pack {pack:?}. {status}"); - } - } - p.finish(); - Ok(()) -} - -pub(crate) fn warm_up( - be: &impl ReadBackend, - packs: impl ExactSizeIterator, - progress_options: &ProgressOptions, -) -> Result<()> { - let mut be = be.clone(); - be.set_option("retry", "false")?; - - let p = progress_options.progress_counter("warming up packs..."); - p.set_length(packs.len() as u64); - - let pool = ThreadPoolBuilder::new() - .num_threads(constants::MAX_READER_THREADS_NUM) - .build()?; - let p = &p; - let be = &be; - pool.in_place_scope(|s| { - for pack in packs { - s.spawn(move |_| { - // ignore errors as they are expected from the warm-up - _ = be.read_partial(FileType::Pack, &pack, false, 0, 1); - p.inc(1); - }); - } - }); - - p.finish(); - - Ok(()) -} +use crate::application::RUSTIC_APP; pub(crate) fn copy

( snapshots: &[SnapshotFile],