graph.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. #include "graph.h"
  2. /*
  3. * Data types.
  4. */
  5. struct graph_t {
  6. LSUP_Term *uri; ///< Graph "name" (URI).
  7. LSUP_Store * store; ///< Store handle.
  8. LSUP_NSMap * nsm; /**< Namespace map.
  9. *
  10. * NOTE: This is
  11. * NULL for permanent stores.
  12. */
  13. void * txn; ///< Store transaction.
  14. };
  15. struct graph_iter_t {
  16. const LSUP_Graph * graph; ///< Parent graph.
  17. void * data; ///< Iterator state.
  18. size_t ct; ///< Total lookup matches.
  19. };
  20. /*
  21. * Static prototypes.
  22. */
  23. inline static LSUP_rc
  24. graph_iter_next_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo);
  25. #define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
  26. static inline bool
  27. check_backend (LSUP_StoreType be)
  28. { return (BACKEND_TBL false); }
  29. #undef ENTRY
  30. /*
  31. * Graph API.
  32. */
  33. LSUP_Graph *
  34. LSUP_graph_new (
  35. LSUP_Term *uri, const LSUP_StoreType store_type, const char *store_id,
  36. LSUP_NSMap *nsm, size_t size)
  37. {
  38. if (UNLIKELY (!LSUP_IS_INIT)) {
  39. log_error (
  40. "Environment is not initialized. Did you call LSUP_init()?");
  41. return NULL;
  42. }
  43. if (UNLIKELY (!check_backend (store_type))) return NULL;
  44. LSUP_Graph *gr;
  45. MALLOC_GUARD (gr, NULL);
  46. gr->uri = uri;
  47. MALLOC_GUARD (gr->store, NULL);
  48. gr->store->type = store_type;
  49. gr->store->id = store_id ? strdup (store_id) : NULL;
  50. switch (gr->store->type) {
  51. #define ENTRY(a, b) \
  52. case LSUP_STORE_##a: gr->store->sif = &b; break;
  53. BACKEND_TBL
  54. #undef ENTRY
  55. default:
  56. log_error ("Not a valid store type: %d", store_type); return NULL;
  57. };
  58. // TODO implement custom default context.
  59. gr->store->data = gr->store->sif->new_fn (store_id, size);
  60. if (gr->store->sif->features & LSUP_STORE_PERM) gr->nsm = NULL;
  61. else gr->nsm = nsm ? nsm : LSUP_default_nsm;
  62. log_debug ("Graph created.");
  63. return gr;
  64. }
  65. LSUP_rc
  66. LSUP_graph_bool_op(
  67. const LSUP_bool_op op, const LSUP_Graph *gr1, const LSUP_Graph *gr2,
  68. void *txn, LSUP_Graph *res)
  69. {
  70. LSUP_rc rc = LSUP_NOACTION;
  71. if (UNLIKELY (
  72. op != LSUP_BOOL_UNION
  73. && op != LSUP_BOOL_SUBTRACTION
  74. && op != LSUP_BOOL_INTERSECTION
  75. && op != LSUP_BOOL_XOR)) {
  76. log_error ("Invalid boolean operation: %d.", op);
  77. return LSUP_VALUE_ERR;
  78. }
  79. if (op == LSUP_BOOL_UNION) {
  80. rc = LSUP_graph_copy_contents (gr1, res);
  81. PCHECK (rc, fail);
  82. rc = LSUP_graph_copy_contents (gr2, res);
  83. PCHECK (rc, fail);
  84. return LSUP_OK;
  85. }
  86. LSUP_Buffer
  87. *res_sc = LSUP_term_serialize (res->uri),
  88. *gr1_sc = LSUP_term_serialize (gr1->uri),
  89. *gr2_sc = LSUP_term_serialize (gr2->uri);
  90. void *lu1_it, *lu2_it, *add_it;
  91. LSUP_BufferTriple *sspo = BTRP_DUMMY;
  92. size_t ct;
  93. add_it = res->store->sif->add_init_fn (res->store->data, res_sc, txn);
  94. if (op == LSUP_BOOL_XOR) {
  95. // Add triples from gr2 if not found in gr1.
  96. lu2_it = gr2->store->sif->lookup_fn (
  97. gr2->store->data, NULL, NULL, NULL, gr2_sc, NULL, txn);
  98. while (gr2->store->sif->lu_next_fn (lu2_it, sspo, NULL) == LSUP_OK) {
  99. lu1_it = gr1->store->sif->lookup_fn (
  100. gr1->store->data, sspo->s, sspo->p, sspo->o, gr1_sc,
  101. txn, &ct);
  102. if (ct > 0)
  103. res->store->sif->add_iter_fn (add_it, sspo);
  104. gr1->store->sif->lu_free_fn (lu1_it);
  105. }
  106. gr2->store->sif->lu_free_fn (lu2_it);
  107. }
  108. lu1_it = gr1->store->sif->lookup_fn (
  109. gr1->store->data, NULL, NULL, NULL, gr1_sc, txn, NULL);
  110. while (gr1->store->sif->lu_next_fn (lu1_it, sspo, NULL) == LSUP_OK) {
  111. lu2_it = gr2->store->sif->lookup_fn (
  112. gr2->store->data, sspo->s, sspo->p, sspo->o, gr2_sc, txn, &ct);
  113. // For XOR and subtraction, add if not found.
  114. // For intersection, add if found.
  115. if ((ct == 0) ^ (op == LSUP_BOOL_INTERSECTION))
  116. res->store->sif->add_iter_fn (add_it, sspo);
  117. gr2->store->sif->lu_free_fn (lu2_it);
  118. }
  119. gr1->store->sif->lu_free_fn (lu1_it);
  120. res->store->sif->add_done_fn (add_it);
  121. LSUP_buffer_free (res_sc);
  122. LSUP_buffer_free (gr1_sc);
  123. LSUP_buffer_free (gr2_sc);
  124. return rc;
  125. fail:
  126. LSUP_graph_free (res);
  127. return rc;
  128. }
  129. void
  130. LSUP_graph_free (LSUP_Graph *gr)
  131. {
  132. if (UNLIKELY (!gr)) return;
  133. LSUP_term_free (gr->uri);
  134. free (gr->store->id);
  135. gr->store->sif->free_fn (gr->store->data);
  136. free (gr->store);
  137. free (gr);
  138. }
  139. LSUP_Term *
  140. LSUP_graph_uri (const LSUP_Graph *gr) { return gr->uri; }
  141. LSUP_rc
  142. LSUP_graph_set_uri (LSUP_Graph *gr, LSUP_Term *uri)
  143. {
  144. if (!LSUP_IS_IRI (uri)) {
  145. log_error ("Term provided is not a IRI.");
  146. return LSUP_VALUE_ERR;
  147. }
  148. LSUP_term_free (gr->uri);
  149. gr->uri = uri;
  150. return LSUP_OK;
  151. }
  152. LSUP_NSMap *
  153. LSUP_graph_namespace (const LSUP_Graph *gr)
  154. {
  155. // If nsm_get_fn is not defined, the store has no own NS map.
  156. if (!gr->store->sif->nsm_get_fn) return gr->nsm;
  157. return gr->store->sif->nsm_get_fn (gr->store->data);
  158. }
  159. void
  160. LSUP_graph_set_namespace (LSUP_Graph *gr, LSUP_NSMap *nsm)
  161. {
  162. if (!gr->store->sif->nsm_get_fn) gr->nsm = nsm;
  163. else log_warn ("Graph back end has a stored NS map.");
  164. }
  165. size_t
  166. LSUP_graph_size (const LSUP_Graph *gr)
  167. { return gr->store->sif->size_fn (gr->store->data); }
  168. bool
  169. LSUP_graph_equals (const LSUP_Graph *gr1, const LSUP_Graph *gr2)
  170. {
  171. LSUP_Graph *res = LSUP_graph_new (NULL, LSUP_STORE_HTABLE, NULL, NULL, 0);
  172. LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2, gr1->txn, res);
  173. bool ret = (LSUP_graph_size (res) == 0);
  174. LSUP_graph_free (res);
  175. return ret;
  176. }
  177. LSUP_GraphIterator *
  178. LSUP_graph_add_init (LSUP_Graph *gr)
  179. {
  180. LSUP_GraphIterator *it;
  181. CALLOC_GUARD (it, NULL);
  182. LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
  183. it->data = gr->store->sif->add_init_fn (gr->store->data, sc, gr->txn);
  184. LSUP_buffer_free (sc);
  185. it->graph = gr;
  186. return it;
  187. }
  188. LSUP_rc
  189. LSUP_graph_add_iter (LSUP_GraphIterator *it, const LSUP_Triple *spo)
  190. {
  191. LSUP_BufferTriple *sspo = LSUP_triple_serialize (spo);
  192. if (UNLIKELY (!sspo)) return LSUP_MEM_ERR;
  193. const LSUP_StoreInt *sif = it->graph->store->sif;
  194. LSUP_rc rc = sif->add_iter_fn (it->data, sspo);
  195. PCHECK (rc, finally);
  196. // Store datatype term permanently if the store supports it.
  197. if (rc == LSUP_OK && sif->add_term_fn) {
  198. for (int i = 0; i < 3; i++) {
  199. LSUP_Term *term = LSUP_triple_pos (spo, i);
  200. if (term->type == LSUP_TERM_LITERAL) {
  201. LSUP_Buffer *ser_dtype = LSUP_term_serialize (term->datatype);
  202. sif->add_term_fn (
  203. it->graph->store->data, ser_dtype, it->graph->txn);
  204. LSUP_buffer_free (ser_dtype);
  205. }
  206. }
  207. }
  208. finally:
  209. LSUP_btriple_free (sspo);
  210. return rc;
  211. }
  212. void
  213. LSUP_graph_add_done (LSUP_GraphIterator *it)
  214. {
  215. it->graph->store->sif->add_done_fn (it->data);
  216. free (it);
  217. }
  218. LSUP_rc
  219. LSUP_graph_add (LSUP_Graph *gr, const LSUP_Triple trp[], size_t *ct)
  220. {
  221. LSUP_rc rc = LSUP_NOACTION;
  222. // Initialize iterator.
  223. LSUP_GraphIterator *it = LSUP_graph_add_init (gr);
  224. if (ct) *ct = 0;
  225. // Serialize and insert RDF triples.
  226. for (size_t i = 0; trp[i].s != NULL; i++) {
  227. log_trace ("Inserting triple #%lu", i);
  228. LSUP_rc db_rc = LSUP_graph_add_iter (it, trp + i);
  229. if (db_rc == LSUP_OK) {
  230. rc = LSUP_OK;
  231. if (ct) (*ct)++;
  232. // A duplicate will return LSUP_NOACTION and not increment the
  233. // counter.
  234. }
  235. if (UNLIKELY (db_rc < 0)) {
  236. rc = db_rc;
  237. goto finally;
  238. }
  239. }
  240. finally:
  241. LSUP_graph_add_done (it);
  242. return rc;
  243. }
  244. LSUP_rc
  245. LSUP_graph_remove (
  246. LSUP_Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
  247. const LSUP_Term *o, size_t *ct)
  248. {
  249. LSUP_rc rc;
  250. LSUP_Buffer
  251. *ss = LSUP_term_serialize (s),
  252. *sp = LSUP_term_serialize (p),
  253. *so = LSUP_term_serialize (o),
  254. *sc = LSUP_term_serialize (gr->uri);
  255. rc = gr->store->sif->remove_fn (
  256. gr->store->data, ss, sp, so, sc, gr->txn, ct);
  257. LSUP_buffer_free (ss);
  258. LSUP_buffer_free (sp);
  259. LSUP_buffer_free (so);
  260. LSUP_buffer_free (sc);
  261. return rc;
  262. }
  263. /**
  264. * Copy triples from a source graph into a destination one.
  265. *
  266. * The destination graph is not initialized here, so the copy is cumulative.
  267. */
  268. LSUP_rc
  269. LSUP_graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest)
  270. {
  271. LSUP_rc rc = LSUP_NOACTION;
  272. LSUP_GraphIterator *it = LSUP_graph_lookup (src, NULL, NULL, NULL, NULL);
  273. LSUP_Triple spo;
  274. LSUP_GraphIterator *add_it = LSUP_graph_add_init (dest);
  275. while (LSUP_graph_iter_next (it, &spo) != LSUP_END) {
  276. LSUP_rc add_rc = LSUP_graph_add_iter (add_it, &spo);
  277. LSUP_triple_done (&spo);
  278. if (LIKELY (add_rc == LSUP_OK)) rc = LSUP_OK;
  279. else if (add_rc < 0) {
  280. rc = add_rc;
  281. break;
  282. }
  283. }
  284. LSUP_graph_add_done (add_it);
  285. LSUP_graph_iter_free (it);
  286. return rc;
  287. }
  288. LSUP_GraphIterator *
  289. LSUP_graph_lookup (
  290. const LSUP_Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
  291. const LSUP_Term *o, size_t *ct)
  292. {
  293. LSUP_GraphIterator *it;
  294. MALLOC_GUARD (it, NULL);
  295. LSUP_Buffer
  296. *ss = LSUP_term_serialize (s),
  297. *sp = LSUP_term_serialize (p),
  298. *so = LSUP_term_serialize (o),
  299. *sc = LSUP_term_serialize (gr->uri);
  300. it->data = gr->store->sif->lookup_fn (
  301. gr->store->data, ss, sp, so, sc, gr->txn, ct);
  302. LSUP_buffer_free (ss);
  303. LSUP_buffer_free (sp);
  304. LSUP_buffer_free (so);
  305. LSUP_buffer_free (sc);
  306. if (UNLIKELY (!it->data)) {
  307. free (it);
  308. return NULL;
  309. }
  310. it->graph = gr;
  311. return it;
  312. }
  313. LSUP_rc
  314. LSUP_graph_iter_next (LSUP_GraphIterator *it, LSUP_Triple *spo)
  315. {
  316. LSUP_Buffer *ss, *sp, *so;
  317. LSUP_BufferTriple *sspo;
  318. if (it->graph->store->sif->features & LSUP_STORE_COW) {
  319. CALLOC_GUARD (ss, LSUP_MEM_ERR);
  320. CALLOC_GUARD (sp, LSUP_MEM_ERR);
  321. CALLOC_GUARD (so, LSUP_MEM_ERR);
  322. sspo = LSUP_btriple_new (ss, sp, so);
  323. } else {
  324. // TODO copy-on-retrieval stores. None yet.
  325. }
  326. LSUP_rc rc = graph_iter_next_buffer (it, sspo);
  327. if (rc == LSUP_OK) {
  328. spo->s = LSUP_term_new_from_buffer (sspo->s);
  329. if (!spo->s) return LSUP_ERROR;
  330. spo->p = LSUP_term_new_from_buffer (sspo->p);
  331. if (!spo->p) return LSUP_ERROR;
  332. spo->o = LSUP_term_new_from_buffer (sspo->o);
  333. if (!spo->o) return LSUP_ERROR;
  334. }
  335. if (it->graph->store->sif->features & LSUP_STORE_COW) {
  336. LSUP_btriple_free_shallow (sspo);
  337. } else {
  338. // TODO copy-on-retrieval stores. None yet.
  339. }
  340. return rc;
  341. }
  342. void
  343. LSUP_graph_iter_free (LSUP_GraphIterator *it)
  344. {
  345. it->graph->store->sif->lu_free_fn (it->data);
  346. free (it);
  347. }
  348. bool
  349. LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
  350. {
  351. LSUP_GraphIterator *it = LSUP_graph_lookup (
  352. gr, spo->s, spo->p, spo->o, NULL);
  353. LSUP_Triple *tmp_spo = TRP_DUMMY;
  354. bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
  355. LSUP_triple_free (tmp_spo);
  356. LSUP_graph_iter_free (it);
  357. return rc;
  358. }
  359. LSUP_rc
  360. LSUP_graph_begin (LSUP_Graph *gr, int flags) {
  361. if (!(gr->store->sif->features & LSUP_STORE_TXN)) return LSUP_VALUE_ERR;
  362. return gr->store->sif->txn_begin_fn(gr->store->data, flags, &gr->txn);
  363. }
  364. LSUP_rc
  365. LSUP_graph_commit (LSUP_Graph *gr)
  366. {
  367. LSUP_rc rc = gr->store->sif->txn_commit_fn (gr->txn);
  368. if (rc == LSUP_OK) gr->txn = NULL;
  369. return rc;
  370. }
  371. void
  372. LSUP_graph_abort (LSUP_Graph *gr)
  373. {
  374. gr->store->sif->txn_abort_fn (gr->txn);
  375. gr->txn = NULL;
  376. }
  377. /*
  378. * Static functions.
  379. */
  380. /** @brief Advance an iterator and return a serialized triple.
  381. *
  382. * This is an internal function to pass raw buffers between higher-level
  383. * functions without serializing and deserializing triples.
  384. */
  385. inline static LSUP_rc
  386. graph_iter_next_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo)
  387. { return it->graph->store->sif->lu_next_fn (it->data, sspo, NULL); }
  388. /**
  389. * Extern inline definitions.
  390. */
  391. size_t LSUP_graph_size (const LSUP_Graph *gr);