pub mod options;
pub mod source;
pub mod volume;
mod encode;
mod metal;
mod output;
mod plan;
mod transform;
pub use encode::ForwardKernel;
pub(crate) use encode::configured_create_threads as configured_create_threads_for_pool;
pub use options::{BlockSizing, CreationBackend, Par2CreatorOptions, RecoveryAmount, VolumeScheme};
pub use output::Par2CreateOutcome;
pub use plan::{Par2CreatePlan, Par2MemoryPlan};
pub use source::CreationSource;
pub use volume::RecoveryVolumePlan;
use crate::error::{Par2Error, Result};
use self::output::write_outputs;
use self::plan::build_plan_with_cache;
#[derive(Clone)]
pub struct Par2Creator {
options: Par2CreatorOptions,
scan: std::sync::Arc<self::source::SourceScanCache>,
}
impl Par2Creator {
pub fn new(options: Par2CreatorOptions) -> Self {
Self {
options,
scan: std::sync::Arc::new(self::source::SourceScanCache::new()),
}
}
pub fn options(&self) -> &Par2CreatorOptions {
&self.options
}
pub fn plan(&self) -> Result<Par2CreatePlan> {
build_plan_with_cache(&self.options, Some(&self.scan))
}
pub fn create(&self, plan: &Par2CreatePlan) -> Result<Par2CreateOutcome> {
if self.options.cancellation.is_cancelled() {
return Err(Par2Error::Cancelled);
}
reedsolomon_rs::threading::ensure_pool(self::encode::configured_create_threads);
plan.validate_integrity()?;
self::plan::validate_output_targets(
&plan.output_paths,
&plan.sources,
self.options.overwrite,
)?;
let canonical = self::plan::build_plan_with_cache(&self.options, Some(&self.scan))?;
if plan != &canonical {
return Err(Par2Error::InvalidCreationOptions {
reason: "creation plan differs from creator options or current inputs".to_string(),
});
}
let slice_size =
usize::try_from(plan.slice_size).map_err(|_| Par2Error::ResourceLimitExceeded {
reason: "slice size exceeds addressable memory".to_string(),
})?;
let selected = metal::select_backend(
self.options.backend,
slice_size,
plan.source_slice_count as usize,
plan.recovery_count as usize,
self.options.memory_limit,
)?;
let selected_backend = metal::selected_policy(&selected);
if self.options.dry_run {
return Ok(Par2CreateOutcome {
recovery_set_id: plan.recovery_set_id,
main_path: plan.main_path.clone(),
volume_paths: plan.volume_paths.clone(),
output_paths: plan.output_paths.clone(),
source_slice_count: plan.source_slice_count,
recovery_count: plan.recovery_count,
bytes_written: 0,
dry_run: true,
requested_backend: self.options.backend,
selected_backend,
});
}
write_outputs(plan, canonical.sources, &self.options, selected)
}
}