Skip to content

Commit d9f21b4

Browse files
committed
generate_nodeid now generates random id's
Since the sqlite address-space is lazy loading, the old approach with incremental identifiers is very slow, as it requires loading the complete address space in memory before the highest identifier is found. Generating a random uid and checking if it already exists in the address space is much faster, especially for hunderds of nodes.
1 parent 6290f0f commit d9f21b4

File tree

1 file changed

+10
-15
lines changed

1 file changed

+10
-15
lines changed

opcua/server/address_space.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
22
from datetime import datetime
3+
import random
34

45
from opcua import ua
56
from opcua.server.user_manager import UserManager
@@ -473,40 +474,34 @@ def _call(self, method):
473474

474475

475476
class AddressSpace(ThreadSafeDict):
476-
477477
"""
478478
The address space object stores all the nodes of the OPC-UA server
479479
and helper methods.
480480
The methods are thread safe
481481
"""
482+
# https://opcfoundation.org/UA/schemas/1.03/Opc.Ua.Types.bsd
483+
# numeric nodeid is UInt32, but Siemens MindSphere uses Int32.
484+
MAX_NUMERIC_IDENTIFIER = 0x7fffffff
482485
DEFAULT_USER_NAMESPACE_INDEX = 2
483486

484487
def __init__(self, cache=None):
485488
super(AddressSpace, self).__init__(cache)
486489
self.logger = logging.getLogger(__name__)
487490
self._datachange_callback_counter = 200
488491
self._handle_to_attribute_map = {}
489-
self._nodeid_counter = {0: 20000, 1: 2000}
490492

491493
def generate_nodeid(self, idx=DEFAULT_USER_NAMESPACE_INDEX):
492-
if idx in self._nodeid_counter:
493-
self._nodeid_counter[idx] += 1
494-
else:
495-
# get the biggest identifier number from the existed nodes in address space
496-
identifier_list = sorted([nodeid.Identifier for nodeid in self
497-
if nodeid.NamespaceIndex == idx and nodeid.NodeIdType
498-
in (ua.NodeIdType.Numeric, ua.NodeIdType.TwoByte, ua.NodeIdType.FourByte)])
499-
if identifier_list:
500-
self._nodeid_counter[idx] = identifier_list[-1]
501-
else:
502-
self._nodeid_counter[idx] = 1
503-
nodeid = ua.NodeId(self._nodeid_counter[idx], idx)
494+
nodeid = ua.NodeId(
495+
identifier=random.randrange(AddressSpace.MAX_NUMERIC_IDENTIFIER),
496+
namespaceidx=idx
497+
)
504498
with self._lock: # OK since reentrant lock
505-
while True:
499+
for retry in range(0, 10):
506500
if nodeid in self:
507501
nodeid = self.generate_nodeid(idx)
508502
else:
509503
return nodeid
504+
assert(False) # What are the odds?
510505

511506
def get_attribute_value(self, nodeid, attr):
512507
with self._lock:

0 commit comments

Comments
 (0)