Commit a4ecc92
committed
Prevent overflow when all entries are visited
This fixes a correctness bug where `insert()` could exceed the configured
capacity if the cache was full and every entry had `visited = true`.
This also adds a test showing how to trigger the now-fixed bug.
The `evict()` implementation can return `None` after a full scan that only
clears `visited` bits (first pass), without actually evicting an item.
`insert()` calls `evict()` once and then proceeds, which leaves
`len() == capacity` and allows the subsequent push to grow past capacity.
In the SIEVE paper, Algorithm 1 scans while clearing `visited` and *wraps once*,
then evicts the next unvisited entry in the same operation. Practically, this
is equivalent to "two passes": first clears bits, second finds a candidate.
Capacity is never exceeded.
In `insert()`, if the first `evict()` returns `None` (meaning only bits were
cleared), we now call `evict()` a second time and assert that it evicts one
entry. This guarantees a free slot before insertion and aligns behavior with
the SIEVE pseudocode.
The fix was applied in `insert()` as that's the only code path able to exceed
capacity. Doing this in `evict()` is another possible approach here.1 parent a78672f commit a4ecc92
1 file changed
+25
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
420 | 420 | | |
421 | 421 | | |
422 | 422 | | |
423 | | - | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
424 | 433 | | |
425 | 434 | | |
426 | 435 | | |
427 | 436 | | |
428 | 437 | | |
429 | 438 | | |
430 | 439 | | |
| 440 | + | |
431 | 441 | | |
432 | 442 | | |
433 | 443 | | |
| |||
1186 | 1196 | | |
1187 | 1197 | | |
1188 | 1198 | | |
| 1199 | + | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
0 commit comments