ua_nodestore_concurrent.c 8.2 KB

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