ua_namespace_concurrent.c 9.6 KB

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