docs(worker): record live item-handle-reuse probe for ack writer
ci / windows-x86 (push) Successful in 1m29s
ci / nightly-windev (push) Has been skipped
ci / java (push) Successful in 2m47s
ci / nightly-windev (pull_request) Has been skipped
ci / portable (push) Failing after 3m1s
ci / portable (pull_request) Failing after 1m46s
ci / windows-x86 (pull_request) Successful in 1m24s
ci / java (pull_request) Successful in 2m36s
ci / windows-x86 (push) Successful in 1m29s
ci / nightly-windev (push) Has been skipped
ci / java (push) Successful in 2m47s
ci / nightly-windev (pull_request) Has been skipped
ci / portable (push) Failing after 3m1s
ci / portable (pull_request) Failing after 1m46s
ci / windows-x86 (pull_request) Successful in 1m24s
ci / java (pull_request) Successful in 2m36s
Add the Skip-gated ItemHandleReuseProbeTests probe and its windev result (2026-10-20): within one MXAccess registration, item handles increase monotonically and are never reused across remove/re-add, so the ack writer's Unconfirmed drop-and-re-add mitigation holds and no per-handle generation counter is needed. Numbering restarts only on a new registration, which teardown already isolates. Document the guarantee at the Dirty re-add and in AlarmProbeFindings.md. Fixes #166 Claude-Session: https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
This commit is contained in:
@@ -515,3 +515,32 @@ returns gRPC `InvalidArgument`.
|
||||
The GUID arm of the ack command was not driven live. The public alarm RPCs expose only
|
||||
the full reference, so clients reach the by-name arm; worker unit tests cover the GUID
|
||||
arm.
|
||||
|
||||
## Item handle reuse
|
||||
|
||||
`AlarmAckWriter` correlates an ack with its `OnWriteComplete` by the
|
||||
(server handle, item handle) pair, because the callback carries no per-write id.
|
||||
After an unconfirmed ack it drops the `AckMsg` item and re-adds it so the next
|
||||
ack waits on a new handle that a late completion for the old one cannot match.
|
||||
That only works if MXAccess does not hand the same number out again.
|
||||
|
||||
`ItemHandleReuseProbeTests` (Skip-gated, worker tests) checked this on windev
|
||||
(`10.100.0.48`, Galaxy `DEV`) on 2026-10-20 against
|
||||
`TestMachine_001.TestAlarm001.AckMsg`, without writing:
|
||||
|
||||
| Sequence on one registration (server handle 1) | Item handles returned |
|
||||
|---|---|
|
||||
| `AddItem` + `Advise`, then `UnAdvise` + `RemoveItem`, five times | 1, 2, 3, 4, 5 |
|
||||
| `AddItem`, then `RemoveItem`, five times | 6, 7, 8, 9, 10 |
|
||||
| Add and remove `AckMsg`, add `Acked`, add `AckMsg` again | 11, then 12 (`Acked`), 13 |
|
||||
| Add `AckMsg` twice while both are held | 14, 15 |
|
||||
|
||||
Within a registration the numbers increase and a freed number is never reused,
|
||||
so the drop-and-re-add mitigation holds. Numbering is per registration:
|
||||
`Unregister` + `Register` on the same COM object returned server handle 2 and
|
||||
item handle 1, and a new `LMXProxyServerClass` returned server handle 1 and
|
||||
item handle 1 again. The writer is not exposed to that restart because its
|
||||
teardown detaches its `OnWriteComplete` handler from the old COM object and
|
||||
clears that server handle's completion entries before it creates a new one.
|
||||
No per-handle generation counter is needed.
|
||||
|
||||
|
||||
@@ -356,7 +356,10 @@ stay acceptance-only regardless of which completion (if any) was attributed.
|
||||
`MxAccessWriteCompletionCache` and reuses one advised `AckMsg` item per alarm
|
||||
(least-recently-used, capped at 256). After an ack ends unconfirmed it marks the
|
||||
item dirty, and the next ack to that alarm removes and re-adds the item so the
|
||||
write waits on a fresh item handle the stale completion cannot match. Every
|
||||
write waits on a fresh item handle the stale completion cannot match. This
|
||||
relies on MXAccess never reusing an item handle number within one
|
||||
registration, which a live probe confirmed (see "Item handle reuse" in
|
||||
[Alarm Probe Findings](./AlarmProbeFindings.md)). Every
|
||||
drop of an item (dirty re-add, eviction, or a failed `AddItem`/`Advise`/`Write`)
|
||||
also removes that handle's completion entry, and tearing down the registration
|
||||
removes every entry for its server handle, so the cache does not grow by one
|
||||
|
||||
Reference in New Issue
Block a user