Commit 2fcbbf85 authored by Dominik Luntzer's avatar Dominik Luntzer

Perform lazy loading when restoring a cached address space

When starting an opcua server, the creation of the address space is
currently a performance bottleneck. The startup process can be accelerated
by loading a pre-generated address space pickle.
However, the startup process still takes ~25 seconds on a raspberry pi
model b (compared to ~125 seconds when generating the address space from code).
Storing the address space in a shelve, where the data for each node is
pickeled individually, allows to further improve the startup performance
since only the nodes that are actually accessed are loaded from
disc (all other nodes are loaded later when they are accessed).
Since the default address space contains thousands of nodes but just a
small amount is actually accessed during startup, the startuptime could
be improved to ~3.5 seconds.
parent 2f5a26fb
from threading import RLock from threading import RLock
import logging import logging
from datetime import datetime from datetime import datetime
import collections
import shelve
try: try:
import cPickle as pickle import cPickle as pickle
except: except:
...@@ -466,15 +468,43 @@ class AddressSpace(object): ...@@ -466,15 +468,43 @@ class AddressSpace(object):
""" """
dump address space as binary to file dump address space as binary to file
""" """
with open(path, 'wb') as f: s = shelve.open(path, "n", protocol = pickle.HIGHEST_PROTOCOL)
pickle.dump(self._nodes, f, pickle.HIGHEST_PROTOCOL) for nodeid in self._nodes.keys():
s[nodeid.to_string()] = self._nodes[nodeid]
s.close()
def load(self, path): def load(self, path):
""" """
load address space from file, overwritting everything current address space load address space from file, overwritting everything current address space
""" """
with open(path, 'rb') as f: class LazyLoadingDict(collections.MutableMapping):
self._nodes = pickle.load(f) def __init__(self, source):
self.source = source
self.cache = {}
def __getitem__(self, key):
try:
return self.cache[key]
except KeyError:
node = self.cache[key] = self.source[key.to_string()]
return node
def __setitem__(self, key, value):
self.cache[key] = value
def __contains__(self, key):
return key in self.cache or key.to_string() in self.source
def __delitem__(self, key):
raise NotImplementedError
def __iter__(self):
raise NotImplementedError
def __len__(self):
raise NotImplementedError
self._nodes = LazyLoader(shelve.open(path, "r"))
def get_attribute_value(self, nodeid, attr): def get_attribute_value(self, nodeid, attr):
with self._lock: with self._lock:
......
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