ua_nodestore.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #include "ua_nodestore.h"
  2. #include "ua_util.h"
  3. #include "ua_statuscodes.h"
  4. #define UA_NODESTORE_MINSIZE 64
  5. typedef struct {
  6. UA_Boolean taken;
  7. union {
  8. UA_Node node;
  9. UA_ObjectNode objectNode;
  10. UA_ObjectTypeNode objectTypeNode;
  11. UA_VariableNode variableNode;
  12. UA_VariableTypeNode variableTypeNode;
  13. UA_ReferenceTypeNode referenceTypeNode;
  14. UA_MethodNode methodeNode;
  15. UA_ViewNode viewNode;
  16. UA_DataTypeNode dataTypeNode;
  17. } node;
  18. } UA_NodeStoreEntry;
  19. struct UA_NodeStore {
  20. UA_NodeStoreEntry *entries;
  21. UA_UInt32 size;
  22. UA_UInt32 count;
  23. UA_UInt32 sizePrimeIndex;
  24. };
  25. #include "ua_nodestore_hash.inc"
  26. /* The size of the hash-map is always a prime number. They are chosen to be
  27. close to the next power of 2. So the size ca. doubles with each prime. */
  28. static hash_t const primes[] = {
  29. 7, 13, 31, 61, 127, 251,
  30. 509, 1021, 2039, 4093, 8191, 16381,
  31. 32749, 65521, 131071, 262139, 524287, 1048573,
  32. 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
  33. 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291
  34. };
  35. static UA_Int16 higher_prime_index(hash_t n) {
  36. UA_UInt16 low = 0;
  37. UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
  38. while(low != high) {
  39. UA_UInt16 mid = low + (high - low) / 2;
  40. if(n > primes[mid])
  41. low = mid + 1;
  42. else
  43. high = mid;
  44. }
  45. return low;
  46. }
  47. /* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
  48. false and sets slot to a pointer to the next free slot. */
  49. static UA_Boolean
  50. containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, UA_NodeStoreEntry **entry) {
  51. hash_t h = hash(nodeid);
  52. UA_UInt32 size = ns->size;
  53. hash_t index = mod(h, size);
  54. UA_NodeStoreEntry *e = &ns->entries[index];
  55. if(!e->taken) {
  56. *entry = e;
  57. return UA_FALSE;
  58. }
  59. if(UA_NodeId_equal(&e->node.node.nodeId, nodeid)) {
  60. *entry = e;
  61. return UA_TRUE;
  62. }
  63. hash_t hash2 = mod2(h, size);
  64. for(;;) {
  65. index += hash2;
  66. if(index >= size)
  67. index -= size;
  68. e = &ns->entries[index];
  69. if(!e->taken) {
  70. *entry = e;
  71. return UA_FALSE;
  72. }
  73. if(UA_NodeId_equal(&e->node.node.nodeId, nodeid)) {
  74. *entry = e;
  75. return UA_TRUE;
  76. }
  77. }
  78. /* NOTREACHED */
  79. return UA_TRUE;
  80. }
  81. /* The following function changes size of memory allocated for the entries and
  82. repeatedly inserts the table elements. The occupancy of the table after the
  83. call will be about 50%. */
  84. static UA_StatusCode expand(UA_NodeStore *ns) {
  85. UA_UInt32 osize = ns->size;
  86. UA_UInt32 count = ns->count;
  87. /* Resize only when table after removal of unused elements is either too full or too empty. */
  88. if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODESTORE_MINSIZE))
  89. return UA_STATUSCODE_GOOD;
  90. UA_UInt32 nindex = higher_prime_index(count * 2);
  91. UA_Int32 nsize = primes[nindex];
  92. UA_NodeStoreEntry *nentries;
  93. if(!(nentries = UA_calloc(nsize, sizeof(UA_NodeStoreEntry))))
  94. return UA_STATUSCODE_BADOUTOFMEMORY;
  95. UA_NodeStoreEntry *oentries = ns->entries;
  96. ns->entries = nentries;
  97. ns->size = nsize;
  98. ns->sizePrimeIndex = nindex;
  99. // recompute the position of every entry and insert the pointer
  100. for(size_t i = 0, j = 0; i < osize && j < count; i++) {
  101. if(!oentries[i].taken)
  102. continue;
  103. UA_NodeStoreEntry *e;
  104. containsNodeId(ns, &oentries[i].node.node.nodeId, &e); /* We know this returns an empty entry here */
  105. *e = oentries[i];
  106. j++;
  107. }
  108. UA_free(oentries);
  109. return UA_STATUSCODE_GOOD;
  110. }
  111. /* Marks the entry dead and deletes if necessary. */
  112. static UA_INLINE void
  113. deleteEntry(UA_NodeStoreEntry *entry) {
  114. UA_Node_deleteMembersAnyNodeClass(&entry->node.node);
  115. entry->taken = UA_FALSE;
  116. }
  117. /** Copies the node into the entry. Then free the original node (but not its content). */
  118. static void fillEntry(UA_NodeStoreEntry *entry, UA_Node *node) {
  119. size_t nodesize = 0;
  120. switch(node->nodeClass) {
  121. case UA_NODECLASS_OBJECT:
  122. nodesize = sizeof(UA_ObjectNode);
  123. break;
  124. case UA_NODECLASS_VARIABLE:
  125. nodesize = sizeof(UA_VariableNode);
  126. break;
  127. case UA_NODECLASS_METHOD:
  128. nodesize = sizeof(UA_MethodNode);
  129. break;
  130. case UA_NODECLASS_OBJECTTYPE:
  131. nodesize = sizeof(UA_ObjectTypeNode);
  132. break;
  133. case UA_NODECLASS_VARIABLETYPE:
  134. nodesize = sizeof(UA_VariableTypeNode);
  135. break;
  136. case UA_NODECLASS_REFERENCETYPE:
  137. nodesize = sizeof(UA_ReferenceTypeNode);
  138. break;
  139. case UA_NODECLASS_DATATYPE:
  140. nodesize = sizeof(UA_DataTypeNode);
  141. break;
  142. case UA_NODECLASS_VIEW:
  143. nodesize = sizeof(UA_ViewNode);
  144. break;
  145. default:
  146. UA_assert(UA_FALSE);
  147. }
  148. memcpy(&entry->node, node, nodesize);
  149. UA_free(node);
  150. entry->taken = UA_TRUE;
  151. }
  152. /**********************/
  153. /* Exported functions */
  154. /**********************/
  155. UA_NodeStore * UA_NodeStore_new(void) {
  156. UA_NodeStore *ns;
  157. if(!(ns = UA_malloc(sizeof(UA_NodeStore))))
  158. return NULL;
  159. ns->sizePrimeIndex = higher_prime_index(UA_NODESTORE_MINSIZE);
  160. ns->size = primes[ns->sizePrimeIndex];
  161. ns->count = 0;
  162. if(!(ns->entries = UA_calloc(ns->size, sizeof(UA_NodeStoreEntry)))) {
  163. UA_free(ns);
  164. return NULL;
  165. }
  166. return ns;
  167. }
  168. void UA_NodeStore_delete(UA_NodeStore *ns) {
  169. UA_UInt32 size = ns->size;
  170. UA_NodeStoreEntry *entries = ns->entries;
  171. for(UA_UInt32 i = 0;i < size;i++) {
  172. if(entries[i].taken)
  173. deleteEntry(&entries[i]);
  174. }
  175. UA_free(ns->entries);
  176. UA_free(ns);
  177. }
  178. UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_Node **inserted) {
  179. if(ns->size * 3 <= ns->count * 4) {
  180. if(expand(ns) != UA_STATUSCODE_GOOD)
  181. return UA_STATUSCODE_BADINTERNALERROR;
  182. }
  183. UA_NodeStoreEntry *entry;
  184. UA_NodeId tempNodeid;
  185. tempNodeid = node->nodeId;
  186. tempNodeid.namespaceIndex = 0;
  187. if(UA_NodeId_isNull(&tempNodeid)) {
  188. /* find a free nodeid */
  189. if(node->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1
  190. node->nodeId.namespaceIndex = 1;
  191. UA_Int32 identifier = ns->count+1; // start value
  192. UA_Int32 size = ns->size;
  193. hash_t increase = mod2(identifier, size);
  194. while(UA_TRUE) {
  195. node->nodeId.identifier.numeric = identifier;
  196. if(!containsNodeId(ns, &node->nodeId, &entry))
  197. break;
  198. identifier += increase;
  199. if(identifier >= size)
  200. identifier -= size;
  201. }
  202. } else {
  203. if(containsNodeId(ns, &node->nodeId, &entry))
  204. return UA_STATUSCODE_BADNODEIDEXISTS;
  205. }
  206. fillEntry(entry, node);
  207. ns->count++;
  208. if(inserted)
  209. *inserted = &entry->node.node;
  210. return UA_STATUSCODE_GOOD;
  211. }
  212. UA_StatusCode
  213. UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *oldNode,
  214. UA_Node *node, UA_Node **inserted) {
  215. UA_NodeStoreEntry *slot;
  216. if(!containsNodeId(ns, &node->nodeId, &slot))
  217. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  218. /* that is not the node you are looking for */
  219. if(&slot->node.node != oldNode)
  220. return UA_STATUSCODE_BADINTERNALERROR;
  221. deleteEntry(slot);
  222. fillEntry(slot, node);
  223. if(inserted)
  224. *inserted = &slot->node.node;
  225. return UA_STATUSCODE_GOOD;
  226. }
  227. UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
  228. UA_NodeStoreEntry *slot;
  229. if(!containsNodeId(ns, nodeid, &slot))
  230. return NULL;
  231. return &slot->node.node;
  232. }
  233. UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
  234. UA_NodeStoreEntry *slot;
  235. if(!containsNodeId(ns, nodeid, &slot))
  236. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  237. deleteEntry(slot);
  238. ns->count--;
  239. /* Downsize the hashmap if it is very empty */
  240. if(ns->count * 8 < ns->size && ns->size > 32)
  241. expand(ns); // this can fail. we just continue with the bigger hashmap.
  242. return UA_STATUSCODE_GOOD;
  243. }
  244. void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
  245. for(UA_UInt32 i = 0;i < ns->size;i++) {
  246. if(ns->entries[i].taken)
  247. visitor(&ns->entries[i].node.node);
  248. }
  249. }