#![deny(missing_docs)]
use serde::Deserialize;
use serde::Serialize;
use crate::dht::did::BiasId;
use crate::dht::Did;
pub const DEFAULT_FINGER_TABLE_SIZE: usize = 160;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FingerTable {
did: Did,
size: usize,
finger: Vec<Option<Did>>,
pub(super) fix_finger_index: usize,
}
impl PartialEq for FingerTable {
fn eq(&self, other: &Self) -> bool {
self.did == other.did && self.size == other.size && self.finger == other.finger
}
}
impl Eq for FingerTable {}
impl FingerTable {
pub fn new(did: Did, size: usize) -> Self {
let size = size.min(DEFAULT_FINGER_TABLE_SIZE);
Self {
did,
size,
finger: vec![None; size],
fix_finger_index: 0,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn first(&self) -> Option<Did> {
self.finger.iter().flatten().next().copied()
}
pub fn get(&self, index: usize) -> Option<Did> {
self.finger.get(index).copied().flatten()
}
fn write_slot(&mut self, index: usize, did: Option<Did>) {
if let Some(slot) = self.finger.get_mut(index) {
*slot = did;
}
}
pub fn set(&mut self, index: usize, did: Did) {
tracing::debug!("set finger table index: {} did: {}", index, did);
if index >= self.finger.len() {
tracing::error!("set finger index out of range, index: {}", index);
return;
}
if did == self.did {
tracing::trace!("set finger table with self did, ignore it");
return;
}
self.write_slot(index, Some(did));
}
pub fn set_fix(&mut self, did: Did) {
let index = self.fix_finger_index;
self.set(index, did)
}
pub fn remove(&mut self, did: Did) {
self.finger = crate::dht::topology::remove_finger_peer(&self.finger, did);
}
pub fn join(&mut self, did: Did) {
let observer = self.did;
let bias = did.bias(observer);
for k in 0..self.size {
let pos = Did::power_of_two(k);
if bias.pos() < pos {
continue;
}
if let Some(v) = self.finger.get(k).copied().flatten() {
if BiasId::cmp_from_observer(observer, did, v) == std::cmp::Ordering::Greater {
continue;
}
}
self.write_slot(k, Some(did));
}
}
pub fn contains(&self, v: Option<Did>) -> bool {
self.finger.contains(&v)
}
pub fn closest_predecessor(&self, did: Did) -> Did {
let observer = self.did;
for i in (0..self.size).rev() {
if let Some(v) = self.finger.get(i).copied().flatten() {
if BiasId::cmp_from_observer(observer, v, did) == std::cmp::Ordering::Less {
return v;
}
}
}
self.did
}
pub fn len(&self) -> usize {
self.finger.iter().flatten().count()
}
pub fn slot_count(&self) -> usize {
self.size
}
pub fn fix_finger_index(&self) -> usize {
self.fix_finger_index
}
pub fn list(&self) -> &Vec<Option<Did>> {
&self.finger
}
pub(crate) fn replace_state(&mut self, fingers: &[Option<Did>], fix_finger_index: usize) {
self.finger = fingers.iter().copied().take(self.size).collect();
self.finger.resize(self.size, None);
self.fix_finger_index = if self.size == 0 {
0
} else {
fix_finger_index % self.size
};
}
#[cfg(test)]
pub fn reset_finger(&mut self) {
self.finger = vec![None; self.size]
}
#[cfg(test)]
pub fn clone_finger(self) -> Vec<Option<Did>> {
self.finger
}
}
#[cfg(test)]
mod test_finger;