rustic_rs/commands/
prune.rs1use 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#[allow(clippy::struct_excessive_bools)]
15#[derive(clap::Parser, Command, Debug, Clone)]
16pub(crate) struct PruneCmd {
17 #[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#[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}