()
| 162 | /// Shard 0 GCs below hlc=50; shard 1 has no acks yet (no-op). |
| 163 | #[test] |
| 164 | fn per_shard_gc_is_independent() { |
| 165 | let log0 = InMemoryOpLog::new(); |
| 166 | let log1 = InMemoryOpLog::new(); |
| 167 | |
| 168 | // 3 ops in shard0, 2 ops in shard1. |
| 169 | for ms in [10u64, 20, 30] { |
| 170 | log0.append(&put_op("arr", (ms / 10) as i64, ms)) |
| 171 | .expect("shard0 append"); |
| 172 | } |
| 173 | for ms in [100u64, 200] { |
| 174 | log1.append(&put_op("arr", (ms / 10) as i64, ms)) |
| 175 | .expect("shard1 append"); |
| 176 | } |
| 177 | |
| 178 | // Shard 0 receives an ack at frontier=25; shard 1 has no acks. |
| 179 | let mut acks0 = AckVector::new(); |
| 180 | acks0.record(rep(1), hlc(25, 1)); |
| 181 | let acks1 = AckVector::new(); // empty → no-op GC |
| 182 | |
| 183 | let sink0 = MockSnapshotSink::new(); |
| 184 | let sink1 = MockSnapshotSink::new(); |
| 185 | |
| 186 | let report0 = collapse_below(&log0, &acks0, &sink0, |a, f| Ok(Some(dummy_snap(a, f)))) |
| 187 | .expect("shard0 gc"); |
| 188 | |
| 189 | let report1 = collapse_below(&log1, &acks1, &sink1, |a, f| Ok(Some(dummy_snap(a, f)))) |
| 190 | .expect("shard1 gc"); |
| 191 | |
| 192 | // Shard 0: ops at ms=10 and ms=20 are < 25 → dropped; ms=30 survives. |
| 193 | assert_eq!(report0.ops_dropped, 2, "shard0 must drop 2 ops"); |
| 194 | assert_eq!(log0.len().expect("len"), 1, "shard0 retains ms=30"); |
| 195 | |
| 196 | // Shard 1: no acks → no GC. |
| 197 | assert_eq!(report1.ops_dropped, 0, "shard1 must drop 0 ops (no acks)"); |
| 198 | assert_eq!(log1.len().expect("len"), 2, "shard1 log unchanged"); |
| 199 | } |
| 200 | |
| 201 | /// Cross-shard: ops for different arrays on different shards each get |
| 202 | /// their own snapshot on GC, and the snapshots are independent. |
nothing calls this directly
no test coverage detected