use crate::{
Application, RUSTIC_APP, helpers::bytes_size_to_string, repository::OpenRepo, status_err,
};
use abscissa_core::{Command, Runnable, Shutdown};
use log::{debug, info};
use anyhow::Result;
use rustic_core::{PruneOptions, PruneStats};
#[allow(clippy::struct_excessive_bools)]
#[derive(clap::Parser, Command, Debug, Clone)]
pub(crate) struct PruneCmd {
#[clap(flatten)]
pub(crate) opts: PruneOptions,
}
impl Runnable for PruneCmd {
fn run(&self) {
if let Err(err) = RUSTIC_APP
.config()
.repository
.run_open(|repo| self.inner_run(repo))
{
status_err!("{}", err);
RUSTIC_APP.shutdown(Shutdown::Crash);
};
}
}
impl PruneCmd {
fn inner_run(&self, repo: OpenRepo) -> Result<()> {
let config = RUSTIC_APP.config();
let prune_plan = repo.prune_plan(&self.opts)?;
print_stats(&prune_plan.stats);
let dry_run = config.global.dry_run;
if dry_run && config.global.dry_run_warmup {
repo.warm_up(prune_plan.repack_packs().into_iter())?;
} else if !config.global.dry_run_warmup {
debug!("Ignoring --dry-run-warmup works only in combination with --dry-run");
}
if !dry_run {
repo.prune(&self.opts, prune_plan)?;
}
Ok(())
}
}
#[allow(clippy::cast_precision_loss)]
fn print_stats(stats: &PruneStats) {
let pack_stat = &stats.packs;
let blob_stat = stats.blobs_sum();
let size_stat = stats.size_sum();
debug!("statistics:");
debug!("{:#?}", stats.debug);
debug!(
"used: {:>10} blobs, {:>10}",
blob_stat.used,
bytes_size_to_string(size_stat.used)
);
debug!(
"unused: {:>10} blobs, {:>10}",
blob_stat.unused,
bytes_size_to_string(size_stat.unused)
);
debug!(
"total: {:>10} blobs, {:>10}",
blob_stat.total(),
bytes_size_to_string(size_stat.total())
);
info!(
"to repack: {:>10} packs, {:>10} blobs, {:>10}",
pack_stat.repack,
blob_stat.repack,
bytes_size_to_string(size_stat.repack)
);
info!(
"this removes: {:>10} blobs, {:>10}",
blob_stat.repackrm,
bytes_size_to_string(size_stat.repackrm)
);
info!(
"to delete: {:>10} packs, {:>10} blobs, {:>10}",
pack_stat.unused,
blob_stat.remove,
bytes_size_to_string(size_stat.remove)
);
if stats.packs_unref > 0 {
info!(
"unindexed: {:>10} packs, ?? blobs, {:>10}",
stats.packs_unref,
bytes_size_to_string(stats.size_unref)
);
}
info!(
"total prune: {:>10} blobs, {:>10}",
blob_stat.repackrm + blob_stat.remove,
bytes_size_to_string(size_stat.repackrm + size_stat.remove + stats.size_unref)
);
info!(
"remaining: {:>10} blobs, {:>10}",
blob_stat.total_after_prune(),
bytes_size_to_string(size_stat.total_after_prune())
);
info!(
"unused size after prune: {:>10} ({:.2}% of remaining size)",
bytes_size_to_string(size_stat.unused_after_prune()),
size_stat.unused_after_prune() as f64 / size_stat.total_after_prune() as f64 * 100.0
);
info!(
"packs marked for deletion: {:>10}, {:>10}",
stats.packs_to_delete.total(),
bytes_size_to_string(stats.size_to_delete.total()),
);
info!(
" - complete deletion: {:>10}, {:>10}",
stats.packs_to_delete.remove,
bytes_size_to_string(stats.size_to_delete.remove),
);
info!(
" - keep marked: {:>10}, {:>10}",
stats.packs_to_delete.keep,
bytes_size_to_string(stats.size_to_delete.keep),
);
info!(
" - recover: {:>10}, {:>10}",
stats.packs_to_delete.recover,
bytes_size_to_string(stats.size_to_delete.recover),
);
debug!(
"index files to rebuild: {} / {}",
stats.index_files_rebuild, stats.index_files
);
}