1use std::sync::atomic::{AtomicUsize, Ordering};
17use std::sync::RwLock;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum BloomError {
22 CapacityExceeded {
24 capacity: usize,
26 requested: usize,
28 },
29}
30
31pub struct BloomFilter {
42 bits: RwLock<Vec<u64>>,
43 num_bits: usize,
44 num_hashes: usize,
45 capacity: usize,
46 count: AtomicUsize,
47}
48
49impl BloomFilter {
50 pub fn new(capacity: usize, fpp: f64) -> Self {
54 let capacity = capacity.max(1);
55 let fpp = fpp.clamp(0.0001, 0.5);
56 let ln2 = std::f64::consts::LN_2;
57 let m = (-(capacity as f64) * fpp.ln() / (ln2 * ln2)).ceil() as usize;
58 let m = m.max(8);
59 let k = ((m as f64 / capacity as f64) * ln2).ceil() as usize;
60 let k = k.max(1);
61 let num_words = m.div_ceil(64);
62 Self {
63 bits: RwLock::new(vec![0u64; num_words]),
64 num_bits: m,
65 num_hashes: k,
66 capacity,
67 count: AtomicUsize::new(0),
68 }
69 }
70
71 pub fn add(&self, key: &str) -> Result<(), BloomError> {
73 let count = self.count.load(Ordering::Relaxed);
74 if count >= self.capacity {
75 return Err(BloomError::CapacityExceeded {
76 capacity: self.capacity,
77 requested: count + 1,
78 });
79 }
80 let (h1, h2) = self.hash(key);
81 let mut bits = self.bits.write().unwrap();
82 for i in 0..self.num_hashes {
83 let combined = h1.wrapping_add((i as u64).wrapping_mul(h2));
84 let idx = (combined as usize) % self.num_bits;
85 bits[idx / 64] |= 1u64 << (idx % 64);
86 }
87 self.count.fetch_add(1, Ordering::Relaxed);
88 Ok(())
89 }
90
91 pub fn might_contain(&self, key: &str) -> bool {
93 let (h1, h2) = self.hash(key);
94 let bits = self.bits.read().unwrap();
95 for i in 0..self.num_hashes {
96 let combined = h1.wrapping_add((i as u64).wrapping_mul(h2));
97 let idx = (combined as usize) % self.num_bits;
98 if bits[idx / 64] & (1u64 << (idx % 64)) == 0 {
99 return false;
100 }
101 }
102 true
103 }
104
105 pub fn count(&self) -> usize {
107 self.count.load(Ordering::Relaxed)
108 }
109
110 pub fn is_empty(&self) -> bool {
112 self.count() == 0
113 }
114
115 pub fn capacity(&self) -> usize {
117 self.capacity
118 }
119
120 pub fn clear(&self) {
122 let mut bits = self.bits.write().unwrap();
123 bits.iter_mut().for_each(|w| *w = 0);
124 self.count.store(0, Ordering::Relaxed);
125 }
126
127 fn hash(&self, key: &str) -> (u64, u64) {
129 let mut h1: u64 = 0xcbf29ce484222325;
130 let mut h2: u64 = 0x9e3779b97f4a7c15;
131 for b in key.bytes() {
132 h1 ^= b as u64;
133 h1 = h1.wrapping_mul(0x100000001b3);
134 h2 = h2.wrapping_add(b as u64);
135 h2 = h2.wrapping_mul(0x100000001b3);
136 }
137 h2 ^= h2 >> 33;
138 h2 = h2.wrapping_mul(0xff51afd7ed558ccd);
139 (h1, h2)
140 }
141}
142
143#[cfg(test)]
147mod concurrent_tests {
148 use super::*;
149
150 #[test]
153 fn bloom_concurrent_add_no_false_negative() {
154 use std::sync::Arc;
155 use std::thread;
156
157 let filter = Arc::new(BloomFilter::new(4096, 0.01));
158 let mut handles = vec![];
159 for t in 0..8 {
160 let f = Arc::clone(&filter);
161 handles.push(thread::spawn(move || {
162 for i in 0..200 {
163 f.add(&format!("thread-{t}-key-{i}")).unwrap();
164 }
165 }));
166 }
167 for h in handles {
168 h.join().unwrap();
169 }
170 for t in 0..8 {
172 for i in 0..200 {
173 assert!(
174 filter.might_contain(&format!("thread-{t}-key-{i}")),
175 "add 后 must_contain 必须命中(并发不漏判): thread-{t}-key-{i}"
176 );
177 }
178 }
179 assert_eq!(filter.count(), 1600);
180 }
181
182 #[test]
184 fn bloom_concurrent_read_write_smoke() {
185 use std::sync::Arc;
186 use std::thread;
187
188 let filter = Arc::new(BloomFilter::new(2048, 0.01));
189 let mut handles = vec![];
190 for t in 0..4 {
191 let f = Arc::clone(&filter);
192 handles.push(thread::spawn(move || {
193 for i in 0..100 {
194 let key = format!("t{t}-k{i}");
195 let _ = f.add(&key);
196 let _ = f.might_contain(&key);
197 let _ = f.count();
198 }
199 }));
200 }
201 for h in handles {
202 h.join().unwrap();
203 }
204 assert!(filter.count() > 0);
205 }
206}