use std::collections::BTreeMap;
use std::ops::Bound::Included;
use std::ops::Deref;
#[derive(Clone, Debug, Default)]
pub struct Consistent {
buckets: BTreeMap<i64, usize>,
}
impl Consistent {
pub fn index(&self, hash: i64) -> usize {
let idxs = self.buckets.range((Included(hash), Included(i64::MAX)));
for (_h, idx) in idxs {
return *idx;
}
for (_h, i) in self.buckets.iter() {
return *i;
}
return 0;
}
pub fn from<T: Deref<Target = str>>(shards: &[T]) -> Self {
Consistent::new(shards, false)
}
pub fn new<T: Deref<Target = str>>(shards: &[T], origin_alg: bool) -> Self {
tracing::debug!("+++ use ketama with origin:{}", origin_alg);
let mut map = BTreeMap::default();
for idx in 0..shards.len() {
let factor = 40;
for i in 0..factor {
let data: String = shards[idx].to_string() + "-" + &i.to_string();
let out_bytes = md5::compute(data.as_str());
for j in 0..4 {
let mut hash = (((out_bytes[3 + j * 4] & 0xFF) as i64) << 24)
| (((out_bytes[2 + j * 4] & 0xFF) as i64) << 16)
| (((out_bytes[1 + j * 4] & 0xFF) as i64) << 8)
| ((out_bytes[0 + j * 4] & 0xFF) as i64);
if !origin_alg {
hash = hash.wrapping_rem(i32::MAX as i64);
}
if hash < 0 {
hash = hash.wrapping_mul(-1);
}
map.insert(hash, idx);
}
}
}
Self { buckets: map }
}
}