ua_nodestore_concurrent.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #include "ua_util.h"
  2. #include "ua_nodestore.h"
  3. #include "ua_server_internal.h"
  4. #ifdef UA_ENABLE_MULTITHREADING /* conditional compilation */
  5. #include <urcu/rculfhash.h>
  6. struct nodeEntry {
  7. struct cds_lfht_node htn; ///< Contains the next-ptr for urcu-hashmap
  8. struct rcu_head rcu_head; ///< For call-rcu
  9. struct nodeEntry *orig; //< the version this is a copy from (or NULL)
  10. UA_Node node; ///< Might be cast from any _bigger_ UA_Node* type. Allocate enough memory!
  11. };
  12. #include "ua_nodestore_hash.inc"
  13. static struct nodeEntry * instantiateEntry(UA_NodeClass class) {
  14. size_t size = sizeof(struct nodeEntry) - sizeof(UA_Node);
  15. switch(class) {
  16. case UA_NODECLASS_OBJECT:
  17. size += sizeof(UA_ObjectNode);
  18. break;
  19. case UA_NODECLASS_VARIABLE:
  20. size += sizeof(UA_VariableNode);
  21. break;
  22. case UA_NODECLASS_METHOD:
  23. size += sizeof(UA_MethodNode);
  24. break;
  25. case UA_NODECLASS_OBJECTTYPE:
  26. size += sizeof(UA_ObjectTypeNode);
  27. break;
  28. case UA_NODECLASS_VARIABLETYPE:
  29. size += sizeof(UA_VariableTypeNode);
  30. break;
  31. case UA_NODECLASS_REFERENCETYPE:
  32. size += sizeof(UA_ReferenceTypeNode);
  33. break;
  34. case UA_NODECLASS_DATATYPE:
  35. size += sizeof(UA_DataTypeNode);
  36. break;
  37. case UA_NODECLASS_VIEW:
  38. size += sizeof(UA_ViewNode);
  39. break;
  40. default:
  41. return NULL;
  42. }
  43. struct nodeEntry *entry = UA_calloc(1, size);
  44. if(!entry)
  45. return NULL;
  46. entry->node.nodeClass = class;
  47. return entry;
  48. }
  49. static void deleteEntry(struct rcu_head *head) {
  50. struct nodeEntry *entry = container_of(head, struct nodeEntry, rcu_head);
  51. UA_Node_deleteMembersAnyNodeClass(&entry->node);
  52. UA_free(entry);
  53. }
  54. /* We are in a rcu_read lock. So the node will not be freed under our feet. */
  55. static int compare(struct cds_lfht_node *htn, const void *orig) {
  56. const UA_NodeId *origid = (const UA_NodeId *)orig;
  57. /* The htn is first in the entry structure. */
  58. const UA_NodeId *newid = &((struct nodeEntry *)htn)->node.nodeId;
  59. return UA_NodeId_equal(newid, origid);
  60. }
  61. UA_NodeStore * UA_NodeStore_new() {
  62. /* 64 is the minimum size for the hashtable. */
  63. return (UA_NodeStore*)cds_lfht_new(64, 64, 0, CDS_LFHT_AUTO_RESIZE, NULL);
  64. }
  65. /* do not call with read-side critical section held!! */
  66. void UA_NodeStore_delete(UA_NodeStore *ns) {
  67. UA_ASSERT_RCU_LOCKED();
  68. struct cds_lfht *ht = (struct cds_lfht*)ns;
  69. struct cds_lfht_iter iter;
  70. cds_lfht_first(ht, &iter);
  71. while(iter.node) {
  72. if(!cds_lfht_del(ht, iter.node)) {
  73. /* points to the htn entry, which is first */
  74. struct nodeEntry *entry = (struct nodeEntry*) iter.node;
  75. call_rcu(&entry->rcu_head, deleteEntry);
  76. }
  77. cds_lfht_next(ht, &iter);
  78. }
  79. cds_lfht_destroy(ht, NULL);
  80. UA_free(ns);
  81. }
  82. UA_Node * UA_NodeStore_newNode(UA_NodeClass class) {
  83. struct nodeEntry *entry = instantiateEntry(class);
  84. if(!entry)
  85. return NULL;
  86. return (UA_Node*)&entry->node;
  87. }
  88. void UA_NodeStore_deleteNode(UA_Node *node) {
  89. struct nodeEntry *entry = container_of(node, struct nodeEntry, node);
  90. deleteEntry(&entry->rcu_head);
  91. }
  92. UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node) {
  93. UA_ASSERT_RCU_LOCKED();
  94. struct nodeEntry *entry = container_of(node, struct nodeEntry, node);
  95. struct cds_lfht *ht = (struct cds_lfht*)ns;
  96. cds_lfht_node_init(&entry->htn);
  97. struct cds_lfht_node *result;
  98. //namespace index is assumed to be valid
  99. UA_NodeId tempNodeid;
  100. tempNodeid = node->nodeId;
  101. tempNodeid.namespaceIndex = 0;
  102. if(!UA_NodeId_isNull(&tempNodeid)) {
  103. hash_t h = hash(&node->nodeId);
  104. result = cds_lfht_add_unique(ht, h, compare, &node->nodeId, &entry->htn);
  105. /* If the nodeid exists already */
  106. if(result != &entry->htn) {
  107. deleteEntry(&entry->rcu_head);
  108. return UA_STATUSCODE_BADNODEIDEXISTS;
  109. }
  110. } else {
  111. /* create a unique nodeid */
  112. node->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
  113. if(node->nodeId.namespaceIndex == 0) // original request for ns=0 should yield ns=1
  114. node->nodeId.namespaceIndex = 1;
  115. unsigned long identifier;
  116. long before, after;
  117. cds_lfht_count_nodes(ht, &before, &identifier, &after); // current number of nodes stored
  118. ++identifier;
  119. node->nodeId.identifier.numeric = (UA_UInt32)identifier;
  120. while(true) {
  121. hash_t h = hash(&node->nodeId);
  122. result = cds_lfht_add_unique(ht, h, compare, &node->nodeId, &entry->htn);
  123. if(result == &entry->htn)
  124. break;
  125. node->nodeId.identifier.numeric += (UA_UInt32)(identifier * 2654435761);
  126. }
  127. }
  128. return UA_STATUSCODE_GOOD;
  129. }
  130. UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *node) {
  131. UA_ASSERT_RCU_LOCKED();
  132. struct nodeEntry *entry = container_of(node, struct nodeEntry, node);
  133. struct cds_lfht *ht = (struct cds_lfht*)ns;
  134. /* Get the current version */
  135. hash_t h = hash(&node->nodeId);
  136. struct cds_lfht_iter iter;
  137. cds_lfht_lookup(ht, h, compare, &node->nodeId, &iter);
  138. if(!iter.node)
  139. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  140. /* We try to replace an obsolete version of the node */
  141. struct nodeEntry *oldEntry = (struct nodeEntry*)iter.node;
  142. if(oldEntry != entry->orig)
  143. return UA_STATUSCODE_BADINTERNALERROR;
  144. cds_lfht_node_init(&entry->htn);
  145. if(cds_lfht_replace(ht, &iter, h, compare, &node->nodeId, &entry->htn) != 0) {
  146. /* Replacing failed. Maybe the node got replaced just before this thread tried to.*/
  147. deleteEntry(&entry->rcu_head);
  148. return UA_STATUSCODE_BADINTERNALERROR;
  149. }
  150. /* If an entry got replaced, mark it as dead. */
  151. call_rcu(&oldEntry->rcu_head, deleteEntry);
  152. return UA_STATUSCODE_GOOD;
  153. }
  154. UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
  155. UA_ASSERT_RCU_LOCKED();
  156. struct cds_lfht *ht = (struct cds_lfht*)ns;
  157. hash_t h = hash(nodeid);
  158. struct cds_lfht_iter iter;
  159. cds_lfht_lookup(ht, h, compare, nodeid, &iter);
  160. if(!iter.node || cds_lfht_del(ht, iter.node) != 0)
  161. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  162. struct nodeEntry *entry = (struct nodeEntry*)iter.node;
  163. call_rcu(&entry->rcu_head, deleteEntry);
  164. return UA_STATUSCODE_GOOD;
  165. }
  166. const UA_Node * UA_NodeStore_get(UA_NodeStore *ns, const UA_NodeId *nodeid) {
  167. UA_ASSERT_RCU_LOCKED();
  168. struct cds_lfht *ht = (struct cds_lfht*)ns;
  169. hash_t h = hash(nodeid);
  170. struct cds_lfht_iter iter;
  171. cds_lfht_lookup(ht, h, compare, nodeid, &iter);
  172. struct nodeEntry *found_entry = (struct nodeEntry*)iter.node;
  173. if(!found_entry)
  174. return NULL;
  175. return &found_entry->node;
  176. }
  177. UA_Node * UA_NodeStore_getCopy(UA_NodeStore *ns, const UA_NodeId *nodeid) {
  178. UA_ASSERT_RCU_LOCKED();
  179. struct cds_lfht *ht = (struct cds_lfht*)ns;
  180. hash_t h = hash(nodeid);
  181. struct cds_lfht_iter iter;
  182. cds_lfht_lookup(ht, h, compare, nodeid, &iter);
  183. struct nodeEntry *entry = (struct nodeEntry*)iter.node;
  184. if(!entry)
  185. return NULL;
  186. struct nodeEntry *new = instantiateEntry(entry->node.nodeClass);
  187. if(!new)
  188. return NULL;
  189. if(UA_Node_copyAnyNodeClass(&entry->node, &new->node) != UA_STATUSCODE_GOOD) {
  190. deleteEntry(&new->rcu_head);
  191. return NULL;
  192. }
  193. new->orig = entry;
  194. return &new->node;
  195. }
  196. void UA_NodeStore_iterate(UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
  197. UA_ASSERT_RCU_LOCKED();
  198. struct cds_lfht *ht = (struct cds_lfht*)ns;
  199. struct cds_lfht_iter iter;
  200. cds_lfht_first(ht, &iter);
  201. while(iter.node != NULL) {
  202. struct nodeEntry *found_entry = (struct nodeEntry*)iter.node;
  203. visitor(&found_entry->node);
  204. cds_lfht_next(ht, &iter);
  205. }
  206. }
  207. #endif /* UA_ENABLE_MULTITHREADING */