ua_nodestore_concurrent.c 8.1 KB

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