mod thread_local;
mod worker;
pub use thread_local::ThreadLocalClient;
pub use worker::{LeaseGuard, WorkerClient};
use crate::error::{Error, Result};
use crate::failover::FailoverPolicy;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum WorkerBalance {
#[default]
RoundRobin,
LeastInFlight,
KeyHash,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WorkerConfig {
pub slots_per_thread: usize,
pub balance: WorkerBalance,
pub stripe_endpoints: bool,
}
impl Default for WorkerConfig {
fn default() -> Self {
Self {
slots_per_thread: 4,
balance: WorkerBalance::RoundRobin,
stripe_endpoints: true,
}
}
}
impl WorkerConfig {
#[must_use]
pub const fn slot_count(&self) -> usize {
if self.slots_per_thread == 0 {
1
} else {
self.slots_per_thread
}
}
}
#[must_use]
pub fn stripe_shift(endpoint_count: usize, worker_id: u64, slot: usize) -> usize {
if endpoint_count == 0 {
0
} else {
usize::try_from(worker_id)
.unwrap_or(usize::MAX)
.wrapping_add(slot)
% endpoint_count
}
}
#[must_use]
pub fn striped_endpoints(
endpoints: &[String],
worker_id: u64,
slot: usize,
enabled: bool,
) -> Vec<String> {
let mut rotated = endpoints.to_vec();
if enabled {
let shift = stripe_shift(rotated.len(), worker_id, slot);
if shift != 0 {
rotated.rotate_left(shift);
}
}
rotated
}
pub(crate) fn thread_already_gone(_: std::thread::AccessError) {}
pub(crate) fn reject_observer(policy: &FailoverPolicy) -> Result<()> {
if policy.has_observer() {
Err(Error::InvalidConfig(
"failover observers are thread-affine and cannot be shared".into(),
))
} else {
Ok(())
}
}
#[must_use]
pub fn close_thread_caches() -> usize {
thread_local::close_thread_caches() + worker::close_thread_caches()
}