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        if config.global.dry_run {
44            repo.warm_up(prune_plan.repack_packs().into_iter())?;
45        } else {
46            repo.prune(&self.opts, prune_plan)?;
47        }
48
49        Ok(())
50    }
51}
52
53/// Print statistics about the prune operation
54///
55/// # Arguments
56///
57/// * `stats` - Statistics about the prune operation
58#[allow(clippy::cast_precision_loss)]
59fn print_stats(stats: &PruneStats) {
60    let pack_stat = &stats.packs;
61    let blob_stat = stats.blobs_sum();
62    let size_stat = stats.size_sum();
63
64    debug!("statistics:");
65    debug!("{:#?}", stats.debug);
66
67    debug!(
68        "used:   {:>10} blobs, {:>10}",
69        blob_stat.used,
70        bytes_size_to_string(size_stat.used)
71    );
72
73    debug!(
74        "unused: {:>10} blobs, {:>10}",
75        blob_stat.unused,
76        bytes_size_to_string(size_stat.unused)
77    );
78    debug!(
79        "total:  {:>10} blobs, {:>10}",
80        blob_stat.total(),
81        bytes_size_to_string(size_stat.total())
82    );
83
84    info!(
85        "to repack: {:>10} packs, {:>10} blobs, {:>10}",
86        pack_stat.repack,
87        blob_stat.repack,
88        bytes_size_to_string(size_stat.repack)
89    );
90    info!(
91        "this removes:                {:>10} blobs, {:>10}",
92        blob_stat.repackrm,
93        bytes_size_to_string(size_stat.repackrm)
94    );
95    info!(
96        "to delete: {:>10} packs, {:>10} blobs, {:>10}",
97        pack_stat.unused,
98        blob_stat.remove,
99        bytes_size_to_string(size_stat.remove)
100    );
101    if stats.packs_unref > 0 {
102        info!(
103            "unindexed: {:>10} packs,         ?? blobs, {:>10}",
104            stats.packs_unref,
105            bytes_size_to_string(stats.size_unref)
106        );
107    }
108
109    info!(
110        "total prune:                 {:>10} blobs, {:>10}",
111        blob_stat.repackrm + blob_stat.remove,
112        bytes_size_to_string(size_stat.repackrm + size_stat.remove + stats.size_unref)
113    );
114    info!(
115        "remaining:                   {:>10} blobs, {:>10}",
116        blob_stat.total_after_prune(),
117        bytes_size_to_string(size_stat.total_after_prune())
118    );
119    info!(
120        "unused size after prune: {:>10} ({:.2}% of remaining size)",
121        bytes_size_to_string(size_stat.unused_after_prune()),
122        size_stat.unused_after_prune() as f64 / size_stat.total_after_prune() as f64 * 100.0
123    );
124
125    info!(
126        "packs marked for deletion: {:>10}, {:>10}",
127        stats.packs_to_delete.total(),
128        bytes_size_to_string(stats.size_to_delete.total()),
129    );
130    info!(
131        " - complete deletion:      {:>10}, {:>10}",
132        stats.packs_to_delete.remove,
133        bytes_size_to_string(stats.size_to_delete.remove),
134    );
135    info!(
136        " - keep marked:            {:>10}, {:>10}",
137        stats.packs_to_delete.keep,
138        bytes_size_to_string(stats.size_to_delete.keep),
139    );
140    info!(
141        " - recover:                {:>10}, {:>10}",
142        stats.packs_to_delete.recover,
143        bytes_size_to_string(stats.size_to_delete.recover),
144    );
145
146    debug!(
147        "index files to rebuild: {} / {}",
148        stats.index_files_rebuild, stats.index_files
149    );
150}