Run anti-entropy sweep. For each ghost stub, the caller must verify against the target shard: 1. Does the target shard acknowledge the node exists? 2. Do any local edges still reference this ghost? `verify_fn` takes (node_id, target_shard) and returns SweepVerdict. The sweeper runs at lowest I/O priority and is rate-limited.
(&mut self, verify_fn: F)
| 142 | /// `verify_fn` takes (node_id, target_shard) and returns SweepVerdict. |
| 143 | /// The sweeper runs at lowest I/O priority and is rate-limited. |
| 144 | pub fn sweep<F>(&mut self, verify_fn: F) -> SweepReport |
| 145 | where |
| 146 | F: Fn(&str, u32) -> SweepVerdict, |
| 147 | { |
| 148 | let now_ms = std::time::SystemTime::now() |
| 149 | .duration_since(std::time::UNIX_EPOCH) |
| 150 | .unwrap_or_default() |
| 151 | .as_millis() as u64; |
| 152 | self.last_sweep_ms = now_ms; |
| 153 | |
| 154 | let mut report = SweepReport::default(); |
| 155 | let mut to_purge = Vec::new(); |
| 156 | |
| 157 | for (node_id, stub) in &self.stubs { |
| 158 | report.checked += 1; |
| 159 | |
| 160 | // Fast path: if refcount is already 0, purge without remote check. |
| 161 | if stub.refcount == 0 { |
| 162 | to_purge.push(node_id.clone()); |
| 163 | report.purged += 1; |
| 164 | continue; |
| 165 | } |
| 166 | |
| 167 | match verify_fn(node_id, stub.target_shard) { |
| 168 | SweepVerdict::Purge => { |
| 169 | to_purge.push(node_id.clone()); |
| 170 | report.purged += 1; |
| 171 | } |
| 172 | SweepVerdict::Keep => { |
| 173 | report.kept += 1; |
| 174 | } |
| 175 | SweepVerdict::Inconclusive => { |
| 176 | report.inconclusive += 1; |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | for node_id in to_purge { |
| 182 | self.stubs.remove(&node_id); |
| 183 | self.purge_count += 1; |
| 184 | } |
| 185 | |
| 186 | if report.purged > 0 { |
| 187 | info!( |
| 188 | purged = report.purged, |
| 189 | kept = report.kept, |
| 190 | inconclusive = report.inconclusive, |
| 191 | total_ghosts = self.stubs.len(), |
| 192 | "anti-entropy sweep complete" |
| 193 | ); |
| 194 | } |
| 195 | |
| 196 | report |
| 197 | } |
| 198 | |
| 199 | pub fn len(&self) -> usize { |
| 200 | self.stubs.len() |