rustic_rs/commands/
prune.rs

1//! `prune` subcommand
2
3use crate::{
4    Application, RUSTIC_APP, helpers::bytes_size_to_string, repository::CliOpenRepo, status_err,
5};
6use abscissa_core::{Command, Runnable, Shutdown};
7use log::{debug, info};
8
9use anyhow::Result;
10
11use rustic_core::{PruneOptions, PruneStats};
12
13/// `prune` subcommand
14#[allow(clippy::struct_excessive_bools)]
15#[derive(clap::Parser, Command, Debug, Clone)]
16pub(crate) struct PruneCmd {
17    /// Prune options
18    #[clap(flatten)]
19    pub(crate) opts: PruneOptions,
20}
21
22impl Runnable for PruneCmd {
23    fn run(&self) {
24        if let Err(err) = RUSTIC_APP
25            .config()
26            .repository
27            .run_open(|repo| self.inner_run(repo))
28        {
29            status_err!("{}", err);
30            RUSTIC_APP.shutdown(Shutdown::Crash);
31        };
32    }
33}
34
35impl PruneCmd {
36    fn inner_run(&self, repo: CliOpenRepo) -> Result<()> {
37        let config = RUSTIC_APP.config();
38
39        let prune_plan = repo.prune_plan(&self.opts)?;
40
41        print_stats(&prune_plan.stats);
42
43        let dry_run = config.global.dry_run;
44        if dry_run && config.global.dry_run_warmup {
45            repo.warm_up(prune_plan.repack_packs().into_iter())?;
46        } else if !config.global.dry_run_warmup {
47            debug!("Ignoring --dry-run-warmup works only in combination with --dry-run");
48        }
49        if !dry_run {
50            repo.prune(&self.opts, prune_plan)?;
51        }
52
53        Ok(())
54    }
55}
56
57/// Print statistics about the prune operation
58///
59/// # Arguments
60///
61/// * `stats` - Statistics about the prune operation
62#[allow(clippy::cast_precision_loss)]
63fn print_stats(stats: &PruneStats) {
64    let pack_stat = &stats.packs;
65    let blob_stat = stats.blobs_sum();
66    let size_stat = stats.size_sum();
67
68    debug!("statistics:");
69    debug!("{:#?}", stats.debug);
70
71    debug!(
72        "used:   {:>10} blobs, {:>10}",
73        blob_stat.used,
74        bytes_size_to_string(size_stat.used)
75    );
76
77    debug!(
78        "unused: {:>10} blobs, {:>10}",
79        blob_stat.unused,
80        bytes_size_to_string(size_stat.unused)
81    );
82    debug!(
83        "total:  {:>10} blobs, {:>10}",
84        blob_stat.total(),
85        bytes_size_to_string(size_stat.total())
86    );
87
88    info!(
89        "to repack: {:>10} packs, {:>10} blobs, {:>10}",
90        pack_stat.repack,
91        blob_stat.repack,
92        bytes_size_to_string(size_stat.repack)
93    );
94    info!(
95        "this removes:                {:>10} blobs, {:>10}",
96        blob_stat.repackrm,
97        bytes_size_to_string(size_stat.repackrm)
98    );
99    info!(
100        "to delete: {:>10} packs, {:>10} blobs, {:>10}",
101        pack_stat.unused,
102        blob_stat.remove,
103        bytes_size_to_string(size_stat.remove)
104    );
105    if stats.packs_unref > 0 {
106        info!(
107            "unindexed: {:>10} packs,         ?? blobs, {:>10}",
108            stats.packs_unref,
109            bytes_size_to_string(stats.size_unref)
110        );
111    }
112
113    info!(
114        "total prune:                 {:>10} blobs, {:>10}",
115        blob_stat.repackrm + blob_stat.remove,
116        bytes_size_to_string(size_stat.repackrm + size_stat.remove + stats.size_unref)
117    );
118    info!(
119        "remaining:                   {:>10} blobs, {:>10}",
120        blob_stat.total_after_prune(),
121        bytes_size_to_string(size_stat.total_after_prune())
122    );
123    info!(
124        "unused size after prune: {:>10} ({:.2}% of remaining size)",
125        bytes_size_to_string(size_stat.unused_after_prune()),
126        size_stat.unused_after_prune() as f64 / size_stat.total_after_prune() as f64 * 100.0
127    );
128
129    info!(
130        "packs marked for deletion: {:>10}, {:>10}",
131        stats.packs_to_delete.total(),
132        bytes_size_to_string(stats.size_to_delete.total()),
133    );
134    info!(
135        " - complete deletion:      {:>10}, {:>10}",
136        stats.packs_to_delete.remove,
137        bytes_size_to_string(stats.size_to_delete.remove),
138    );
139    info!(
140        " - keep marked:            {:>10}, {:>10}",
141        stats.packs_to_delete.keep,
142        bytes_size_to_string(stats.size_to_delete.keep),
143    );
144    info!(
145        " - recover:                {:>10}, {:>10}",
146        stats.packs_to_delete.recover,
147        bytes_size_to_string(stats.size_to_delete.recover),
148    );
149
150    debug!(
151        "index files to rebuild: {} / {}",
152        stats.index_files_rebuild, stats.index_files
153    );
154}