Commit 9b7a27d3 authored by Elmo von Weissenberg's avatar Elmo von Weissenberg Committed by oroulet

perf: optimize XML importing

Optimize processing with some standard data structures.
Stop adding reverse references to HasTypeDefinitions.
parent db9e81d9
...@@ -4,7 +4,7 @@ format is the one from opc-ua specification ...@@ -4,7 +4,7 @@ format is the one from opc-ua specification
""" """
import logging import logging
import uuid import uuid
from typing import Union, Dict, List from typing import Union, Dict, List, Tuple
from dataclasses import fields, is_dataclass from dataclasses import fields, is_dataclass
from asyncua import ua from asyncua import ua
...@@ -138,27 +138,43 @@ class XmlImporter: ...@@ -138,27 +138,43 @@ class XmlImporter:
ua.ObjectIds.TransitionVariableType, ua.ObjectIds.StateMachineType, ua.ObjectIds.TransitionVariableType, ua.ObjectIds.StateMachineType,
ua.ObjectIds.StateVariableType, ua.ObjectIds.TwoStateVariableType, ua.ObjectIds.StateVariableType, ua.ObjectIds.TwoStateVariableType,
ua.ObjectIds.StateType, ua.ObjectIds.TransitionType, ua.ObjectIds.StateType, ua.ObjectIds.TransitionType,
ua.ObjectIds.FiniteTransitionVariableType, ua.ObjectIds.HasInterface} ua.ObjectIds.FiniteTransitionVariableType, ua.ObjectIds.HasInterface,
dangling_refs_to_missing_nodes = set() ua.ObjectIds.HasTypeDefinition, ua.ObjectIds.HasComponent}
dangling_refs_to_missing_nodes = set(new_nodes)
RefSpecKey = Tuple[ua.NodeId, ua.NodeId, ua.NodeId] # (source_node_id, target_node_id, ref_type_id)
node_reference_map: Dict[RefSpecKey, ua.ReferenceDescription] = {}
for new_node_id in new_nodes: for new_node_id in new_nodes:
new_n = self.server.get_node(new_node_id) node = self.server.get_node(new_node_id)
new_n_refs = await new_n.get_references() node_ref_list: List[ua.ReferenceDescription] = await node.get_references()
if len(new_n_refs) == 0:
_logger.warning("Node %s has no references, so it does not exist in Server!", new_node_id) for ref in node_ref_list:
continue if ref.ReferenceTypeId.Identifier in __unidirectional_types:
for ref in new_n_refs: continue
if ref.ReferenceTypeId not in __unidirectional_types: ref_key = (new_node_id, ref.NodeId, ref.ReferenceTypeId)
n = self.server.get_node(ref.NodeId) node_reference_map[ref_key] = ref
n_refs = await n.get_references()
if len(n_refs) == 0: dangling_refs_to_missing_nodes.discard(new_node_id)
_logger.warning("Node %s has no references, so it does not exist in Server!", ref.NodeId) dangling_refs_to_missing_nodes.discard(ref.NodeId)
dangling_refs_to_missing_nodes.add(ref.NodeId)
continue for node in dangling_refs_to_missing_nodes:
for n_ref in n_refs: _logger.warning("Node %s has no references, so it does not exist in Server!", node)
if new_node_id == n_ref.NodeId and n_ref.ReferenceTypeId == ref.ReferenceTypeId:
break reference_fixes = []
else:
await n.add_reference(new_node_id, ref.ReferenceTypeId, not ref.IsForward) for ref_spec, ref in node_reference_map.items():
source_node_id, target_node_id, ref_type = ref_spec
reverse_ref_spec = (target_node_id, source_node_id, ref_type)
if reverse_ref_spec not in node_reference_map:
_logger.debug("Adding missing reference: %s <-> %s (%s)", target_node_id, source_node_id, ref.ReferenceTypeId)
new_ref = ua.AddReferencesItem(SourceNodeId=target_node_id, TargetNodeId=source_node_id,
ReferenceTypeId=ref_type, IsForward=(not ref.IsForward))
reference_fixes.append(new_ref)
await self._add_references(reference_fixes)
return dangling_refs_to_missing_nodes return dangling_refs_to_missing_nodes
def _add_missing_parents(self, dnodes): def _add_missing_parents(self, dnodes):
...@@ -629,19 +645,19 @@ class XmlImporter: ...@@ -629,19 +645,19 @@ class XmlImporter:
""" """
sorted_ndatas = [] sorted_ndatas = []
sorted_nodes_ids = [] sorted_nodes_ids = set()
all_node_ids = [data.nodeid for data in ndatas] all_node_ids = set(data.nodeid for data in ndatas)
while ndatas: while len(sorted_nodes_ids) < len(ndatas):
for ndata in ndatas[:]: for ndata in ndatas:
if (ndata.nodeid.NamespaceIndex not in self.namespaces.values() or ndata.parent is None or ndata.parent not in all_node_ids): if ndata.nodeid in sorted_nodes_ids:
continue
elif (ndata.parent is None or ndata.parent not in all_node_ids):
sorted_ndatas.append(ndata) sorted_ndatas.append(ndata)
sorted_nodes_ids.append(ndata.nodeid) sorted_nodes_ids.add(ndata.nodeid)
ndatas.remove(ndata)
else: else:
# Check if the nodes parent is already in the list of # Check if the nodes parent is already in the list of
# inserted nodes # inserted nodes
if ndata.parent in sorted_nodes_ids: if ndata.parent in sorted_nodes_ids:
sorted_ndatas.append(ndata) sorted_ndatas.append(ndata)
sorted_nodes_ids.append(ndata.nodeid) sorted_nodes_ids.add(ndata.nodeid)
ndatas.remove(ndata)
return sorted_ndatas return sorted_ndatas
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment