ソースを参照

Server: Reuse recursive browse in many places

Julius Pfrommer 5 年 前
コミット
da428e25af
共有5 個のファイルを変更した120 個の追加273 個の削除を含む
  1. 9 22
      src/server/ua_server_internal.h
  2. 26 171
      src/server/ua_server_utils.c
  3. 11 7
      src/server/ua_services_nodemanagement.c
  4. 46 2
      src/server/ua_services_view.c
  5. 28 71
      src/server/ua_subscription_events.c

+ 9 - 22
src/server/ua_server_internal.h

@@ -147,31 +147,18 @@ isNodeInTree(void *nsCtx, const UA_NodeId *leafNode,
              const UA_NodeId *nodeToFind, const UA_NodeId *referenceTypeIds,
              size_t referenceTypeIdsSize);
 
-/* Returns an array with the hierarchy of type nodes. The returned array starts
- * at the leaf and continues "upwards" or "downwards" in the hierarchy based on the
- * ``hasSubType`` references. Since multiple-inheritance is possible in general,
- * duplicate entries are removed.
- * The parameter `walkDownwards` indicates the direction of search.
- * If set to TRUE it will get all the subtypes of the given
- * leafType (including leafType).
- * If set to FALSE it will get all the parent types of the given
- * leafType (including leafType)*/
+/* Returns an array with the hierarchy of nodes. The start nodes are returned as
+ * well. The returned array starts at the leaf and continues "upwards" or
+ * "downwards". Duplicate entries are removed. The parameter `walkDownwards`
+ * indicates the direction of search. */
 UA_StatusCode
-getTypeHierarchy(void *nsCtx, const UA_NodeId *leafType,
-                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
-                 UA_Boolean walkDownwards);
+getLocalRecursiveHierarchy(UA_Server *server, const UA_NodeId *startNodes, size_t startNodesSize,
+                           const UA_NodeId *refTypes, size_t refTypesSize, UA_Boolean walkDownwards,
+                           UA_NodeId **results, size_t *resultsSize);
 
-/* Same as getTypeHierarchy but takes multiple leafTypes as parameter and returns
- * an combined list of all the found types for all the leaf types */
+/* Returns the recursive type and interface hierarchy of the node */ 
 UA_StatusCode
