ua_nodestore.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #include "ua_nodestore.h"
  2. #include "ua_util.h"
  3. #include "ua_statuscodes.h"
  4. /* It could happen that we want to delete a node even though a function higher
  5. in the call-chain still has a reference. So we count references and delete
  6. once the count falls to zero. That means we copy every node to a new place
  7. where it is right behind the refcount integer.
  8. Since we copy nodes on the heap, we make the alloc for the nodeEntry bigger
  9. to accommodate for the different nodeclasses (the nodeEntry may have an
  10. overlength "tail"). */
  11. #define ALIVE_BIT (1 << 15) /* Alive bit in the refcount */
  12. struct nodeEntry {
  13. UA_UInt16 refcount;
  14. const UA_Node node;
  15. };
  16. struct UA_NodeStore {
  17. struct nodeEntry **entries;
  18. UA_UInt32 size;
  19. UA_UInt32 count;
  20. UA_UInt32 sizePrimeIndex;
  21. };
  22. #include "ua_nodestore_hash.inc"
  23. /* The size of the hash-map is always a prime number. They are chosen to be
  24. close to the next power of 2. So the size ca. doubles with each prime. */
  25. static hash_t const primes[] = {
  26. 7, 13, 31, 61, 127, 251,
  27. 509, 1021, 2039, 4093, 8191, 16381,
  28. 32749, 65521, 131071, 262139, 524287, 1048573,
  29. 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
  30. 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291
  31. };
  32. static INLINE UA_Int16 higher_prime_index(hash_t n) {
  33. UA_UInt16 low = 0;
  34. UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
  35. while(low != high) {
  36. UA_UInt16 mid = low + (high - low) / 2;
  37. if(n > primes[mid])
  38. low = mid + 1;
  39. else
  40. high = mid;
  41. }
  42. return low;
  43. }
  44. /* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
  45. false and sets slot to a pointer to the next free slot. */
  46. static UA_Boolean __containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, struct nodeEntry ***entry) {
  47. hash_t h = hash(nodeid);
  48. UA_UInt32 size = ns->size;
  49. hash_t index = mod(h, size);
  50. struct nodeEntry **e = &ns->entries[index];
  51. if(*e == UA_NULL) {
  52. *entry = e;
  53. return UA_FALSE;
  54. }
  55. if(UA_NodeId_equal(&(*e)->node.nodeId, nodeid)) {
  56. *entry = e;
  57. return UA_TRUE;
  58. }
  59. hash_t hash2 = mod2(h, size);
  60. for(;;) {
  61. index += hash2;
  62. if(index >= size)
  63. index -= size;
  64. e = &ns->entries[index];
  65. if(*e == UA_NULL) {
  66. *entry = e;
  67. return UA_FALSE;
  68. }
  69. if(UA_NodeId_equal(&(*e)->node.nodeId, nodeid)) {
  70. *entry = e;
  71. return UA_TRUE;
  72. }
  73. }
  74. /* NOTREACHED */
  75. return UA_TRUE;
  76. }
  77. /* The following function changes size of memory allocated for the entries and
  78. repeatedly inserts the table elements. The occupancy of the table after the
  79. call will be about 50%. */
  80. static UA_StatusCode __expand(UA_NodeStore *ns) {
  81. UA_Int32 osize = ns->size;
  82. UA_Int32 count = ns->count;
  83. /* Resize only when table after removal of unused elements is either too full or too empty. */
  84. if(count * 2 < osize && (count * 8 > osize || osize <= 32))
  85. return UA_STATUSCODE_GOOD;
  86. UA_UInt32 nindex = higher_prime_index(count * 2);
  87. UA_Int32 nsize = primes[nindex];
  88. struct nodeEntry **nentries;
  89. if(!(nentries = UA_alloc(sizeof(struct nodeEntry *) * nsize)))
  90. return UA_STATUSCODE_BADOUTOFMEMORY;
  91. memset(nentries, 0, nsize * sizeof(struct nodeEntry *));
  92. struct nodeEntry **oentries = ns->entries;
  93. ns->entries = nentries;
  94. ns->size = nsize;
  95. ns->sizePrimeIndex = nindex;
  96. // recompute the position of every entry and insert the pointer
  97. for(UA_Int32 i=0, j=0;i<osize && j<count;i++) {
  98. if(!oentries[i])
  99. continue;
  100. struct nodeEntry **e;
  101. __containsNodeId(ns, &(*oentries[i]).node.nodeId, &e); /* We know this returns an empty entry here */
  102. *e = oentries[i];
  103. j++;
  104. }
  105. UA_free(oentries);
  106. return UA_STATUSCODE_GOOD;
  107. }
  108. /* Marks the entry dead and deletes if necessary. */
  109. static void __deleteEntry(struct nodeEntry *entry) {
  110. if(entry->refcount > 0)
  111. return;
  112. const UA_Node *node = &entry->node;
  113. switch(node->nodeClass) {
  114. case UA_NODECLASS_OBJECT:
  115. UA_ObjectNode_deleteMembers((UA_ObjectNode *)node);
  116. break;
  117. case UA_NODECLASS_VARIABLE:
  118. UA_VariableNode_deleteMembers((UA_VariableNode *)node);
  119. break;
  120. case UA_NODECLASS_METHOD:
  121. UA_MethodNode_deleteMembers((UA_MethodNode *)node);
  122. break;
  123. case UA_NODECLASS_OBJECTTYPE:
  124. UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode *)node);
  125. break;
  126. case UA_NODECLASS_VARIABLETYPE:
  127. UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode *)node);
  128. break;
  129. case UA_NODECLASS_REFERENCETYPE:
  130. UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode *)node);
  131. break;
  132. case UA_NODECLASS_DATATYPE:
  133. UA_DataTypeNode_deleteMembers((UA_DataTypeNode *)node);
  134. break;
  135. case UA_NODECLASS_VIEW:
  136. UA_ViewNode_deleteMembers((UA_ViewNode *)node);
  137. break;
  138. default:
  139. UA_assert(UA_FALSE);
  140. break;
  141. }
  142. UA_free(entry);
  143. }
  144. static INLINE struct nodeEntry * __nodeEntryFromNode(const UA_Node *node) {
  145. UA_UInt32 nodesize = 0;
  146. /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
  147. switch(node->nodeClass) {
  148. case UA_NODECLASS_OBJECT:
  149. nodesize = sizeof(UA_ObjectNode);
  150. break;
  151. case UA_NODECLASS_VARIABLE:
  152. nodesize = sizeof(UA_VariableNode);
  153. break;
  154. case UA_NODECLASS_METHOD:
  155. nodesize = sizeof(UA_MethodNode);
  156. break;
  157. case UA_NODECLASS_OBJECTTYPE:
  158. nodesize = sizeof(UA_ObjectTypeNode);
  159. break;
  160. case UA_NODECLASS_VARIABLETYPE:
  161. nodesize = sizeof(UA_VariableTypeNode);
  162. break;
  163. case UA_NODECLASS_REFERENCETYPE:
  164. nodesize = sizeof(UA_ReferenceTypeNode);
  165. break;
  166. case UA_NODECLASS_DATATYPE:
  167. nodesize = sizeof(UA_DataTypeNode);
  168. break;
  169. case UA_NODECLASS_VIEW:
  170. nodesize = sizeof(UA_ViewNode);
  171. break;
  172. default:
  173. UA_assert(UA_FALSE);
  174. }
  175. struct nodeEntry *entry;
  176. if(!(entry = UA_alloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
  177. return UA_NULL;
  178. memcpy((void *)&entry->node, node, nodesize);
  179. UA_free((void*)node);
  180. return entry;
  181. }
  182. /**********************/
  183. /* Exported functions */
  184. /**********************/
  185. UA_NodeStore * UA_NodeStore_new() {
  186. UA_NodeStore *ns;
  187. if(!(ns = UA_alloc(sizeof(UA_NodeStore))))
  188. return UA_NULL;
  189. ns->sizePrimeIndex = higher_prime_index(32);
  190. ns->size = primes[ns->sizePrimeIndex];
  191. ns->count = 0;
  192. if(!(ns->entries = UA_alloc(sizeof(struct nodeEntry *) * ns->size))) {
  193. UA_free(ns);
  194. return UA_NULL;
  195. }
  196. memset(ns->entries, 0, ns->size * sizeof(struct nodeEntry *));
  197. return ns;
  198. }
  199. void UA_NodeStore_delete(UA_NodeStore *ns) {
  200. UA_UInt32 size = ns->size;
  201. struct nodeEntry **entries = ns->entries;
  202. for(UA_UInt32 i = 0;i < size;i++) {
  203. if(entries[i] != UA_NULL) {
  204. entries[i]->refcount &= ~ALIVE_BIT; // mark dead
  205. __deleteEntry(entries[i]);
  206. entries[i] = UA_NULL;
  207. ns->count--;
  208. }
  209. }
  210. UA_free(ns->entries);
  211. UA_free(ns);
  212. }
  213. UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged) {
  214. if(ns->size * 3 <= ns->count * 4) {
  215. if(__expand(ns) != UA_STATUSCODE_GOOD)
  216. return UA_STATUSCODE_BADINTERNALERROR;
  217. }
  218. // get a free slot
  219. struct nodeEntry **slot;
  220. UA_NodeId *nodeId = (UA_NodeId *)&(*node)->nodeId;
  221. if(UA_NodeId_isNull(nodeId)) {
  222. // find a unique nodeid that is not taken
  223. nodeId->identifierType = UA_NODEIDTYPE_NUMERIC;
  224. nodeId->namespaceIndex = 1; // namespace 1 is always in the local nodestore
  225. UA_Int32 identifier = ns->count+1; // start value
  226. UA_Int32 size = ns->size;
  227. hash_t increase = mod2(identifier, size);
  228. while(UA_TRUE) {
  229. nodeId->identifier.numeric = identifier;
  230. if(!__containsNodeId(ns, nodeId, &slot))
  231. break;
  232. identifier += increase;
  233. if(identifier >= size)
  234. identifier -= size;
  235. }
  236. } else {
  237. if(__containsNodeId(ns, nodeId, &slot))
  238. return UA_STATUSCODE_BADNODEIDEXISTS;
  239. }
  240. struct nodeEntry *entry = __nodeEntryFromNode(*node);
  241. if(!entry)
  242. return UA_STATUSCODE_BADOUTOFMEMORY;
  243. *slot = entry;
  244. ns->count++;
  245. if(getManaged) {
  246. entry->refcount = ALIVE_BIT + 1;
  247. *node = &entry->node;
  248. } else {
  249. entry->refcount = ALIVE_BIT;
  250. *node = UA_NULL;
  251. }
  252. return UA_STATUSCODE_GOOD;
  253. }
  254. UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged) {
  255. struct nodeEntry **slot;
  256. const UA_NodeId *nodeId = &(*node)->nodeId;
  257. if(!__containsNodeId(ns, nodeId, &slot))
  258. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  259. struct nodeEntry *entry = __nodeEntryFromNode(*node);
  260. if(!entry)
  261. return UA_STATUSCODE_BADOUTOFMEMORY;
  262. (*slot)->refcount &= ~ALIVE_BIT; // mark dead
  263. __deleteEntry(*slot);
  264. *slot = entry;
  265. if(getManaged) {
  266. entry->refcount = ALIVE_BIT + 1;
  267. *node = &entry->node;
  268. } else {
  269. entry->refcount = ALIVE_BIT;
  270. *node = UA_NULL;
  271. }
  272. return UA_STATUSCODE_GOOD;
  273. }
  274. const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
  275. struct nodeEntry **slot;
  276. if(!__containsNodeId(ns, nodeid, &slot))
  277. return UA_NULL;
  278. (*slot)->refcount++;
  279. return &(*slot)->node;
  280. }
  281. UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
  282. struct nodeEntry **slot;
  283. if(!__containsNodeId(ns, nodeid, &slot))
  284. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  285. // Check before if deleting the node makes the UA_NodeStore inconsistent.
  286. (*slot)->refcount &= ~ALIVE_BIT; // mark dead
  287. __deleteEntry(*slot);
  288. *slot = UA_NULL;
  289. ns->count--;
  290. /* Downsize the hashmap if it is very empty */
  291. if(ns->count * 8 < ns->size && ns->size > 32)
  292. __expand(ns); // this can fail. we just continue with the bigger hashmap.
  293. return UA_STATUSCODE_GOOD;
  294. }
  295. void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
  296. for(UA_UInt32 i = 0;i < ns->size;i++) {
  297. if(ns->entries[i] != UA_NULL)
  298. visitor(&ns->entries[i]->node);
  299. }
  300. }
  301. void UA_NodeStore_release(const UA_Node *managed) {
  302. struct nodeEntry *entry = (struct nodeEntry *) ((char*)managed - offsetof(struct nodeEntry, node));
  303. entry->refcount--;
  304. __deleteEntry(entry);
  305. }