Skip to content

Commit

Permalink
Fix server CurrentTime source timestamp and improve readerwriter locks (
Browse files Browse the repository at this point in the history
#2903)

Fix server time source timestamp is not updated.
There are duplicate objects in generated code, on of which which holds the last timestamp was not updated.

Move all readerwriter locks outside of try/finally to avoid a SynchronizationLockException when a reader writer lock is disposed or is cancelled.

Currently there is no obvious fundamental bug in how the readerwriter locks are used, but outside the try/finally clause e.g. a disposed lock may not trigger a false exception.
  • Loading branch information
mregen authored Dec 13, 2024
1 parent f431d53 commit dc661ba
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 83 deletions.
94 changes: 41 additions & 53 deletions Libraries/Opc.Ua.Client/NodeCache/NodeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ public INode Find(ExpandedNodeId nodeId)
}

INode node;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

// check if node already exists.
node = m_nodes.Find(nodeId);
}
Expand Down Expand Up @@ -155,10 +155,10 @@ public IList<INode> Find(IList<ExpandedNodeId> nodeIds)
for (ii = 0; ii < count; ii++)
{
INode node;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

// check if node already exists.
node = m_nodes.Find(nodeIds[ii]);
}
Expand Down Expand Up @@ -235,10 +235,10 @@ public INode Find(
}

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

// find all references.
references = source.ReferenceTable.Find(referenceTypeId, isInverse, includeSubtypes, m_typeTree);
}
Expand Down Expand Up @@ -285,10 +285,9 @@ public IList<INode> Find(
}

IList<IReference> references;
m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

// find all references.
references = source.ReferenceTable.Find(referenceTypeId, isInverse, includeSubtypes, m_typeTree);
}
Expand Down Expand Up @@ -325,10 +324,9 @@ public bool IsKnown(ExpandedNodeId typeId)
return false;
}

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

return m_typeTree.IsKnown(typeId);
}
finally
Expand All @@ -347,10 +345,9 @@ public bool IsKnown(NodeId typeId)
return false;
}

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

return m_typeTree.IsKnown(typeId);
}
finally
Expand All @@ -369,10 +366,9 @@ public NodeId FindSuperType(ExpandedNodeId typeId)
return null;
}

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

return m_typeTree.FindSuperType(typeId);
}
finally
Expand All @@ -392,10 +388,9 @@ public NodeId FindSuperType(NodeId typeId)
return null;
}

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

return m_typeTree.FindSuperType(typeId);
}
finally
Expand All @@ -409,18 +404,18 @@ public NodeId FindSuperType(NodeId typeId)
public IList<NodeId> FindSubTypes(ExpandedNodeId typeId)
{
ILocalNode type = Find(typeId) as ILocalNode;
List<NodeId> subtypes = new List<NodeId>();

if (type == null)
{
return new List<NodeId>();
return subtypes;
}

List<NodeId> subtypes = new List<NodeId>();
IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = type.References.Find(ReferenceTypeIds.HasSubtype, false, true, m_typeTree);
}
finally
Expand Down Expand Up @@ -459,10 +454,10 @@ public bool IsTypeOf(ExpandedNodeId subTypeId, ExpandedNodeId superTypeId)
while (supertype != null)
{
ExpandedNodeId currentId;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

currentId = supertype.References.FindTarget(ReferenceTypeIds.HasSubtype, true, true, m_typeTree, 0);
}
finally
Expand Down Expand Up @@ -501,10 +496,10 @@ public bool IsTypeOf(NodeId subTypeId, NodeId superTypeId)
while (supertype != null)
{
ExpandedNodeId currentId;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

currentId = supertype.References.FindTarget(ReferenceTypeIds.HasSubtype, true, true, m_typeTree, 0);
}
finally
Expand All @@ -526,10 +521,9 @@ public bool IsTypeOf(NodeId subTypeId, NodeId superTypeId)
/// <inheritdoc/>
public QualifiedName FindReferenceTypeName(NodeId referenceTypeId)
{
m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

return m_typeTree.FindReferenceTypeName(referenceTypeId);
}
finally
Expand All @@ -541,10 +535,9 @@ public QualifiedName FindReferenceTypeName(NodeId referenceTypeId)
/// <inheritdoc/>
public NodeId FindReferenceType(QualifiedName browseName)
{
m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

return m_typeTree.FindReferenceType(browseName);
}
finally
Expand All @@ -564,10 +557,10 @@ public bool IsEncodingOf(ExpandedNodeId encodingId, ExpandedNodeId datatypeId)
}

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = encoding.References.Find(ReferenceTypeIds.HasEncoding, true, true, m_typeTree);
}
finally
Expand Down Expand Up @@ -611,10 +604,10 @@ public bool IsEncodingFor(NodeId expectedTypeId, ExtensionObject value)
}

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = encoding.References.Find(ReferenceTypeIds.HasEncoding, true, true, m_typeTree);
}
finally
Expand Down Expand Up @@ -706,10 +699,10 @@ public NodeId FindDataTypeId(ExpandedNodeId encodingId)
}

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = encoding.References.Find(ReferenceTypeIds.HasEncoding, true, true, m_typeTree);
}
finally
Expand All @@ -736,10 +729,10 @@ public NodeId FindDataTypeId(NodeId encodingId)
}

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = encoding.References.Find(ReferenceTypeIds.HasEncoding, true, true, m_typeTree);
}
finally
Expand Down Expand Up @@ -769,10 +762,9 @@ public void LoadUaDefinedTypes(ISystemContext context)
var assembly = typeof(ArgumentCollection).GetTypeInfo().Assembly;
predefinedNodes.LoadFromBinaryResource(context, "Opc.Ua.Stack.Generated.Opc.Ua.PredefinedNodes.uanodes", assembly, true);

