Commit ebe1ab2
committed
fix: make _mark_seen safe under free-threaded contention
Address review feedback on #1717. The previous eviction body —
``del seen[next(iter(seen))]`` — relied on the GIL to serialize the
compound iter/next/del. Under the free-threaded build (3.14t) and
under multi-instance sync use where multiple ``Zeroconf`` instances
share the module-level ``_seen_logs``, callers can race:
- Two threads pop the same victim — ``del`` raises ``KeyError`` on
the loser
- One thread mutates the dict between another's ``iter()`` and
``next()`` — the iterator's mutation-count check raises
``RuntimeError`` ("dictionary changed size during iteration")
Switch to ``seen.pop(next(iter(seen), None), None)`` so the pop is
idempotent (no ``KeyError``) and the iter start handles the empty-
dict edge case (no ``StopIteration``), and wrap the iter/next in a
``try/except RuntimeError`` so concurrent mutation during eviction
is absorbed. Worst case under contention is a transient overshoot of
the cap by one entry per racing thread, which clears as soon as the
contention does.
Add ``test_mark_seen_absorbs_runtime_error_during_eviction`` which
substitutes a dict subclass whose ``__iter__`` always raises, proving
the new ``except`` branch lets the insert still complete.
Also tighten ``tests/test_protocol.py::test_seen_logs_is_bounded`` per
Kōan's review comment: previously asserted ``<= _MAX_SEEN_LOGS``,
which would still pass if a future refactor collapsed the per-port
keys to a single dedup string. Now asserts ``== _MAX_SEEN_LOGS`` and
verifies port 0's exception text is gone while the highest port's is
still present — pins both the bound and that the parser exception
path actually enters the dict with per-source-unique keys.1 parent 9a64353 commit ebe1ab2
3 files changed
Lines changed: 50 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
53 | 64 | | |
54 | 65 | | |
55 | 66 | | |
56 | 67 | | |
57 | | - | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
58 | 74 | | |
59 | 75 | | |
60 | 76 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
88 | 108 | | |
89 | 109 | | |
90 | 110 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
965 | 965 | | |
966 | 966 | | |
967 | 967 | | |
968 | | - | |
| 968 | + | |
969 | 969 | | |
970 | 970 | | |
971 | 971 | | |
972 | 972 | | |
973 | 973 | | |
| 974 | + | |
974 | 975 | | |
975 | | - | |
| 976 | + | |
976 | 977 | | |
977 | | - | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
978 | 987 | | |
979 | 988 | | |
980 | 989 | | |
| |||
0 commit comments