pub const QUORUM_ONE: u32 = u32::MAX;
pub const QUORUM_QUORUM: u32 = u32::MAX - 1;
pub const QUORUM_ALL: u32 = u32::MAX - 2;
pub const QUORUM_DEFAULT: u32 = u32::MAX - 3;
#[must_use]
pub fn resolve(knob: Option<u32>, n_val: u8, bucket_default: Option<u32>) -> u32 {
let n = u32::from(n_val.max(1));
match knob {
None | Some(QUORUM_DEFAULT) => resolve_default(bucket_default, n),
Some(QUORUM_ONE) => 1,
Some(QUORUM_QUORUM) => n / 2 + 1,
Some(QUORUM_ALL) => n,
Some(k) => k.clamp(1, n),
}
}
fn resolve_default(bucket_default: Option<u32>, n: u32) -> u32 {
match bucket_default {
None | Some(QUORUM_DEFAULT | QUORUM_QUORUM) => n / 2 + 1,
Some(QUORUM_ONE) => 1,
Some(QUORUM_ALL) => n,
Some(k) => k.clamp(1, n),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn symbolic_values_resolve_against_n() {
assert_eq!(resolve(Some(QUORUM_QUORUM), 3, None), 2);
assert_eq!(resolve(Some(QUORUM_ALL), 3, None), 3);
assert_eq!(resolve(Some(QUORUM_ONE), 3, None), 1);
assert_eq!(resolve(Some(QUORUM_QUORUM), 5, None), 3);
}
#[test]
fn unset_and_default_fall_back_to_bucket_default_then_quorum() {
assert_eq!(resolve(None, 3, None), 2);
assert_eq!(resolve(Some(QUORUM_DEFAULT), 3, None), 2);
assert_eq!(resolve(None, 3, Some(QUORUM_ALL)), 3);
assert_eq!(resolve(None, 3, Some(QUORUM_ONE)), 1);
assert_eq!(resolve(Some(QUORUM_DEFAULT), 3, Some(QUORUM_ALL)), 3);
}
#[test]
fn literal_counts_are_clamped_to_the_replica_range() {
assert_eq!(resolve(Some(2), 3, None), 2);
assert_eq!(resolve(Some(0), 3, None), 1);
assert_eq!(resolve(Some(9), 3, None), 3);
}
#[test]
fn per_request_overrides_the_bucket_default() {
assert_eq!(resolve(Some(QUORUM_ONE), 3, Some(QUORUM_ALL)), 1);
assert_eq!(resolve(Some(2), 3, Some(QUORUM_ALL)), 2);
}
#[test]
fn n_val_of_one_always_resolves_to_one() {
assert_eq!(resolve(Some(QUORUM_QUORUM), 1, None), 1);
assert_eq!(resolve(Some(QUORUM_ALL), 1, None), 1);
assert_eq!(resolve(None, 1, None), 1);
}
}