//! Settings for parallelism level.
//!
//! Really, this is config/command-line stuff, but quite often pool setup
//! is a long way removed from having that, so we'll just stash up info
//! globally.  Of course, Rust doesn't love that for mostly good reasons,
//! but it seems like using atomics works, and we only need little
//! numbers anyway, so...

use std::sync::atomic::{AtomicU32, Ordering};


/// How many threads to use on network workloads; e.g., HTTP fetching.
static JOBS_NET: AtomicU32 = AtomicU32::new(4);

/// How many threads to use on more CPU-bound tasks, like hash checking.
/// We also use this for filesystem scanning sort of things, which are
/// technically more IO bound, but...
static JOBS_CPU: AtomicU32 = AtomicU32::new(4);

/// Read the network job limit
pub(crate) fn net() -> u32 { JOBS_NET.load(Ordering::Relaxed) }
/// Read the CPU job limit
pub(crate) fn cpu() -> u32 { JOBS_CPU.load(Ordering::Relaxed) }


/// Initialize parallelism levels.  This is expected to just get called
/// once up-front.  If None is passed for either, they'll be initialized
/// with a default value.
///
/// The default for network parallelism is 4; cranking it may be useful
/// with high bandwidth and latency, or reducing it if you're limited on
/// bandwidth or server load.
///
/// The default for CPU parallelism is the number of CPU's, up to a
/// default max of 6.  Because this is both CPU and IO in some ways, if
/// you have a high-latency IO subsystem and a single CPU, it may still
/// be useful to have a >1 value in here.  If you have a lot of CPU's but
/// slow IO, higher values may be less useful.  The default cap of 6 is
/// because it's probably fast enough for most uses, and you might want
/// your system to not be swamped out by this, but hey, you do you.
pub(crate) fn init(net: &Option<u32>, cpu: &Option<u32>)
{
	let newnet = net.unwrap_or(4);
	let newcpu = match cpu {
		Some(c) => *c,
		None => {
			let def: std::num::NonZeroUsize = 1.try_into().unwrap();
			let def: Result<_, std::io::Error> = Ok(def);
			let mut ncpu = std::thread::available_parallelism().or(def)
					.unwrap().get().try_into().unwrap();
			if ncpu > 6 { ncpu = 6; }
			ncpu
		},
	};

	// Guard against somebody setting 0
	if newnet < 1 { panic!("{newnet} network threads is insane."); }
	if newcpu < 1 { panic!("{newcpu} cpu threads is insane."); }

	JOBS_NET.store(newnet, Ordering::Relaxed);
	JOBS_CPU.store(newcpu, Ordering::Relaxed);
}