-getTypesHierarchy(void *nsCtx, const UA_NodeId *leafType, size_t leafTypeSize,
-                  UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
-                  UA_Boolean walkDownwards);
-
-/* Same as getTypeHierarchy aside of the ``hasSubType`` reference, this also includes
- * the ``hasInterface`` reference */
-UA_StatusCode
-getParentTypeAndInterfaceHierarchy(void *nsCtx, const UA_NodeId *leafType,
+getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode,
                                    UA_NodeId **typeHierarchy, size_t *typeHierarchySize);
 
 /* Returns the type node from the node on the stack top. The type node is pushed

+ 26 - 171
src/server/ua_server_utils.c

@@ -164,187 +164,42 @@ UA_Node_hasSubTypeOrInstances(const UA_Node *node) {
     return false;
 }
 
-static const UA_NodeId hasSubtypeNodeId =
-    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
 static const UA_NodeId hasInterfaceNodeId =
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASINTERFACE}};
 
-/**
- * Gets a list of nodeIds which are referenced by this node.
- * Hereby the list will be filtered to only include references
- * which are of the given `references` types.
- */
-static UA_StatusCode
-getReferencedNodesWithReferenceType(UA_NodeId **results_ptr, size_t *results_count,
-                         size_t *results_size, const UA_Node *node,
-                         const UA_NodeReferenceKind *references, size_t referencesSize) {
-    UA_NodeId *results = *results_ptr;
-    for(size_t i = 0; i < node->referencesSize; ++i) {
-        /* Is the reference kind relevant? */
-        UA_NodeReferenceKind *refs = &node->references[i];
-
-        bool referenceInList = false;
-        for (size_t j=0; j<referencesSize && !referenceInList; j++) {
-            referenceInList = refs->isInverse == references[j].isInverse &&
-                    UA_NodeId_equal(&references[j].referenceTypeId, &refs->referenceTypeId);
-        }
-        if (!referenceInList)
-            continue;
-
-        /* Append all targets of the reference kind .. if not a duplicate */
-        for(size_t j = 0; j < refs->targetIdsSize; ++j) {
-            /* Is the target a duplicate? (multi-inheritance) */
-            UA_NodeId *targetId = &refs->targetIds[j].nodeId;
-            UA_Boolean duplicate = false;
-            for(size_t k = 0; k < *results_count; ++k) {
-                if(UA_NodeId_equal(targetId, &results[k])) {
-                    duplicate = true;
-                    break;
-                }
-            }
-            if(duplicate)
-                continue;
-
-            /* Increase array length if necessary */
-            if(*results_count >= *results_size) {
-                size_t new_size = sizeof(UA_NodeId) * (*results_size) * 2;
-                UA_NodeId *new_results = (UA_NodeId*)UA_realloc(results, new_size);
-                if(!new_results) {
-                    UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]);
-                    return UA_STATUSCODE_BADOUTOFMEMORY;
-                }
-                results = new_results;
-                *results_ptr = results;
-                *results_size *= 2;
-            }
-
-            /* Copy new nodeid to the end of the list */
-            UA_StatusCode retval = UA_NodeId_copy(targetId, &results[*results_count]);
-            if(retval != UA_STATUSCODE_GOOD) {
-                UA_Array_delete(results, *results_count, &UA_TYPES[UA_TYPES_NODEID]);
-                return retval;
-            }
-            *results_count += 1;
-        }
-    }
-    return UA_STATUSCODE_GOOD;
-}
-
-
-static UA_StatusCode
-getHierarchyForReferenceTypes(void *nsCtx, const UA_NodeId *leafType,
-                              const UA_NodeReferenceKind *references, size_t referencesSize,
-                              UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
-    /* Allocate the results array. Probably too big, but saves mallocs. */
-    size_t results_size = 20;
-    UA_NodeId *results = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * results_size);
-    if(!results)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+UA_StatusCode
+getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode,
+                                   UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
+    UA_NodeId *subTypes = NULL;
+    size_t subTypesSize = 0;
+    UA_StatusCode retval =
+        getLocalRecursiveHierarchy(server, typeNode, 1, &subtypeId, 1,
+                                   false, &subTypes, &subTypesSize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
 
-    /* The leaf is the first element */
-    size_t results_count = 1;
-    UA_StatusCode retval = UA_NodeId_copy(leafType, &results[0]);
+    UA_NodeId *interfaces = NULL;
+    size_t interfacesSize = 0;
+    retval = getLocalRecursiveHierarchy(server, typeNode, 1, &hasInterfaceNodeId, 1,
+                                        true, &interfaces, &interfacesSize);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_free(results);
+        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
         return retval;
     }
 
