rocketmq_model/
consistent_hash.rs1use std::collections::BTreeMap;
16use std::sync::Arc;
17
18use md5::Digest;
19use rocketmq_error::Result;
20
21pub trait Node {
23 fn get_key(&self) -> &str;
24}
25
26pub trait HashFunction {
28 fn hash(&self, key: &str) -> i64;
29}
30
31#[derive(Debug, Clone)]
33pub struct VirtualNode<T: Node> {
34 physical_node: T,
35 replica_index: i32,
36 key: String,
37}
38
39impl<T: Node> VirtualNode<T> {
40 pub fn new(physical_node: T, replica_index: i32) -> Self {
41 let key = format!("{}-{replica_index}", physical_node.get_key());
42 Self {
43 physical_node,
44 replica_index,
45 key,
46 }
47 }
48
49 pub fn is_virtual_node_of(&self, physical_node: &T) -> bool {
50 self.physical_node.get_key() == physical_node.get_key()
51 }
52
53 pub fn physical_node(&self) -> &T {
54 &self.physical_node
55 }
56
57 pub fn replica_index(&self) -> i32 {
58 self.replica_index
59 }
60}
61
62impl<T: Node> Node for VirtualNode<T> {
63 fn get_key(&self) -> &str {
64 &self.key
65 }
66}
67
68#[derive(Debug, Clone, Default)]
70pub struct MD5Hash;
71
72impl MD5Hash {
73 pub fn new() -> Self {
74 Self
75 }
76}
77
78impl HashFunction for MD5Hash {
79 fn hash(&self, key: &str) -> i64 {
80 let mut hasher = md5::Md5::new();
81 hasher.update(key.as_bytes());
82 let digest = hasher.finalize();
83 digest[..4]
84 .iter()
85 .fold(0_i64, |hash, byte| (hash << 8) | i64::from(*byte))
86 }
87}
88
89#[derive(Clone)]
91pub struct ConsistentHashRouter<T: Node + Clone> {
92 ring: BTreeMap<i64, VirtualNode<T>>,
93 hash_function: Arc<dyn HashFunction>,
94}
95
96impl<T: Node + Clone> ConsistentHashRouter<T> {
97 pub fn new(physical_nodes: Vec<T>, virtual_node_count: i32) -> Self {
98 Self::new_with_hash_function(physical_nodes, virtual_node_count, Arc::new(MD5Hash))
99 }
100
101 pub fn try_new(physical_nodes: Vec<T>, virtual_node_count: i32) -> Result<Self> {
102 Self::try_new_with_hash_function(physical_nodes, virtual_node_count, Arc::new(MD5Hash))
103 }
104
105 pub fn new_with_hash_function(
106 physical_nodes: Vec<T>,
107 virtual_node_count: i32,
108 hash_function: Arc<dyn HashFunction>,
109 ) -> Self {
110 if virtual_node_count < 0 {
111 return Self {
112 ring: BTreeMap::new(),
113 hash_function,
114 };
115 }
116 let mut router = Self {
117 ring: BTreeMap::new(),
118 hash_function,
119 };
120 for node in physical_nodes {
121 router.add_node(node, virtual_node_count);
122 }
123 router
124 }
125
126 pub fn try_new_with_hash_function(
127 physical_nodes: Vec<T>,
128 virtual_node_count: i32,
129 hash_function: Arc<dyn HashFunction>,
130 ) -> Result<Self> {
131 if virtual_node_count < 0 {
132 return Err(crate::error::invalid_argument(format!(
133 "illegal virtual node counts: {virtual_node_count}"
134 )));
135 }
136 let mut router = Self {
137 ring: BTreeMap::new(),
138 hash_function,
139 };
140 for node in physical_nodes {
141 router.try_add_node(node, virtual_node_count)?;
142 }
143 Ok(router)
144 }
145
146 pub fn add_node(&mut self, physical_node: T, virtual_node_count: i32) {
147 let _ = self.try_add_node(physical_node, virtual_node_count);
148 }
149
150 pub fn try_add_node(&mut self, physical_node: T, virtual_node_count: i32) -> Result<()> {
151 if virtual_node_count < 0 {
152 return Err(crate::error::invalid_argument(format!(
153 "illegal virtual node counts: {virtual_node_count}"
154 )));
155 }
156 let existing = self.get_existing_replicas(&physical_node);
157 for replica in 0..virtual_node_count {
158 let virtual_node = VirtualNode::new(physical_node.clone(), existing + replica);
159 self.ring
160 .insert(self.hash_function.hash(virtual_node.get_key()), virtual_node);
161 }
162 Ok(())
163 }
164
165 pub fn remove_node(&mut self, physical_node: &T) {
166 self.ring
167 .retain(|_, virtual_node| !virtual_node.is_virtual_node_of(physical_node));
168 }
169
170 pub fn route_node_ref(&self, object_key: &str) -> Option<&T> {
171 let hash = self.hash_function.hash(object_key);
172 self.ring
173 .range(hash..)
174 .next()
175 .or_else(|| self.ring.iter().next())
176 .map(|(_, node)| node.physical_node())
177 }
178
179 pub fn route_node(&self, object_key: &str) -> Option<T> {
180 self.route_node_ref(object_key).cloned()
181 }
182
183 pub fn get_existing_replicas(&self, physical_node: &T) -> i32 {
184 self.ring
185 .values()
186 .filter(|node| node.is_virtual_node_of(physical_node))
187 .count() as i32
188 }
189
190 pub fn size(&self) -> usize {
191 self.ring.len()
192 }
193
194 pub fn is_empty(&self) -> bool {
195 self.ring.is_empty()
196 }
197}