Volksdata 1.0b12
RDF library and triple store
Loading...
Searching...
No Matches
graph.c
Go to the documentation of this file.
1#include "volksdata/graph.h"
2
3/*
4 * Data types.
5 */
6
11
13 const VOLK_Graph * graph;
14 void * data;
15 size_t ct;
21};
22
23
24/*
25 * Static prototypes.
26 */
27
28inline static VOLK_rc
29graph_iter_next_buffer (VOLK_GraphIterator *it);
30
31
32/*TODO
33#define ENTRY(a, b) (be) == (VOLK_STORE_##a) ||
34static inline bool
35check_backend (VOLK_StoreType be)
36{ return (BACKEND_TBL false); }
37#undef ENTRY
38*/
39
40/*
41 * Graph API.
42 */
43
44VOLK_Graph *
45VOLK_graph_new (VOLK_Store *store, const char *uri_str)
46{
47 // Create a HTable graph by default.
48 VOLK_Graph *gr;
49 MALLOC_GUARD (gr, NULL);
50
51 gr->uri =
52 uri_str? VOLK_iriref_new (uri_str) :
53 VOLK_iriref_new (NULL);
54 NLNL (gr->uri);
55
56 // An embedded store has the same ID as the graph.
57 gr->store = (store) ? store : VOLK_store_new (
58 VOLK_STORE_HTABLE, gr->uri->data, 0, false);
59 NLNL (gr->store);
60
61 log_debug ("Graph created.");
62 return gr;
63}
64
65
66VOLK_Graph *
68 void *txn, VOLK_Store *store, const VOLK_Term *uri, size_t *ct)
69{
71 void *it = VOLK_store_lookup_txn (
72 store, txn, NULL, NULL, NULL, sc, NULL);
73
74 void *_txn;
75 if (txn) _txn = txn;
76 else if (VOLK_store_features (store) & VOLK_STORE_TXN) {
77 RCNL (VOLK_store_begin (store, 0, &_txn));
78 } else _txn = NULL;
79
80 VOLK_Graph *gr = VOLK_graph_new (NULL, uri->data);
82 void *add_it = VOLK_graph_add_init_txn (_txn, gr);
83
84 size_t _ct = 0;
85 while (VOLK_store_iter_next (store, it, sspo, NULL) == VOLK_OK) {
86 // This is deserializing a buffer triple that will be re-serialized by
87 // VOLK_graph_add_iter. But it's necessary to relativize URIs.
89 VOLK_graph_add_iter (add_it, spo);
90 VOLK_triple_free (spo);
91 _ct++;
92 }
93 VOLK_graph_iter_free (add_it);
94 VOLK_store_iter_free (store, it);
96 VOLK_btriple_free (sspo);
97
98 // Do not create a new graph if no results were found.
99 if (_ct == 0) {
100 VOLK_graph_free (gr);
101 gr = NULL;
102 }
103 if (ct) *ct = _ct;
104 if (_txn != txn) VOLK_store_abort (store, _txn);
105
106 return gr;
107}
108
109
112 void *txn, const VOLK_bool_op op,
113 const VOLK_Graph *gr1, const VOLK_Graph *gr2, VOLK_Graph *res)
114{
116 if (UNLIKELY (
117 op != VOLK_BOOL_UNION
118 && op != VOLK_BOOL_SUBTRACTION
120 && op != VOLK_BOOL_XOR)) {
121 log_error ("Invalid boolean operation: %d.", op);
122
123 return VOLK_VALUE_ERR;
124 }
125
126 /*
127 * Graphs could possibly be in different storage back ends, and may or
128 * may not have independently opened transactions, so they have to be
129 * handled individually.
130 */
131 void
132 *lu1_txn = NULL,
133 *lu2_txn = NULL,
134 *res_txn = NULL;
135
136 /* BEGIN union block. */
137
138 if (op == VOLK_BOOL_UNION) {
139 // No need to use a transaction here: the graph is freed on failure.
140 rc = VOLK_graph_copy_contents (gr1, res, NULL, NULL, NULL);
141 PCHECK (rc, fail);
142 rc = VOLK_graph_copy_contents (gr2, res, NULL, NULL, NULL);
143 PCHECK (rc, fail);
144
145 return VOLK_OK;
146 }
147
148 /* END union block. */
149
151 *res_sc = VOLK_store_features (res->store) & VOLK_STORE_CTX ?
152 VOLK_term_serialize (res->uri) : NULL,
153 *gr1_sc = VOLK_store_features (gr1->store) & VOLK_STORE_CTX ?
154 VOLK_term_serialize (gr1->uri) : NULL,
155 *gr2_sc = VOLK_store_features (gr2->store) & VOLK_STORE_CTX ?
156 VOLK_term_serialize (gr2->uri) : NULL;
157 void *lu1_it, *lu2_it, *add_it;
159 size_t ct;
160
161 // Whether gr1 or gr2 txn will be open independently from res txn.
162 bool
163 open_txn1 = false,
164 open_txn2 = false;
165
166 // TODO check for transaction consistency here, and if it needs a separate
167 // transaction handle.
168 add_it = VOLK_store_add_init_txn (res->store, txn, res_sc);
169
170 if (VOLK_store_features (res->store) & VOLK_STORE_TXN)
171 res_txn = VOLK_store_iter_txn (res->store, add_it);
172
173 /* If either source graph is in the same store as the destination and has
174 * an open transaction, reuse that transaction. A new reader cannot be
175 * opened in LMDB while a writer is open already.
176 */
177 // Handle gr1 transaction.
178 if (VOLK_store_features (gr1->store) & VOLK_STORE_TXN) {
179 if (gr1->store == res->store) lu1_txn = res_txn;
180 else {
182 gr1->store, VOLK_STORE_TXN_RO, &lu1_txn), fail);
183 open_txn1 = true;
184 }
185 }
186
187 // Handle gr2 transaction.
188 if (VOLK_store_features (gr2->store) & VOLK_STORE_TXN) {
189 if (gr2->store == res->store) lu2_txn = res_txn;
190 else if (gr2->store == gr1->store) lu2_txn = lu1_txn;
191 // FIXME: see above.
192 else {
194 gr2->store, VOLK_STORE_TXN_RO, &lu2_txn), fail);
195 open_txn2 = true;
196 }
197 }
198 log_trace (
199 "lu1_txn: %p ; lu2_txn: %p ; res_txn: %p",
200 lu1_txn, lu2_txn, res_txn);
201
202 /* BEGIN XOR block. */
203
204 if (op == VOLK_BOOL_XOR) {
205 // Add triples from gr2 if not found in gr1.
206 lu2_it = VOLK_store_lookup_txn (
207 gr2->store, lu2_txn, NULL, NULL, NULL, gr2_sc, NULL);
208 while (VOLK_store_iter_next (
209 gr2->store, lu2_it, sspo, NULL) == VOLK_OK) {
210 lu1_it = VOLK_store_lookup_txn (
211 gr1->store, lu1_txn, sspo->s, sspo->p, sspo->o, gr1_sc, &ct
212 );
213 if (ct == 0) {
214 VOLK_store_add_iter (res->store, add_it, sspo);
215 rc = VOLK_OK;
216 }
217 VOLK_store_iter_free (gr1->store, lu1_it);
218 }
219 VOLK_store_iter_free (gr2->store, lu2_it);
220 }
221
222 /* BEGIN subtraction and intersection block. */
223
224 lu1_it = VOLK_store_lookup_txn (
225 gr1->store, lu1_txn, NULL, NULL, NULL, gr1_sc, NULL);
226 while (VOLK_store_iter_next (gr1->store, lu1_it, sspo, NULL) == VOLK_OK) {
227 lu2_it = VOLK_store_lookup_txn (
228 gr2->store, lu2_txn, sspo->s, sspo->p, sspo->o, gr2_sc, &ct);
229 if (UNLIKELY (!lu2_it)) {
230 rc = VOLK_DB_ERR;
231 VOLK_store_iter_free (gr1->store, lu1_it);
232 goto fail;
233 }
234 // For XOR and subtraction, add if not found.
235 // For intersection, add if found.
236 if ((ct == 0) ^ (op == VOLK_BOOL_INTERSECTION)) {
237 VOLK_store_add_iter (res->store, add_it, sspo);
238 rc = VOLK_OK;
239 }
240 VOLK_store_iter_free (gr2->store, lu2_it);
241 }
242 VOLK_store_iter_free (gr1->store, lu1_it);
243
244 if (open_txn1) VOLK_store_commit (gr1->store, lu1_txn);
245 if (open_txn2) VOLK_store_commit (gr2->store, lu2_txn);
246
247 VOLK_store_add_done (res->store, add_it);
248 VOLK_btriple_free (sspo);
249 VOLK_buffer_free (res_sc);
250 VOLK_buffer_free (gr1_sc);
251 VOLK_buffer_free (gr2_sc);
252
253 /* END subtraction, intersection, XOR block. */
254
255 return rc;
256
257fail:
258 if (lu1_txn) VOLK_store_abort (gr1->store, lu1_txn);
259 if (lu2_txn) VOLK_store_abort (gr2->store, lu2_txn);
260 VOLK_graph_free (res);
261 return rc;
262}
263
264
265void
266VOLK_graph_free (VOLK_Graph *gr)
267{
268 if (UNLIKELY (!gr)) return;
269
270 VOLK_term_free (gr->uri);
271 // If the store is embedded, it goes away with the associated graph.
272 if (VOLK_store_features (gr->store) & VOLK_STORE_EMBED) {
273 VOLK_store_free (gr->store);
274 }
275
276 free (gr);
277}
278
279
280const VOLK_Term *
281VOLK_graph_uri (const VOLK_Graph *gr) { return gr->uri; }
282
283
285VOLK_graph_store (const VOLK_Graph *gr)
286{ return gr->store; }
287
288
290VOLK_graph_set_uri_txn (void *txn, VOLK_Graph *gr, const char *uri_str)
291{
292 VOLK_rc rc = VOLK_OK;
293 VOLK_Buffer *old_sc = NULL, *new_sc = NULL;
294
295 VOLK_Term *uri = VOLK_iriref_new (uri_str);
296 if (UNLIKELY (!uri)) {
297 rc = VOLK_MEM_ERR;
298 goto finally;
299 }
300
301 // Update context for triples in the graph.
302 if (VOLK_store_features (gr->store) & VOLK_STORE_CTX) {
303 old_sc = VOLK_term_serialize (gr->uri);
304 new_sc = VOLK_term_serialize (uri);
305 if (UNLIKELY (!old_sc || !new_sc)) {
306 rc = VOLK_MEM_ERR;
307 goto finally;
308 }
309
310 PCHECK (
311 rc = VOLK_store_update_ctx_txn (gr->store, txn, old_sc, new_sc),
312 finally
313 );
314
315 // Overall success even if rc of underlying fn was VOLK_NOACTION.
316 if (rc == VOLK_NOACTION) rc = VOLK_OK;
317 }
318
319 VOLK_term_free (gr->uri);
320 gr->uri = uri;
321
322finally:
323 if (old_sc) VOLK_buffer_free (old_sc);
324 if (new_sc) VOLK_buffer_free (new_sc);
325
326 return rc;
327}
328
329
330size_t
331VOLK_graph_size_txn (void *txn, const VOLK_Graph *gr)
332{
333 void *_txn;
334 if (txn) _txn = txn;
335 else if (VOLK_store_features (gr->store) & VOLK_STORE_TXN)
336 RCCK (VOLK_store_begin (gr->store, 0, &_txn));
337 else _txn = NULL;
338
339 size_t ct = 0;
340 VOLK_Buffer *sc =
341 VOLK_store_features (gr->store) & VOLK_STORE_TXN ?
342 VOLK_term_serialize (gr->uri) : NULL;
343 void *it = VOLK_store_lookup_txn (
344 gr->store, _txn, NULL, NULL, NULL, sc, &ct);
345 if (!it) {
346 log_error ("Error initializing lookup.");
347 ct = -1;
348 }
349 VOLK_store_iter_free (gr->store, it);
350
351 VOLK_buffer_free (sc);
352 if (_txn != txn) VOLK_store_abort (gr->store, _txn);
353
354 return ct;
355}
356
357
358bool
359VOLK_graph_equals_txn (void *txn, const VOLK_Graph *gr1, const VOLK_Graph *gr2)
360{
361 void *_txn1, *_txn2;
362 if (txn) {
363 if (gr1->store == gr2->store) _txn2 = _txn1 = txn;
364 else {
365 log_error (
366 "Graphs must be from the same store when a transaction handle "
367 "is passed."
368 );
369 return false;
370 }
371 }
372 else {
373 if (VOLK_store_features (gr1->store) & VOLK_STORE_TXN)
374 RCCK (VOLK_store_begin (gr1->store, VOLK_STORE_TXN_RO, &_txn1));
375 else _txn1 = NULL;
376
377 if (gr2->store == gr1->store) _txn2 = _txn1;
378 else if (VOLK_store_features (gr2->store) & VOLK_STORE_TXN)
379 RCCK (VOLK_store_begin (gr2->store, VOLK_STORE_TXN_RO, &_txn2));
380 else _txn2 = NULL;
381 }
382
383 VOLK_Triple *spo = NULL;
384 bool match = true;
385
386 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
387 _txn1, gr1, NULL, NULL, NULL, NULL);
388 NLNL (it);
389 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
390 match = VOLK_graph_contains_txn (_txn2, gr2, spo);
391 VOLK_triple_free (spo);
392 if (!match) goto finally;
393 }
395
397 _txn2, gr2, NULL, NULL, NULL, NULL);
398 NLNL (it);
399 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
400 match = VOLK_graph_contains_txn (_txn1, gr1, spo);
401 VOLK_triple_free (spo);
402 if (!match) goto finally;
403 }
404
405finally:
407 if (_txn1 != txn) VOLK_store_abort (gr1->store, _txn1);
408 if (_txn2 != txn && _txn2 != _txn1) VOLK_store_abort (gr2->store, _txn2);
409
410 return match;
411}
412
413
414VOLK_GraphIterator *
415VOLK_graph_add_init_txn (void *txn, VOLK_Graph *gr)
416{
417 VOLK_GraphIterator *it;
418 CALLOC_GUARD (it, NULL);
419
420 VOLK_Buffer *sc = VOLK_term_serialize (gr->uri);
421
422 it->data = VOLK_store_add_init_txn (gr->store, txn, sc);
423 VOLK_buffer_free (sc);
424
425 it->graph = gr;
426
427 return it;
428}
429
430
432VOLK_graph_add_iter (VOLK_GraphIterator *it, const VOLK_Triple *spo)
433{
434 log_trace (
435 "Adding triple {%s, %s, %s} to %s",
436 spo->s->data, spo->p->data, spo->o->data,
437 VOLK_graph_uri(it->graph)->data);
438
439 // Make relative s and o.
440 VOLK_Term *rel_s, *rel_o;
441 if (spo->s->type == VOLK_TERM_IRIREF)
442 rel_s = VOLK_iriref_new_rel (it->graph->uri, spo->s);
443 else rel_s = spo->s;
444 if (spo->o->type == VOLK_TERM_IRIREF)
445 rel_o = VOLK_iriref_new_rel (it->graph->uri, spo->o);
446 else rel_o = spo->o;
447
448 VOLK_Triple *rel_spo = VOLK_triple_new (rel_s, spo->p, rel_o);
449 log_trace (
450 "Adding relative triple: {%s, %s, %s}",
451 rel_s->data, spo->p->data, rel_o->data);
452
453 // Serialize relative triple.
455 NLRCCK (sspo, VOLK_MEM_ERR);
456
457 // Selectively free triple members and structure.
458 if (rel_s != spo->s) VOLK_term_free (rel_s);
459 if (rel_o != spo->o) VOLK_term_free (rel_o);
460 free (rel_spo);
461
462 VOLK_rc rc = VOLK_store_add_iter (it->graph->store, it->data, sspo);
463 PCHECK (rc, finally);
464
465 // Store datatype term permanently.
466 if (rc == VOLK_OK) {
467 for (int i = 0; i < 3; i++) {
468 VOLK_Term *term = VOLK_triple_pos (spo, i);
469 if (term->type == VOLK_TERM_LITERAL) {
470 VOLK_Buffer *ser_dtype = VOLK_term_serialize (term->datatype);
471 void *txn = VOLK_store_iter_txn (it->graph->store, it->data);
473 it->graph->store, txn, ser_dtype);
474 PCHECK (term_rc, finally);
475 VOLK_buffer_free (ser_dtype);
476 }
477 }
478 }
479
480
481finally:
482 VOLK_btriple_free (sspo);
483
484 return rc;
485}
486
487
490 void *txn, VOLK_Graph *gr, VOLK_Triple *const *trp, size_t *ct)
491{
493
494 // Initialize iterator.
495 VOLK_GraphIterator *it = VOLK_graph_add_init_txn (txn, gr);
496
497 if (ct) *ct = 0;
498 // Serialize and insert RDF triples.
499 for (size_t i = 0; trp[i] != NULL; i++) {
500 log_trace ("Inserting triple #%lu", i);
501
502 VOLK_rc db_rc = VOLK_graph_add_iter (it, trp[i]);
503
504 if (db_rc == VOLK_OK) {
505 rc = VOLK_OK;
506 if (ct) (*ct)++;
507 // A duplicate will return VOLK_NOACTION and not increment ct.
508 }
509 if (UNLIKELY (db_rc < 0)) {
510 rc = db_rc;
511 goto finally;
512 }
513 }
514
515finally:
517
518 return rc;
519}
520
521
524 void *txn, VOLK_Graph *gr,
525 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o,
526 size_t *ct)
527{
529 *ss = VOLK_term_serialize (s),
530 *sp = VOLK_term_serialize (p),
531 *so = VOLK_term_serialize (o),
532 *sc = VOLK_term_serialize (gr->uri);
533
534 log_debug (
535 "Removing triples by terms: %s %s %s",
536 s ? s->data : "<nil>",
537 p ? p->data : "<nil>",
538 o ? o->data : "<nil>"
539 );
540
542 gr->store, txn, ss, sp, so, sc, ct);
543
544 VOLK_buffer_free (ss);
545 VOLK_buffer_free (sp);
546 VOLK_buffer_free (so);
547 VOLK_buffer_free (sc);
548
549 return rc;
550}
551
552
555 void *txn, const VOLK_Graph *src, VOLK_Graph *dest,
556 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o)
557{
558 void *_txn1, *_txn2;
559 bool
560 src_is_txn = VOLK_store_features (src->store) & VOLK_STORE_TXN,
561 dest_is_txn = VOLK_store_features (dest->store) & VOLK_STORE_TXN;
562
563 if (txn) {
564 if (
565 src_is_txn && dest_is_txn &&
566 strcmp (src->store->id, dest->store->id)) {
567 log_error (
568 "Graphs must be from the same store when a transaction handle "
569 "is passed."
570 );
571 return VOLK_VALUE_ERR;
572 }
573 _txn1 = src_is_txn ? txn : NULL;
574 _txn2 = dest_is_txn ? txn : NULL;
575 } else {
576 if (src_is_txn)
577 RCCK (VOLK_store_begin (src->store, VOLK_STORE_TXN_RO, &_txn1));
578 else _txn1 = NULL;
579 if (dest_is_txn)
580 RCCK (VOLK_store_begin (dest->store, 0, &_txn2));
581 else _txn2 = NULL;
582 }
583
585
586 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (_txn1, src, s, p, o, NULL);
587
588 VOLK_Triple *spo = NULL;
589 VOLK_GraphIterator *add_it = VOLK_graph_add_init_txn (_txn2, dest);
590 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
591 VOLK_rc add_rc = VOLK_graph_add_iter (add_it, spo);
592 VOLK_triple_free (spo);
593 if (LIKELY (add_rc == VOLK_OK)) rc = VOLK_OK;
594 else if (add_rc < 0) {
595 rc = add_rc;
596 break;
597 }
598 }
599
600 VOLK_graph_iter_free (add_it);
602 if (_txn1 != txn) VOLK_store_abort (src->store, _txn1);
603 if (_txn2 != txn) VOLK_store_commit (dest->store, _txn2);
604
605 return rc;
606}
607
608
609VOLK_GraphIterator *
611 void *txn, const VOLK_Graph *gr,
612 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o,
613 size_t *ct)
614{
615 VOLK_GraphIterator *it = malloc (sizeof (*it));
616 NLNL (it);
617
618 // Make relative s and o.
619 VOLK_Term *rel_s, *rel_o;
620 if (s && s->type == VOLK_TERM_IRIREF) {
621 rel_s = VOLK_iriref_new_rel (gr->uri, s);
622 log_debug ("Relative S lookup: %s", rel_s->data);
623 } else rel_s = (VOLK_Term *)s;
624 if (o && o->type == VOLK_TERM_IRIREF) {
625 rel_o = VOLK_iriref_new_rel (gr->uri, o);
626 log_debug ("Relative O lookup: %s", rel_o->data);
627 } else rel_o = (VOLK_Term *)o;
628
630 *ss = VOLK_term_serialize (rel_s),
631 *sp = VOLK_term_serialize (p),
632 *so = VOLK_term_serialize (rel_o),
633 *sc = VOLK_store_features (gr->store) & VOLK_STORE_CTX ?
634 VOLK_term_serialize (gr->uri) : NULL;
635
636 // Selectively free triple members and structure.
637 if (rel_s != s) VOLK_term_free (rel_s);
638 if (rel_o != o) VOLK_term_free (rel_o);
639
640 it->data = VOLK_store_lookup_txn (gr->store, txn, ss, sp, so, sc, ct);
641
642 VOLK_buffer_free (ss);
643 VOLK_buffer_free (sp);
644 VOLK_buffer_free (so);
645 VOLK_buffer_free (sc);
646
647 if (UNLIKELY (!it->data)) {
648 free (it);
649 return NULL;
650 }
651
652 it->graph = gr;
653
654 if (VOLK_store_features (it->graph->store) & VOLK_STORE_COW) {
655 // Copy-on-write store.
656 it->sspo = BTRP_DUMMY;
657 if (UNLIKELY (it->sspo == NULL)) return NULL;
658 it->sspo->s->flags |= VOLK_BUF_BORROWED;
659 it->sspo->p->flags |= VOLK_BUF_BORROWED;
660 it->sspo->o->flags |= VOLK_BUF_BORROWED;
661 } else {
662 // TODO copy-on-retrieval store. No implementations yet.
663 }
664
665 return it;
666}
667
668
670VOLK_graph_iter_next (VOLK_GraphIterator *it, VOLK_Triple **spo_p)
671{
672 VOLK_rc rc;
673 PRCCK (rc = graph_iter_next_buffer (it));
674 if (rc != VOLK_OK) return rc;
675
677 VOLK_term_new_from_buffer (it->sspo->s),
678 VOLK_term_new_from_buffer (it->sspo->p),
679 VOLK_term_new_from_buffer (it->sspo->o)
680 );
681 if (UNLIKELY (!spo)) return VOLK_MEM_ERR;
682
683 *spo_p = spo;
684
685 return VOLK_OK;
686}
687
688
689const VOLK_Graph *
690VOLK_graph_iter_graph (VOLK_GraphIterator *it)
691{ return it->graph; }
692
693
694bool
695VOLK_graph_iter_is_add (VOLK_GraphIterator *it)
696{ return it->sspo == NULL; }
697
698
699void
700VOLK_graph_iter_free (VOLK_GraphIterator *it)
701{
702 if (UNLIKELY (!it)) return;
703
704 if (it->sspo) {
705 // Free lookup iterator.
706 VOLK_store_iter_free (it->graph->store, it->data);
707
708 /*
709 * This deallocates resources properly by preserving borrowed pointers
710 * from the store in case of VOLK_STORE_COW stores.
711 */
712 if (VOLK_store_features (it->graph->store) & VOLK_STORE_COW) {
713 VOLK_btriple_free (it->sspo);
714 log_debug ("Freeing dummy triple @ %p", it->sspo);
715 } else {
716 // TODO copy-on-retrieval stores. None yet.
717 }
718
719 } else {
720 // Add iterator has sspo == NULL. Use add_done_fn for that.
721 VOLK_store_add_done (it->graph->store, it->data);
722 }
723
724 free (it);
725}
726
727
728bool
730 void *txn, const VOLK_Graph *gr, const VOLK_Triple *spo)
731{
732 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
733 txn, gr, spo->s, spo->p, spo->o, NULL);
734 VOLK_Triple *tmp_spo = NULL;
735 bool rc = VOLK_graph_iter_next (it, &tmp_spo) != VOLK_END;
736
737 VOLK_triple_free (tmp_spo);
739
740 return rc;
741}
742
743
744void
745VOLK_graph_print (const VOLK_Graph *gr)
746{
747 size_t ct;
748 VOLK_GraphIterator *it = VOLK_graph_lookup (gr, NULL, NULL, NULL, &ct);
749 if (UNLIKELY (!it)) {
750 log_error ("Could not inspect graph for printing.");
751 return;
752 }
753
754 printf ("\n*** Graph %s (%zu triples):\n", gr->uri->data, ct);
755
756 VOLK_Triple *spo = NULL;
757 ct = 0;
759 while ((rc = VOLK_graph_iter_next (it, &spo)) == VOLK_OK) {
760 printf (
761 "#%-6zu {%s %s %s}\n",
762 ct, spo->s->data, spo->p->data, spo->o->data);
763 VOLK_triple_free (spo);
764 ct++;
765 }
767 if (rc != VOLK_END)
768 log_error (
769 "Output truncated due to abnormal return: %s",
770 VOLK_strerror (rc));
771}
772
773
776 void *txn, const VOLK_Graph *gr, const VOLK_Term *t,
777 const VOLK_LinkType type
778)
779{
780 const VOLK_Term
781 *s = NULL,
782 *p = NULL,
783 *o = NULL;
784
785 // Position of passed term and link terms, respectively.
786 VOLK_TriplePos pos1, pos2;
787
788 if (type == VOLK_LINK_INBOUND) {
789 o = t;
790 pos1 = TRP_POS_O;
791 pos2 = TRP_POS_P;
792 } else if (type == VOLK_LINK_OUTBOUND) {
793 s = t;
794 pos1 = TRP_POS_S;
795 pos2 = TRP_POS_P;
796 } else if (type == VOLK_LINK_EDGE) {
797 p = t;
798 pos1 = TRP_POS_P;
799 pos2 = TRP_POS_S;
800 } else {
801 log_error ("Invalid connection type: %d", type);
802 return NULL;
803 }
804
805 void *_txn;
806 if (txn) _txn = txn;
807 else if (VOLK_store_features (gr->store) & VOLK_STORE_TXN) {
808 RCNL (VOLK_store_begin (gr->store, VOLK_STORE_TXN_RO, &_txn));
809 } else _txn = NULL;
810
811 // Gather all linking terms in a set first.
812 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (_txn, gr, s, p, o, NULL);
813 NLNL (it);
814
816 while (graph_iter_next_buffer (it) != VOLK_END) {
817 VOLK_Term *ex = NULL;
819 VOLK_btriple_pos (it->sspo, pos2));
820 VOLK_term_set_add (lts, ins, &ex);
821 }
823
824 VOLK_LinkMap *ret = VOLK_link_map_new (t, type);
825 if (!ret) return NULL;
826 size_t i = 0;
827 VOLK_Term *lt;
828 while (VOLK_term_set_next (lts, &i, &lt) != VOLK_END) {
830 ret, VOLK_term_copy (lt),
831 VOLK_graph_term_set_txn (_txn, gr, t, pos1, lt, pos2));
832 }
833 VOLK_term_set_free (lts);
834 if (_txn != txn) VOLK_store_abort (gr->store, _txn);
835
836 return ret;
837}
838
839
842 void *txn, const VOLK_Graph *gr,
843 const VOLK_Term *t1, const VOLK_TriplePos t1_pos,
844 const VOLK_Term *t2, const VOLK_TriplePos t2_pos)
845{
846 if (t1_pos == t2_pos) {
847 log_error ("Term 1 and 2 positions cannot be the same!");
848 return NULL;
849 }
850
851 const VOLK_Term *spo_l[3] = {NULL};
852 spo_l[t1_pos] = t1;
853 spo_l[t2_pos] = t2;
854 VOLK_TriplePos rpos = 0; // Position of term to be added to results.
855 for (unsigned i = 0; i < 3; i++)
856 if (t1_pos != i && t2_pos != i) rpos = i;
857
858 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
859 txn, gr, spo_l[0], spo_l[1], spo_l[2], NULL);
860
862 while (graph_iter_next_buffer (it) != VOLK_END) {
863 // There cannot be duplicates in a 2-bound lookup.
865 ts,
867 NULL);
868 }
870
871 return ts;
872}
873
874
877 void *txn, const VOLK_Graph *gr, VOLK_TriplePos pos)
878{
879 // TODO We should use spo indices for stores that have them...
880 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
881 txn, gr, NULL, NULL, NULL, NULL);
882
884 while (graph_iter_next_buffer (it) != VOLK_END) {
886 *ex = NULL,
887 *ins = VOLK_term_new_from_buffer (VOLK_btriple_pos (it->sspo, pos));
888 VOLK_term_set_add (ts, ins, &ex);
889 }
891
892 return ts;
893}
894
895
896size_t
897VOLK_graph_add_link_map (VOLK_GraphIterator *it, VOLK_LinkMap *lm)
898{
899 VOLK_Triple *spo = TRP_DUMMY;
900 size_t ct = 0;
901 VOLK_LinkMapIterator *lmit = VOLK_link_map_iter_new (lm);
902
903 while (VOLK_link_map_triples (lmit, spo) != VOLK_END) {
904 VOLK_rc rc = VOLK_graph_add_iter (it, spo);
905 if (rc >= 0) ct++;
906 PRCCK (rc);
907 }
909 free (spo);
910
911 return ct;
912}
913
914
915VOLK_Term *
916VOLK_bnode_add_collection (VOLK_GraphIterator *it, VOLK_TermSet *ts)
917{
919 *s = VOLK_term_new (VOLK_TERM_BNODE, NULL, NULL),
920 *rdf_first = VOLK_iriref_new ("rdf:first"),
921 *rdf_rest = VOLK_iriref_new ("rdf:rest"),
922 *rdf_nil = VOLK_iriref_new ("rdf:nil"),
923 *link;
924
925 VOLK_Triple *spo = TRP_DUMMY;
926 link = s;
927 size_t i = 0;
928 VOLK_Term *t;
929 while (VOLK_term_set_next (ts, &i, &t) != VOLK_END) {
930 spo->s = link;
931 spo->p = rdf_first;
932 spo->o = t;
933 PRCNL (VOLK_graph_add_iter (it, spo));
934
935 spo->p = rdf_rest;
936 size_t save_i = i; // Save iterator position to restore it after peek.
937 spo->o = (
938 // Peek into the next result.
939 VOLK_term_set_next (ts, &i, NULL) != VOLK_END ?
940 VOLK_term_new (VOLK_TERM_BNODE, NULL, NULL)
941 : rdf_nil);
942 i = save_i; // Restore the iterator that advanced when peeking.
943
944 PRCNL (VOLK_graph_add_iter (it, spo));
945
946 if (link != s) VOLK_term_free (link);
947 // Current object becomes next subject. Irrelevant for last item.
948 link = spo->o;
949 }
950
951 VOLK_term_free (rdf_first);
952 VOLK_term_free (rdf_rest);
953 VOLK_term_free (rdf_nil);
954 free (spo);
955
956 return s;
957}
958
959
960/*
961 * Static functions.
962 */
963
971inline static VOLK_rc
972graph_iter_next_buffer (VOLK_GraphIterator *it)
973{ return VOLK_store_iter_next (it->graph->store, it->data, it->sspo, NULL); }
974
975
979
980VOLK_Graph * VOLK_graph_new_ns (VOLK_Store *store, const char *ns_str);
#define UNLIKELY(x)
Definition core.h:65
#define LIKELY(x)
Definition core.h:64
bool VOLK_graph_iter_is_add(VOLK_GraphIterator *it)
Definition graph.c:695
#define MALLOC_GUARD(var, rc)
Allocate one pointer with malloc and return rc if it fails.
Definition core.h:435
#define RCNL(exp)
Return NULL if exp returns a nonzero value.
Definition core.h:405
#define PCHECK(exp, marker)
Jump to marker if exp returns a negative value (skip warnings).
Definition core.h:350
#define PRCNL(exp)
Return NULL if exp returns a negative value (=error).
Definition core.h:416
#define CHECK(exp, marker)
Jump to marker if exp does not return VOLK_OK.
Definition core.h:337
#define NLNL(exp)
Log error and return NULL if exp is NULL.
Definition core.h:427
#define CALLOC_GUARD(var, rc)
Allocate one pointer with calloc and return rc if it fails.
Definition core.h:441
#define log_debug(...)
Definition core.h:320
#define RCCK(exp)
Return exp return value if it is of VOLK_rc type and nonzero.
Definition core.h:372
#define NLRCCK(exp, _rc)
Return rc return code if exp is NULL.
Definition core.h:396
#define PRCCK(exp)
Return exp return value if it is of VOLK_rc type and negative (=error).
Definition core.h:384
#define log_trace(...)
Definition core.h:322
#define VOLK_VALUE_ERR
An invalid input value was provided.
Definition core.h:167
#define VOLK_MEM_ERR
Memory allocation error.
Definition core.h:182
#define VOLK_NORESULT
No result yielded.
Definition core.h:138
#define VOLK_DB_ERR
Low-level database error.
Definition core.h:173
#define VOLK_END
Loop end.
Definition core.h:145
#define VOLK_OK
Generic success return code.
Definition core.h:121
#define VOLK_NOACTION
No action taken.
Definition core.h:131
int VOLK_rc
Return code.
Definition core.h:117
const char * VOLK_strerror(VOLK_rc rc)
Return an error message for a return code.
Definition core.c:196
void * VOLK_store_add_init_txn(VOLK_Store *store, void *txn, const VOLK_Buffer *sc)
Initialize bulk triple load.
Definition store.c:136
VOLK_rc VOLK_store_add_done(VOLK_Store *store, void *it)
Finalize an add loop and free iterator.
Definition store.c:160
VOLK_rc VOLK_store_add_iter(VOLK_Store *store, void *it, const VOLK_BufferTriple *sspo)
Add one triple into the store.
Definition store.c:142
VOLK_StoreFeature VOLK_store_features(const VOLK_Store *store)
Feature flags belonging to the store interface.
Definition store.c:86
VOLK_rc VOLK_store_add_term_txn(VOLK_Store *store, void *txn, VOLK_Buffer *sterm)
Add a single term to the store.
Definition store.c:165
void * VOLK_store_lookup_txn(const VOLK_Store *store, void *txn, const VOLK_Buffer *ss, const VOLK_Buffer *sp, const VOLK_Buffer *so, const VOLK_Buffer *sc, size_t *ct)
Look up triples by pattern matching.
Definition store.c:170
VOLK_rc VOLK_store_iter_next(VOLK_Store *store, void *it, VOLK_BufferTriple *sspo, VOLK_Buffer **sc)
Yield the matching triples and advance the iterator.
Definition store.c:184
void VOLK_store_iter_free(VOLK_Store *store, void *it)
Free an iterator allocated by a lookup.
Definition store.c:199
VOLK_Store * VOLK_store_new(const VOLK_StoreType store_type, const char *store_id, size_t size, bool clear)
Create a new store.
Definition store.c:28
void * VOLK_store_iter_txn(const VOLK_Store *store, void *it)
Get iterator active transaction handle.
Definition store.c:204
VOLK_rc VOLK_store_begin(VOLK_Store *store, VOLK_StoreFlags flags, void **txn)
Begin a transaction.
Definition store.c:96
VOLK_rc VOLK_store_commit(VOLK_Store *store, void *txn)
Commit a transaction.
Definition store.c:105
VOLK_rc VOLK_store_remove_txn(VOLK_Store *store, void *txn, const VOLK_Buffer *ss, const VOLK_Buffer *sp, const VOLK_Buffer *so, const VOLK_Buffer *sc, size_t *ct)
Delete triples by pattern matching.
Definition store.c:216
void VOLK_store_abort(VOLK_Store *store, void *txn)
Abort (roll back) a transaction.
Definition store.c:115
void VOLK_store_free(VOLK_Store *store)
Free a store created with VOLK_store_new().
Definition store.c:69
VOLK_rc VOLK_store_update_ctx_txn(VOLK_Store *store, void *txn, const VOLK_Buffer *old_c, const VOLK_Buffer *new_c)
Update the context of triples in a context-aware store.
Definition store.c:124
@ VOLK_STORE_HTABLE
Definition store.h:42
VOLK_Triple * VOLK_triple_new_from_btriple(const VOLK_BufferTriple *sspo)
Definition term.c:470
struct hashmap VOLK_TermSet
a set of unique terms.
Definition term.h:123
VOLK_rc VOLK_term_set_next(VOLK_TermSet *ts, size_t *i, VOLK_Term **term)
Iterate trough a term set.
Definition term.c:597
VOLK_Triple * VOLK_triple_new(VOLK_Term *s, VOLK_Term *p, VOLK_Term *o)
Create a new triple from three terms.
Definition term.c:455
VOLK_Term * VOLK_iriref_new_rel(const VOLK_Term *root, const VOLK_Term *iri)
Create a new relative IRI from an absolute IRI and a web root IRI.
Definition term.c:278
void VOLK_link_map_iter_free(VOLK_LinkMapIterator *it)
Free a link map iterator.
Definition term.c:741
VOLK_LinkType
Link type.
Definition term.h:93
VOLK_Term * VOLK_iriref_new(const char *data)
Create an IRI reference.
Definition term.h:191
VOLK_LinkMapIterator * VOLK_link_map_iter_new(const VOLK_LinkMap *lmap)
Create a new iterator to loop through a link map.
Definition term.c:729
VOLK_LinkMap * VOLK_link_map_new(const VOLK_Term *linked_term, VOLK_LinkType type)
New link map.
Definition term.c:651
VOLK_rc VOLK_link_map_triples(VOLK_LinkMapIterator *it, VOLK_Triple *spo)
Iterate over a link map and generate triples.
Definition term.c:760
VOLK_TermSet * VOLK_term_set_new()
Create a new term set.
Definition term.c:548
void VOLK_term_set_free(VOLK_TermSet *ts)
Free a term set.
Definition term.c:609
#define TRP_DUMMY
Dummy triple with NULL slots. It is not a valid triple.
Definition term.h:444
void VOLK_term_free(VOLK_Term *term)
Definition term.c:392
VOLK_Term * VOLK_triple_pos(const VOLK_Triple *trp, VOLK_TriplePos n)
Get triple by term position.
Definition term.h:501
VOLK_Buffer * VOLK_term_serialize(const VOLK_Term *term)
Serialize a term into a buffer.
Definition term.c:298
VOLK_Term * VOLK_term_new_from_buffer(const VOLK_Buffer *sterm)
See notes in VOLK_term_serialize function body for format info.
Definition term.c:194
VOLK_rc VOLK_link_map_add(VOLK_LinkMap *lmap, VOLK_Term *term, VOLK_TermSet *tset)
Add a term - term set pair to a link map.
Definition term.c:686
VOLK_rc VOLK_term_set_add(VOLK_TermSet *ts, VOLK_Term *term, VOLK_Term **ins)
Add term to a term set.
Definition term.c:561
VOLK_BufferTriple * VOLK_triple_serialize(const VOLK_Triple *spo)
Definition term.c:484
VOLK_Term * VOLK_term_new(VOLK_TermType type, const char *data, void *metadata)
Create a new term.
Definition term.c:157
void VOLK_triple_free(VOLK_Triple *spo)
Free a triple and all its internal pointers.
Definition term.c:531
VOLK_Term * VOLK_term_copy(const VOLK_Term *src)
Copy a term.
Definition term.c:174
@ VOLK_LINK_EDGE
Edge link (p:so).
Definition term.h:96
@ VOLK_LINK_INBOUND
Inbound link (o:sp).
Definition term.h:94
@ VOLK_LINK_OUTBOUND
Outbound link (s:po).
Definition term.h:95
@ VOLK_TERM_IRIREF
IRI reference.
Definition term.h:34
@ VOLK_TERM_LITERAL
Literal without language tag.
Definition term.h:35
@ VOLK_TERM_BNODE
Blank node.
Definition term.h:37
VOLK_Buffer * VOLK_btriple_pos(const VOLK_BufferTriple *trp, VOLK_TriplePos n)
Get serialized triple by term position.
Definition buffer.h:297
#define BTRP_DUMMY
Dummy buffer triple.
Definition buffer.h:336
void VOLK_btriple_free(VOLK_BufferTriple *sspo)
Free a buffer triple and all its internal pointers.
Definition buffer.c:147
VOLK_TriplePos
Triple position of s, p, o.
Definition buffer.h:19
void VOLK_buffer_free(VOLK_Buffer *buf)
Free a buffer.
Definition buffer.c:97
@ VOLK_BUF_BORROWED
Definition buffer.h:28
@ TRP_POS_O
Definition buffer.h:22
@ TRP_POS_S
Definition buffer.h:20
@ TRP_POS_P
Definition buffer.h:21
#define VOLK_graph_lookup(...)
Non-transactional version of VOLK_graph_lookup_txn.
Definition graph.h:416
VOLK_Graph * VOLK_graph_new_ns(VOLK_Store *store, const char *ns_str)
Create an empty graph using a namespace-prefixed string for its URI.
Definition graph.h:75
bool VOLK_graph_contains_txn(void *txn, const VOLK_Graph *gr, const VOLK_Triple *spo)
Whether a graph contains a triple.
Definition graph.c:729
const VOLK_Graph * VOLK_graph_iter_graph(VOLK_GraphIterator *it)
Return the graph related to an iterator.
Definition graph.c:690
void VOLK_graph_print(const VOLK_Graph *gr)
Print graph information and triples to stdout.
Definition graph.c:745
size_t VOLK_graph_size_txn(void *txn, const VOLK_Graph *gr)
Number of triples in a graph.
Definition graph.c:331
VOLK_Graph * VOLK_graph_get_txn(void *txn, VOLK_Store *store, const VOLK_Term *uri, size_t *ct)
Create a temp graph from stored triples.
Definition graph.c:67
VOLK_LinkMap * VOLK_graph_connections_txn(void *txn, const VOLK_Graph *gr, const VOLK_Term *t, const VOLK_LinkType type)
Get term pairs connected to a term in a graph.
Definition graph.c:775
size_t VOLK_graph_add_link_map(VOLK_GraphIterator *it, VOLK_LinkMap *lm)
Add triples for a term and related link map to a graph.
Definition graph.c:897
VOLK_rc VOLK_graph_remove_txn(void *txn, VOLK_Graph *gr, const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o, size_t *ct)
Delete triples by a matching pattern.
Definition graph.c:523
VOLK_rc VOLK_graph_copy_contents_txn(void *txn, const VOLK_Graph *src, VOLK_Graph *dest, const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o)
Copy triples from a source graph into a destination one.
Definition graph.c:554
void VOLK_graph_free(VOLK_Graph *gr)
Free a graph.
Definition graph.c:266
VOLK_rc VOLK_graph_add_txn(void *txn, VOLK_Graph *gr, VOLK_Triple *const *trp, size_t *ct)
Add triples to a graph.
Definition graph.c:489
VOLK_GraphIterator * VOLK_graph_lookup_txn(void *txn, const VOLK_Graph *gr, const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o, size_t *ct)
Look up triples by a matching pattern and yield an iterator.
Definition graph.c:610
#define VOLK_graph_copy_contents(...)
Definition graph.h:159
VOLK_rc VOLK_graph_bool_op_txn(void *txn, const VOLK_bool_op op, const VOLK_Graph *gr1, const VOLK_Graph *gr2, VOLK_Graph *res)
Definition graph.c:111
VOLK_rc VOLK_graph_set_uri_txn(void *txn, VOLK_Graph *gr, const char *uri_str)
Definition graph.c:290
VOLK_Store * VOLK_graph_store(const VOLK_Graph *gr)
Underlying graph store handle.
Definition graph.c:285
VOLK_TermSet * VOLK_graph_unique_terms_txn(void *txn, const VOLK_Graph *gr, VOLK_TriplePos pos)
Get all unique subjcts, predicates, or objects in a graph.
Definition graph.c:876
VOLK_GraphIterator * VOLK_graph_add_init_txn(void *txn, VOLK_Graph *gr)
Initialize an iterator to add triples.
Definition graph.c:415
VOLK_rc VOLK_graph_iter_next(VOLK_GraphIterator *it, VOLK_Triple **spo_p)
Advance a cursor obtained by a lookup and return a matching triple.
Definition graph.c:670
VOLK_TermSet * VOLK_graph_term_set_txn(void *txn, const VOLK_Graph *gr, const VOLK_Term *t1, const VOLK_TriplePos t1_pos, const VOLK_Term *t2, const VOLK_TriplePos t2_pos)
Get a list of terms related to a term pair in a graph.
Definition graph.c:841
VOLK_Term * VOLK_bnode_add_collection(VOLK_GraphIterator *it, VOLK_TermSet *ts)
Add triples for an anonymous collection to a graph.
Definition graph.c:916
bool VOLK_graph_equals_txn(void *txn, const VOLK_Graph *gr1, const VOLK_Graph *gr2)
Compare two graphs.
Definition graph.c:359
VOLK_rc VOLK_graph_add_iter(VOLK_GraphIterator *it, const VOLK_Triple *spo)
Add a single triple to the store.
Definition graph.c:432
void VOLK_graph_iter_free(VOLK_GraphIterator *it)
Free a graph iterator.
Definition graph.c:700
VOLK_Graph * VOLK_graph_new(VOLK_Store *store, const char *uri_str)
Create new graph.
Definition graph.c:45
const VOLK_Term * VOLK_graph_uri(const VOLK_Graph *gr)
Read-only graph URI.
Definition graph.c:281
VOLK_bool_op
Boolean operations that can be performed on a graph.
Definition core.h:261
@ VOLK_BOOL_XOR
Boolean XOR.
Definition core.h:265
@ VOLK_BOOL_UNION
Boolean union.
Definition core.h:262
@ VOLK_BOOL_SUBTRACTION
Boolean subtraction.
Definition core.h:263
@ VOLK_BOOL_INTERSECTION
Boolean intersection.
Definition core.h:264
@ VOLK_STORE_TXN_RO
Start a read-only transaction.
@ VOLK_STORE_TXN
Supports transaction handling.
@ VOLK_STORE_EMBED
@ VOLK_STORE_COW
Copy on write.
@ VOLK_STORE_CTX
Triple of byte buffers.
Definition buffer.h:60
VOLK_Buffer * o
Definition buffer.h:63
VOLK_Buffer * s
Definition buffer.h:61
VOLK_Buffer * p
Definition buffer.h:62
General-purpose data buffer.
Definition buffer.h:47
Store structure.
Definition store.h:59
RDF term.
Definition term.h:61
char * data
URI, literal value, or BNode label.
Definition term.h:62
struct term_t * datatype
Data type IRI for VOLK_TERM_LITERAL.
Definition term.h:64
VOLK_TermType type
Term type.
Definition term.h:69
RDF triple.
Definition term.h:85
VOLK_Term * p
Predicate.
Definition term.h:87
VOLK_Term * s
Subject.
Definition term.h:86
VOLK_Term * o
Object.
Definition term.h:88
Graph iterator.
Definition graph.c:12
const VOLK_Graph * graph
Parent graph.
Definition graph.c:13
size_t ct
Total lookup matches.
Definition graph.c:15
void * data
Iterator state.
Definition graph.c:14
VOLK_BufferTriple * sspo
Definition graph.c:16
Graph object.
Definition graph.c:7
VOLK_Store * store
Store handle.
Definition graph.c:9
VOLK_Term * uri
Graph "name" (URI).
Definition graph.c:8