diff --git a/sharding/src/hash/bkdrabscrc32.rs b/sharding/src/hash/bkdrabscrc32.rs new file mode 100644 index 000000000..cb65e8688 --- /dev/null +++ b/sharding/src/hash/bkdrabscrc32.rs @@ -0,0 +1,46 @@ +use super::{bkdr::Bkdr, crc32::Crc32, Hash}; + +/// key:${num}#suffix,对数字部分进行 bkdr + abs + crc32;属小众业务算法。 +/// 对于i32溢出,一般有类型提升 vs abs两种策略,bkdr自身是有abs,但考虑避免后面bkdr符号变化的影响,此处仍然进行abs; +#[derive(Debug, Clone)] +pub struct BkdrAbsCrc32 { + bkdr: Bkdr, + crc32: Crc32, +} + +impl Default for BkdrAbsCrc32 { + fn default() -> Self { + Self { + bkdr: Default::default(), + crc32: Default::default(), + } + } +} + +impl Hash for BkdrAbsCrc32 { + fn hash(&self, key: &S) -> i64 { + // 定位到num结束的位置,拿到hashkey + let mut hash_key = String::with_capacity(key.len()); + for i in 0..key.len() { + let c = key.at(i); + if c.is_ascii_digit() { + hash_key.push(c as char); + } else { + // 遇到第一个非数字停止 + break; + } + } + + if hash_key.len() == 0 { + log::warn!("found malformed bkdrabscrc32 key:{:?}", key); + return 0; + } + + // bkdr + let hash = self.bkdr.hash(&hash_key.as_bytes()); + // abs + string + let hash_abs = hash.abs().to_string(); + // crc32 + self.crc32.hash(&hash_abs.as_bytes()) + } +} diff --git a/sharding/src/hash/mod.rs b/sharding/src/hash/mod.rs index 94bd6ff08..81ff2d329 100644 --- a/sharding/src/hash/mod.rs +++ b/sharding/src/hash/mod.rs @@ -1,4 +1,5 @@ pub mod bkdr; +pub mod bkdrabscrc32; pub mod bkdrsub; pub mod crc32; pub mod crc32local; @@ -11,6 +12,7 @@ pub mod rawcrc32local; pub mod rawsuffix; pub use bkdr::Bkdr; +pub use bkdrabscrc32::BkdrAbsCrc32; pub use crc32::*; pub use crc32local::*; pub use lbcrc32local::LBCrc32localDelimiter; @@ -66,6 +68,7 @@ pub enum Hasher { Raw(Raw), // redis raw, long型字符串直接用数字作为hash Bkdr(Bkdr), Bkdrsub(Bkdrsub), + BkdrAbsCrc32(BkdrAbsCrc32), // 混合三种hash:先bkdr,再abs,最后进行crc32计算 Crc32(Crc32), Crc32Short(Crc32Short), // mc short crc32 Crc32Num(Crc32Num), // crc32 for a hash key whick is a num, @@ -114,6 +117,7 @@ impl Hasher { HASH_PADDING => Self::Padding(Default::default()), "bkdr" => Self::Bkdr(Default::default()), "bkdrsub" => Self::Bkdrsub(Default::default()), + "bkdrabscrc32" => Self::BkdrAbsCrc32(Default::default()), "raw" => Self::Raw(Raw::from(Default::default())), "crc32" => Self::Crc32(Default::default()), "crc32local" => Self::Crc32local(Default::default()), diff --git a/tests/src/hash_test.rs b/tests/src/hash_test.rs index f6de078cd..2d1690359 100644 --- a/tests/src/hash_test.rs +++ b/tests/src/hash_test.rs @@ -101,4 +101,16 @@ mod hash_test { println!("key:{}, crc64: {}, dist: {}", key, crc, idx); assert_eq!(-7536761181773004100_i64, crc); } + + #[test] + fn bkdrabscrc32() { + let hasher = Hasher::from("bkdrabscrc32"); + let key1 = "1234567890#123"; + let key2 = "1234567890Abc"; + + let hash1 = hasher.hash(&key1.as_bytes()); + let hash2 = hasher.hash(&key2.as_bytes()); + println!("bkdrabscrc32: {} : {}", hash1, hash2); + assert_eq!(hash1, hash2); + } }