Selaa lähdekoodia

refactored namespace API

Julius Pfrommer 11 vuotta sitten
vanhempi
commit
39c4cb8dd0
7 muutettua tiedostoa jossa 272 lisäystä ja 315 poistoa
  1. 4 4
      examples/src/xml2ns0.c
  2. 6 4
      src/ua_application.c
  3. 206 227
      src/ua_namespace.c
  4. 34 47
      src/ua_namespace.h
  5. 4 4
      src/ua_services_attribute.c
  6. 16 28
      tests/check_namespace.c
  7. 2 1
      tools/indent.sh

+ 4 - 4
examples/src/xml2ns0.c

@@ -101,11 +101,11 @@ UA_Int32 UA_NodeSetAliases_println(cstring_t label, UA_NodeSetAliases *p) {
 
 /* A nodeset consist of a namespace and a list of aliases */
 typedef struct T_UA_NodeSet {
-	namespace* ns;
+	Namespace* ns;
 	UA_NodeSetAliases aliases;
 } UA_NodeSet;
 UA_Int32 UA_NodeSet_init(UA_NodeSet* p) {
-	create_ns(&(p->ns), 100);
+	Namespace_create(&(p->ns), 100);
 	p->aliases.size = -1;
 	p->aliases.aliases = UA_NULL;
 	return UA_SUCCESS;
@@ -820,7 +820,7 @@ UA_Int32 UA_NodeSet_decodeXML(XML_Stack_t* s, XML_Attr_t* attr, UA_NodeSet* dst,
 		if (attr != UA_NULL) {
 			UA_Node* node = (UA_Node*) attr;
 			DBG_VERBOSE(printf("finished node: node=%p\n", (void* )node));
-			insert_node(dst->ns, node);
+			Namespace_insert(dst->ns, node);
 			DBG_VERBOSE(printf("Inserting "));DBG_VERBOSE(print_node(node));
 		}
 			break;
@@ -951,7 +951,7 @@ int main() {
 		}
 	}
 	XML_ParserFree(parser);
-	iterate_ns(n.ns, print_node);
+	Namespace_iterate(n.ns, print_node);
 	printf("aliases addr=%p, size=%d\n", (void*) &(n.aliases), n.aliases.size);
 	UA_NodeSetAliases_println("aliases in nodeset: ", &n.aliases);
 	return 0;

+ 6 - 4
src/ua_application.c

@@ -27,11 +27,13 @@ UA_Node* create_node_ns0(UA_Int32 class, UA_Int32 nodeClass, UA_Int32 const id,
 #define C2UA_STRING(s) (UA_String) { sizeof(s)-1, (UA_Byte*) s }
 void appMockup_init() {
 	// create namespaces
-	namespace* ns0; create_ns(&ns0,100);
+	Namespace* ns0;
+	Namespace_create(&ns0,100);
 	ns0->namespaceId = 0;
 	ns0->namespaceUri = C2UA_STRING("http://opcfoundation.org/UA/");
 
-	namespace* local; create_ns(&local,100);
+	Namespace* local;
+	Namespace_create(&local,100);
 	local->namespaceId = 1;
 	local->namespaceUri = C2UA_STRING("http://localhost:16664/open62541/");
 
@@ -42,7 +44,7 @@ void appMockup_init() {
 
 	UA_Node* np;
 	np = create_node_ns0(UA_OBJECTNODE, UA_NODECLASS_OBJECT, 2253, "Server", "open62541", "...");
-	insert_node(ns0,np);
+	Namespace_insert(ns0,np);
 	UA_ObjectNode* o = (UA_ObjectNode*)np;
 	o->eventNotifier = UA_FALSE;
 
@@ -60,7 +62,7 @@ void appMockup_init() {
 	v->minimumSamplingInterval = 1.0;
 	v->historizing = UA_FALSE;
 
-	insert_node(ns0,np);
+	Namespace_insert(ns0,np);
 
 #if defined(DEBUG) && defined(VERBOSE)
 	uint32_t i, j;

+ 206 - 227
src/ua_namespace.c

@@ -2,26 +2,11 @@
 #include <string.h>
 #include <stdio.h>
 
-static hash_t hash_string(const UA_Byte * data, UA_Int32 len);
-static hash_t hash(const UA_NodeId * n);
-static unsigned int higher_prime_index(unsigned long n);
-static inline hash_t mod_1(hash_t x, hash_t y, hash_t inv, int shift);
-static inline hash_t mod(hash_t hash, const namespace * ns);
-static inline hash_t htab_mod_m2(hash_t hash, const namespace * ns);
-static inline void clear_slot(namespace * ns, ns_entry * slot);
-static void clear_ns(namespace * ns);
-static UA_Int32 find_slot(const namespace * ns, ns_entry ** slot, const UA_NodeId * nodeid);
-static ns_entry *find_empty_slot(const namespace * ns, hash_t hash);
-static UA_Int32 expand(namespace * ns);
-
-/* /\* We store UA_MethodNode_Callback instead of UA_MethodNode in the namespace. Pointer casting to */
-/*    UA_MethodNode is possible since pointers point to the first element anyway. *\/ */
-/* typedef struct UA_MethodNode_Callback_T { */
-/* 	UA_MethodNode *method_node; */
-/* 	 UA_Int32(*method_callback) (UA_list_List * input_args, UA_list_List * output_args); */
-/* } UA_MethodNode_Callback; */
-
-UA_Int32 init_tc(transaction_context * tc) {
+/*****************************************/
+/* Internal (not exported) functionality */
+/*****************************************/
+
+UA_Int32 Namespace_TransactionContext_init(Namespace_TransactionContext * tc) {
 	return UA_list_init((UA_list_List *) tc);
 }
 
@@ -29,6 +14,7 @@ UA_Int32 init_tc(transaction_context * tc) {
    Knuth's TAOCP (no linked lists here). Table of primes and mod-functions are from libiberty
    (licensed under LGPL) */
 
+typedef UA_UInt32 hash_t;
 struct prime_ent {
 	hash_t prime;
 	hash_t inv;
@@ -70,164 +56,6 @@ static struct prime_ent const prime_tab[] = {
 	{0xfffffffb, 0x00000006, 0x00000008, 31}
 };
 
-UA_Int32 create_ns(namespace ** result, uint32_t size) {
-	namespace *ns = UA_NULL;
-	uint32_t sizePrimeIndex = higher_prime_index(size);
-	size = prime_tab[sizePrimeIndex].prime;
-
-	if(UA_alloc((void **)&ns, sizeof(namespace)) != UA_SUCCESS)
-		return UA_ERR_NO_MEMORY;
-
-	if(UA_alloc((void **)&ns->entries, sizeof(ns_entry) * size) != UA_SUCCESS) {
-		UA_free(ns);
-		return UA_ERR_NO_MEMORY;
-	}
-
-	/**
-	   set entries to zero:
-	   ns->entries[i].lock = UA_NUll;
-	   ns->entries[i].node = UA_NULL;
-	*/
-	memset(ns->entries, 0, size * sizeof(ns_entry));
-
-	ns->size = size;
-	ns->count = 0;
-	ns->sizePrimeIndex = sizePrimeIndex;
-	*result = ns;
-	return UA_SUCCESS;
-}
-
-void empty_ns(namespace * ns) {
-	clear_ns(ns);
-
-	/* Downsize the table.  */
-	if(ns->size > 1024 * 1024 / sizeof(ns_entry)) {
-		int nindex = higher_prime_index(1024 / sizeof(ns_entry));
-		int nsize = prime_tab[nindex].prime;
-		UA_free(ns->entries);
-		UA_alloc((void **)&ns->entries, sizeof(ns_entry) * nsize);	// FIXME: Check return value
-		ns->size = nsize;
-		ns->sizePrimeIndex = nindex;
-	}
-}
-
-/* This function frees all memory allocated for a namespace */
-void delete_ns(namespace * ns) {
-	clear_ns(ns);
-	UA_free(ns->entries);
-	UA_free(ns);
-}
-
-UA_Int32 insert_node(namespace * ns, UA_Node * node) {
-	if(ns->size * 3 <= ns->count * 4) {
-		if(expand(ns) != UA_SUCCESS)
-			return UA_ERROR;
-	}
-
-	hash_t h = hash(&node->nodeId);
-	ns_entry *slot = find_empty_slot(ns, h);
-
-#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 get_node(namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result,
-				  ns_lock ** lock) {
-	ns_entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
-
-#ifdef MULTITHREADING
-	if(pthread_rwlock_rdlock((pthread_rwlock_t *) slot->lock) != 0)
-		return UA_ERROR;
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
-
-UA_Int32 get_writable_node(const namespace * ns, const UA_NodeId * nodeid, UA_Node ** result,
-						   ns_lock ** lock) {
-	ns_entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
-
-#ifdef MULTITHREADING
-	if(pthread_rwlock_wrlock((pthread_rwlock_t *) slot->lock) != 0)
-		return UA_ERROR;
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
-
-#ifdef MULTITHREADING
-static inline void release_context_walker(void *lock) {
-	pthread_rwlock_unlock(lock);
-}
-#endif
-
-UA_Int32 get_tc_node(namespace * ns, transaction_context * tc, const UA_NodeId * nodeid,
-					 UA_Node ** const result, ns_lock ** lock) {
-	ns_entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
-
-#ifdef MULTITHREADING
-	if(pthread_rwlock_tryrdlock((pthread_rwlock_t *) slot->lock) != 0) {
-		/* Transaction failed. Release all acquired locks and bail out. */
-		UA_list_destroy((UA_list_List *) tc, release_context_walker);
-		return UA_ERROR;
-	}
-	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
-
-UA_Int32 get_tc_writable_node(namespace * ns, transaction_context * tc, const UA_NodeId * nodeid,
-							  UA_Node ** result, ns_lock ** lock) {
-	ns_entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
-
-#ifdef MULTITHREADING
-	if(pthread_rwlock_trywrlock((pthread_rwlock_t *) slot->lock) != 0) {
-		/* Transaction failed. Release all acquired locks and bail out. */
-		UA_list_destroy((UA_list_List *) tc, release_context_walker);
-		return UA_ERROR;
-	}
-	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
-
-void delete_node(namespace * ns, UA_NodeId * nodeid) {
-	ns_entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return;
-	// TODO: Check if deleting the node makes the namespace inconsistent.
-	clear_slot(ns, slot);
-
-	/* Downsize the hashmap if it is very empty */
-	if(ns->count * 8 < ns->size && ns->size > 32)
-		expand(ns);
-}
-
 /* Hashing inspired by code from from http://www.azillionmonkeys.com/qed/hash.html, licensed under
    the LGPL 2.1 */
 #undef get16bits
@@ -237,11 +65,11 @@ void delete_node(namespace * ns, UA_NodeId * nodeid) {
 #endif
 
 #if !defined (get16bits)
-#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) + \
-					  (uint32_t)(((const uint8_t *)(d))[0]) )
+#define get16bits(d) ((((UA_UInt32)(((const uint8_t *)(d))[1])) << 8) + \
+					  (UA_UInt32)(((const uint8_t *)(d))[0]) )
 #endif
 
-static hash_t hash_string(const UA_Byte * data, UA_Int32 len) {
+static inline hash_t hash_string(const UA_Byte * data, UA_Int32 len) {
 	hash_t hash = len;
 	hash_t tmp;
 	int rem;
@@ -292,7 +120,7 @@ static hash_t hash_string(const UA_Byte * data, UA_Int32 len) {
 	return hash;
 }
 
-static hash_t hash(const UA_NodeId * n) {
+static inline hash_t hash(const UA_NodeId * n) {
 	switch (n->encodingByte) {
 	case UA_NODEIDTYPE_TWOBYTE:
 	case UA_NODEIDTYPE_FOURBYTE:
@@ -303,8 +131,7 @@ static hash_t hash(const UA_NodeId * n) {
 	case UA_NODEIDTYPE_GUID:
 		return hash_string((UA_Byte *) & (n->identifier.guid), sizeof(UA_Guid));
 	case UA_NODEIDTYPE_BYTESTRING:
-		return hash_string((UA_Byte *) n->identifier.byteString.data,
-						   n->identifier.byteString.length);
+		return hash_string((UA_Byte *) n->identifier.byteString.data, n->identifier.byteString.length);
 	default:
 		return 0;
 	}
@@ -312,7 +139,7 @@ static hash_t hash(const UA_NodeId * n) {
 
 /* The following function returns an index into the above table of the nearest prime number which
    is greater than N, and near a power of two. */
-static unsigned int higher_prime_index(unsigned long n) {
+static inline unsigned int higher_prime_index(unsigned long n) {
 	unsigned int low = 0;
 	unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
 
@@ -324,14 +151,10 @@ static unsigned int higher_prime_index(unsigned long n) {
 			high = mid;
 	}
 
-	/* if (n > prime_tab[low].prime) */
-	/* abort (); */
 	return low;
 }
 
-/* Return X % Y. */
 static inline hash_t mod_1(hash_t x, hash_t y, hash_t inv, int shift) {
-
 	/* The multiplicative inverses computed above are for 32-bit types, and requires that we are
 	   able to compute a highpart multiply.  */
 #ifdef UNSIGNED_64BIT_TYPE
@@ -347,21 +170,20 @@ static inline hash_t mod_1(hash_t x, hash_t y, hash_t inv, int shift) {
 		return r;
 	}
 #endif
-
-	return x % y;	/* Otherwise just use the native division routines.  */
+	return x % y;
 }
 
-static inline hash_t mod(hash_t h, const namespace * ns) {
+static inline hash_t mod(hash_t h, const Namespace * ns) {
 	const struct prime_ent *p = &prime_tab[ns->sizePrimeIndex];
 	return mod_1(h, p->prime, p->inv, p->shift);
 }
 
-static inline hash_t mod_m2(hash_t h, const namespace * ns) {
+static inline hash_t mod_m2(hash_t h, const Namespace * ns) {
 	const struct prime_ent *p = &prime_tab[ns->sizePrimeIndex];
 	return 1 + mod_1(h, p->prime - 2, p->inv_m2, p->shift);
 }
 
-static inline void clear_slot(namespace * ns, ns_entry * slot) {
+static inline void clear_slot(Namespace * ns, Namespace_Entry * slot) {
 	if(slot->node == UA_NULL)
 		return;
 
@@ -406,20 +228,11 @@ static inline void clear_slot(namespace * ns, ns_entry * slot) {
 
 }
 
-/* Delete all entries */
-static void clear_ns(namespace * ns) {
-	uint32_t size = ns->size;
-	ns_entry *entries = ns->entries;
-	for(uint32_t i = 0; i < size; i++)
-		clear_slot(ns, &entries[i]);
-	ns->count = 0;
-}
-
-static UA_Int32 find_slot(const namespace * ns, ns_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 index, hash2;
-	uint32_t size;
-	ns_entry *entry;
+	UA_UInt32 size;
+	Namespace_Entry *entry;
 
 	size = ns->size;
 	index = mod(h, ns);
@@ -449,21 +262,11 @@ static UA_Int32 find_slot(const namespace * ns, ns_entry ** slot, const UA_NodeI
 	return UA_SUCCESS;
 }
 
-UA_Int32 iterate_ns(const namespace * ns, node_visitor visitor) {
-	uint32_t i;
-	for(i = 0; i < ns->size; i++) {
-		ns_entry *entry = &ns->entries[i];
-		if(entry != UA_NULL && visitor != UA_NULL)
-			visitor(entry->node);
-	}
-	return UA_SUCCESS;
-}
-
 /* Always returns an empty slot. This is inevitable if the entries are not completely full. */
-static ns_entry *find_empty_slot(const namespace * ns, hash_t h) {
+static Namespace_Entry *find_empty_slot(const Namespace * ns, hash_t h) {
 	hash_t index = mod(h, ns);
-	uint32_t size = ns->size;
-	ns_entry *slot = &ns->entries[index];
+	UA_UInt32 size = ns->size;
+	Namespace_Entry *slot = &ns->entries[index];
 
 	if(slot->node == UA_NULL)
 		return slot;
@@ -486,14 +289,14 @@ static ns_entry *find_empty_slot(const namespace * ns, hash_t h) {
    hash table must already exist. Remember also that the place of the table entries is changed. If
    memory allocation failures are allowed, this function will return zero, indicating that the
    table could not be expanded. If all goes well, it will return a non-zero value. */
-static UA_Int32 expand(namespace * ns) {
-	ns_entry *nentries;
+static UA_Int32 expand(Namespace * ns) {
+	Namespace_Entry *nentries;
 	int32_t nsize;
-	uint32_t nindex;
+	UA_UInt32 nindex;
 
-	ns_entry *oentries = ns->entries;
+	Namespace_Entry *oentries = ns->entries;
 	int32_t osize = ns->size;
-	ns_entry *olimit = &oentries[osize];
+	Namespace_Entry *olimit = &oentries[osize];
 	int32_t count = ns->count;
 
 	/* Resize only when table after removal of unused elements is either too full or too empty.  */
@@ -504,16 +307,16 @@ static UA_Int32 expand(namespace * ns) {
 	nindex = higher_prime_index(count * 2);
 	nsize = prime_tab[nindex].prime;
 
-	if(UA_alloc((void **)&nentries, sizeof(ns_entry) * nsize) != UA_SUCCESS)
+	if(UA_alloc((void **)&nentries, sizeof(Namespace_Entry) * nsize) != UA_SUCCESS)
 		return UA_ERR_NO_MEMORY;
 	ns->entries = nentries;
 	ns->size = nsize;
 	ns->sizePrimeIndex = nindex;
 
-	ns_entry *p = oentries;
+	Namespace_Entry *p = oentries;
 	do {
 		if(p->node != UA_NULL) {
-			ns_entry *q = find_empty_slot(ns, hash(&p->node->nodeId));
+			Namespace_Entry *q = find_empty_slot(ns, hash(&p->node->nodeId));
 			*q = *p;
 		}
 		p++;
@@ -522,3 +325,179 @@ static UA_Int32 expand(namespace * ns) {
 	UA_free(oentries);
 	return UA_SUCCESS;
 }
+
+/**********************/
+/* Exported functions */
+/**********************/
+
+UA_Int32 Namespace_create(Namespace ** result, UA_UInt32 size) {
+	Namespace *ns = UA_NULL;
+	UA_UInt32 sizePrimeIndex = higher_prime_index(size);
+	size = prime_tab[sizePrimeIndex].prime;
+
+	if(UA_alloc((void **)&ns, sizeof(Namespace)) != UA_SUCCESS)
+		return UA_ERR_NO_MEMORY;
+
+	if(UA_alloc((void **)&ns->entries, sizeof(Namespace_Entry) * size) != UA_SUCCESS) {
+		UA_free(ns);
+		return UA_ERR_NO_MEMORY;
+	}
+
+	/**
+	   set entries to zero:
+	   ns->entries[i].lock = UA_NUll;
+	   ns->entries[i].node = UA_NULL;
+	*/
+	memset(ns->entries, 0, size * sizeof(Namespace_Entry));
+
+	ns->size = size;
+	ns->count = 0;
+	ns->sizePrimeIndex = sizePrimeIndex;
+	*result = ns;
+	return UA_SUCCESS;
+}
+
+static void Namespace_clear(Namespace * ns) {
+	UA_UInt32 size = ns->size;
+	Namespace_Entry *entries = ns->entries;
+	for(UA_UInt32 i = 0; i < size; i++)
+		clear_slot(ns, &entries[i]);
+	ns->count = 0;
+}
+
+void Namespace_empty(Namespace * ns) {
+	Namespace_clear(ns);
+
+	/* Downsize the table.  */
+	if(ns->size > 1024 * 1024 / sizeof(Namespace_Entry)) {
+		int nindex = higher_prime_index(1024 / sizeof(Namespace_Entry));
+		int nsize = prime_tab[nindex].prime;
+		UA_free(ns->entries);
+		UA_alloc((void **)&ns->entries, sizeof(Namespace_Entry) * nsize);	// FIXME: Check return
+		// value
+		ns->size = nsize;
+		ns->sizePrimeIndex = nindex;
+	}
+}
+
+void Namespace_delete(Namespace * ns) {
+	Namespace_clear(ns);
+	UA_free(ns->entries);
+	UA_free(ns);
+}
+
+UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node) {
+	if(ns->size * 3 <= ns->count * 4) {
+		if(expand(ns) != UA_SUCCESS)
+			return UA_ERROR;
+	}
+
+	hash_t h = hash(&node->nodeId);
+	Namespace_Entry *slot = find_empty_slot(ns, h);
+
+#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_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock) {
+	Namespace_Entry *slot;
+	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+		return UA_ERROR;
+
+#ifdef MULTITHREADING
+	if(pthread_rwlock_rdlock((pthread_rwlock_t *) slot->lock) != 0)
+		return UA_ERROR;
+	*lock = slot->lock;
+#endif
+
+	*result = slot->node;
+	return UA_SUCCESS;
+}
+
+UA_Int32 Namespace_getWritable(const Namespace * ns, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock) {
+	Namespace_Entry *slot;
+	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+		return UA_ERROR;
+
+#ifdef MULTITHREADING
+	if(pthread_rwlock_wrlock((pthread_rwlock_t *) slot->lock) != 0)
+		return UA_ERROR;
+	*lock = slot->lock;
+#endif
+
+	*result = slot->node;
+	return UA_SUCCESS;
+}
+
+#ifdef MULTITHREADING
+static inline void release_context_walker(void *lock) {
+	pthread_rwlock_unlock(lock);
+}
+#endif
+
+UA_Int32 Namespace_transactionGet(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** const result, Namespace_Lock ** lock) {
+	Namespace_Entry *slot;
+	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+		return UA_ERROR;
+
+#ifdef MULTITHREADING
+	if(pthread_rwlock_tryrdlock((pthread_rwlock_t *) slot->lock) != 0) {
+		/* Transaction failed. Release all acquired locks and bail out. */
+		UA_list_destroy((UA_list_List *) tc, release_context_walker);
+		return UA_ERROR;
+	}
+	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
+	*lock = slot->lock;
+#endif
+
+	*result = slot->node;
+	return UA_SUCCESS;
+}
+
+UA_Int32 Namespace_transactionGetWritable(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock) {
+	Namespace_Entry *slot;
+	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+		return UA_ERROR;
+
+#ifdef MULTITHREADING
+	if(pthread_rwlock_trywrlock((pthread_rwlock_t *) slot->lock) != 0) {
+		/* Transaction failed. Release all acquired locks and bail out. */
+		UA_list_destroy((UA_list_List *) tc, release_context_walker);
+		return UA_ERROR;
+	}
+	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
+	*lock = slot->lock;
+#endif
+
+	*result = slot->node;
+	return UA_SUCCESS;
+}
+
+void Namespace_remove(Namespace * ns, UA_NodeId * nodeid) {
+	Namespace_Entry *slot;
+	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+		return;
+	// TODO: Check if deleting the node makes the Namespace inconsistent.
+	clear_slot(ns, slot);
+
+	/* Downsize the hashmap if it is very empty */
+	if(ns->count * 8 < ns->size && ns->size > 32)
+		expand(ns);
+}
+
+UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor) {
+	UA_UInt32 i;
+	for(i = 0; i < ns->size; i++) {
+		Namespace_Entry *entry = &ns->entries[i];
+		if(entry != UA_NULL && visitor != UA_NULL)
+			visitor(entry->node);
+	}
+	return UA_SUCCESS;
+}

+ 34 - 47
src/ua_namespace.h

@@ -9,68 +9,55 @@
 #define _XOPEN_SOURCE 500
 #define __USE_UNIX98
 #include <pthread.h>
-typedef struct pthread_rwlock_t ns_lock;
+typedef struct pthread_rwlock_t Namespace_Lock;
 #else
-typedef void ns_lock;
+typedef void Namespace_Lock;
 #endif
 
+static inline void Namespace_Lock_release(Namespace_Lock * lock) {
+#ifdef MULTITHREADING
+	pthread_rwlock_unlock((pthread_rwlock_t *) lock);
+#endif
+}
+
 /* Poor-man's transactions: If we need multiple locks and at least one of them is a writelock
    ("transaction"), a deadlock can be introduced in conjunction with a second thread.
 
    Convention: All nodes in a transaction (read and write) must be locked before the first write.
-   If one write-lock cannot be acquired immediately, bail out and restart the transaction.
-
-   A transaction_context is currently only a linked list of the acquired locks.
-
-   More advanced transaction mechanisms will be established once the runtime behavior can be
-   observed. */
-typedef UA_list_List transaction_context;
-UA_Int32 init_tc(transaction_context * tc);
+   If one write-lock cannot be acquired immediately, bail out and restart the transaction. A
+   Namespace_TransactionContext is currently only a linked list of the acquired locks. More advanced
+   transaction mechanisms will be established once the runtime behavior can be observed. */
+typedef UA_list_List Namespace_TransactionContext;
+UA_Int32 Namespace_TransactionContext_init(Namespace_TransactionContext * tc);
 
 /* Each namespace is a hash-map of NodeIds to Nodes. Every entry in the hashmap consists of a
    pointer to a read-write lock and a pointer to the Node. */
-typedef struct ns_entry_t {
+typedef struct Namespace_Entry_T {
 #ifdef MULTITHREADING
-	ns_lock *lock;	/* locks are heap-allocated, so we can resize the entry-array online */
+	Namespace_Lock *lock;	/* locks are heap-allocated */
 #endif
 	UA_Node *node;
-} ns_entry;
+} Namespace_Entry;
 
-typedef struct namespace_t {
+typedef struct Namespace_T {
 	UA_Int32 namespaceId;
 	UA_String namespaceUri;
-	ns_entry *entries;
-	uint32_t size;
-	uint32_t count;
-	uint32_t sizePrimeIndex;	/* Current size, as an index into the table of primes.  */
-} namespace;
-
-UA_Int32 create_ns(namespace ** result, uint32_t size);
-void empty_ns(namespace * ns);
-void delete_ns(namespace * ns);
-UA_Int32 insert_node(namespace * ns, UA_Node * node);
-UA_Int32 get_node(namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result,
-				  ns_lock ** lock);
-
-// use only for _single_ writes.
-UA_Int32 get_writable_node(namespace const *ns, const UA_NodeId * nodeid, UA_Node ** result,
-						   ns_lock ** lock);
-UA_Int32 get_tc_node(namespace * ns, transaction_context * tc, const UA_NodeId * nodeid,
-					 UA_Node ** const result, ns_lock ** lock);
-UA_Int32 get_tc_writable_node(namespace * ns, transaction_context * tc, const UA_NodeId * nodeid,
-							  UA_Node ** result, ns_lock ** lock);
-typedef void (*node_visitor) (UA_Node const *node);
-UA_Int32 iterate_ns(const namespace * ns, node_visitor visitor);
-void delete_node(namespace * ns, UA_NodeId * nodeid);
-
-// inline void release_node(ns_lock *lock);
-// portable solution, see http://www.greenend.org.uk/rjk/tech/inline.html
-static inline void release_node(ns_lock * lock) {
-#ifdef MULTITHREADING
-	pthread_rwlock_unlock((pthread_rwlock_t *) lock);
-#endif
-}
-
-typedef uint32_t hash_t;
+	Namespace_Entry *entries;
+	UA_UInt32 size;
+	UA_UInt32 count;
+	UA_UInt32 sizePrimeIndex;	/* Current size, as an index into the table of primes.  */
+} Namespace;
+
+UA_Int32 Namespace_create(Namespace ** result, UA_UInt32 size);
+void Namespace_empty(Namespace * ns);
+void Namespace_delete(Namespace * ns);
+UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node);
+void Namespace_remove(Namespace * ns, UA_NodeId * nodeid);
+UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock);
+UA_Int32 Namespace_getWritable(Namespace const *ns, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock);
+UA_Int32 Namespace_transactionGet(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** const result, Namespace_Lock ** lock);
+UA_Int32 Namespace_transactionGetWritable(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock);
+typedef void (*Namespace_nodeVisitor) (UA_Node const *node);
+UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor);
 
 #endif /* __NAMESPACE_H */

+ 4 - 4
src/ua_services_attribute.c

@@ -30,7 +30,7 @@ static UA_DataValue * service_read_node(Application *app, const UA_ReadValueId *
 	UA_DataValue *v; UA_DataValue_new(&v);
 	
 	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n",id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
-	namespace *ns = UA_indexedList_findValue(app->namespaces, id->nodeId.namespace);
+	Namespace *ns = UA_indexedList_findValue(app->namespaces, id->nodeId.namespace);
 
 	if (ns == UA_NULL) {
 		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n",id->nodeId.namespace));
@@ -41,9 +41,9 @@ static UA_DataValue * service_read_node(Application *app, const UA_ReadValueId *
 	DBG_VERBOSE(UA_String_printf(",namespaceUri=",&(ns->namespaceUri)));
 	
 	UA_Node const *node = UA_NULL;
-	ns_lock *lock = UA_NULL;
+	Namespace_Lock *lock = UA_NULL;
 	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ",&(id->nodeId)));
-	UA_Int32 result = get_node(ns, &(id->nodeId), &node, &lock);
+	UA_Int32 result = Namespace_get(ns, &(id->nodeId), &node, &lock);
 	if(result != UA_SUCCESS || node == UA_NULL) {
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
@@ -167,7 +167,7 @@ static UA_DataValue * service_read_node(Application *app, const UA_ReadValueId *
 		v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 	}
-	release_node(lock);
+	Namespace_Lock_release(lock);
 	return v;
 }
 

+ 16 - 28
tests/check_namespace.c

@@ -1,13 +1,3 @@
-/*
- ============================================================================
- Name        : check_stack.c
- Author      :
- Version     :
- Copyright   : Your copyright notice
- Description :
- ============================================================================
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -15,12 +5,10 @@
 #include "ua_namespace.h"
 #include "check.h"
 
-
-
 START_TEST(test_Namespace) {
-	namespace *ns = UA_NULL;
-	create_ns(&ns, 512);
-	delete_ns(ns);
+	Namespace *ns = UA_NULL;
+	Namespace_create(&ns, 512);
+	Namespace_delete(ns);
 }
 END_TEST
 
@@ -34,39 +22,39 @@ UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 	// given
-	namespace *ns;
-	create_ns(&ns, 512);
-	UA_Node* n1; createNode(&n1,0,2253); insert_node(ns,n1);
+	Namespace *ns;
+	Namespace_create(&ns, 512);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	const UA_Node* nr = UA_NULL;
-	ns_lock* nl = UA_NULL;
+	Namespace_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	// when
-	retval = get_node(ns,&(n1->nodeId),&nr,&nl);
+	retval = Namespace_get(ns,&(n1->nodeId),&nr,&nl);
 	// then
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_ptr_eq(nr,n1);
 	// finally
-	delete_ns(ns);
+	Namespace_delete(ns);
 }
 END_TEST
 
 START_TEST(findNodeInNamespaceWithTwoEntries) {
 	// given
-	namespace *ns;
-	create_ns(&ns, 512);
-	UA_Node* n1; createNode(&n1,0,2253); insert_node(ns,n1);
-	UA_Node* n2; createNode(&n2,0,2255); insert_node(ns,n2);
+	Namespace *ns;
+	Namespace_create(&ns, 512);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
 
 	const UA_Node* nr = UA_NULL;
-	ns_lock* nl = UA_NULL;
+	Namespace_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	// when
-	retval = get_node(ns,&(n2->nodeId),&nr,&nl);
+	retval = Namespace_get(ns,&(n2->nodeId),&nr,&nl);
 	// then
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_ptr_eq(nr,n2);
 	// finally
-	delete_ns(ns);
+	Namespace_delete(ns);
 }
 END_TEST
 

+ 2 - 1
tools/indent.sh

@@ -12,7 +12,8 @@ fi
 # E.g. when indenting to the opening braces of an argument list.
 
 indent \
---line-length100 \
+--line-length160 \
+--comment-line-length100 \
 --indent-level4 \
 --use-tabs \
 --tab-size4 \