hash_rings/mpc.rs
1//! Hashing ring implemented using multi-probe consistent hashing.
2
3use crate::util;
4use rand::{Rng, XorShiftRng};
5use siphasher::sip::SipHasher;
6use std::collections::hash_map::RandomState;
7use std::collections::BTreeMap;
8use std::hash::{BuildHasher, Hash, Hasher};
9
10const PRIME: u64 = 0xFFFF_FFFF_FFFF_FFC5;
11
12/// A hashing ring implemented using multi-probe consistent hashing.
13///
14/// Multi-probe consistent hashing is a variation on consistent hashing where instead of the nodes
15/// being hashed multiple times to reduce variance, the keys are hashed multiple times. Each key is
16/// hashed `hash_count` times and the closest node over all hashes is returned.
17///
18/// # Examples
19/// ```
20/// use hash_rings::mpc::Ring;
21/// use std::collections::hash_map::DefaultHasher;
22/// use std::hash::BuildHasherDefault;
23///
24/// type DefaultBuildHasher = BuildHasherDefault<DefaultHasher>;
25///
26/// let mut ring = Ring::with_hasher(DefaultBuildHasher::default(), 2);
27///
28/// ring.insert_node(&"node-1");
29/// ring.insert_node(&"node-2");
30///
31/// ring.remove_node(&"node-1");
32///
33/// assert_eq!(ring.get_node(&"point-1"), &"node-2");
34/// assert_eq!(ring.len(), 1);
35///
36/// let mut iterator = ring.iter();
37/// assert_eq!(iterator.next(), Some(&"node-2"));
38/// assert_eq!(iterator.next(), None);
39/// ```
40pub struct Ring<'a, T, H = RandomState> {
41 nodes: BTreeMap<u64, &'a T>,
42 hash_count: u64,
43 hashers: [SipHasher; 2],
44 hash_builder: H,
45}
46
47impl<'a, T> Ring<'a, T, RandomState> {
48 /// Constructs a new, empty `Ring<T>` that hashes `hash_count` times when a key is inserted.
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// use hash_rings::mpc::Ring;
54 ///
55 /// let mut ring: Ring<&str> = Ring::new(2);
56 /// ```
57 pub fn new(hash_count: u64) -> Self {
58 assert!(hash_count > 0);
59 Self {
60 nodes: BTreeMap::new(),
61 hash_count,
62 hashers: Self::get_hashers(),
63 hash_builder: Default::default(),
64 }
65 }
66}
67
68impl<'a, T, H> Ring<'a, T, H> {
69 fn get_hashers() -> [SipHasher; 2] {
70 let mut rng = XorShiftRng::new_unseeded();
71 [
72 SipHasher::new_with_keys(rng.next_u64(), rng.next_u64()),
73 SipHasher::new_with_keys(rng.next_u64(), rng.next_u64()),
74 ]
75 }
76
77 fn get_hashes<U>(&self, item: &U) -> [u64; 2]
78 where
79 U: Hash,
80 {
81 let mut ret = [0; 2];
82 for (index, hash) in ret.iter_mut().enumerate() {
83 let mut sip = self.hashers[index];
84 item.hash(&mut sip);
85 *hash = sip.finish();
86 }
87 ret
88 }
89
90 fn get_distance(hash: u64, next_hash: u64) -> u64 {
91 if hash > next_hash {
92 next_hash + (<u64>::max_value() - hash)
93 } else {
94 next_hash - hash
95 }
96 }
97
98 fn get_next_hash(&self, hash: u64) -> u64 {
99 let next_hash_opt = self
100 .nodes
101 .range(hash..)
102 .next()
103 .or_else(|| self.nodes.iter().next())
104 .map(|entry| *entry.0);
105 match next_hash_opt {
106 Some(hash) => hash,
107 None => panic!("Error: empty ring."),
108 }
109 }
110
111 /// Constructs a new, empty `Ring<T>` that hashes `hash_count` times when a key is inserted
112 /// with a specified hash builder.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use hash_rings::mpc::Ring;
118 /// use std::collections::hash_map::DefaultHasher;
119 /// use std::hash::BuildHasherDefault;
120 ///
121 /// type DefaultBuildHasher = BuildHasherDefault<DefaultHasher>;
122 ///
123 /// let mut ring: Ring<&str, _> = Ring::with_hasher(DefaultBuildHasher::default(), 2);
124 /// ```
125 pub fn with_hasher(hash_builder: H, hash_count: u64) -> Self {
126 assert!(hash_count > 0);
127 Self {
128 nodes: BTreeMap::new(),
129 hash_count,
130 hashers: Self::get_hashers(),
131 hash_builder,
132 }
133 }
134
135 /// Inserts a node into the ring with a number of replicas.
136 ///
137 /// Increasing the number of replicas will increase the number of expected points mapped to the
138 /// node. For example, a node with three replicas will receive approximately three times more
139 /// points than a node with one replica.
140 ///
141 /// # Examples
142 ///
143 /// ```
144 /// use hash_rings::mpc::Ring;
145 ///
146 /// let mut ring: Ring<&str> = Ring::new(2);
147 /// ring.insert_node(&"node-1");
148 /// ```
149 pub fn insert_node(&mut self, id: &'a T)
150 where
151 T: Hash,
152 H: BuildHasher,
153 {
154 self.nodes
155 .insert(util::gen_hash(&self.hash_builder, id), id);
156 }
157
158 /// Removes a node.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use hash_rings::mpc::Ring;
164 ///
165 /// let mut ring: Ring<&str> = Ring::new(2);
166 ///
167 /// ring.insert_node(&"node-1");
168 /// ring.remove_node(&"node-1");
169 /// ```
170 pub fn remove_node(&mut self, id: &T)
171 where
172 T: Hash,
173 H: BuildHasher,
174 {
175 self.nodes.remove(&util::gen_hash(&self.hash_builder, id));
176 }
177
178 /// Returns the node associated with a point.
179 ///
180 /// # Panics
181 ///
182 /// Panics if the ring is empty.
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use hash_rings::mpc::Ring;
188 ///
189 /// let mut ring: Ring<&str> = Ring::new(2);
190 ///
191 /// ring.insert_node(&"node-1");
192 /// assert_eq!(ring.get_node(&"point-1"), &"node-1");
193 /// ```
194 pub fn get_node<U>(&self, point: &U) -> &T
195 where
196 U: Hash,
197 {
198 let hashes = self.get_hashes(point);
199 let hash = (0..self.hash_count)
200 .map(|i| {
201 let hash = hashes[0].wrapping_add((i as u64).wrapping_mul(hashes[1]) % PRIME);
202 let next_hash = self.get_next_hash(hash);
203 (Self::get_distance(hash, next_hash), next_hash)
204 })
205 .min()
206 .expect("Error: expected positive hash count.");
207
208 self.nodes[&hash.1]
209 }
210
211 /// Returns the number of nodes in the ring.
212 ///
213 /// # Examples
214 ///
215 /// ```
216 /// use hash_rings::mpc::Ring;
217 ///
218 /// let mut ring: Ring<&str> = Ring::new(2);
219 ///
220 /// ring.insert_node(&"node-1");
221 /// assert_eq!(ring.len(), 1);
222 /// ```
223 pub fn len(&self) -> usize {
224 self.nodes.len()
225 }
226
227 /// Returns `true` if the ring is empty.
228 ///
229 /// # Examples
230 ///
231 /// ```
232 /// use hash_rings::mpc::Ring;
233 ///
234 /// let mut ring: Ring<&str> = Ring::new(2);
235 ///
236 /// assert!(ring.is_empty());
237 /// ring.insert_node(&"node-1");
238 /// assert!(!ring.is_empty());
239 /// ```
240 pub fn is_empty(&self) -> bool {
241 self.nodes.is_empty()
242 }
243
244 /// Returns an iterator over the ring. The iterator will yield the nodes in the ring in no
245 /// particular order.
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use hash_rings::mpc::Ring;
251 ///
252 /// let mut ring = Ring::new(2);
253 /// ring.insert_node(&"node-1");
254 ///
255 /// let mut iterator = ring.iter();
256 /// assert_eq!(iterator.next(), Some(&"node-1"));
257 /// assert_eq!(iterator.next(), None);
258 /// ```
259 pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
260 self.nodes.iter().map(|node| *node.1)
261 }
262}
263
264impl<'a, T, H> IntoIterator for &'a Ring<'a, T, H>
265where
266 T: Hash + Eq,
267{
268 type IntoIter = Box<dyn Iterator<Item = &'a T> + 'a>;
269 type Item = (&'a T);
270
271 fn into_iter(self) -> Self::IntoIter {
272 Box::new(self.iter())
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use super::Ring;
279 use crate::test_util::BuildDefaultHasher;
280
281 #[test]
282 #[should_panic]
283 fn test_new_zero_hash_count() {
284 let _ring: Ring<'_, u32, BuildDefaultHasher> =
285 Ring::with_hasher(BuildDefaultHasher::default(), 0);
286 }
287
288 #[test]
289 #[should_panic]
290 fn test_get_node_empty_ring() {
291 let ring: Ring<'_, u32, BuildDefaultHasher> =
292 Ring::with_hasher(BuildDefaultHasher::default(), 2);
293 ring.get_node(&0);
294 }
295
296 #[test]
297 fn test_get_node() {
298 let mut ring = Ring::with_hasher(BuildDefaultHasher::default(), 2);
299
300 ring.insert_node(&0);
301 assert_eq!(ring.get_node(&2), &0);
302
303 ring.insert_node(&1);
304 assert_eq!(ring.get_node(&2), &1);
305
306 ring.remove_node(&1);
307 assert_eq!(ring.get_node(&2), &0);
308 }
309
310 #[test]
311 fn test_len() {
312 let mut ring = Ring::with_hasher(BuildDefaultHasher::default(), 2);
313 ring.insert_node(&0);
314
315 assert_eq!(ring.len(), 1);
316 }
317
318 #[test]
319 fn test_is_empty() {
320 let mut ring = Ring::with_hasher(BuildDefaultHasher::default(), 2);
321 assert!(ring.is_empty());
322
323 ring.insert_node(&0);
324 assert!(!ring.is_empty());
325 }
326
327 #[test]
328 fn test_iter() {
329 let mut ring = Ring::with_hasher(BuildDefaultHasher::default(), 2);
330 ring.insert_node(&0);
331
332 let mut iterator = ring.iter();
333 assert_eq!(iterator.next(), Some(&0));
334 assert_eq!(iterator.next(), None);
335 }
336}