store_htable.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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. LSUP_Buffer * sterm; ///> Serialized term.
  11. } IndexEntry;
  12. typedef struct ht_store_t {
  13. struct hashmap * keys; ///> Triple keys (set).
  14. struct hashmap * idx; ///> Map of keys to serialized terms.
  15. } HTStore;
  16. typedef struct ht_iterator_t {
  17. HTStore * store; ///> Store being iterated.
  18. size_t cur; ///> Internal hash table cursor.
  19. LSUP_Key luk[3]; ///> 0÷3 lookup keys.
  20. LSUP_key_eq_fn_t eq_fn; ///> Equality function to test triples.
  21. int rc; ///> Return code for *next* result.
  22. ///> When the end of results is reached,
  23. ///> this is set to LSUP_END.
  24. LSUP_TripleKey * entry; ///> Retrieved SPO key.
  25. } HTIterator;
  26. /**
  27. * Dummy callback for queries with all parameters unbound. Returns true.
  28. */
  29. static bool lookup_none_eq_fn (
  30. const LSUP_Key spok[], const LSUP_Key luk[])
  31. { return true; }
  32. /**
  33. * Keyset lookup for S key.
  34. */
  35. static bool lookup_sk_eq_fn (
  36. const LSUP_Key spok[], const LSUP_Key luk[])
  37. { return spok[0] == luk[0]; }
  38. /**
  39. * Keyset lookup for P key.
  40. */
  41. static bool lookup_pk_eq_fn (
  42. const LSUP_Key spok[], const LSUP_Key luk[])
  43. { return spok[1] == luk[1]; }
  44. /**
  45. * Keyset lookup for O key.
  46. */
  47. static bool lookup_ok_eq_fn (
  48. const LSUP_Key spok[], const LSUP_Key luk[])
  49. { return spok[2] == luk[2]; }
  50. /**
  51. * Keyset lookup for S and P keys.
  52. */
  53. static bool lookup_spk_eq_fn (
  54. const LSUP_Key spok[], const LSUP_Key luk[])
  55. { return spok[0] == luk[0] && spok[1] == luk[1]; }
  56. /**
  57. * Keyset lookup for S and O keys.
  58. */
  59. static bool lookup_sok_eq_fn (
  60. const LSUP_Key spok[], const LSUP_Key luk[])
  61. { return spok[0] == luk[0] && spok[2] == luk[2]; }
  62. /**
  63. * Keyset lookup for P and O keys.
  64. */
  65. static bool lookup_pok_eq_fn (
  66. const LSUP_Key spok[], const LSUP_Key luk[])
  67. { return spok[1] == luk[1] && spok[2] == luk[2]; }
  68. /**
  69. * Keyset lookup for S, P and O keys.
  70. */
  71. static bool lookup_spok_eq_fn (
  72. const LSUP_Key spok[], const LSUP_Key luk[])
  73. { return spok[0] == luk[0] && spok[1] == luk[1] && spok[2] == luk[2]; }
  74. /* * * CALLBACKS * * */
  75. uint64_t trp_key_hash_fn (
  76. const void *item, uint64_t seed0, uint64_t seed1)
  77. { return (uint64_t) (LSUP_HASH (item, TRP_KLEN, seed0)); }
  78. int trp_key_cmp_fn (const void *a, const void *b, void *udata)
  79. { return memcmp (a, b, TRP_KLEN); }
  80. /**
  81. * Hash callback function for index hashmap.
  82. */
  83. static uint64_t htstore_idx_hash_fn (
  84. const void *item, uint64_t seed0, uint64_t seed1)
  85. { return ((IndexEntry *) item)->key; }
  86. /**
  87. * Compare callback function for index hashmap.
  88. */
  89. static int htstore_idx_cmp_fn (const void *a, const void *b, void *udata)
  90. { return ((const IndexEntry *) a)->key - ((const IndexEntry *) b)->key; }
  91. /**
  92. * Delete callback function for hashmap.
  93. */
  94. static void htstore_idx_free_fn (void *item)
  95. { LSUP_buffer_free (((IndexEntry *) item)->sterm); }
  96. /* * * Other prototypes. * * */
  97. inline static LSUP_rc
  98. tkey_to_strp (
  99. const HTStore *store, const LSUP_Key *spok, LSUP_BufferTriple *sspo);
  100. static LSUP_rc
  101. htstore_add_key_iter (HTIterator *it, const LSUP_Key *spok);
  102. /** @brief Advance iterator by next key.
  103. *
  104. * Result is stored in it->entry.
  105. */
  106. static LSUP_rc
  107. htiter_next_key (HTIterator *it);
  108. /* * * API * * */
  109. HTStore *
  110. LSUP_htstore_new (const size_t size)
  111. {
  112. HTStore *ht;
  113. CALLOC_GUARD (ht, NULL);
  114. ht->idx = hashmap_new (
  115. sizeof (IndexEntry), 0, LSUP_HASH_SEED, 0,
  116. htstore_idx_hash_fn, htstore_idx_cmp_fn, htstore_idx_free_fn,
  117. NULL);
  118. ht->keys = hashmap_new (
  119. sizeof (LSUP_TripleKey), size, LSUP_HASH_SEED, 0,
  120. trp_key_hash_fn, trp_key_cmp_fn, NULL,
  121. NULL);
  122. return ht;
  123. }
  124. HTStore *
  125. LSUP_htstore_copy (const HTStore *src)
  126. {
  127. HTStore *dest = LSUP_htstore_new (LSUP_htstore_size (src));
  128. if (UNLIKELY (!dest)) return NULL;
  129. if (UNLIKELY (LSUP_htstore_copy_contents (dest, src) < 0)) {
  130. LSUP_htstore_free (dest);
  131. return NULL;
  132. }
  133. return dest;
  134. }
  135. LSUP_rc
  136. LSUP_htstore_copy_contents (HTStore *dest, const HTStore *src)
  137. {
  138. size_t i = 0;
  139. LSUP_TripleKey *spok;
  140. IndexEntry *entry;
  141. while (hashmap_iter (src->keys, &i, (void **) &spok)) {
  142. hashmap_set (dest->keys, spok);
  143. if (UNLIKELY (hashmap_oom (dest->keys))) return LSUP_MEM_ERR;
  144. }
  145. i = 0;
  146. while (hashmap_iter (src->idx, &i, (void **) &entry)) {
  147. hashmap_set (dest->idx, entry);
  148. if (UNLIKELY (hashmap_oom (dest->idx))) return LSUP_MEM_ERR;
  149. }
  150. return LSUP_OK;
  151. }
  152. HTStore *
  153. LSUP_htstore_bool_op(
  154. const LSUP_bool_op op, const HTStore *s1, const HTStore *s2)
  155. {
  156. if (UNLIKELY (
  157. op != LSUP_BOOL_UNION
  158. && op != LSUP_BOOL_SUBTRACTION
  159. && op != LSUP_BOOL_INTERSECTION
  160. && op != LSUP_BOOL_XOR)) {
  161. log_error ("Invalid boolean operation.");
  162. return NULL;
  163. }
  164. HTStore *dest = LSUP_htstore_new (0);
  165. if (op == LSUP_BOOL_UNION) {
  166. dest = LSUP_htstore_copy (s1);
  167. if (UNLIKELY (!dest) || LSUP_htstore_copy_contents (dest, s2) < 0)
  168. goto fail;
  169. return dest;
  170. }
  171. LSUP_TripleKey *src_tkey;
  172. LSUP_HTIterator *it = LSUP_htstore_add_init(dest);
  173. size_t i = 0;
  174. if (op == LSUP_BOOL_XOR) {
  175. // Add triples from s2 if not found in s1.
  176. while (hashmap_iter (s2->keys, &i, (void **) &src_tkey)) {
  177. if (!hashmap_get (s1->keys, src_tkey))
  178. htstore_add_key_iter (it, *src_tkey);
  179. }
  180. }
  181. i = 0;
  182. while (hashmap_iter (s1->keys, &i, (void **) &src_tkey)) {
  183. // For XOR and subtraction, add if not found.
  184. // For intersection, add if found.
  185. if (
  186. (op == LSUP_BOOL_INTERSECTION)
  187. ^ (hashmap_get (s2->keys, src_tkey) == NULL)
  188. )
  189. htstore_add_key_iter (it, *src_tkey);
  190. }
  191. LSUP_htstore_add_done (it);
  192. return dest;
  193. fail:
  194. LSUP_htstore_free (dest);
  195. return NULL;
  196. }
  197. void
  198. LSUP_htstore_free (HTStore *ht)
  199. {
  200. hashmap_free (ht->idx);
  201. hashmap_free (ht->keys);
  202. free (ht);
  203. }
  204. size_t
  205. LSUP_htstore_size (const LSUP_HTStore *ht)
  206. { return hashmap_count (ht->keys); }
  207. LSUP_rc
  208. LSUP_htstore_add_term (HTStore *store, const LSUP_Buffer *sterm)
  209. {
  210. if (hashmap_get (store->idx, sterm)) return LSUP_NOACTION;
  211. LSUP_Key tk = LSUP_buffer_hash (sterm);
  212. log_trace ("Adding term key: %lx", tk);
  213. hashmap_set (
  214. store->idx, &(IndexEntry){
  215. .key = tk,
  216. // This shall be freed with the index hashmap.
  217. .sterm = LSUP_buffer_new (sterm->size, sterm->addr)
  218. });
  219. return LSUP_OK;
  220. }
  221. LSUP_HTIterator *
  222. LSUP_htstore_add_init (HTStore *store)
  223. {
  224. HTIterator *it;
  225. MALLOC_GUARD (it, NULL);
  226. it->store = store;
  227. return it;
  228. }
  229. LSUP_rc
  230. LSUP_htstore_add_iter (HTIterator *it, const LSUP_BufferTriple *sspo)
  231. {
  232. LSUP_TripleKey spok = {
  233. LSUP_buffer_hash (sspo->s),
  234. LSUP_buffer_hash (sspo->p),
  235. LSUP_buffer_hash (sspo->o),
  236. };
  237. LSUP_rc rc = htstore_add_key_iter (it, spok);
  238. if (rc != LSUP_OK) return rc;
  239. for (int i = 0; i < 3; i++) {
  240. rc = LSUP_htstore_add_term (it->store, LSUP_btriple_pos (sspo, i));
  241. if (rc != LSUP_OK) return rc;
  242. }
  243. return rc;
  244. }
  245. void
  246. LSUP_htstore_add_done (HTIterator *it)
  247. { LSUP_htiter_free (it); }
  248. LSUP_rc
  249. LSUP_htstore_remove(
  250. LSUP_HTStore *store, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
  251. const LSUP_Buffer *so, size_t *ct)
  252. {
  253. LSUP_rc rc = LSUP_NOACTION;
  254. LSUP_HTIterator *it = LSUP_htstore_lookup (store, ss, sp, so, ct);
  255. if (UNLIKELY (!it)) return LSUP_DB_ERR;
  256. while (htiter_next_key (it)) {
  257. if (it->rc == LSUP_OK) {
  258. LSUP_TripleKey *del = hashmap_delete (store->keys, it->entry);
  259. free (del);
  260. rc = LSUP_OK;
  261. }
  262. }
  263. LSUP_htiter_free (it);
  264. return rc;
  265. }
  266. HTIterator *
  267. LSUP_htstore_lookup (HTStore *store, const LSUP_Buffer *ss,
  268. const LSUP_Buffer *sp, const LSUP_Buffer *so, size_t *ct)
  269. {
  270. HTIterator *it;
  271. CALLOC_GUARD (it, NULL);
  272. it->store = store;
  273. it->rc = LSUP_END;
  274. if (hashmap_count (store->keys) == 0) return it;
  275. if (ct) *ct = 0;
  276. it->luk[0] = LSUP_buffer_hash (ss);
  277. it->luk[1] = LSUP_buffer_hash (sp);
  278. it->luk[2] = LSUP_buffer_hash (so);
  279. // s p o
  280. if (ss && sp && so) {
  281. it->eq_fn = lookup_spok_eq_fn;
  282. } else if (ss) {
  283. // s p ?
  284. if (sp) {
  285. it->eq_fn = lookup_spk_eq_fn;
  286. // s ? o
  287. } else if (so) {
  288. it->eq_fn = lookup_sok_eq_fn;
  289. // s ? ?
  290. } else {
  291. it->eq_fn = lookup_sk_eq_fn;
  292. }
  293. } else if (sp) {
  294. // ? p o
  295. if (so) {
  296. it->eq_fn = lookup_pok_eq_fn;
  297. // ? p ?
  298. } else it->eq_fn = lookup_pk_eq_fn;
  299. // ? ? o
  300. } else if (so) {
  301. it->eq_fn = lookup_ok_eq_fn;
  302. // ? ? ?
  303. } else it->eq_fn = lookup_none_eq_fn;
  304. log_trace ("LUK: {%lx, %lx, %lx}", it->luk[0], it->luk[1], it->luk[2]);
  305. if (ct) {
  306. // Loop over results to determine count.
  307. while (htiter_next_key (it) == LSUP_OK) {
  308. (*ct)++;
  309. log_trace ("ct: %lu", *ct);
  310. }
  311. // Reposition cursor to the hashtable beginning.
  312. it->cur = 0;
  313. it->rc = LSUP_OK;
  314. }
  315. return it;
  316. }
  317. void
  318. LSUP_htiter_free (LSUP_HTIterator *it)
  319. { free (it); }
  320. LSUP_rc
  321. htiter_next_key (HTIterator *it)
  322. {
  323. if (UNLIKELY (!it)) return LSUP_VALUE_ERR;
  324. // This value is for internal looping only. It shall never be returned.
  325. it->rc = LSUP_NORESULT;
  326. do {
  327. // Loop through all triples until a match is found, or end is reached.
  328. if (hashmap_iter (it->store->keys, &it->cur, (void **) &it->entry)) {
  329. //log_trace("it->cur: %lu", it->cur);
  330. if (it->eq_fn (*it->entry, it->luk)) {
  331. log_trace (
  332. "Found spok: {%lx, %lx, %lx}",
  333. it->entry[0][0], it->entry[0][1], it->entry[0][2]
  334. );
  335. it->rc = LSUP_OK;
  336. }
  337. }
  338. else it->rc = LSUP_END;
  339. } while (it->rc == LSUP_NORESULT);
  340. return it->rc;
  341. }
  342. LSUP_rc
  343. LSUP_htiter_next (HTIterator *it, LSUP_BufferTriple *sspo)
  344. {
  345. LSUP_rc rc = htiter_next_key (it);
  346. if (rc != LSUP_OK) return rc;
  347. return tkey_to_strp (it->store, *it->entry, sspo);
  348. }
  349. /* * * Statics * * */
  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. tmp = hashmap_get (store->idx, spok + 0);
  357. if (UNLIKELY (!tmp)) return LSUP_DB_ERR;
  358. sspo->s = tmp->sterm;
  359. tmp = hashmap_get (store->idx, spok + 1);
  360. if (UNLIKELY (!tmp)) return LSUP_DB_ERR;
  361. sspo->p = tmp->sterm;
  362. tmp = hashmap_get (store->idx, spok + 2);
  363. if (UNLIKELY (!tmp)) return LSUP_DB_ERR;
  364. sspo->o = tmp->sterm;
  365. return LSUP_OK;
  366. }
  367. static LSUP_rc
  368. htstore_add_key_iter (HTIterator *it, const LSUP_Key *spok)
  369. {
  370. // Add triple.
  371. log_trace ("Inserting spok: {%lx, %lx, %lx}", spok[0], spok[1], spok[2]);
  372. if (hashmap_get (it->store->keys, spok)) {
  373. log_trace ("Triple found. Not adding.");
  374. return LSUP_NOACTION;
  375. }
  376. log_trace ("Triple not found, inserting.");
  377. hashmap_set (it->store->keys, (void *)spok);
  378. if (hashmap_oom(it->store->keys)) return LSUP_MEM_ERR;
  379. return LSUP_OK;
  380. }