m_cacheLock.EnterWriteLock();
try
{
m_cacheLock.EnterWriteLock();

for (int ii = 0; ii < predefinedNodes.Count; ii++)
{
BaseTypeState type = predefinedNodes[ii] as BaseTypeState;
Expand All @@ -795,11 +787,10 @@ public void LoadUaDefinedTypes(ISystemContext context)
/// <inheritdoc/>
public void Clear()
{
m_uaTypesLoaded = false;
m_cacheLock.EnterWriteLock();
try
{
m_cacheLock.EnterWriteLock();

m_uaTypesLoaded = false;
m_nodes.Clear();
}
finally
Expand All @@ -826,10 +817,9 @@ public Node FetchNode(ExpandedNodeId nodeId)
// fetch references from server.
ReferenceDescriptionCollection references = m_session.FetchReferences(localId);

m_cacheLock.EnterUpgradeableReadLock();
try
{
m_cacheLock.EnterUpgradeableReadLock();

foreach (ReferenceDescription reference in references)
{
// create a placeholder for the node if it does not already exist.
Expand Down Expand Up @@ -896,10 +886,9 @@ public IList<Node> FetchNodes(IList<ExpandedNodeId> nodeIds)

foreach (ReferenceDescription reference in references)
{
m_cacheLock.EnterUpgradeableReadLock();
try
{
m_cacheLock.EnterUpgradeableReadLock();

// create a placeholder for the node if it does not already exist.
if (!m_nodes.Exists(reference.NodeId))
{
Expand Down Expand Up @@ -976,10 +965,10 @@ public IList<INode> FindReferences(
}

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = source.ReferenceTable.Find(referenceTypeId, isInverse, includeSubtypes, m_typeTree);
}
finally
Expand Down Expand Up @@ -1026,10 +1015,10 @@ public IList<INode> FindReferences(
foreach (var referenceTypeId in referenceTypeIds)
{
IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = node.ReferenceTable.Find(referenceTypeId, isInverse, includeSubtypes, m_typeTree);
}
finally
Expand Down Expand Up @@ -1077,10 +1066,10 @@ public string GetDisplayText(INode node)
NodeId modellingRule = target.ModellingRule;

IList<IReference> references;

m_cacheLock.EnterReadLock();
try
{
m_cacheLock.EnterReadLock();

references = target.ReferenceTable.Find(ReferenceTypeIds.Aggregates, true, true, m_typeTree);
}
finally
Expand Down Expand Up @@ -1167,10 +1156,9 @@ public NodeId BuildBrowsePath(ILocalNode node, IList<QualifiedName> browsePath)
#region Private Methods
private void InternalWriteLockedAttach(ILocalNode node)
{
m_cacheLock.EnterWriteLock();
try
{
m_cacheLock.EnterWriteLock();

// add to cache.
m_nodes.Attach(node);
}
Expand Down
Loading

0 comments on commit dc661ba

Please sign in to comment.