ua_nodestore_concurrent.c 7.8 KB

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