-    /* Loop over the array members .. and add new elements to the end */
-    for(size_t idx = 0; idx < results_count; ++idx) {
-        /* Get the node */
-        const UA_Node *node = UA_Nodestore_getNode(nsCtx, &results[idx]);
-
-        /* Invalid node, remove from the array */
-        if(!node) {
-            for(size_t i = idx; i < results_count-1; ++i)
-                results[i] = results[i+1];
-            results_count--;
-            continue;
-        }
-
-        /* Add references from the current node to the end of the array */
-        retval = getReferencedNodesWithReferenceType(&results, &results_count,
-                                          &results_size, node, references, referencesSize);
-
-        /* Release the node */
-        UA_Nodestore_releaseNode(nsCtx, node);
-
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_Array_delete(results, results_count, &UA_TYPES[UA_TYPES_NODEID]);
-            return retval;
-        }
-    }
-
-    /* Zero results. The leaf node was not found */
-    if(results_count == 0) {
-        UA_free(results);
-        results = NULL;
+    UA_NodeId *total = (UA_NodeId*)
+        UA_realloc(subTypes, sizeof(UA_NodeId)*(subTypesSize + interfacesSize - 1));
+    if(!total) {
+        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
+        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
-    *typeHierarchy = results;
-    *typeHierarchySize = results_count;
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode
-getTypeHierarchy(void *nsCtx, const UA_NodeId *leafType,
-                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
-                 UA_Boolean walkDownwards) {
-    UA_NodeReferenceKind subtypeRef;
-    // if downwards, we do not want inverse, if upwards we want inverse
-    subtypeRef.isInverse = !walkDownwards;
-    subtypeRef.referenceTypeId = hasSubtypeNodeId;
-
-
-    return getHierarchyForReferenceTypes(nsCtx, leafType,
-            &subtypeRef, 1, typeHierarchy, typeHierarchySize);
-}
-
-UA_StatusCode
-getParentTypeAndInterfaceHierarchy(void *nsCtx, const UA_NodeId *leafType,
-                 UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
-
-    UA_NodeReferenceKind subtypeRef[2];
-    subtypeRef[0].isInverse = true;
-    subtypeRef[0].referenceTypeId = hasSubtypeNodeId;
-
-    subtypeRef[1].isInverse = false;
-    subtypeRef[1].referenceTypeId = hasInterfaceNodeId;
-
-    return getHierarchyForReferenceTypes(nsCtx, leafType,
-                                         subtypeRef, 2, typeHierarchy, typeHierarchySize);
-}
-
-UA_StatusCode
-getTypesHierarchy(void *nsCtx, const UA_NodeId *leafType, size_t leafTypeSize,
-                  UA_NodeId **typeHierarchy, size_t *typeHierarchySize,
-                  UA_Boolean walkDownwards) {
-    UA_NodeId *results = NULL;
-    size_t results_count = 0;
-    for (size_t i = 0; i < leafTypeSize; i++) {
-        UA_NodeId *tmpResults = NULL;
-        size_t tmpResults_size = 0;
-        UA_StatusCode retval = getTypeHierarchy(nsCtx, &leafType[i], &tmpResults, &tmpResults_size, walkDownwards);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_Array_delete(results, results_count, &UA_TYPES[UA_TYPES_NODEID]);
-            return retval;
-        }
-        if (tmpResults_size == 0 || tmpResults == NULL )
-            continue;
-        size_t new_size = sizeof(UA_NodeId) * (results_count + tmpResults_size);
-        UA_NodeId *new_results = (UA_NodeId*)UA_realloc(results, new_size);
-        if(!new_results) {
-            UA_Array_delete(results, results_count, &UA_TYPES[UA_TYPES_NODEID]);
-            return UA_STATUSCODE_BADOUTOFMEMORY;
-        }
-        results = new_results;
-        memcpy(&results[results_count],tmpResults, sizeof(UA_NodeId)*tmpResults_size);
-        /* do not use UA_Array_delete since we still need the content of the nodes */
-        UA_free(tmpResults);
-        results_count = results_count + tmpResults_size;
-    }
-    *typeHierarchy = results;
-    *typeHierarchySize = results_count;
+    memcpy(&total[subTypesSize], &interfaces[1], sizeof(UA_NodeId)*(interfacesSize-1));
+    UA_free(interfaces);
+    
+    *typeHierarchy = total;
+    *typeHierarchySize = subTypesSize + interfacesSize - 1;
     return UA_STATUSCODE_GOOD;
 }
 

+ 11 - 7
src/server/ua_services_nodemanagement.c

@@ -548,8 +548,8 @@ addTypeChildren(UA_Server *server, UA_Session *session,
     /* Get the hierarchy of the type and all its supertypes */
     UA_NodeId *hierarchy = NULL;
     size_t hierarchySize = 0;
-    UA_StatusCode retval = getParentTypeAndInterfaceHierarchy(server->nsCtx, &type->nodeId,
-                                            &hierarchy, &hierarchySize);
+    UA_StatusCode retval = getParentTypeAndInterfaceHierarchy(server, &type->nodeId,
+                                                              &hierarchy, &hierarchySize);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -695,8 +695,10 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                 /* Get subtypes of the parent reference types */
                 UA_NodeId *parentTypeHierachy = NULL;
                 size_t parentTypeHierachySize = 0;
-                getTypesHierarchy(server->nsCtx, parentReferences,UA_PARENT_REFERENCES_COUNT,
-                                  &parentTypeHierachy, &parentTypeHierachySize, true);
+                retval = getLocalRecursiveHierarchy(server, parentReferences, UA_PARENT_REFERENCES_COUNT,
+                                                    &subtypeId, 1, true, &parentTypeHierachy, &parentTypeHierachySize);
+                if(retval != UA_STATUSCODE_GOOD)
+                    goto cleanup;
                 /* Abstract variable is allowed if parent is a children of a base data variable */
                 const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
                 /* A variable may be of an object type which again is below BaseObjectType */
@@ -722,8 +724,10 @@ AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                 /* Get subtypes of the parent reference types */
                 UA_NodeId *parentTypeHierachy = NULL;
                 size_t parentTypeHierachySize = 0;
-                getTypesHierarchy(server->nsCtx, parentReferences,UA_PARENT_REFERENCES_COUNT,
-                                  &parentTypeHierachy, &parentTypeHierachySize, true);
+                retval = getLocalRecursiveHierarchy(server, parentReferences, UA_PARENT_REFERENCES_COUNT,
+                                                    &subtypeId, 1, true, &parentTypeHierachy, &parentTypeHierachySize);
+                if(retval != UA_STATUSCODE_GOOD)
+                    goto cleanup;
                 /* Object node created of an abstract ObjectType. Only allowed
                  * if within BaseObjectType folder */
                 const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
@@ -1497,7 +1501,7 @@ deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
     UA_NodeId *hierarchicalRefs = NULL;
     size_t hierarchicalRefsSize = 0;
     UA_NodeId hr = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
-    getTypeHierarchy(server->nsCtx, &hr, &hierarchicalRefs, &hierarchicalRefsSize, true);
+    getLocalRecursiveHierarchy(server, &hr, 1, &subtypeId, 1, true, &hierarchicalRefs, &hierarchicalRefsSize);
     if(!hierarchicalRefs) {
         UA_LOG_WARNING_SESSION(&server->config.logger, session,
                                "Delete Nodes: Cannot test for hierarchical "

+ 46 - 2
src/server/ua_services_view.c

@@ -414,8 +414,8 @@ browseWithCp(UA_Server *server, UA_Session *session, ContinuationPoint *cp,
 
         if(!UA_NodeId_isNull(&cp->bd.referenceTypeId)) {
             if(cp->bd.includeSubtypes) {
-                retval = getTypesHierarchy(server->nsCtx, &cp->bd.referenceTypeId, 1,
-                                           &referenceTypes, &referenceTypesSize, true);
+                retval = getLocalRecursiveHierarchy(server, &cp->bd.referenceTypeId, 1, &subtypeId, 1,
+                                                    true, &referenceTypes, &referenceTypesSize);
                 if(retval != UA_STATUSCODE_GOOD)
                     return retval;
                 UA_assert(referenceTypesSize > 0); /* The original referenceTypeId has been mirrored back */
@@ -708,6 +708,50 @@ UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
     return result;
 }
 
+UA_StatusCode
+getLocalRecursiveHierarchy(UA_Server *server, const UA_NodeId *startNodes, size_t startNodesSize,
+                           const UA_NodeId *refTypes, size_t refTypesSize, UA_Boolean walkDownwards,
+                           UA_NodeId **results, size_t *resultsSize) {
+    ContinuationPoint cp;
+    UA_StatusCode retval = ContinuationPoint_init(&cp, 0, true);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    for(size_t i = 0; i < startNodesSize; i++)
+        retval |= RefTree_add(&cp.rt, &startNodes[i]);
+    if(retval != UA_STATUSCODE_GOOD) {
+        ContinuationPoint_clear(&cp);
+        return retval;
+    }
+
+    if(!walkDownwards)
+        cp.bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
+
+    UA_Boolean maxed = false;
+    for(; cp.n < cp.rt.size; cp.n++, cp.nk = 0, cp.nki = 0) {
+        /* Get the node */
+        const UA_Node *node = UA_Nodestore_getNode(server->nsCtx, &cp.rt.targets[cp.n]);
+        if(!node)
+            continue;
+
+        /* Browse the references in the current node */
+        retval = browseNode(server, &server->adminSession, &cp, NULL,
+                            &maxed, refTypesSize, refTypes, node);
+        UA_Nodestore_releaseNode(server->nsCtx, node);
+        if(retval != UA_STATUSCODE_GOOD)
+            break;
+    }
+    
+    if(retval == UA_STATUSCODE_GOOD) {
+        *results = cp.rt.targets;
+        *resultsSize = cp.rt.size;
+        cp.rt.targets = NULL;
+        cp.rt.size = 0;
+    }
+    ContinuationPoint_clear(&cp);
+    return retval;
+}
+
 /***********************/
 /* TranslateBrowsePath */
 /***********************/

+ 28 - 71
src/server/ua_subscription_events.c

@@ -38,16 +38,6 @@ UA_MonitoredItem_removeNodeEventCallback(UA_Server *server, UA_Session *session,
     return UA_STATUSCODE_BADNOTFOUND;
 }
 
-typedef struct Events_nodeListElement {
-    LIST_ENTRY(Events_nodeListElement) listEntry;
-    UA_NodeId nodeId;
-} Events_nodeListElement;
-
-struct getNodesHandle {
-    UA_Server *server;
-    LIST_HEAD(Events_nodeList, Events_nodeListElement) nodes;
-};
-
 /* We use a 16-Byte ByteString as an identifier */
 static UA_StatusCode
 generateEventId(UA_ByteString *generatedId) {
@@ -245,8 +235,7 @@ UA_Server_filterEvent(UA_Server *server, UA_Session *session,
     UA_EventFilterResult_init(&notification->result); */
 
     notification->fields.eventFields = (UA_Variant *)
-        UA_Array_new(notification->fields.eventFieldsSize,
-                     &UA_TYPES[UA_TYPES_VARIANT]);
+        UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_VARIANT]);
     if(!notification->fields.eventFields) {
         /* EventFilterResult currently isn't being used
         UA_EventFiterResult_deleteMembers(&notification->result); */
@@ -355,38 +344,6 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
     return UA_STATUSCODE_GOOD;
 }
 
-/* Insert each node into the list (passed as handle) */
-static UA_StatusCode
-getParentsNodeIteratorCallback(UA_NodeId parentId, UA_Boolean isInverse,
-                               UA_NodeId referenceTypeId, struct getNodesHandle *handle) {
-    /* Parents have an inverse reference */
-    if(!isInverse)
-        return UA_STATUSCODE_GOOD;
-
-    /* Is this a hierarchical reference? */
-    if(!isNodeInTree(handle->server->nsCtx, &referenceTypeId,
-                     &hierarchicalReferences, &subtypeId, 1))
-        return UA_STATUSCODE_GOOD;
-
-    Events_nodeListElement *entry = (Events_nodeListElement *)
-        UA_malloc(sizeof(Events_nodeListElement));
-    if(!entry)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-
-    UA_StatusCode retval = UA_NodeId_copy(&parentId, &entry->nodeId);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_free(entry);
-        return retval;
-    }
-
-    LIST_INSERT_HEAD(&handle->nodes, entry, listEntry);
-
-    /* Recursion */
-    UA_Server_forEachChildNodeCall(handle->server, parentId,
-                                   (UA_NodeIteratorCallback)getParentsNodeIteratorCallback, handle);
-    return UA_STATUSCODE_GOOD;
-}
-
 /* Filters an event according to the filter specified by mon and then adds it to
  * mons notification queue */
 static UA_StatusCode
@@ -432,18 +389,17 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
     }
     UA_Nodestore_releaseNode(server->nsCtx, originNode);
 
-
     /* Make sure the origin is in the ObjectsFolder (TODO: or in the ViewsFolder) */
     UA_NodeId *parentTypeHierachy = NULL;
     size_t parentTypeHierachySize = 0;
-    getTypesHierarchy(server->nsCtx, parentReferences_events, 2,
-                      &parentTypeHierachy, &parentTypeHierachySize, true);
+    getLocalRecursiveHierarchy(server, parentReferences_events, 2, &subtypeId, 1,
+                               true, &parentTypeHierachy, &parentTypeHierachySize);
     UA_Boolean isInObjectsFolder = isNodeInTree(server->nsCtx, &origin, &objectsFolderId,
                                                 parentTypeHierachy, parentTypeHierachySize);
-    UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
     if(!isInObjectsFolder) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "Node for event must be in ObjectsFolder!");
+        UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     }
 
@@ -452,16 +408,17 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Events: Could not set the standard event fields with StatusCode %s",
                        UA_StatusCode_name(retval));
+        UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
         return retval;
     }
 
