fix(code-review): resolve OpcUaServer-001 — UNS Area/Line rename refreshes folder DisplayName
A rename-only deploy produced an IsEmpty plan that short-circuited before MaterialiseHierarchy, leaving the OPC UA folder DisplayName stale. AddressSpacePlanner now diffs UnsAreas/UnsLines by stable id into a RenamedFolders set (counted in IsEmpty); the applier refreshes the folder in place via a new UpdateFolderDisplayName on ISurgicalAddressSpaceSink (forwarded through DeferredAddressSpaceSink so it is NOT inert on driver hosts; falls back to rebuild when the sink is non-surgical). DeploymentArtifact byte-parity untouched (rename rides the existing Name round-trip). No EF migration, no serialized wire/proto contract change. +13 OpcUaServer tests, Runtime rebuild test.
This commit is contained in:
@@ -87,4 +87,17 @@ public sealed class DeferredAddressSpaceSink : IOpcUaAddressSpaceSink, ISurgical
|
||||
public bool UpdateTagAttributes(string variableNodeId, bool writable, string? historianTagname, string dataType, bool isArray, uint? arrayLength)
|
||||
=> _inner is ISurgicalAddressSpaceSink surgical
|
||||
&& surgical.UpdateTagAttributes(variableNodeId, writable, historianTagname, dataType, isArray, arrayLength);
|
||||
|
||||
/// <summary>Forwards an in-place folder-display-name update (OpcUaServer-001 — UNS Area / Line
|
||||
/// rename) to the inner sink when it supports the surgical capability. Returns false otherwise —
|
||||
/// before the real <c>SdkAddressSpaceSink</c> is swapped in (inner is still the null sink), or any
|
||||
/// inner sink that isn't surgical — so the caller (AddressSpaceApplier) falls back to a full rebuild.
|
||||
/// Without this forward the rename-refresh optimization is inert on every driver-role host, because
|
||||
/// actors inject THIS wrapper, not the inner sink.</summary>
|
||||
/// <param name="folderNodeId">The folder node id whose display name to update in place.</param>
|
||||
/// <param name="displayName">The new display name to apply.</param>
|
||||
/// <returns>True when the inner sink applied the update; false when it lacks the capability or the folder is missing.</returns>
|
||||
public bool UpdateFolderDisplayName(string folderNodeId, string displayName)
|
||||
=> _inner is ISurgicalAddressSpaceSink surgical
|
||||
&& surgical.UpdateFolderDisplayName(folderNodeId, displayName);
|
||||
}
|
||||
|
||||
@@ -23,4 +23,15 @@ public interface ISurgicalAddressSpaceSink
|
||||
/// <param name="arrayLength">The declared length of the 1-D array when <paramref name="isArray"/> is true; ignored for scalars.</param>
|
||||
/// <returns>True when the in-place update was applied; false when the node is missing (caller rebuilds).</returns>
|
||||
bool UpdateTagAttributes(string variableNodeId, bool writable, string? historianTagname, string dataType, bool isArray, uint? arrayLength);
|
||||
|
||||
/// <summary>Update an existing folder node's <c>DisplayName</c> IN PLACE, notifying subscribers
|
||||
/// (ClearChangeMasks) without a rebuild — used by AddressSpaceApplier to apply a UNS Area / Line
|
||||
/// rename without tearing down + repopulating the whole address space (which would drop every
|
||||
/// client's MonitoredItems). The folder's NodeId is unchanged (a rename only touches the friendly
|
||||
/// browse/display name, not the logical id). Returns false if the folder does not exist (caller
|
||||
/// should rebuild instead).</summary>
|
||||
/// <param name="folderNodeId">The node id of the folder whose display name to update in place.</param>
|
||||
/// <param name="displayName">The new display name to apply.</param>
|
||||
/// <returns>True when the in-place update was applied; false when the folder is missing (caller rebuilds).</returns>
|
||||
bool UpdateFolderDisplayName(string folderNodeId, string displayName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user