ua_nodestore_concurrent.c 7.7 KB

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