1use std::collections::HashSet;
16use std::net::IpAddr;
17use std::net::Ipv4Addr;
18use std::net::Ipv6Addr;
19use std::net::SocketAddr;
20
21use bytes::BufMut;
22use cheetah_string::CheetahFinder;
23use cheetah_string::CheetahString;
24
25use crate::codec::bytes_to_string;
26use crate::codec::string_to_bytes;
27use crate::codec::NAME_VALUE_SEPARATOR;
28use crate::codec::PROPERTY_SEPARATOR;
29use crate::common::message::message_ext::MessageExt;
30use crate::common::message::MessageConst;
31
32pub fn get_sharding_key_index(sharding_key: &str, index_size: usize) -> usize {
33 if index_size == 0 {
34 return 0;
35 }
36
37 let hash = murmur3_32_java_hash(sharding_key.as_bytes()) as i64;
38 (hash % index_size as i64).unsigned_abs() as usize
39}
40
41fn murmur3_32_java_hash(bytes: &[u8]) -> i32 {
42 const C1: u32 = 0xcc9e2d51;
43 const C2: u32 = 0x1b873593;
44
45 let mut h1 = 0u32;
46 let block_count = bytes.len() / 4;
47
48 for block_index in 0..block_count {
49 let offset = block_index * 4;
50 let mut k1 = u32::from_le_bytes([bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]]);
51
52 k1 = k1.wrapping_mul(C1);
53 k1 = k1.rotate_left(15);
54 k1 = k1.wrapping_mul(C2);
55
56 h1 ^= k1;
57 h1 = h1.rotate_left(13);
58 h1 = h1.wrapping_mul(5).wrapping_add(0xe6546b64);
59 }
60
61 let tail = &bytes[block_count * 4..];
62 let mut k1 = 0u32;
63 match tail.len() {
64 3 => {
65 k1 ^= (tail[2] as u32) << 16;
66 k1 ^= (tail[1] as u32) << 8;
67 k1 ^= tail[0] as u32;
68 }
69 2 => {
70 k1 ^= (tail[1] as u32) << 8;
71 k1 ^= tail[0] as u32;
72 }
73 1 => {
74 k1 ^= tail[0] as u32;
75 }
76 _ => {}
77 }
78
79 if !tail.is_empty() {
80 k1 = k1.wrapping_mul(C1);
81 k1 = k1.rotate_left(15);
82 k1 = k1.wrapping_mul(C2);
83 h1 ^= k1;
84 }
85
86 h1 ^= bytes.len() as u32;
87 h1 ^= h1 >> 16;
88 h1 = h1.wrapping_mul(0x85ebca6b);
89 h1 ^= h1 >> 13;
90 h1 = h1.wrapping_mul(0xc2b2ae35);
91 h1 ^= h1 >> 16;
92
93 h1 as i32
94}
95
96pub fn get_sharding_key_index_by_msg(msg: &MessageExt, index_size: usize) -> usize {
97 let sharding_key = msg
98 .message
99 .properties()
100 .as_map()
101 .get(MessageConst::PROPERTY_SHARDING_KEY)
102 .cloned()
103 .unwrap_or_default();
104
105 get_sharding_key_index(sharding_key.as_str(), index_size)
106}
107
108pub fn get_sharding_key_indexes(msgs: &[MessageExt], index_size: usize) -> HashSet<usize> {
109 let mut index_set = HashSet::with_capacity(index_size);
110 for msg in msgs {
111 let idx = get_sharding_key_index_by_msg(msg, index_size);
112 index_set.insert(idx);
113 }
114 index_set
115}
116
117fn delete_property_if_present(properties_string: &str, name: &str) -> Option<String> {
118 if properties_string.is_empty() || name.is_empty() {
119 return None;
120 }
121
122 fn find_from(finder: &CheetahFinder<'_>, haystack: &str, start: usize) -> Option<usize> {
123 haystack
124 .get(start..)
125 .and_then(|remaining| finder.find_in(remaining).map(|offset| start + offset))
126 }
127
128 fn find_property_name_from(
129 finder: &CheetahFinder<'_>,
130 haystack: &str,
131 bytes: &[u8],
132 name_len: usize,
133 start: usize,
134 ) -> Option<usize> {
135 let property_separator = PROPERTY_SEPARATOR as u8;
136 let name_value_separator = NAME_VALUE_SEPARATOR as u8;
137 let mut start_idx = start;
138
139 loop {
140 let candidate_idx = find_from(finder, haystack, start_idx)?;
141 start_idx = candidate_idx + name_len;
142
143 let before_ok = candidate_idx == 0 || bytes.get(candidate_idx - 1) == Some(&property_separator);
144 let after_idx = candidate_idx + name_len;
145 let after_ok = bytes.get(after_idx) == Some(&name_value_separator);
146 if before_ok && after_ok {
147 return Some(candidate_idx);
148 }
149 }
150 }
151
152 let finder = CheetahFinder::new(name);
153 let bytes = properties_string.as_bytes();
154 let mut next_property_idx = find_property_name_from(&finder, properties_string, bytes, name.len(), 0)?;
155
156 let mut idx0 = 0;
157 let mut string_builder = String::with_capacity(properties_string.len());
158
159 loop {
160 string_builder.push_str(&properties_string[idx0..next_property_idx]);
162 let value_start = next_property_idx + name.len() + 1;
164 match properties_string
165 .get(value_start..)
166 .and_then(|rest| rest.find(PROPERTY_SEPARATOR))
167 .map(|offset| value_start + offset)
168 {
169 Some(idx2) => {
170 idx0 = idx2 + 1;
171 let Some(idx1) = find_property_name_from(&finder, properties_string, bytes, name.len(), idx0) else {
172 string_builder.push_str(&properties_string[idx0..]);
174 break;
175 };
176 next_property_idx = idx1;
177 }
178 None => {
179 break;
180 }
181 }
182 }
183
184 Some(string_builder)
185}
186
187pub fn delete_property(properties_string: &str, name: &str) -> String {
188 delete_property_if_present(properties_string, name).unwrap_or_else(|| properties_string.to_string())
189}
190
191pub fn delete_property_v2(properties_str: &str, name: &str) -> String {
192 delete_property(properties_str, name)
193}
194
195pub fn delete_property_to_cheetah_string(properties_string: &CheetahString, name: &str) -> CheetahString {
196 delete_property_if_present(properties_string.as_str(), name)
197 .map(CheetahString::from_string)
198 .unwrap_or_else(|| properties_string.clone())
199}
200
201pub fn build_message_id(socket_addr: SocketAddr, wrote_offset: i64) -> String {
202 let mut msg_id_vec = match socket_addr {
203 SocketAddr::V4(addr) => {
204 let mut msg_id_vec = Vec::<u8>::with_capacity(16);
205 msg_id_vec.extend_from_slice(&addr.ip().octets());
206 msg_id_vec.put_i32(addr.port() as i32);
207 msg_id_vec
208 }
209 SocketAddr::V6(addr) => {
210 let mut msg_id_vec = Vec::<u8>::with_capacity(28);
211 msg_id_vec.extend_from_slice(&addr.ip().octets());
212 msg_id_vec.put_i32(addr.port() as i32);
213 msg_id_vec
214 }
215 };
216 msg_id_vec.put_i64(wrote_offset);
217 bytes_to_string(msg_id_vec.as_slice())
218}
219
220pub fn socket_address_to_vec(socket_addr: SocketAddr) -> Vec<u8> {
221 match socket_addr {
222 SocketAddr::V4(addr) => {
223 let mut msg_id_vec = Vec::<u8>::with_capacity(8);
224 msg_id_vec.extend_from_slice(&addr.ip().octets());
225 msg_id_vec.put_i32(addr.port() as i32);
226 msg_id_vec
227 }
228 SocketAddr::V6(addr) => {
229 let mut msg_id_vec = Vec::<u8>::with_capacity(20);
230 msg_id_vec.extend_from_slice(&addr.ip().octets());
231 msg_id_vec.put_i32(addr.port() as i32);
232 msg_id_vec
233 }
234 }
235}
236
237pub fn build_batch_message_id(
238 socket_addr: SocketAddr,
239 store_host_length: i32,
240 batch_size: usize,
241 phy_pos: &[i64],
242) -> String {
243 if batch_size == 0 {
244 return String::new();
245 }
246 let msg_id_len = (store_host_length + 8) as usize;
247 let mut msg_id_vec = vec![0u8; msg_id_len];
248 msg_id_vec[..store_host_length as usize].copy_from_slice(&socket_address_to_vec(socket_addr));
249 let mut message_id = String::with_capacity(batch_size * msg_id_len * 2 + batch_size - 1);
250 for (index, value) in phy_pos.iter().enumerate() {
251 msg_id_vec[msg_id_len - 8..msg_id_len].copy_from_slice(&value.to_be_bytes());
252 if index != 0 {
253 message_id.push(',');
254 }
255 message_id.push_str(&bytes_to_string(&msg_id_vec));
256 }
257 message_id
258}
259
260pub fn parse_message_id(msg_id: impl Into<String>) -> (SocketAddr, i64) {
261 fn invalid_message_id() -> (SocketAddr, i64) {
262 (SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0), -1)
263 }
264
265 let msg_id = msg_id.into();
266 let Some(bytes) = string_to_bytes(&msg_id) else {
267 return invalid_message_id();
268 };
269
270 let ip_len = match bytes.len() {
271 16 => 4,
272 28 => 16,
273 _ => return invalid_message_id(),
274 };
275
276 let port_start = ip_len;
277 let offset_start = port_start + 4;
278 let Some(port_bytes) = bytes.get(port_start..offset_start) else {
279 return invalid_message_id();
280 };
281 let Some(offset_bytes) = bytes.get(offset_start..offset_start + 8) else {
282 return invalid_message_id();
283 };
284
285 let port = i32::from_be_bytes([port_bytes[0], port_bytes[1], port_bytes[2], port_bytes[3]]);
286 if !(0..=u16::MAX as i32).contains(&port) {
287 return invalid_message_id();
288 }
289
290 let addr = if ip_len == 4 {
291 SocketAddr::new(
292 IpAddr::V4(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])),
293 port as u16,
294 )
295 } else {
296 let mut ip = [0u8; 16];
297 ip.copy_from_slice(&bytes[..16]);
298 SocketAddr::new(IpAddr::V6(Ipv6Addr::from(ip)), port as u16)
299 };
300
301 let offset = i64::from_be_bytes([
302 offset_bytes[0],
303 offset_bytes[1],
304 offset_bytes[2],
305 offset_bytes[3],
306 offset_bytes[4],
307 offset_bytes[5],
308 offset_bytes[6],
309 offset_bytes[7],
310 ]);
311
312 (addr, offset)
313}
314
315#[cfg(test)]
316mod tests {
317 use std::net::Ipv4Addr;
318
319 use super::*;
320 use crate::common::message::message_ext::MessageExt;
321
322 #[test]
323 fn test_get_sharding_key_index() {
324 let sharding_key = "example_key";
325 let index_size = 10;
326 let result = get_sharding_key_index(sharding_key, index_size);
327 assert!(result < index_size);
328 }
329
330 #[test]
331 fn murmur3_32_java_hash_matches_guava_hash_bytes() {
332 let cases = [
333 ("", 0),
334 ("example_key", 1_493_934_834),
335 ("key1", -1_684_602_587),
336 ("key2", 1_936_800_180),
337 ("order-123", -1_381_100_355),
338 ("\u{4e2d}\u{6587}key", 1_259_819_139),
339 ("rocketmq", -184_929_330),
340 ("sharding-999", 467_656_710),
341 ];
342
343 for (key, expected_hash) in cases {
344 assert_eq!(murmur3_32_java_hash(key.as_bytes()), expected_hash, "key={key}");
345 }
346 }
347
348 #[test]
349 fn get_sharding_key_index_matches_java_remainder_semantics() {
350 let cases = [
351 ("example_key", 10, 4),
352 ("example_key", 32, 18),
353 ("example_key", 1024, 754),
354 ("key1", 10, 7),
355 ("key1", 16, 11),
356 ("key1", 1024, 731),
357 ("key2", 10, 0),
358 ("order-123", 10, 5),
359 ("\u{4e2d}\u{6587}key", 10, 9),
360 ("\u{4e2d}\u{6587}key", 1024, 131),
361 ("rocketmq", 1024, 50),
362 ("sharding-999", 1024, 6),
363 ];
364
365 for (key, index_size, expected_index) in cases {
366 assert_eq!(
367 get_sharding_key_index(key, index_size),
368 expected_index,
369 "key={key}, index_size={index_size}"
370 );
371 }
372 }
373
374 #[test]
375 fn get_sharding_key_index_zero_size_returns_zero() {
376 assert_eq!(get_sharding_key_index("key1", 0), 0);
377 }
378
379 #[test]
380 fn test_get_sharding_key_index_by_msg() {
381 let mut message = MessageExt::default();
382 message
383 .message
384 .properties_mut()
385 .as_map_mut()
386 .insert(MessageConst::PROPERTY_SHARDING_KEY.into(), "example_key".into());
387 let index_size = 10;
388 let result = get_sharding_key_index_by_msg(&message, index_size);
389 assert!(result < index_size);
390 }
391
392 #[test]
393 fn test_get_sharding_key_indexes() {
394 let mut messages = Vec::new();
395 let mut message1 = MessageExt::default();
396 message1
397 .message
398 .properties_mut()
399 .as_map_mut()
400 .insert(MessageConst::PROPERTY_SHARDING_KEY.into(), "key1".into());
401 messages.push(message1);
402 let mut message2 = MessageExt::default();
403 message2
404 .message
405 .properties_mut()
406 .as_map_mut()
407 .insert(MessageConst::PROPERTY_SHARDING_KEY.into(), "key2".into());
408 messages.push(message2);
409 let index_size = 10;
410 let result = get_sharding_key_indexes(&messages, index_size);
411 assert_eq!(result.len(), 2);
412 }
413
414 #[test]
415 fn test_delete_property() {
416 let properties_string = "aa\u{0001}bb\u{0002}cc\u{0001}bb\u{0002}";
417 let name = "aa";
418 let result = delete_property(properties_string, name);
419 assert_eq!(result, "cc\u{0001}bb\u{0002}");
420
421 let result = delete_property_v2(properties_string, name);
422 assert_eq!(result, "cc\u{0001}bb\u{0002}");
423 }
424
425 #[test]
426 fn delete_property_removes_property_correctly() {
427 let properties_string = "key1\u{0001}value1\u{0002}key2\u{0001}value2\u{0002}key3\u{0001}value3";
428 let name = "key2";
429 let result = delete_property(properties_string, name);
430 assert_eq!(result, "key1\u{0001}value1\u{0002}key3\u{0001}value3");
431
432 let result = delete_property_v2(properties_string, name);
433 assert_eq!(result, "key1\u{0001}value1\u{0002}key3\u{0001}value3");
434 }
435
436 #[test]
437 fn delete_property_handles_empty_string() {
438 let properties_string = "";
439 let name = "key";
440 let result = delete_property(properties_string, name);
441 assert_eq!(result, "");
442 }
443
444 #[test]
445 fn delete_property_handles_non_existent_key() {
446 let properties_string = "key1\u{0001}value1\u{0002}key2\u{0001}value2";
447 let name = "key3";
448 let result = delete_property(properties_string, name);
449 assert_eq!(result, "key1\u{0001}value1\u{0002}key2\u{0001}value2");
450 }
451
452 #[test]
453 fn delete_property_handles_key_at_start() {
454 let properties_string = "key1\u{0001}value1\u{0002}key2\u{0001}value2";
455 let name = "key1";
456 let result = delete_property(properties_string, name);
457 assert_eq!(result, "key2\u{0001}value2");
458 }
459
460 #[test]
461 fn delete_property_handles_key_at_end() {
462 let properties_string = "key1\u{0001}value1\u{0002}key2\u{0001}value2";
463 let name = "key2";
464 let result = delete_property(properties_string, name);
465 assert_eq!(result, "key1\u{0001}value1\u{0002}");
466 }
467
468 #[test]
469 fn delete_property_handles_multiple_occurrences() {
470 let properties_string = "key1\u{0001}value1\u{0002}key2\u{0001}value2\u{0002}key1\u{0001}value3";
471 let name = "key1";
472 let result = delete_property(properties_string, name);
473 assert_eq!(result, "key2\u{0001}value2\u{0002}");
474 }
475
476 #[test]
477 fn delete_property_handles_single_character_key() {
478 let properties_string = "a\u{0001}alpha\u{0002}ba\u{0001}keep";
479
480 assert_eq!(delete_property(properties_string, "a"), "ba\u{0001}keep");
481 assert_eq!(delete_property_v2(properties_string, "a"), "ba\u{0001}keep");
482 }
483
484 #[test]
485 fn delete_property_handles_multi_character_key_boundaries() {
486 let properties_string = "Order\u{0001}remove\u{0002}OrderId\u{0001}keep";
487
488 assert_eq!(delete_property(properties_string, "Order"), "OrderId\u{0001}keep");
489 assert_eq!(delete_property_v2(properties_string, "Order"), "OrderId\u{0001}keep");
490 }
491
492 #[test]
493 fn delete_property_preserves_input_for_empty_name() {
494 let properties_string = "key\u{0001}value";
495
496 assert_eq!(delete_property(properties_string, ""), properties_string);
497 assert_eq!(delete_property_v2(properties_string, ""), properties_string);
498 }
499
500 #[test]
501 fn delete_property_preserves_unicode_value_boundaries() {
502 let properties_string = "region\u{0001}\u{534e}\u{4e1c}\u{0002}tier\u{0001}gold";
503
504 assert_eq!(
505 delete_property(properties_string, "tier"),
506 "region\u{0001}\u{534e}\u{4e1c}\u{0002}"
507 );
508 assert_eq!(
509 delete_property_v2(properties_string, "tier"),
510 "region\u{0001}\u{534e}\u{4e1c}\u{0002}"
511 );
512 }
513
514 #[test]
515 fn delete_property_matches_java_edge_cases() {
516 let cases = [
517 ("", "KeyA", ""),
518 ("KeyA\u{0001}ValueA", "KeyA", ""),
519 ("KeyA\u{0001}ValueA\u{0002}", "KeyA", ""),
520 ("KeyA\u{0001}ValueA\u{0002}KeyA\u{0001}ValueA", "KeyA", ""),
521 ("KeyA\u{0001}ValueA\u{0002}KeyA\u{0001}ValueA\u{0002}", "KeyA", ""),
522 (
523 "KeyB\u{0001}ValueB\u{0002}KeyA\u{0001}ValueA",
524 "KeyA",
525 "KeyB\u{0001}ValueB\u{0002}",
526 ),
527 (
528 "KeyB\u{0001}ValueB\u{0002}KeyA\u{0001}ValueA\u{0002}",
529 "KeyA",
530 "KeyB\u{0001}ValueB\u{0002}",
531 ),
532 (
533 "KeyB\u{0001}ValueB\u{0002}KeyA\u{0001}ValueA\u{0002}KeyB\u{0001}ValueB\u{0002}",
534 "KeyA",
535 "KeyB\u{0001}ValueB\u{0002}KeyB\u{0001}ValueB\u{0002}",
536 ),
537 (
538 "KeyA\u{0001}ValueA\u{0002}KeyB\u{0001}ValueB\u{0002}",
539 "KeyA",
540 "KeyB\u{0001}ValueB\u{0002}",
541 ),
542 (
543 "KeyA\u{0001}ValueA\u{0002}KeyB\u{0001}ValueB",
544 "KeyA",
545 "KeyB\u{0001}ValueB",
546 ),
547 (
548 "KeyA\u{0001}ValueA\u{0002}KeyB\u{0001}ValueBKeyA\u{0001}ValueA\u{0002}",
549 "KeyA",
550 "KeyB\u{0001}ValueBKeyA\u{0001}ValueA\u{0002}",
551 ),
552 (
553 "KeyA\u{0001}ValueA\u{0002}KeyB\u{0001}ValueBKeyA\u{0001}",
554 "KeyA",
555 "KeyB\u{0001}ValueBKeyA\u{0001}",
556 ),
557 (
558 "KeyA\u{0001}ValueA\u{0002}KeyB\u{0001}ValueBKeyA",
559 "KeyA",
560 "KeyB\u{0001}ValueBKeyA",
561 ),
562 ("KeyA\u{0001}ValueA", "", "KeyA\u{0001}ValueA"),
563 ];
564
565 for (properties, name, expected) in cases {
566 assert_eq!(delete_property(properties, name), expected);
567 assert_eq!(delete_property_v2(properties, name), expected);
568 }
569 }
570
571 #[test]
572 fn delete_property_to_cheetah_string_matches_string_deletion() {
573 let cases = [
574 (
575 "key1\u{0001}value1\u{0002}key2\u{0001}value2\u{0002}key3\u{0001}value3",
576 "key2",
577 ),
578 ("key1\u{0001}value1\u{0002}key2\u{0001}value2", "key3"),
579 ("Order\u{0001}remove\u{0002}OrderId\u{0001}keep", "Order"),
580 ("key\u{0001}value", ""),
581 ];
582
583 for (properties, name) in cases {
584 let properties = CheetahString::from_static_str(properties);
585
586 assert_eq!(
587 delete_property_to_cheetah_string(&properties, name),
588 delete_property(properties.as_str(), name)
589 );
590 }
591 }
592
593 #[test]
594 fn test_build_message_id() {
595 let socket_addr = "127.0.0.1:12".parse().unwrap();
596 let wrote_offset = 1;
597 let result = build_message_id(socket_addr, wrote_offset);
598 assert_eq!(result, "7F0000010000000C0000000000000001");
599 }
600
601 #[test]
602 fn build_batch_message_id_creates_correct_id_for_single_position() {
603 let socket_addr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
604 let store_host_length = 8;
605 let batch_size = 1;
606 let phy_pos = vec![12345];
607
608 let result = build_batch_message_id(socket_addr, store_host_length, batch_size, &phy_pos);
609
610 assert_eq!(result, "7F00000100001F900000000000003039");
611 }
612
613 #[test]
614 fn build_batch_message_id_creates_correct_id_for_multiple_positions() {
615 let socket_addr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
616 let store_host_length = 8;
617 let batch_size = 2;
618 let phy_pos = vec![12345, 67890];
619
620 let result = build_batch_message_id(socket_addr, store_host_length, batch_size, &phy_pos);
621
622 assert_eq!(
623 result,
624 "7F00000100001F900000000000003039,7F00000100001F900000000000010932"
625 );
626 }
627
628 #[test]
629 fn build_batch_message_id_creates_empty_id_for_no_positions() {
630 let socket_addr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
631 let store_host_length = 8;
632 let batch_size = 0;
633 let phy_pos = vec![];
634
635 let result = build_batch_message_id(socket_addr, store_host_length, batch_size, &phy_pos);
636
637 assert_eq!(result, "");
638 }
639}