fix(opcua): stale-cut clear keeps newer episodes, dispose barrier + timeout warning, replay marker cleared on throw (#854 re-review)
This commit is contained in:
@@ -624,7 +624,10 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2, INodeManager3
|
||||
// #854 review: refuse new Server-object refreshes and let the ones in flight finish (the base's private
|
||||
// NodeManagerOperation guard does this for its own paths).
|
||||
_disposing = true;
|
||||
SpinWait.SpinUntil(() => Volatile.Read(ref _refreshesInFlight) == 0, TimeSpan.FromSeconds(10));
|
||||
Interlocked.MemoryBarrier(); // the flag write must not be reordered after the in-flight read (#854 re-review)
|
||||
if (!SpinWait.SpinUntil(() => Volatile.Read(ref _refreshesInFlight) == 0, TimeSpan.FromSeconds(10)))
|
||||
_logger.LogWarning("Node manager disposed with {Count} Server-object ConditionRefresh call(s) still in flight after 10 s",
|
||||
Volatile.Read(ref _refreshesInFlight));
|
||||
Volatile.Read(ref _dataPlaneAuthority).Changed -= OnAuthorityChanged;
|
||||
_liveItems.Clear();
|
||||
_eventItems.Clear();
|
||||
@@ -1812,7 +1815,7 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2, INodeManager3
|
||||
if (!_allEventsItemStates.TryGetValue(item, out var state)) continue;
|
||||
lock (state.Gate)
|
||||
{
|
||||
if (state.Cut is { } cut && cut.Episode != current) state.Cut = null;
|
||||
if (state.Cut is { } cut && cut.Episode < current) state.Cut = null; // episodes only grow: never clear a newer cut (#854 re-review)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6472,6 +6475,10 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2, INodeManager3
|
||||
var states = items.Select(AllEventsItemStateOf).ToList();
|
||||
var perItem = new List<(IFilterTarget Event, AlarmConditionState Condition)>[items.Count];
|
||||
var generation = Interlocked.Increment(ref _refreshGeneration);
|
||||
// #854 re-review: a throw between installing the "replay pending" markers and finishing the replay must not leave
|
||||
// a marker set (every sync event to that item would keep taking the gate until its next refresh).
|
||||
try
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
var watermark = Interlocked.Read(ref _conditionEventSequence);
|
||||
@@ -6560,6 +6567,19 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2, INodeManager3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var state in states)
|
||||
{
|
||||
lock (state.Gate)
|
||||
{
|
||||
if (state.PendingReplay != generation) continue;
|
||||
state.PendingReplay = 0;
|
||||
state.NewerSinceCut.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user