use super::ParallelConfigError;
use std::{num::NonZeroUsize, path::PathBuf};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SegmentSize(NonZeroUsize);
impl SegmentSize {
pub const DEFAULT: Self = Self(NonZeroUsize::new(4 << 20).unwrap());
pub const fn get(self) -> usize {
self.0.get()
}
}
impl TryFrom<usize> for SegmentSize {
type Error = ParallelConfigError;
fn try_from(bytes: usize) -> Result<Self, Self::Error> {
match NonZeroUsize::new(bytes) {
Some(n) if (64 << 10..=16 << 20).contains(&bytes) => Ok(Self(n)),
_ => Err(ParallelConfigError::InvalidSegmentSize { bytes }),
}
}
}
impl Default for SegmentSize {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TaskCount(NonZeroUsize);
impl TaskCount {
pub const ONE: Self = Self(NonZeroUsize::MIN);
pub const fn get(self) -> usize {
self.0.get()
}
pub fn available() -> std::io::Result<Self> {
std::thread::available_parallelism().map(Self)
}
}
impl TryFrom<usize> for TaskCount {
type Error = ParallelConfigError;
fn try_from(count: usize) -> Result<Self, Self::Error> {
match NonZeroUsize::new(count) {
Some(n) if u32::try_from(count).is_ok() => Ok(Self(n)),
_ => Err(ParallelConfigError::InvalidTaskCount { count }),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SourceConsistency {
AssumeImmutable,
VerifyLength,
VerifyLengthAndIdentity,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParallelConfig {
pub(super) segment_size: SegmentSize,
pub(super) minimum_parallel_size: u64,
pub(super) aggregate_memory_limit: Option<usize>,
pub(super) max_retained_workers: usize,
pub(super) source_consistency: SourceConsistency,
}
impl From<SegmentSize> for ParallelConfig {
fn from(segment_size: SegmentSize) -> Self {
Self {
segment_size,
..Self::default()
}
}
}
impl Default for ParallelConfig {
fn default() -> Self {
Self {
segment_size: SegmentSize::DEFAULT,
minimum_parallel_size: 8 << 20,
aggregate_memory_limit: None,
max_retained_workers: 0,
source_consistency: SourceConsistency::VerifyLengthAndIdentity,
}
}
}
impl ParallelConfig {
pub const fn with_minimum_parallel_size(mut self, bytes: u64) -> Self {
self.minimum_parallel_size = bytes;
self
}
pub const fn with_aggregate_memory_limit(mut self, bytes: Option<usize>) -> Self {
self.aggregate_memory_limit = bytes;
self
}
pub const fn with_max_retained_workers(mut self, count: usize) -> Self {
self.max_retained_workers = count;
self
}
pub const fn with_source_consistency(mut self, policy: SourceConsistency) -> Self {
self.source_consistency = policy;
self
}
}
#[derive(Clone, Debug)]
pub struct MemoryStaging {
pub(super) max_total_bytes: usize,
}
impl From<usize> for MemoryStaging {
fn from(max_total_bytes: usize) -> Self {
Self { max_total_bytes }
}
}
#[derive(Clone, Debug)]
pub struct DirectoryStaging {
pub(super) directory: PathBuf,
}
impl From<PathBuf> for DirectoryStaging {
fn from(directory: PathBuf) -> Self {
Self { directory }
}
}
#[derive(Clone, Debug)]
pub enum Staging {
Memory(MemoryStaging),
Directory(DirectoryStaging),
}
#[derive(Clone, Debug)]
pub struct BatchConfig {
pub(super) task_count: TaskCount,
pub(super) staging: Staging,
}
impl BatchConfig {
pub const fn new(task_count: TaskCount, staging: Staging) -> Self {
Self {
task_count,
staging,
}
}
pub const fn auto(task_count: TaskCount) -> Self {
Self::memory(task_count, usize::MAX)
}
pub const fn memory(task_count: TaskCount, max_total_bytes: usize) -> Self {
Self::new(
task_count,
Staging::Memory(MemoryStaging { max_total_bytes }),
)
}
pub fn directory(task_count: TaskCount, directory: impl Into<PathBuf>) -> Self {
Self::new(
task_count,
Staging::Directory(DirectoryStaging {
directory: directory.into(),
}),
)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParallelRetentionPolicy {
CurrentPlan,
Bounded {
max_bytes: usize,
},
Aggressive,
ReleaseAll,
}