1use crate::{
2 ip::sample::SampleHashSet,
3 node_database::NodeDatabase,
4 node_table::{NodeContact, NodeId},
5};
6use rand::{prelude::ThreadRng, thread_rng, Rng};
7use std::time::Duration;
8
9#[derive(Default, Debug)]
12pub struct NodeBucket {
13 nodes: SampleHashSet<NodeId>,
14}
15
16impl NodeBucket {
17 #[inline]
18 pub fn count(&self) -> usize { self.nodes.len() }
19
20 #[inline]
21 pub fn add(&mut self, id: NodeId) -> bool { self.nodes.insert(id) }
22
23 #[inline]
24 pub fn remove(&mut self, id: &NodeId) -> bool { self.nodes.remove(id) }
25
26 #[inline]
27 pub fn sample(&self, rng: &mut ThreadRng) -> Option<NodeId> {
28 self.nodes.sample(rng)
29 }
30
31 pub fn select_evictee(
37 &self, db: &NodeDatabase, evict_timeout: Duration,
38 ) -> Option<NodeId> {
39 let mut long_time_nodes = Vec::new();
40 let mut evictable_nodes = Vec::new();
41
42 for id in self.nodes.iter() {
43 if let Some(node) = db.get(id, false ) {
44 if let Some(NodeContact::Success(_)) = node.last_connected {
46 continue;
47 }
48
49 match node.last_contact {
50 Some(contact) => match contact.time().elapsed() {
51 Ok(d) => {
52 if d > evict_timeout {
53 long_time_nodes.push(id);
54 } else {
55 evictable_nodes.push(id);
56 }
57 }
58 Err(_) => long_time_nodes.push(id),
59 },
60 None => long_time_nodes.push(id),
61 }
62 }
63 }
64
65 let mut rng = thread_rng();
66
67 if !long_time_nodes.is_empty() {
69 let index = rng.random_range(0..long_time_nodes.len());
70 return Some(long_time_nodes[index].clone());
71 }
72
73 if !evictable_nodes.is_empty() {
75 let index = rng.random_range(0..evictable_nodes.len());
76 return Some(evictable_nodes[index].clone());
77 }
78
79 None
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::{NodeBucket, NodeId};
86 use rand::thread_rng;
87
88 #[test]
89 fn test_add_remove() {
90 let mut bucket = NodeBucket::default();
91 assert_eq!(bucket.count(), 0);
92
93 let n1 = NodeId::random();
95 assert_eq!(bucket.add(n1.clone()), true);
96 assert_eq!(bucket.count(), 1);
97
98 assert_eq!(bucket.add(n1.clone()), false);
100 assert_eq!(bucket.count(), 1);
101
102 let n2 = NodeId::random();
104 assert_eq!(bucket.add(n2.clone()), true);
105 assert_eq!(bucket.count(), 2);
106
107 let n3 = NodeId::random();
109 assert_eq!(bucket.remove(&n3), false);
110
111 assert_eq!(bucket.remove(&n1), true);
113 assert_eq!(bucket.count(), 1);
114
115 assert_eq!(bucket.remove(&n2), true);
116 assert_eq!(bucket.count(), 0);
117 }
118
119 #[test]
120 fn test_sample() {
121 let mut bucket = NodeBucket::default();
122 let mut rng = thread_rng();
123
124 assert_eq!(bucket.sample(&mut rng), None);
126
127 let n1 = NodeId::random();
129 assert_eq!(bucket.add(n1.clone()), true);
130 assert_eq!(bucket.sample(&mut rng), Some(n1.clone()));
131 }
132}