store_htable.c 11 KB

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