ua_namespace_concurrent.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #include "ua_namespace.h"
  2. #include <urcu.h>
  3. #include <urcu/compiler.h> // for caa_container_of
  4. #include <urcu/uatomic.h>
  5. #include <urcu/rculfhash.h>
  6. #define ALIVE_BIT (1 << 15) /* Alive bit in the readcount */
  7. typedef struct UA_Namespace_Entry {
  8. struct cds_lfht_node htn; /* contains next-ptr for urcu-hashmap */
  9. struct rcu_head rcu_head; /* For call-rcu */
  10. UA_UInt16 readcount; /* Counts the amount of readers on it [alive-bit, 15 counter-bits] */
  11. UA_Node node; /* Might be cast from any _bigger_ UA_Node* type. Allocate enough memory! */
  12. } UA_Namespace_Entry;
  13. struct UA_Namespace {
  14. struct cds_lfht *ht; /* Hash table */
  15. };
  16. /********/
  17. /* Hash */
  18. /********/
  19. typedef UA_UInt32 hash_t;
  20. /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
  21. static inline hash_t hash_array(const UA_Byte *data, UA_UInt32 len) {
  22. static const uint32_t c1 = 0xcc9e2d51;
  23. static const uint32_t c2 = 0x1b873593;
  24. static const uint32_t r1 = 15;
  25. static const uint32_t r2 = 13;
  26. static const uint32_t m = 5;
  27. static const uint32_t n = 0xe6546b64;
  28. hash_t hash = len;
  29. if(data == UA_NULL) return 0;
  30. const int32_t nblocks = len / 4;
  31. const uint32_t *blocks = (const uint32_t *)data;
  32. for(int32_t i = 0;i < nblocks;i++) {
  33. uint32_t k = blocks[i];
  34. k *= c1;
  35. k = (k << r1) | (k >> (32 - r1));
  36. k *= c2;
  37. hash ^= k;
  38. hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
  39. }
  40. const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
  41. uint32_t k1 = 0;
  42. switch(len & 3) {
  43. case 3:
  44. k1 ^= tail[2] << 16;
  45. case 2:
  46. k1 ^= tail[1] << 8;
  47. case 1:
  48. k1 ^= tail[0];
  49. k1 *= c1;
  50. k1 = (k1 << r1) | (k1 >> (32 - r1));
  51. k1 *= c2;
  52. hash ^= k1;
  53. }
  54. hash ^= len;
  55. hash ^= (hash >> 16);
  56. hash *= 0x85ebca6b;
  57. hash ^= (hash >> 13);
  58. hash *= 0xc2b2ae35;
  59. hash ^= (hash >> 16);
  60. return hash;
  61. }
  62. static inline hash_t hash(const UA_NodeId *n) {
  63. switch(n->identifierType) {
  64. case UA_NODEIDTYPE_NUMERIC:
  65. /* Knuth's multiplicative hashing */
  66. return n->identifier.numeric * 2654435761; // mod(2^32) is implicit
  67. case UA_NODEIDTYPE_STRING:
  68. return hash_array(n->identifier.string.data, n->identifier.string.length);
  69. case UA_NODEIDTYPE_GUID:
  70. return hash_array((UA_Byte *)&(n->identifier.guid), sizeof(UA_Guid));
  71. case UA_NODEIDTYPE_BYTESTRING:
  72. return hash_array((UA_Byte *)n->identifier.byteString.data, n->identifier.byteString.length);
  73. default:
  74. return 0;
  75. }
  76. }
  77. /*************/
  78. /* UA_Namespace */
  79. /*************/
  80. static inline void node_deleteMembers(const UA_Node *node) {
  81. switch(node->nodeClass) {
  82. case UA_NODECLASS_OBJECT:
  83. UA_ObjectNode_deleteMembers((UA_ObjectNode *)node);
  84. break;
  85. case UA_NODECLASS_VARIABLE:
  86. UA_VariableNode_deleteMembers((UA_VariableNode *)node);
  87. break;
  88. case UA_NODECLASS_METHOD:
  89. UA_MethodNode_deleteMembers((UA_MethodNode *)node);
  90. break;
  91. case UA_NODECLASS_OBJECTTYPE:
  92. UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode *)node);
  93. break;
  94. case UA_NODECLASS_VARIABLETYPE:
  95. UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode *)node);
  96. break;
  97. case UA_NODECLASS_REFERENCETYPE:
  98. UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode *)node);
  99. break;
  100. case UA_NODECLASS_DATATYPE:
  101. UA_DataTypeNode_deleteMembers((UA_DataTypeNode *)node);
  102. break;
  103. case UA_NODECLASS_VIEW:
  104. UA_ViewNode_deleteMembers((UA_ViewNode *)node);
  105. break;
  106. default:
  107. break;
  108. }
  109. }
  110. /* We are in a rcu_read lock. So the node will not be freed under our feet. */
  111. static int compare(struct cds_lfht_node *htn, const void *orig) {
  112. UA_NodeId *origid = (UA_NodeId *)orig;
  113. UA_NodeId *newid = &((UA_Namespace_Entry *)htn)->node.nodeId; /* The htn is first in the entry structure. */
  114. return UA_NodeId_equal(newid, origid) == UA_EQUAL;
  115. }
  116. /* The entry was removed from the hashtable. No more readers can get it. Since
  117. all readers using the node for a longer time (outside the rcu critical
  118. section) increased the readcount, we only need to wait for the readcount
  119. to reach zero. */
  120. static void markDead(struct rcu_head *head) {
  121. UA_Namespace_Entry *entry = caa_container_of(head, UA_Namespace_Entry, rcu_head);
  122. if(uatomic_sub_return(&entry->readcount, ALIVE_BIT) > 0)
  123. return;
  124. node_deleteMembers(&entry->node);
  125. UA_free(entry);
  126. return;
  127. }
  128. /* Free the entry if it is dead and nobody uses it anymore */
  129. void UA_Namespace_releaseManagedNode(const UA_Node *managed) {
  130. if(managed == UA_NULL)
  131. return;
  132. UA_Namespace_Entry *entry = caa_container_of(managed, UA_Namespace_Entry, node); // pointer to the first entry
  133. if(uatomic_sub_return(&entry->readcount, 1) > 0)
  134. return;
  135. node_deleteMembers(managed);
  136. UA_free(entry);
  137. return;
  138. }
  139. UA_Int32 UA_Namespace_new(UA_Namespace **result, UA_UInt32 namespaceIndex) {
  140. UA_Namespace *ns;
  141. if(UA_alloc((void **)&ns, sizeof(UA_Namespace)) != UA_SUCCESS)
  142. return UA_ERR_NO_MEMORY;
  143. /* 32 is the minimum size for the hashtable. */
  144. ns->ht = cds_lfht_new(32, 32, 0, CDS_LFHT_AUTO_RESIZE, NULL);
  145. if(!ns->ht) {
  146. UA_free(ns);
  147. return UA_ERR_NO_MEMORY;
  148. }
  149. ns->namespaceIndex = namespaceIndex;
  150. *result = ns;
  151. return UA_SUCCESS;
  152. }
  153. UA_Int32 UA_Namespace_delete(UA_Namespace *ns) {
  154. if(ns == UA_NULL)
  155. return UA_ERROR;
  156. struct cds_lfht *ht = ns->ht;
  157. struct cds_lfht_iter iter;
  158. struct cds_lfht_node *found_htn;
  159. rcu_read_lock();
  160. cds_lfht_first(ht, &iter);
  161. while(iter.node != UA_NULL) {
  162. found_htn = cds_lfht_iter_get_node(&iter);
  163. if(!cds_lfht_del(ht, found_htn)) {
  164. UA_Namespace_Entry *entry = caa_container_of(found_htn, UA_Namespace_Entry, htn);
  165. call_rcu(&entry->rcu_head, markDead);
  166. }
  167. cds_lfht_next(ht, &iter);
  168. }
  169. rcu_read_unlock();
  170. if(!cds_lfht_destroy(ht, UA_NULL)) {
  171. UA_free(ns);
  172. return UA_SUCCESS;
  173. }else
  174. return UA_ERROR;
  175. }
  176. UA_Int32 UA_Namespace_insert(UA_Namespace *ns, UA_Node **node, UA_Byte flags) {
  177. if(ns == UA_NULL || node == UA_NULL || *node == UA_NULL || (*node)->nodeId.namespaceIndex !=
  178. ns->namespaceIndex)
  179. return UA_ERROR;
  180. UA_UInt32 nodesize;
  181. /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
  182. switch((*node)->nodeClass) {
  183. case UA_NODECLASS_OBJECT:
  184. nodesize = sizeof(UA_ObjectNode);
  185. break;
  186. case UA_NODECLASS_VARIABLE:
  187. nodesize = sizeof(UA_VariableNode);
  188. break;
  189. case UA_NODECLASS_METHOD:
  190. nodesize = sizeof(UA_MethodNode);
  191. break;
  192. case UA_NODECLASS_OBJECTTYPE:
  193. nodesize = sizeof(UA_ObjectTypeNode);
  194. break;
  195. case UA_NODECLASS_VARIABLETYPE:
  196. nodesize = sizeof(UA_VariableTypeNode);
  197. break;
  198. case UA_NODECLASS_REFERENCETYPE:
  199. nodesize = sizeof(UA_ReferenceTypeNode);
  200. break;
  201. case UA_NODECLASS_DATATYPE:
  202. nodesize = sizeof(UA_DataTypeNode);
  203. break;
  204. case UA_NODECLASS_VIEW:
  205. nodesize = sizeof(UA_ViewNode);
  206. break;
  207. default:
  208. return UA_ERROR;
  209. }
  210. UA_Namespace_Entry *entry;
  211. if(UA_alloc((void **)&entry, sizeof(UA_Namespace_Entry) - sizeof(UA_Node) + nodesize))
  212. return UA_ERR_NO_MEMORY;
  213. memcpy(&entry->node, *node, nodesize);
  214. cds_lfht_node_init(&entry->htn);
  215. entry->readcount = ALIVE_BIT;
  216. if(flags & UA_NAMESPACE_INSERT_GETMANAGED)
  217. entry->readcount++;
  218. hash_t nhash = hash(&(*node)->nodeId);
  219. struct cds_lfht_node *result;
  220. if(flags & UA_NAMESPACE_INSERT_UNIQUE) {
  221. rcu_read_lock();
  222. result = cds_lfht_add_unique(ns->ht, nhash, compare, &entry->node.nodeId, &entry->htn);
  223. rcu_read_unlock();
  224. /* If the nodeid exists already */
  225. if(result != &entry->htn) {
  226. UA_free(entry);
  227. return UA_ERROR; // TODO: define a UA_EXISTS_ALREADY
  228. }
  229. } else {
  230. rcu_read_lock();
  231. result = cds_lfht_add_replace(ns->ht, nhash, compare, &(*node)->nodeId, &entry->htn);
  232. /* If an entry got replaced, mark it as dead. */
  233. if(result) {
  234. UA_Namespace_Entry *entry = caa_container_of(result, UA_Namespace_Entry, htn);
  235. call_rcu(&entry->rcu_head, markDead); /* Queue this for the next time when no readers are on the entry.*/
  236. }
  237. rcu_read_unlock();
  238. }
  239. UA_free((UA_Node *)*node); /* The old node is replaced by a managed node. */
  240. if(flags & UA_NAMESPACE_INSERT_GETMANAGED)
  241. *node = &entry->node;
  242. else
  243. *node = UA_NULL;
  244. return UA_SUCCESS;
  245. }
  246. UA_Int32 UA_Namespace_remove(UA_Namespace *ns, const UA_NodeId *nodeid) {
  247. hash_t nhash = hash(nodeid);
  248. struct cds_lfht_iter iter;
  249. rcu_read_lock();
  250. cds_lfht_lookup(ns->ht, nhash, compare, &nodeid, &iter);
  251. struct cds_lfht_node *found_htn = cds_lfht_iter_get_node(&iter);
  252. /* If this fails, then the node has already been removed. */
  253. if(!found_htn || cds_lfht_del(ns->ht, found_htn) != 0) {
  254. rcu_read_unlock();
  255. return UA_ERROR;
  256. }
  257. UA_Namespace_Entry *entry = caa_container_of(found_htn, UA_Namespace_Entry, htn);
  258. call_rcu(&entry->rcu_head, markDead);
  259. rcu_read_unlock();
  260. return UA_SUCCESS;
  261. }
  262. UA_Int32 UA_Namespace_get(const UA_Namespace *ns, const UA_NodeId *nodeid, const UA_Node **managedNode) {
  263. hash_t nhash = hash(nodeid);
  264. struct cds_lfht_iter iter;
  265. rcu_read_lock();
  266. cds_lfht_lookup(ns->ht, nhash, compare, nodeid, &iter);
  267. UA_Namespace_Entry *found_entry = (UA_Namespace_Entry *)cds_lfht_iter_get_node(&iter);
  268. if(!found_entry) {
  269. rcu_read_unlock();
  270. return UA_ERROR; // TODO: UA_NOTFOUND
  271. }
  272. /* This is done within a read-lock. The node will not be marked dead within a read-lock. */
  273. uatomic_inc(&found_entry->readcount);
  274. rcu_read_unlock();
  275. *managedNode = &found_entry->node;
  276. return UA_SUCCESS;
  277. }
  278. UA_Int32 UA_Namespace_iterate(const UA_Namespace *ns, UA_Namespace_nodeVisitor visitor) {
  279. if(ns == UA_NULL || visitor == UA_NULL)
  280. return UA_ERROR;
  281. struct cds_lfht *ht = ns->ht;
  282. struct cds_lfht_iter iter;
  283. rcu_read_lock();
  284. cds_lfht_first(ht, &iter);
  285. while(iter.node != UA_NULL) {
  286. UA_Namespace_Entry *found_entry = (UA_Namespace_Entry *)cds_lfht_iter_get_node(&iter);
  287. uatomic_inc(&found_entry->readcount);
  288. const UA_Node *node = &found_entry->node;
  289. rcu_read_unlock();
  290. visitor(node);
  291. UA_Namespace_releaseManagedNode((UA_Node *)node);
  292. rcu_read_lock();
  293. cds_lfht_next(ht, &iter);
  294. }
  295. rcu_read_unlock();
  296. return UA_SUCCESS;
  297. }