store_htable.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. #include "hashmap.h"
  2. #include "volksdata/store_htable.h"
  3. /**
  4. * Callback type for key comparison.
  5. */
  6. typedef bool (*VOLK_key_eq_fn_t)(
  7. const VOLK_Key spok[], const VOLK_Key luk[]);
  8. typedef struct idx_entry_t {
  9. VOLK_Key key; ///< Serialized term key.
  10. void * data; ///< Serialized term data.
  11. size_t size; ///< Serialized term size.
  12. } IndexEntry;
  13. typedef struct ht_store_t {
  14. struct hashmap * keys; ///< Triple keys (set).
  15. struct hashmap * idx; ///< Map of keys to serialized terms.
  16. } HTStore;
  17. typedef struct ht_iterator_t {
  18. HTStore * store; ///< Store being iterated.
  19. size_t cur; ///< Internal hash table cursor.
  20. VOLK_Key luk[3]; ///< 0÷3 lookup keys.
  21. VOLK_key_eq_fn_t eq_fn; ///< Equality function to test triples.
  22. int rc; ///< Return code for *next* result.
  23. ///< When the end of results is reached,
  24. ///< this is set to VOLK_END.
  25. VOLK_TripleKey * entry; ///< Retrieved SPO key.
  26. } HTIterator;
  27. /**
  28. * Dummy callback for queries with all parameters unbound. Returns true.
  29. */
  30. static bool lookup_none_eq_fn (
  31. const VOLK_Key spok[], const VOLK_Key luk[])
  32. {
  33. (void) spok;
  34. (void) luk;
  35. return true;
  36. }
  37. /**
  38. * Keyset lookup for S key.
  39. */
  40. static bool lookup_sk_eq_fn (
  41. const VOLK_Key spok[], const VOLK_Key luk[])
  42. { return spok[0] == luk[0]; }
  43. /**
  44. * Keyset lookup for P key.
  45. */
  46. static bool lookup_pk_eq_fn (
  47. const VOLK_Key spok[], const VOLK_Key luk[])
  48. { return spok[1] == luk[1]; }
  49. /**
  50. * Keyset lookup for O key.
  51. */
  52. static bool lookup_ok_eq_fn (
  53. const VOLK_Key spok[], const VOLK_Key luk[])
  54. { return spok[2] == luk[2]; }
  55. /**
  56. * Keyset lookup for S and P keys.
  57. */
  58. static bool lookup_spk_eq_fn (
  59. const VOLK_Key spok[], const VOLK_Key luk[])
  60. { return spok[0] == luk[0] && spok[1] == luk[1]; }
  61. /**
  62. * Keyset lookup for S and O keys.
  63. */
  64. static bool lookup_sok_eq_fn (
  65. const VOLK_Key spok[], const VOLK_Key luk[])
  66. { return spok[0] == luk[0] && spok[2] == luk[2]; }
  67. /**
  68. * Keyset lookup for P and O keys.
  69. */
  70. static bool lookup_pok_eq_fn (
  71. const VOLK_Key spok[], const VOLK_Key luk[])
  72. { return spok[1] == luk[1] && spok[2] == luk[2]; }
  73. /**
  74. * Keyset lookup for S, P and O keys.
  75. */
  76. static bool lookup_spok_eq_fn (
  77. const VOLK_Key spok[], const VOLK_Key luk[])
  78. { return spok[0] == luk[0] && spok[1] == luk[1] && spok[2] == luk[2]; }
  79. /* * * CALLBACKS * * */
  80. uint64_t trp_key_hash_fn (
  81. const void *item, uint64_t seed0, uint64_t seed1)
  82. {
  83. (void) seed1;
  84. return (uint64_t) (VOLK_HASH (item, TRP_KLEN, seed0));
  85. }
  86. int trp_key_cmp_fn (const void *a, const void *b, void *udata)
  87. {
  88. (void) udata;
  89. return memcmp (a, b, TRP_KLEN);
  90. }
  91. /**
  92. * Hash callback function for index hashmap.
  93. */
  94. static uint64_t htstore_idx_hash_fn (
  95. const void *item, uint64_t seed0, uint64_t seed1)
  96. {
  97. (void) seed0;
  98. (void) seed1;
  99. return ((IndexEntry *) item)->key;
  100. }
  101. /**
  102. * Compare callback function for index hashmap.
  103. */
  104. static int htstore_idx_cmp_fn (const void *a, const void *b, void *udata)
  105. {
  106. (void) udata;
  107. return ((const IndexEntry *) a)->key - ((const IndexEntry *) b)->key;
  108. }
  109. /**
  110. * Delete callback function for hashmap.
  111. */
  112. static void htstore_idx_free_fn (void *item)
  113. { free (((IndexEntry *) item)->data); }
  114. /* * * Other prototypes. * * */
  115. inline static VOLK_rc
  116. tkey_to_strp (
  117. const HTStore *store, const VOLK_Key *spok, VOLK_BufferTriple *sspo);
  118. static VOLK_rc
  119. add_key_iter (HTIterator *it, const VOLK_Key *spok);
  120. /** @brief Advance iterator by next key.
  121. *
  122. * Result is stored in it->entry.
  123. */
  124. static VOLK_rc
  125. htiter_next_key (HTIterator *it);
  126. /*
  127. * Interface members.
  128. */
  129. /** @brief Create a store for an individual graph.
  130. *
  131. * @param[in] id Graph identifier. This may or may not be set. The store does
  132. * not use this value internally, and does not check for duplicates.
  133. *
  134. * @param[in] size Initial size of the store (in number of triples to
  135. * preallocate). It may be 0.
  136. *
  137. * @return New graph store.
  138. */
  139. static void *
  140. htstore_new (const char *id, size_t size)
  141. {
  142. (void) id;
  143. HTStore *ht;
  144. CALLOC_GUARD (ht, NULL);
  145. ht->idx = hashmap_new (
  146. sizeof (IndexEntry), 0, VOLK_HASH_SEED, 0,
  147. htstore_idx_hash_fn, htstore_idx_cmp_fn, htstore_idx_free_fn,
  148. NULL);
  149. ht->keys = hashmap_new (
  150. sizeof (VOLK_TripleKey), size, VOLK_HASH_SEED, 0,
  151. trp_key_hash_fn, trp_key_cmp_fn, NULL,
  152. NULL);
  153. return ht;
  154. }
  155. #if 0
  156. static VOLK_rc
  157. htstore_copy_contents (HTStore *dest, const HTStore *src)
  158. {
  159. size_t i = 0;
  160. VOLK_TripleKey *spok;
  161. IndexEntry *entry;
  162. while (hashmap_iter (src->keys, &i, (void **) &spok)) {
  163. hashmap_set (dest->keys, spok);
  164. if (UNLIKELY (hashmap_oom (dest->keys))) return VOLK_MEM_ERR;
  165. }
  166. i = 0;
  167. while (hashmap_iter (src->idx, &i, (void **) &entry)) {
  168. hashmap_set (dest->idx, entry);
  169. if (UNLIKELY (hashmap_oom (dest->idx))) return VOLK_MEM_ERR;
  170. }
  171. return VOLK_OK;
  172. }
  173. #endif
  174. static void
  175. htstore_free (void *h)
  176. {
  177. HTStore *store = h;
  178. hashmap_free (store->idx);
  179. hashmap_free (store->keys);
  180. free (store);
  181. }
  182. static size_t
  183. htstore_size (const void *h)
  184. {
  185. const HTStore *store = h;
  186. return hashmap_count (store->keys);
  187. }
  188. static VOLK_rc
  189. htstore_add_term (void *h, const VOLK_Buffer *sterm, void *_unused)
  190. {
  191. (void) _unused;
  192. HTStore *store = h;
  193. IndexEntry entry_s = {
  194. .key = VOLK_buffer_hash (sterm),
  195. };
  196. if (hashmap_get (store->idx, &entry_s)) return VOLK_NOACTION;
  197. entry_s.data = malloc (sterm->size);
  198. memcpy (entry_s.data, sterm->addr, sterm->size);
  199. entry_s.size = sterm->size;
  200. LOG_TRACE("Adding term key: %lx", entry_s.key);
  201. hashmap_set (store->idx, &entry_s);
  202. //LOG_TRACE("Term index size: %lu", hashmap_count (store->idx));
  203. return VOLK_OK;
  204. }
  205. static void *
  206. htstore_add_init (void *h, const VOLK_Buffer *_unused, void *_unused2)
  207. {
  208. (void) _unused;
  209. (void) _unused2;
  210. HTIterator *it;
  211. MALLOC_GUARD (it, NULL);
  212. it->store = h;
  213. return it;
  214. }
  215. static VOLK_rc
  216. htstore_add_iter (void *h, const VOLK_BufferTriple *sspo)
  217. {
  218. HTIterator *it = h;
  219. VOLK_TripleKey spok = {
  220. VOLK_buffer_hash (sspo->s),
  221. VOLK_buffer_hash (sspo->p),
  222. VOLK_buffer_hash (sspo->o),
  223. };
  224. VOLK_rc rc = add_key_iter (it, spok);
  225. if (rc != VOLK_OK) return rc;
  226. for (int i = 0; i < 3; i++)
  227. htstore_add_term (it->store, VOLK_btriple_pos (sspo, i), NULL);
  228. return rc;
  229. }
  230. static VOLK_rc
  231. htstore_add_done (void *h)
  232. {
  233. free (h);
  234. return VOLK_OK;
  235. }
  236. static void *
  237. htstore_lookup (
  238. void *h,
  239. const VOLK_Buffer *ss, const VOLK_Buffer *sp, const VOLK_Buffer *so,
  240. const VOLK_Buffer *_unused, void *_unused2, size_t *ct)
  241. {
  242. (void) _unused;
  243. (void) _unused2;
  244. HTStore *store = h;
  245. HTIterator *it;
  246. CALLOC_GUARD (it, NULL);
  247. it->store = store;
  248. it->rc = VOLK_END;
  249. if (ct) *ct = 0;
  250. if (hashmap_count (store->keys) == 0) return it;
  251. it->luk[0] = VOLK_buffer_hash (ss);
  252. it->luk[1] = VOLK_buffer_hash (sp);
  253. it->luk[2] = VOLK_buffer_hash (so);
  254. // s p o
  255. if (ss && sp && so) {
  256. it->eq_fn = lookup_spok_eq_fn;
  257. } else if (ss) {
  258. // s p ?
  259. if (sp) {
  260. it->eq_fn = lookup_spk_eq_fn;
  261. // s ? o
  262. } else if (so) {
  263. it->eq_fn = lookup_sok_eq_fn;
  264. // s ? ?
  265. } else {
  266. it->eq_fn = lookup_sk_eq_fn;
  267. }
  268. } else if (sp) {
  269. // ? p o
  270. if (so) {
  271. it->eq_fn = lookup_pok_eq_fn;
  272. // ? p ?
  273. } else it->eq_fn = lookup_pk_eq_fn;
  274. // ? ? o
  275. } else if (so) {
  276. it->eq_fn = lookup_ok_eq_fn;
  277. // ? ? ?
  278. } else it->eq_fn = lookup_none_eq_fn;
  279. LOG_TRACE("LUK: {%lx, %lx, %lx}", it->luk[0], it->luk[1], it->luk[2]);
  280. if (ct) {
  281. // Loop over results to determine count.
  282. while (htiter_next_key (it) == VOLK_OK) (*ct)++;
  283. // Reposition cursor to the hashtable beginning.
  284. it->cur = 0;
  285. it->rc = VOLK_OK;
  286. }
  287. return it;
  288. }
  289. static VOLK_rc
  290. htstore_remove(
  291. void *h, const VOLK_Buffer *ss, const VOLK_Buffer *sp,
  292. const VOLK_Buffer *so, const VOLK_Buffer *_unused,
  293. void *_unused2, size_t *ct_p)
  294. {
  295. (void) _unused;
  296. (void) _unused2;
  297. HTStore *store = h;
  298. size_t ct;
  299. HTIterator *it = htstore_lookup (store, ss, sp, so, NULL, NULL, &ct);
  300. if (UNLIKELY (!it)) return VOLK_DB_ERR;
  301. VOLK_rc rc;
  302. if (ct == 0) {
  303. rc = VOLK_NOACTION;
  304. goto finally;
  305. }
  306. while (htiter_next_key (it) == VOLK_OK) {
  307. LOG_TRACE(
  308. "Deleting {%lx, %lx, %lx}.",
  309. it->entry[0][0], it->entry[0][1], it->entry[0][2]);
  310. hashmap_delete (store->keys, it->entry);
  311. rc = VOLK_OK;
  312. it->cur = 0; // Reset cursor, buckets are rearranged after deletion.
  313. }
  314. finally:
  315. free (it);
  316. if (ct_p) *ct_p = ct;
  317. return rc;
  318. }
  319. static VOLK_rc
  320. htiter_next_key (HTIterator *it)
  321. {
  322. if (UNLIKELY (!it)) return VOLK_VALUE_ERR;
  323. // This value is for internal looping only. It shall never be returned.
  324. it->rc = VOLK_NORESULT;
  325. do {
  326. // Loop through all triples until a match is found, or end is reached.
  327. if (hashmap_iter (it->store->keys, &it->cur, (void **) &it->entry)) {
  328. //LOG_TRACE("it->cur: %lu", it->cur);
  329. if (it->eq_fn (*it->entry, it->luk)) {
  330. LOG_TRACE(
  331. "Found spok: {%lx, %lx, %lx}",
  332. it->entry[0][0], it->entry[0][1], it->entry[0][2]
  333. );
  334. it->rc = VOLK_OK;
  335. }
  336. }
  337. else it->rc = VOLK_END;
  338. } while (it->rc == VOLK_NORESULT);
  339. return it->rc;
  340. }
  341. static VOLK_rc
  342. htiter_next (void *h, VOLK_BufferTriple *sspo, VOLK_Buffer **_unused)
  343. {
  344. (void) _unused;
  345. HTIterator *it = h;
  346. VOLK_rc rc = htiter_next_key (it);
  347. if (rc != VOLK_OK) return rc;
  348. return tkey_to_strp (it->store, *it->entry, sspo);
  349. }
  350. const VOLK_StoreInt htstore_int = {
  351. .name = "Hashtable Store",
  352. .features = VOLK_STORE_COW,
  353. .setup_fn = NULL,
  354. .new_fn = htstore_new,
  355. .free_fn = htstore_free,
  356. .size_fn = htstore_size,
  357. .add_init_fn = htstore_add_init,
  358. .add_iter_fn = htstore_add_iter,
  359. .add_done_fn = htstore_add_done,
  360. .add_term_fn = htstore_add_term,
  361. .lookup_fn = htstore_lookup,
  362. .lu_next_fn = htiter_next,
  363. .lu_free_fn = free,
  364. .remove_fn = htstore_remove,
  365. };
  366. /*
  367. * Other statics.
  368. */
  369. inline static VOLK_rc
  370. tkey_to_strp (
  371. const HTStore *store, const VOLK_Key *spok, VOLK_BufferTriple *sspo)
  372. {
  373. // Data owned by the store.
  374. const IndexEntry *tmp;
  375. for (int i = 0; i < 3; i++) {
  376. tmp = hashmap_get (store->idx, spok + i);
  377. if (UNLIKELY (!tmp)) return VOLK_DB_ERR;
  378. VOLK_btriple_pos(sspo, i)->addr = tmp->data;
  379. VOLK_btriple_pos(sspo, i)->size = tmp->size;
  380. VOLK_btriple_pos(sspo, i)->flags |= VOLK_BUF_BORROWED;
  381. }
  382. return VOLK_OK;
  383. }
  384. static VOLK_rc
  385. add_key_iter (HTIterator *it, const VOLK_Key *spok)
  386. {
  387. // Add triple.
  388. LOG_TRACE("Inserting spok: {%lx, %lx, %lx}", spok[0], spok[1], spok[2]);
  389. if (hashmap_get (it->store->keys, spok)) {
  390. LOG_TRACE("Triple found. Not adding.");
  391. return VOLK_NOACTION;
  392. }
  393. LOG_TRACE("Triple not found, inserting.");
  394. hashmap_set (it->store->keys, (void *)spok);
  395. if (hashmap_oom(it->store->keys)) return VOLK_MEM_ERR;
  396. return VOLK_OK;
  397. }