-    /* Get an array with all parents. The first call to
-     * getParentsNodeIteratorCallback adds the emitting node itself. */
-    struct getNodesHandle parentHandle;
-    parentHandle.server = server;
-    LIST_INIT(&parentHandle.nodes);
-    retval = getParentsNodeIteratorCallback(origin, true, parentReferences_events[1],
-                                            &parentHandle);
+    /* Get the parents */
+    UA_NodeId *parents = NULL;
+    size_t parentsSize = 0;
+    retval = getLocalRecursiveHierarchy(server, &origin, 1,
+                                        parentTypeHierachy, parentTypeHierachySize,
+                                        false, &parents, &parentsSize);
+    UA_Array_delete(parentTypeHierachy, parentTypeHierachySize, &UA_TYPES[UA_TYPES_NODEID]);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Events: Could not create the list of nodes listening on the "
@@ -470,26 +427,26 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
     }
 
     /* Add the event to each node's monitored items */
-    Events_nodeListElement *parentIter, *tmp_parentIter;
-    LIST_FOREACH_SAFE(parentIter, &parentHandle.nodes, listEntry, tmp_parentIter) {
+    for(size_t i = 0; i < parentsSize; i++) {
         const UA_ObjectNode *node = (const UA_ObjectNode*)
-            UA_Nodestore_getNode(server->nsCtx, &parentIter->nodeId);
-        if(node->nodeClass == UA_NODECLASS_OBJECT) {
-            for(UA_MonitoredItem *monIter = node->monitoredItemQueue;
-                monIter != NULL; monIter = monIter->next) {
-                retval = UA_Event_addEventToMonitoredItem(server, &eventNodeId, monIter);
-                if(retval != UA_STATUSCODE_GOOD)
-                    UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
-                                   "Events: Could not add the event to a listening node with StatusCode %s",
-                                   UA_StatusCode_name(retval));
-            }
+            UA_Nodestore_getNode(server->nsCtx, &parents[i]);
+        if(!node)
+            continue;
+        if(node->nodeClass != UA_NODECLASS_OBJECT) {
+            UA_Nodestore_releaseNode(server->nsCtx, (const UA_Node*)node);
+            continue;
+        }
+        UA_MonitoredItem *monIter = node->monitoredItemQueue;
+        for(; monIter != NULL; monIter = monIter->next) {
+            retval = UA_Event_addEventToMonitoredItem(server, &eventNodeId, monIter);
+            if(retval != UA_STATUSCODE_GOOD)
+                UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
+                               "Events: Could not add the event to a listening node with StatusCode %s",
+                               UA_StatusCode_name(retval));
         }
         UA_Nodestore_releaseNode(server->nsCtx, (const UA_Node*)node);
-
-        LIST_REMOVE(parentIter, listEntry);
-        UA_NodeId_deleteMembers(&parentIter->nodeId);
-        UA_free(parentIter);
     }
+    UA_Array_delete(parents, parentsSize, &UA_TYPES[UA_TYPES_NODEID]);
 
     /* Delete the node representation of the event */
     if(deleteEventNode) {