f37cb2a4a3
N1: a refusal of the DWORD-addressed request permanently settled the layout as per-element, so a tag deployed before the online edit that creates its BOOL array later read DWORD n and published byte 0 as Good. The native runtime now keeps an explicit layout (Unsettled / Packed / PerElement) that ONLY a reply type changes: 0xD3 settles packed (Bits[n/32], bit n%32), 0xC1 settles per-element (Bits[n]). Refusals and comms faults leave it unsettled, so the next read asks again. A reply whose type disagrees with the addressing it was asked under is discarded and re-read once under the shown layout (it would be some other element), also when an online edit re-types a settled array. A scalar BOOL answered 0xD3 with no element bit, or not settled packed, is refused BadTypeMismatch instead of decoding byte 0. m1: the write-owned Degraded marker is set together with the CAS that installs it, under one lock, so concurrent failing writes cannot leave it naming a different instance (a good write then clears it); a refusal-only read batch still keeps it write-owned. m2/m3/m5: documented (breaker accounting of a superseded init; libplctag throw-only NotImplemented assumption; the TypeMismatch write status word is libplctag-only). m4: test for a write on an unsettled layout (settles by a read first). Refs #737 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
19 lines
1.4 KiB
C#
19 lines
1.4 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
|
|
|
/// <summary>
|
|
/// Thrown by <see cref="AbCipDriver.InitializeAsync"/> when a shutdown, dispose or newer initialization retired the
|
|
/// driver's tables while this initialization was building, so it published nothing. Deliberately NOT an
|
|
/// <see cref="OperationCanceledException"/>: nobody cancelled this call, and a caller that treats cancellation as
|
|
/// "my own token fired" must not mistake a superseded attempt for one. The superseding operation owns the driver's
|
|
/// state; the caller (normally the runtime, which has already abandoned this attempt) can ignore the result.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Resilience accounting (#737 m2): not being an OCE, it passes the Initialize pipeline's breaker
|
|
/// <c>ShouldHandle</c> (<c>DriverResiliencePipelineBuilder</c>) and, if its generation still matched, the actor's
|
|
/// <c>RecordFault</c>. That is practically unreachable — <c>DriverInstanceActor</c> runs initialisation single-flight
|
|
/// and drops generation-mismatched results — and a superseded attempt is at worst one counted failure. Recognising
|
|
/// it there is a runtime-side (Lane A) change if it is ever wanted.
|
|
/// </remarks>
|
|
/// <param name="message">The detail.</param>
|
|
public sealed class AbCipInitializationSupersededException(string message) : InvalidOperationException(message);
|