use std::mem;
use std::path::PathBuf;
use clap;
use output::Output;
use ::RawIndexEntry;
use ::convert::utils::*;
use ::misc::*;
use zbackup::disk_format::*;
use zbackup::repository_core::*;
pub fn balance_indexes (
output: & Output,
arguments: & BalanceIndexesArguments,
) -> Result <bool, String> {
let repository_core =
string_result_with_prefix (
|| format! (
"Error opening repository {}: ",
arguments.repository_path.to_string_lossy ()),
RepositoryCore::open (
& output,
& arguments.repository_path,
arguments.password_file_path.clone ()),
) ?;
let atomic_file_writer =
AtomicFileWriter::new (
output,
& arguments.repository_path,
None,
) ?;
let old_index_ids_and_sizes = (
scan_index_files_with_sizes (
& arguments.repository_path)
) ?;
let total_index_size =
old_index_ids_and_sizes.iter ().map (
|& (_, old_index_size)|
old_index_size
).sum ();
output.message_format (
format_args! (
"Found {} index files with total size {}",
old_index_ids_and_sizes.len (),
total_index_size));
let mut entries_buffer: Vec <RawIndexEntry> =
Vec::new ();
let mut balanced_index_size: u64 = 0;
let output_job =
output_job_start! (
output,
"Balancing indexes");
for (
old_index_id,
old_index_size,
) in old_index_ids_and_sizes {
let old_index_path =
repository_core.index_path (
old_index_id);
for old_index_entry in (
index_read_path (
& old_index_path,
repository_core.encryption_key (),
)
) ? {
entries_buffer.push (
old_index_entry);
if entries_buffer.len () as u64 == arguments.bundles_per_index {
let index_entries =
mem::replace (
& mut entries_buffer,
Vec::new ());
flush_index_entries (
output,
& repository_core,
& atomic_file_writer,
& index_entries,
) ?;
}
}
atomic_file_writer.delete (
old_index_path);
balanced_index_size +=
old_index_size;
output_job.progress (
balanced_index_size,
total_index_size);
}
if ! entries_buffer.is_empty () {
flush_index_entries (
output,
& repository_core,
& atomic_file_writer,
& mut entries_buffer,
) ?;
}
output_job.complete ();
let output_job =
output_job_start! (
output,
"Committing changes");
atomic_file_writer.commit () ?;
output_job.complete ();
Ok (true)
}
command! (
name = balance_indexes,
export = balance_indexes_command,
arguments = BalanceIndexesArguments {
repository_path: PathBuf,
password_file_path: Option <PathBuf>,
bundles_per_index: u64,
},
clap_subcommand = {
clap::SubCommand::with_name ("balance-indexes")
.about ("rewrites index files so they are a consistent size")
.arg (
clap::Arg::with_name ("repository")
.long ("repository")
.value_name ("REPOSITORY")
.required (true)
.help ("Path to the repository, used to obtain encryption key")
)
.arg (
clap::Arg::with_name ("password-file")
.long ("password-file")
.value_name ("PASSWORD-FILE")
.required (false)
.help ("Path to the password file")
)
.arg (
clap::Arg::with_name ("bundles-per-index")
.long ("bundles-per-index")
.value_name ("BUNDLES-PER-INDEX")
.default_value ("16384")
.help ("Bundles per index")
)
},
clap_arguments_parse = |clap_matches| {
BalanceIndexesArguments {
repository_path:
args::path_required (
& clap_matches,
"repository"),
password_file_path:
args::path_optional (
& clap_matches,
"password-file"),
bundles_per_index:
args::u64_required (
& clap_matches,
"bundles-per-index"),
}
},
action = |output, arguments| {
balance_indexes (output, arguments)
},
);