ua_nodestore.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. #include "ua_nodestore.h"
  2. #include "ua_util.h"
  3. #include "ua_statuscodes.h"
  4. struct UA_NodeStore {
  5. const UA_Node **entries;
  6. UA_UInt32 size;
  7. UA_UInt32 count;
  8. UA_UInt32 sizePrimeIndex;
  9. };
  10. typedef UA_UInt32 hash_t;
  11. /* The size of the hash-map is always a prime number. They are chosen to be
  12. close to the next power of 2. So the size ca. doubles with each prime. */
  13. static hash_t const primes[] = {
  14. 7, 13, 31, 61, 127, 251,
  15. 509, 1021, 2039, 4093, 8191, 16381,
  16. 32749, 65521, 131071, 262139, 524287, 1048573,
  17. 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
  18. 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291
  19. };
  20. static INLINE hash_t mod(hash_t h, hash_t size) {
  21. return h % size;
  22. }
  23. static INLINE hash_t mod2(hash_t h, hash_t size) {
  24. return 1 + (h % (size - 2));
  25. }
  26. static INLINE UA_Int16 higher_prime_index(hash_t n) {
  27. UA_UInt16 low = 0;
  28. UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
  29. while(low != high) {
  30. UA_UInt16 mid = low + (high - low) / 2;
  31. if(n > primes[mid])
  32. low = mid + 1;
  33. else
  34. high = mid;
  35. }
  36. return low;
  37. }
  38. /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
  39. static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
  40. const int32_t nblocks = len / 4;
  41. const uint32_t *blocks;
  42. static const uint32_t c1 = 0xcc9e2d51;
  43. static const uint32_t c2 = 0x1b873593;
  44. static const uint32_t r1 = 15;
  45. static const uint32_t r2 = 13;
  46. static const uint32_t m = 5;
  47. static const uint32_t n = 0xe6546b64;
  48. hash_t hash = seed;
  49. if(data == UA_NULL)
  50. return 0;
  51. blocks = (const uint32_t *)data;
  52. for(int32_t i = 0;i < nblocks;i++) {
  53. uint32_t k = blocks[i];
  54. k *= c1;
  55. k = (k << r1) | (k >> (32 - r1));
  56. k *= c2;
  57. hash ^= k;
  58. hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
  59. }
  60. const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
  61. uint32_t k1 = 0;
  62. switch(len & 3) {
  63. case 3:
  64. k1 ^= tail[2] << 16;
  65. case 2:
  66. k1 ^= tail[1] << 8;
  67. case 1:
  68. k1 ^= tail[0];
  69. k1 *= c1;
  70. k1 = (k1 << r1) | (k1 >> (32 - r1));
  71. k1 *= c2;
  72. hash ^= k1;
  73. }
  74. hash ^= len;
  75. hash ^= (hash >> 16);
  76. hash *= 0x85ebca6b;
  77. hash ^= (hash >> 13);
  78. hash *= 0xc2b2ae35;
  79. hash ^= (hash >> 16);
  80. return hash;
  81. }
  82. static INLINE hash_t hash(const UA_NodeId *n) {
  83. switch(n->identifierType) {
  84. case UA_NODEIDTYPE_NUMERIC:
  85. /* Knuth's multiplicative hashing */
  86. return (n->identifier.numeric + n->namespaceIndex) * 2654435761; // mod(2^32) is implicit
  87. case UA_NODEIDTYPE_STRING:
  88. return hash_array(n->identifier.string.data, n->identifier.string.length, n->namespaceIndex);
  89. case UA_NODEIDTYPE_GUID:
  90. return hash_array((UA_Byte *)&(n->identifier.guid), sizeof(UA_Guid), n->namespaceIndex);
  91. case UA_NODEIDTYPE_BYTESTRING:
  92. return hash_array((UA_Byte *)n->identifier.byteString.data, n->identifier.byteString.length, n->namespaceIndex);
  93. default:
  94. UA_assert(UA_FALSE);
  95. return 0;
  96. }
  97. }
  98. static INLINE void clear_entry(UA_NodeStore *ns, const UA_Node **entry) {
  99. const UA_Node *node;
  100. if(entry == UA_NULL || *entry == UA_NULL)
  101. return;
  102. node = *entry;
  103. switch(node->nodeClass) {
  104. case UA_NODECLASS_OBJECT:
  105. UA_ObjectNode_delete((UA_ObjectNode *)node);
  106. break;
  107. case UA_NODECLASS_VARIABLE:
  108. UA_VariableNode_delete((UA_VariableNode *)node);
  109. break;
  110. case UA_NODECLASS_METHOD:
  111. UA_MethodNode_delete((UA_MethodNode *)node);
  112. break;
  113. case UA_NODECLASS_OBJECTTYPE:
  114. UA_ObjectTypeNode_delete((UA_ObjectTypeNode *)node);
  115. break;
  116. case UA_NODECLASS_VARIABLETYPE:
  117. UA_VariableTypeNode_delete((UA_VariableTypeNode *)node);
  118. break;
  119. case UA_NODECLASS_REFERENCETYPE:
  120. UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *)node);
  121. break;
  122. case UA_NODECLASS_DATATYPE:
  123. UA_DataTypeNode_delete((UA_DataTypeNode *)node);
  124. break;
  125. case UA_NODECLASS_VIEW:
  126. UA_ViewNode_delete((UA_ViewNode *)node);
  127. break;
  128. default:
  129. UA_assert(UA_FALSE);
  130. break;
  131. }
  132. entry = UA_NULL;
  133. ns->count--;
  134. }
  135. /* Returns UA_STATUSCODE_GOOD if an entry was found. Otherwise, An error code is
  136. returned and the "entry" argument points to the first free entry under the
  137. NodeId. */
  138. static INLINE UA_StatusCode find_entry(const UA_NodeStore *ns, const UA_NodeId *nodeid, const UA_Node ***entry) {
  139. hash_t h = hash(nodeid);
  140. UA_UInt32 size = ns->size;
  141. hash_t index = mod(h, size);
  142. const UA_Node **e = &ns->entries[index];
  143. if(*e == UA_NULL) {
  144. *entry = e;
  145. return UA_STATUSCODE_BADINTERNALERROR;
  146. }
  147. if(UA_NodeId_equal(&(*e)->nodeId, nodeid) == UA_EQUAL) {
  148. *entry = e;
  149. return UA_STATUSCODE_GOOD;
  150. }
  151. hash_t hash2 = mod2(h, size);
  152. for(;;) {
  153. index += hash2;
  154. if(index >= size)
  155. index -= size;
  156. e = &ns->entries[index];
  157. if(*e == UA_NULL) {
  158. *entry = e;
  159. return UA_STATUSCODE_BADINTERNALERROR;
  160. }
  161. if(UA_NodeId_equal(&(*e)->nodeId, nodeid) == UA_EQUAL) {
  162. *entry = e;
  163. return UA_STATUSCODE_GOOD;
  164. }
  165. }
  166. /* NOTREACHED */
  167. return UA_STATUSCODE_GOOD;
  168. }
  169. /* The following function changes size of memory allocated for the entries and
  170. repeatedly inserts the table elements. The occupancy of the table after the
  171. call will be about 50%. */
  172. static UA_StatusCode expand(UA_NodeStore *ns) {
  173. const UA_Node **nentries;
  174. int32_t nsize;
  175. UA_UInt32 nindex;
  176. const UA_Node **oentries = ns->entries;
  177. int32_t osize = ns->size;
  178. const UA_Node **olimit = &oentries[osize];
  179. int32_t count = ns->count;
  180. /* Resize only when table after removal of unused elements is either too full or too empty. */
  181. if(count * 2 < osize && (count * 8 > osize || osize <= 32))
  182. return UA_STATUSCODE_GOOD;
  183. nindex = higher_prime_index(count * 2);
  184. nsize = primes[nindex];
  185. if(!(nentries = UA_alloc(sizeof(UA_Node *) * nsize)))
  186. return UA_STATUSCODE_BADOUTOFMEMORY;
  187. memset(nentries, 0, nsize * sizeof(UA_Node *));
  188. ns->entries = nentries;
  189. ns->size = nsize;
  190. ns->sizePrimeIndex = nindex;
  191. const UA_Node **p = oentries;
  192. do {
  193. if(*p != UA_NULL) {
  194. const UA_Node **e;
  195. find_entry(ns, &(*p)->nodeId, &e); /* We know this returns an empty entry here */
  196. *e = *p;
  197. }
  198. p++;
  199. } while(p < olimit);
  200. UA_free(oentries);
  201. return UA_STATUSCODE_GOOD;
  202. }
  203. /**********************/
  204. /* Exported functions */
  205. /**********************/
  206. UA_StatusCode UA_NodeStore_new(UA_NodeStore **result) {
  207. UA_NodeStore *ns;
  208. UA_UInt32 sizePrimeIndex, size;
  209. if(!(ns = UA_alloc(sizeof(UA_NodeStore))))
  210. return UA_STATUSCODE_BADOUTOFMEMORY;
  211. sizePrimeIndex = higher_prime_index(32);
  212. size = primes[sizePrimeIndex];
  213. if(!(ns->entries = UA_alloc(sizeof(UA_Node *) * size))) {
  214. UA_free(ns);
  215. return UA_STATUSCODE_BADOUTOFMEMORY;
  216. }
  217. /* set entries to zero */
  218. memset(ns->entries, 0, size * sizeof(UA_Node *));
  219. *ns = (UA_NodeStore) {ns->entries, size, 0, sizePrimeIndex };
  220. *result = ns;
  221. return UA_STATUSCODE_GOOD;
  222. }
  223. void UA_NodeStore_delete(UA_NodeStore *ns) {
  224. UA_UInt32 size = ns->size;
  225. const UA_Node **entries = ns->entries;
  226. for(UA_UInt32 i = 0;i < size;i++)
  227. clear_entry(ns, &entries[i]);
  228. UA_free(ns->entries);
  229. UA_free(ns);
  230. }
  231. UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node **node, UA_Byte flags) {
  232. if(ns->size * 3 <= ns->count * 4) {
  233. if(expand(ns) != UA_STATUSCODE_GOOD)
  234. return UA_STATUSCODE_BADINTERNALERROR;
  235. }
  236. const UA_Node **entry;
  237. UA_Int32 found = find_entry(ns, &(*node)->nodeId, &entry);
  238. if(flags & UA_NODESTORE_INSERT_UNIQUE) {
  239. if(found == UA_STATUSCODE_GOOD)
  240. return UA_STATUSCODE_BADINTERNALERROR; /* There is already an entry for that nodeid */
  241. else
  242. *entry = *node;
  243. } else {
  244. if(found == UA_STATUSCODE_GOOD)
  245. clear_entry(ns, entry);
  246. *entry = *node;
  247. }
  248. if(!(flags & UA_NODESTORE_INSERT_GETMANAGED))
  249. *node = UA_NULL;
  250. ns->count++;
  251. return UA_STATUSCODE_GOOD;
  252. }
  253. UA_StatusCode UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid, const UA_Node **managedNode) {
  254. const UA_Node **entry;
  255. if(find_entry(ns, nodeid, &entry) != UA_STATUSCODE_GOOD)
  256. return UA_STATUSCODE_BADINTERNALERROR;
  257. *managedNode = *entry;
  258. return UA_STATUSCODE_GOOD;
  259. }
  260. UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
  261. const UA_Node **entry;
  262. if(find_entry(ns, nodeid, &entry) != UA_STATUSCODE_GOOD)
  263. return UA_STATUSCODE_BADINTERNALERROR;
  264. // Check before if deleting the node makes the UA_NodeStore inconsistent.
  265. clear_entry(ns, entry);
  266. /* Downsize the hashmap if it is very empty */
  267. if(ns->count * 8 < ns->size && ns->size > 32)
  268. expand(ns);
  269. return UA_STATUSCODE_GOOD;
  270. }
  271. void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
  272. for(UA_UInt32 i = 0;i < ns->size;i++) {
  273. const UA_Node *node = ns->entries[i];
  274. if(node != UA_NULL)
  275. visitor(node);
  276. }
  277. }
  278. void UA_NodeStore_releaseManagedNode(const UA_Node *managed) {
  279. ;
  280. }