Browse Source

create unique namespace entry and check membership

the functionality is required for the addnode service
Julius Pfrommer 10 years ago
parent
commit
f69da45e52
2 changed files with 50 additions and 8 deletions
  1. 43 8
      src/ua_namespace.c
  2. 7 0
      src/ua_namespace.h

+ 43 - 8
src/ua_namespace.c

@@ -230,14 +230,10 @@ static inline void clear_slot(Namespace * ns, Namespace_Entry * slot) {
 
 
 static inline UA_Int32 find_slot(const Namespace * ns, Namespace_Entry ** slot, const UA_NodeId * nodeid) {
 static inline UA_Int32 find_slot(const Namespace * ns, Namespace_Entry ** slot, const UA_NodeId * nodeid) {
 	hash_t h = hash(nodeid);
 	hash_t h = hash(nodeid);
-	hash_t index, hash2;
-	UA_UInt32 size;
-	Namespace_Entry *entry;
-
-	size = ns->size;
-	index = mod(h, ns);
+	hash_t index = mod(h, ns);
+	UA_UInt32 size = ns->size;
+	Namespace_Entry *entry = &ns->entries[index];
 
 
-	entry = &ns->entries[index];
 	if(entry == UA_NULL)
 	if(entry == UA_NULL)
 		return UA_ERROR;
 		return UA_ERROR;
 	if(UA_NodeId_compare(&entry->node->nodeId, nodeid) == UA_EQUAL) {
 	if(UA_NodeId_compare(&entry->node->nodeId, nodeid) == UA_EQUAL) {
@@ -245,7 +241,7 @@ static inline UA_Int32 find_slot(const Namespace * ns, Namespace_Entry ** slot,
 		return UA_SUCCESS;
 		return UA_SUCCESS;
 	}
 	}
 
 
-	hash2 = mod_m2(h, ns);
+	hash_t hash2 = mod_m2(h, ns);
 	for(;;) {
 	for(;;) {
 		index += hash2;
 		index += hash2;
 		if(index >= size)
 		if(index >= size)
@@ -406,6 +402,45 @@ UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node) {
 	return UA_SUCCESS;
 	return UA_SUCCESS;
 }
 }
 
 
+UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node, UA_NodeId * new_nodeid) {
+	if(ns->size * 3 <= ns->count * 4) {
+		if(expand(ns) != UA_SUCCESS)
+			return UA_ERROR;
+	}
+
+	// find unoccupied numeric nodeid
+	new_nodeid->identifier.numeric = ns->count;
+	Namespace_Entry *slot = UA_NULL;
+
+	hash_t h = hash(new_nodeid);
+	hash_t hash2 = mod_m2(h, ns);
+	UA_UInt32 size = ns->size;
+
+	// change integer pseudo-randomly until a free slot is found
+	while(1) {
+		if(find_slot(ns, &slot, new_nodeid) != UA_SUCCESS)
+			break;
+		new_nodeid->identifier.numeric += hash2;
+		if(new_nodeid->identifier.numeric >= size)
+			new_nodeid->identifier.numeric -= size;
+	}
+
+#ifdef MULTITHREADING
+	if(UA_alloc((void **)&slot->lock, sizeof(pthread_rwlock_t)) != UA_SUCCESS)
+		return UA_ERR_NO_MEMORY;
+	pthread_rwlock_init((pthread_rwlock_t *) slot->lock, NULL);
+#endif
+
+	slot->node = node;
+	ns->count++;
+	return UA_SUCCESS;
+}
+
+UA_Int32 Namespace_contains(Namespace * ns, UA_NodeId * nodeid) {
+	Namespace_Entry *slot;
+	return find_slot(ns, &slot, nodeid);
+}
+
 UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock) {
 UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock) {
 	Namespace_Entry *slot;
 	Namespace_Entry *slot;
 	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
 	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)

+ 7 - 0
src/ua_namespace.h

@@ -60,9 +60,16 @@ void Namespace_delete(Namespace * ns);
 /** @brief Insert a new node into the namespace */
 /** @brief Insert a new node into the namespace */
 UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node);
 UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node);
 
 
+/** @brief Find an unused (numeric) NodeId in the namespace, create a slot under
+ * the NodeId and return both */
+UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node, UA_NodeId * new_nodeid); 
+
 /** @brief Remove a node from the namespace */
 /** @brief Remove a node from the namespace */
 void Namespace_remove(Namespace * ns, UA_NodeId * nodeid);
 void Namespace_remove(Namespace * ns, UA_NodeId * nodeid);
 
 
+/** @brief Tests whether the namespace contains an entry for a given NodeId */
+UA_Int32 Namespace_contains(Namespace * ns, UA_NodeId * nodeid);
+
 /** @brief Retrieve a node (read-only) from the namespace. Nodes are identified
 /** @brief Retrieve a node (read-only) from the namespace. Nodes are identified
 	by their NodeId. After the Node is no longer used, the lock needs to be
 	by their NodeId. After the Node is no longer used, the lock needs to be
 	released. */
 	released. */