Volksdata 1.0b10
RDF library
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_term_serialize (res->uri),
152 *gr1_sc = VOLK_term_serialize (gr1->uri),
153 *gr2_sc = VOLK_term_serialize (gr2->uri);
154 void *lu1_it, *lu2_it, *add_it;
156 size_t ct;
157
158 // Whether gr1 or gr2 txn will be open independently from res txn.
159 bool
160 open_txn1 = false,
161 open_txn2 = false;
162
163 // TODO check for transaction consistency here, and if it needs a separate
164 // transaction handle.
165 add_it = VOLK_store_add_init_txn (res->store, txn, res_sc);
166
167 if (VOLK_store_features (res->store) & VOLK_STORE_TXN)
168 res_txn = VOLK_store_iter_txn (res->store, add_it);
169
170 /* If either source graph is in the same store as the destination and has
171 * an open transaction, reuse that transaction. A new reader cannot be
172 * opened in LMDB while a writer is open already.
173 */
174 // Handle gr1 transaction.
175 if (VOLK_store_features (gr1->store) & VOLK_STORE_TXN) {
176 if (gr1->store == res->store) lu1_txn = res_txn;
177 else {
179 gr1->store, VOLK_STORE_TXN_RO, &lu1_txn), fail);
180 open_txn1 = true;
181 }
182 }
183
184 // Handle gr2 transaction.
185 if (VOLK_store_features (gr2->store) & VOLK_STORE_TXN) {
186 if (gr2->store == res->store) lu2_txn = res_txn;
187 else if (gr2->store == gr1->store) lu2_txn = lu1_txn;
188 // FIXME: see above.
189 else {
191 gr2->store, VOLK_STORE_TXN_RO, &lu2_txn), fail);
192 open_txn2 = true;
193 }
194 }
195 log_trace (
196 "lu1_txn: %p ; lu2_txn: %p ; res_txn: %p",
197 lu1_txn, lu2_txn, res_txn);
198
199 /* BEGIN XOR block. */
200
201 if (op == VOLK_BOOL_XOR) {
202 // Add triples from gr2 if not found in gr1.
203 lu2_it = VOLK_store_lookup_txn (
204 gr2->store, lu2_txn, NULL, NULL, NULL, gr2_sc, NULL);
205 while (VOLK_store_iter_next (
206 gr2->store, lu2_it, sspo, NULL) == VOLK_OK) {
207 lu1_it = VOLK_store_lookup_txn (
208 gr1->store, lu1_txn, sspo->s, sspo->p, sspo->o, gr1_sc, &ct
209 );
210 if (ct == 0) {
211 VOLK_store_add_iter (res->store, add_it, sspo);
212 rc = VOLK_OK;
213 }
214 VOLK_store_iter_free (gr1->store, lu1_it);
215 }
216 VOLK_store_iter_free (gr2->store, lu2_it);
217 }
218
219 /* BEGIN subtraction and intersection block. */
220
221 lu1_it = VOLK_store_lookup_txn (
222 gr1->store, lu1_txn, NULL, NULL, NULL, gr1_sc, NULL);
223 while (VOLK_store_iter_next (gr1->store, lu1_it, sspo, NULL) == VOLK_OK) {
224 lu2_it = VOLK_store_lookup_txn (
225 gr2->store, lu2_txn, sspo->s, sspo->p, sspo->o, gr2_sc, &ct);
226 if (UNLIKELY (!lu2_it)) {
227 rc = VOLK_DB_ERR;
228 VOLK_store_iter_free (gr1->store, lu1_it);
229 goto fail;
230 }
231 // For XOR and subtraction, add if not found.
232 // For intersection, add if found.
233 if ((ct == 0) ^ (op == VOLK_BOOL_INTERSECTION)) {
234 VOLK_store_add_iter (res->store, add_it, sspo);
235 rc = VOLK_OK;
236 }
237 VOLK_store_iter_free (gr2->store, lu2_it);
238 }
239 VOLK_store_iter_free (gr1->store, lu1_it);
240
241 if (open_txn1) VOLK_store_commit (gr1->store, lu1_txn);
242 if (open_txn2) VOLK_store_commit (gr2->store, lu2_txn);
243
244 VOLK_store_add_done (res->store, add_it);
245 VOLK_btriple_free (sspo);
246 VOLK_buffer_free (res_sc);
247 VOLK_buffer_free (gr1_sc);
248 VOLK_buffer_free (gr2_sc);
249
250 /* END subtraction, intersection, XOR block. */
251
252 return rc;
253
254fail:
255 if (lu1_txn) VOLK_store_abort (gr1->store, lu1_txn);
256 if (lu2_txn) VOLK_store_abort (gr2->store, lu2_txn);
257 VOLK_graph_free (res);
258 return rc;
259}
260
261
262void
263VOLK_graph_free (VOLK_Graph *gr)
264{
265 if (UNLIKELY (!gr)) return;
266
267 VOLK_term_free (gr->uri);
268 // If the store is embedded, it goes away with the associated graph.
269 if (VOLK_store_features (gr->store) & VOLK_STORE_EMBED) {
270 VOLK_store_free (gr->store);
271 }
272
273 free (gr);
274}
275
276
277const VOLK_Term *
278VOLK_graph_uri (const VOLK_Graph *gr) { return gr->uri; }
279
280
282VOLK_graph_store (const VOLK_Graph *gr)
283{ return gr->store; }
284
285
287VOLK_graph_set_uri_txn (void *txn, VOLK_Graph *gr, const char *uri_str)
288{
289 VOLK_rc rc = VOLK_OK;
290 VOLK_Buffer *old_sc = NULL, *new_sc = NULL;
291
292 VOLK_Term *uri = VOLK_iriref_new (uri_str);
293 if (UNLIKELY (!uri)) {
294 rc = VOLK_MEM_ERR;
295 goto finally;
296 }
297
298 // Update context for triples in the graph.
299 if (VOLK_store_features (gr->store) & VOLK_STORE_CTX) {
300 old_sc = VOLK_term_serialize (gr->uri);
301 new_sc = VOLK_term_serialize (uri);
302 if (UNLIKELY (!old_sc || !new_sc)) {
303 rc = VOLK_MEM_ERR;
304 goto finally;
305 }
306
307 PCHECK (
308 rc = VOLK_store_update_ctx_txn (gr->store, txn, old_sc, new_sc),
309 finally
310 );
311
312 // Overall success even if rc of underlying fn was VOLK_NOACTION.
313 if (rc == VOLK_NOACTION) rc = VOLK_OK;
314 }
315
316 VOLK_term_free (gr->uri);
317 gr->uri = uri;
318
319finally:
320 if (old_sc) VOLK_buffer_free (old_sc);
321 if (new_sc) VOLK_buffer_free (new_sc);
322
323 return rc;
324}
325
326
327size_t
328VOLK_graph_size_txn (void *txn, const VOLK_Graph *gr)
329{
330 void *_txn;
331 if (txn) _txn = txn;
332 else if (VOLK_store_features (gr->store) & VOLK_STORE_TXN)
333 RCCK (VOLK_store_begin (gr->store, 0, &_txn));
334 else _txn = NULL;
335
336 size_t ct = 0;
337 VOLK_Buffer *sc = VOLK_term_serialize (gr->uri);
338 void *it = VOLK_store_lookup_txn (
339 gr->store, _txn, NULL, NULL, NULL, sc, &ct);
340 if (!it) {
341 log_error ("Error initializing lookup.");
342 ct = -1;
343 }
344 VOLK_store_iter_free (gr->store, it);
345
346 VOLK_buffer_free (sc);
347 if (_txn != txn) VOLK_store_abort (gr->store, _txn);
348
349 return ct;
350}
351
352
353bool
354VOLK_graph_equals_txn (void *txn, const VOLK_Graph *gr1, const VOLK_Graph *gr2)
355{
356 void *_txn1, *_txn2;
357 if (txn) {
358 if (gr1->store == gr2->store) _txn2 = _txn1 = txn;
359 else {
360 log_error (
361 "Graphs must be from the same store when a transaction handle "
362 "is passed."
363 );
364 return false;
365 }
366 }
367 else {
368 if (VOLK_store_features (gr1->store) & VOLK_STORE_TXN)
369 RCCK (VOLK_store_begin (gr1->store, VOLK_STORE_TXN_RO, &_txn1));
370 else _txn1 = NULL;
371
372 if (gr2->store == gr1->store) _txn2 = _txn1;
373 else if (VOLK_store_features (gr2->store) & VOLK_STORE_TXN)
374 RCCK (VOLK_store_begin (gr2->store, VOLK_STORE_TXN_RO, &_txn2));
375 else _txn2 = NULL;
376 }
377
378 VOLK_Triple *spo = NULL;
379 bool match = true;
380
381 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
382 _txn1, gr1, NULL, NULL, NULL, NULL);
383 NLNL (it);
384 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
385 match = VOLK_graph_contains_txn (_txn2, gr2, spo);
386 VOLK_triple_free (spo);
387 if (!match) goto finally;
388 }
390
392 _txn2, gr2, NULL, NULL, NULL, NULL);
393 NLNL (it);
394 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
395 match = VOLK_graph_contains_txn (_txn1, gr1, spo);
396 VOLK_triple_free (spo);
397 if (!match) goto finally;
398 }
399
400finally:
402 if (_txn1 != txn) VOLK_store_abort (gr1->store, _txn1);
403 if (_txn2 != txn && _txn2 != _txn1) VOLK_store_abort (gr2->store, _txn2);
404
405 return match;
406}
407
408
409VOLK_GraphIterator *
410VOLK_graph_add_init_txn (void *txn, VOLK_Graph *gr)
411{
412 VOLK_GraphIterator *it;
413 CALLOC_GUARD (it, NULL);
414
415 VOLK_Buffer *sc = VOLK_term_serialize (gr->uri);
416
417 it->data = VOLK_store_add_init_txn (gr->store, txn, sc);
418 VOLK_buffer_free (sc);
419
420 it->graph = gr;
421
422 return it;
423}
424
425
427VOLK_graph_add_iter (VOLK_GraphIterator *it, const VOLK_Triple *spo)
428{
429 log_trace (
430 "Adding triple {%s, %s, %s} to %s",
431 spo->s->data, spo->p->data, spo->o->data,
432 VOLK_graph_uri(it->graph)->data);
433
434 // Make relative s and o.
435 VOLK_Term *rel_s, *rel_o;
436 if (spo->s->type == VOLK_TERM_IRIREF)
437 rel_s = VOLK_iriref_new_rel (it->graph->uri, spo->s);
438 else rel_s = spo->s;
439 if (spo->o->type == VOLK_TERM_IRIREF)
440 rel_o = VOLK_iriref_new_rel (it->graph->uri, spo->o);
441 else rel_o = spo->o;
442
443 VOLK_Triple *rel_spo = VOLK_triple_new (rel_s, spo->p, rel_o);
444 log_trace (
445 "Adding relative triple: {%s, %s, %s}",
446 rel_s->data, spo->p->data, rel_o->data);
447
448 // Serialize relative triple.
450 NLRCCK (sspo, VOLK_MEM_ERR);
451
452 // Selectively free triple members and structure.
453 if (rel_s != spo->s) VOLK_term_free (rel_s);
454 if (rel_o != spo->o) VOLK_term_free (rel_o);
455 free (rel_spo);
456
457 VOLK_rc rc = VOLK_store_add_iter (it->graph->store, it->data, sspo);
458 PCHECK (rc, finally);
459
460 // Store datatype term permanently.
461 if (rc == VOLK_OK) {
462 for (int i = 0; i < 3; i++) {
463 VOLK_Term *term = VOLK_triple_pos (spo, i);
464 if (term->type == VOLK_TERM_LITERAL) {
465 VOLK_Buffer *ser_dtype = VOLK_term_serialize (term->datatype);
466 void *txn = VOLK_store_iter_txn (it->graph->store, it->data);
468 it->graph->store, txn, ser_dtype);
469 PCHECK (term_rc, finally);
470 VOLK_buffer_free (ser_dtype);
471 }
472 }
473 }
474
475
476finally:
477 VOLK_btriple_free (sspo);
478
479 return rc;
480}
481
482
485 void *txn, VOLK_Graph *gr, VOLK_Triple *const *trp, size_t *ct)
486{
488
489 // Initialize iterator.
490 VOLK_GraphIterator *it = VOLK_graph_add_init_txn (txn, gr);
491
492 if (ct) *ct = 0;
493 // Serialize and insert RDF triples.
494 for (size_t i = 0; trp[i] != NULL; i++) {
495 log_trace ("Inserting triple #%lu", i);
496
497 VOLK_rc db_rc = VOLK_graph_add_iter (it, trp[i]);
498
499 if (db_rc == VOLK_OK) {
500 rc = VOLK_OK;
501 if (ct) (*ct)++;
502 // A duplicate will return VOLK_NOACTION and not increment ct.
503 }
504 if (UNLIKELY (db_rc < 0)) {
505 rc = db_rc;
506 goto finally;
507 }
508 }
509
510finally:
512
513 return rc;
514}
515
516
519 void *txn, VOLK_Graph *gr,
520 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o,
521 size_t *ct)
522{
524 *ss = VOLK_term_serialize (s),
525 *sp = VOLK_term_serialize (p),
526 *so = VOLK_term_serialize (o),
527 *sc = VOLK_term_serialize (gr->uri);
528
529 log_debug (
530 "Removing triples by terms: %s %s %s",
531 s ? s->data : "<nil>",
532 p ? p->data : "<nil>",
533 o ? o->data : "<nil>"
534 );
535
537 gr->store, txn, ss, sp, so, sc, ct);
538
539 VOLK_buffer_free (ss);
540 VOLK_buffer_free (sp);
541 VOLK_buffer_free (so);
542 VOLK_buffer_free (sc);
543
544 return rc;
545}
546
547
550 void *txn, const VOLK_Graph *src, VOLK_Graph *dest,
551 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o)
552{
553 void *_txn1, *_txn2;
554 if (txn) {
555 if (src->store != dest->store) {
556 log_error (
557 "Graphs must be from the same store when a transaction handle "
558 "is passed."
559 );
560 return VOLK_VALUE_ERR;
561 }
562 _txn2 = _txn1 = txn;
563 }
564 else {
565 if (VOLK_store_features (src->store) & VOLK_STORE_TXN) {
566 RCCK (VOLK_store_begin (src->store, VOLK_STORE_TXN_RO, &_txn1));
567 } else _txn1 = NULL;
568 if (VOLK_store_features (dest->store) & VOLK_STORE_TXN) {
569 RCCK (VOLK_store_begin (dest->store, 0, &_txn2));
570 } else _txn2 = NULL;
571 }
572
574
575 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (_txn1, src, s, p, o, NULL);
576
577 VOLK_Triple *spo = NULL;
578 VOLK_GraphIterator *add_it = VOLK_graph_add_init_txn (_txn2, dest);
579 while (VOLK_graph_iter_next (it, &spo) != VOLK_END) {
580 VOLK_rc add_rc = VOLK_graph_add_iter (add_it, spo);
581 VOLK_triple_free (spo);
582 if (LIKELY (add_rc == VOLK_OK)) rc = VOLK_OK;
583 else if (add_rc < 0) {
584 rc = add_rc;
585 break;
586 }
587 }
588
589 VOLK_graph_iter_free (add_it);
591 if (_txn1 != txn) VOLK_store_abort (src->store, _txn1);
592 if (_txn2 != txn) VOLK_store_commit (dest->store, _txn2);
593
594 return rc;
595}
596
597
598VOLK_GraphIterator *
600 void *txn, const VOLK_Graph *gr,
601 const VOLK_Term *s, const VOLK_Term *p, const VOLK_Term *o,
602 size_t *ct)
603{
604 VOLK_GraphIterator *it = malloc (sizeof (*it));
605 NLNL (it);
606
607 // Make relative s and o.
608 VOLK_Term *rel_s, *rel_o;
609 if (s && s->type == VOLK_TERM_IRIREF) {
610 rel_s = VOLK_iriref_new_rel (gr->uri, s);
611 log_debug ("Relative S lookup: %s", rel_s->data);
612 } else rel_s = (VOLK_Term *)s;
613 if (o && o->type == VOLK_TERM_IRIREF) {
614 rel_o = VOLK_iriref_new_rel (gr->uri, o);
615 log_debug ("Relative O lookup: %s", rel_o->data);
616 } else rel_o = (VOLK_Term *)o;
617
619 *ss = VOLK_term_serialize (rel_s),
620 *sp = VOLK_term_serialize (p),
621 *so = VOLK_term_serialize (rel_o),
622 *sc = VOLK_term_serialize (gr->uri);
623
624 // Selectively free triple members and structure.
625 if (rel_s != s) VOLK_term_free (rel_s);
626 if (rel_o != o) VOLK_term_free (rel_o);
627
628 it->data = VOLK_store_lookup_txn (gr->store, txn, ss, sp, so, sc, ct);
629
630 VOLK_buffer_free (ss);
631 VOLK_buffer_free (sp);
632 VOLK_buffer_free (so);
633 VOLK_buffer_free (sc);
634
635 if (UNLIKELY (!it->data)) {
636 free (it);
637 return NULL;
638 }
639
640 it->graph = gr;
641
642 if (VOLK_store_features (it->graph->store) & VOLK_STORE_COW) {
643 // Copy-on-write store.
644 it->sspo = BTRP_DUMMY;
645 if (UNLIKELY (it->sspo == NULL)) return NULL;
646 it->sspo->s->flags |= VOLK_BUF_BORROWED;
647 it->sspo->p->flags |= VOLK_BUF_BORROWED;
648 it->sspo->o->flags |= VOLK_BUF_BORROWED;
649 } else {
650 // TODO copy-on-retrieval store. No implementations yet.
651 }
652
653 return it;
654}
655
656
658VOLK_graph_iter_next (VOLK_GraphIterator *it, VOLK_Triple **spo_p)
659{
660 VOLK_rc rc;
661 PRCCK (rc = graph_iter_next_buffer (it));
662 if (rc != VOLK_OK) return rc;
663
665 VOLK_term_new_from_buffer (it->sspo->s),
666 VOLK_term_new_from_buffer (it->sspo->p),
667 VOLK_term_new_from_buffer (it->sspo->o)
668 );
669 if (UNLIKELY (!spo)) return VOLK_MEM_ERR;
670
671 *spo_p = spo;
672
673 return VOLK_OK;
674}
675
676
677const VOLK_Graph *
678VOLK_graph_iter_graph (VOLK_GraphIterator *it)
679{ return it->graph; }
680
681
682bool
683VOLK_graph_iter_is_add (VOLK_GraphIterator *it)
684{ return it->sspo == NULL; }
685
686
687void
688VOLK_graph_iter_free (VOLK_GraphIterator *it)
689{
690 if (UNLIKELY (!it)) return;
691
692 if (it->sspo) {
693 // Free lookup iterator.
694 VOLK_store_iter_free (it->graph->store, it->data);
695
696 /*
697 * This deallocates resources properly by preserving borrowed pointers
698 * from the store in case of VOLK_STORE_COW stores.
699 */
700 if (VOLK_store_features (it->graph->store) & VOLK_STORE_COW) {
701 VOLK_btriple_free (it->sspo);
702 log_debug ("Freeing dummy triple @ %p", it->sspo);
703 } else {
704 // TODO copy-on-retrieval stores. None yet.
705 }
706
707 } else {
708 // Add iterator has sspo == NULL. Use add_done_fn for that.
709 VOLK_store_add_done (it->graph->store, it->data);
710 }
711
712 free (it);
713}
714
715
716bool
718 void *txn, const VOLK_Graph *gr, const VOLK_Triple *spo)
719{
720 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
721 txn, gr, spo->s, spo->p, spo->o, NULL);
722 VOLK_Triple *tmp_spo = NULL;
723 bool rc = VOLK_graph_iter_next (it, &tmp_spo) != VOLK_END;
724
725 VOLK_triple_free (tmp_spo);
727
728 return rc;
729}
730
731
732void
733VOLK_graph_print (const VOLK_Graph *gr)
734{
735 size_t ct;
736 VOLK_GraphIterator *it = VOLK_graph_lookup (gr, NULL, NULL, NULL, &ct);
737 if (UNLIKELY (!it)) {
738 log_error ("Could not inspect graph for printing.");
739 return;
740 }
741
742 printf ("\n*** Graph %s (%zu triples):\n", gr->uri->data, ct);
743
744 VOLK_Triple *spo = NULL;
745 ct = 0;
747 while ((rc = VOLK_graph_iter_next (it, &spo)) == VOLK_OK) {
748 printf (
749 "#%-6zu {%s %s %s}\n",
750 ct, spo->s->data, spo->p->data, spo->o->data);
751 VOLK_triple_free (spo);
752 ct++;
753 }
755 if (rc != VOLK_END)
756 log_error (
757 "Output truncated due to abnormal return: %s",
758 VOLK_strerror (rc));
759}
760
761
764 void *txn, const VOLK_Graph *gr, const VOLK_Term *t,
765 const VOLK_LinkType type
766)
767{
768 const VOLK_Term
769 *s = NULL,
770 *p = NULL,
771 *o = NULL;
772
773 // Position of passed term and link terms, respectively.
774 VOLK_TriplePos pos1, pos2;
775
776 if (type == VOLK_LINK_INBOUND) {
777 o = t;
778 pos1 = TRP_POS_O;
779 pos2 = TRP_POS_P;
780 } else if (type == VOLK_LINK_OUTBOUND) {
781 s = t;
782 pos1 = TRP_POS_S;
783 pos2 = TRP_POS_P;
784 } else if (type == VOLK_LINK_EDGE) {
785 p = t;
786 pos1 = TRP_POS_P;
787 pos2 = TRP_POS_S;
788 } else {
789 log_error ("Invalid connection type: %d", type);
790 return NULL;
791 }
792
793 void *_txn;
794 if (txn) _txn = txn;
795 else if (VOLK_store_features (gr->store) & VOLK_STORE_TXN) {
796 RCNL (VOLK_store_begin (gr->store, VOLK_STORE_TXN_RO, &_txn));
797 } else _txn = NULL;
798
799 // Gather all linking terms in a set first.
800 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (_txn, gr, s, p, o, NULL);
801 NLNL (it);
802
804 while (graph_iter_next_buffer (it) != VOLK_END) {
805 VOLK_Term *ex = NULL;
807 VOLK_btriple_pos (it->sspo, pos2));
808 VOLK_term_set_add (lts, ins, &ex);
809 }
811
812 VOLK_LinkMap *ret = VOLK_link_map_new (t, type);
813 if (!ret) return NULL;
814 size_t i = 0;
815 VOLK_Term *lt;
816 while (VOLK_term_set_next (lts, &i, &lt) != VOLK_END) {
818 ret, VOLK_term_copy (lt),
819 VOLK_graph_term_set_txn (_txn, gr, t, pos1, lt, pos2));
820 }
821 VOLK_term_set_free (lts);
822 if (_txn != txn) VOLK_store_abort (gr->store, _txn);
823
824 return ret;
825}
826
827
830 void *txn, const VOLK_Graph *gr,
831 const VOLK_Term *t1, const VOLK_TriplePos t1_pos,
832 const VOLK_Term *t2, const VOLK_TriplePos t2_pos)
833{
834 if (t1_pos == t2_pos) {
835 log_error ("Term 1 and 2 positions cannot be the same!");
836 return NULL;
837 }
838
839 const VOLK_Term *spo_l[3] = {NULL};
840 spo_l[t1_pos] = t1;
841 spo_l[t2_pos] = t2;
842 VOLK_TriplePos rpos = 0; // Position of term to be added to results.
843 for (unsigned i = 0; i < 3; i++)
844 if (t1_pos != i && t2_pos != i) rpos = i;
845
846 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
847 txn, gr, spo_l[0], spo_l[1], spo_l[2], NULL);
848
850 while (graph_iter_next_buffer (it) != VOLK_END) {
851 // There cannot be duplicates in a 2-bound lookup.
853 ts,
855 NULL);
856 }
858
859 return ts;
860}
861
862
865 void *txn, const VOLK_Graph *gr, VOLK_TriplePos pos)
866{
867 // TODO We should use spo indices for stores that have them...
868 VOLK_GraphIterator *it = VOLK_graph_lookup_txn (
869 txn, gr, NULL, NULL, NULL, NULL);
870
872 while (graph_iter_next_buffer (it) != VOLK_END) {
874 *ex = NULL,
875 *ins = VOLK_term_new_from_buffer (VOLK_btriple_pos (it->sspo, pos));
876 VOLK_term_set_add (ts, ins, &ex);
877 }
879
880 return ts;
881}
882
883
884size_t
885VOLK_graph_add_link_map (VOLK_GraphIterator *it, VOLK_LinkMap *lm)
886{
887 VOLK_Triple *spo = TRP_DUMMY;
888 size_t ct = 0;
889 VOLK_LinkMapIterator *lmit = VOLK_link_map_iter_new (lm);
890
891 while (VOLK_link_map_triples (lmit, spo) != VOLK_END) {
892 VOLK_rc rc = VOLK_graph_add_iter (it, spo);
893 if (rc >= 0) ct++;
894 PRCCK (rc);
895 }
897 free (spo);
898
899 return ct;
900}
901
902
903VOLK_Term *
904VOLK_bnode_add_collection (VOLK_GraphIterator *it, VOLK_TermSet *ts)
905{
907 *s = VOLK_term_new (VOLK_TERM_BNODE, NULL, NULL),
908 *rdf_first = VOLK_iriref_new ("rdf:first"),
909 *rdf_rest = VOLK_iriref_new ("rdf:rest"),
910 *rdf_nil = VOLK_iriref_new ("rdf:nil"),
911 *link;
912
913 VOLK_Triple *spo = TRP_DUMMY;
914 link = s;
915 size_t i = 0;
916 VOLK_Term *t;
917 while (VOLK_term_set_next (ts, &i, &t) != VOLK_END) {
918 spo->s = link;
919 spo->p = rdf_first;
920 spo->o = t;
921 PRCNL (VOLK_graph_add_iter (it, spo));
922
923 spo->p = rdf_rest;
924 size_t save_i = i; // Save iterator position to restore it after peek.
925 spo->o = (
926 // Peek into the next result.
927 VOLK_term_set_next (ts, &i, NULL) != VOLK_END ?
928 VOLK_term_new (VOLK_TERM_BNODE, NULL, NULL)
929 : rdf_nil);
930 i = save_i; // Restore the iterator that advanced when peeking.
931
932 PRCNL (VOLK_graph_add_iter (it, spo));
933
934 if (link != s) VOLK_term_free (link);
935 // Current object becomes next subject. Irrelevant for last item.
936 link = spo->o;
937 }
938
939 VOLK_term_free (rdf_first);
940 VOLK_term_free (rdf_rest);
941 VOLK_term_free (rdf_nil);
942 free (spo);
943
944 return s;
945}
946
947
948/*
949 * Static functions.
950 */
951
959inline static VOLK_rc
960graph_iter_next_buffer (VOLK_GraphIterator *it)
961{ return VOLK_store_iter_next (it->graph->store, it->data, it->sspo, NULL); }
962
963
967
968VOLK_Graph * VOLK_graph_new_ns (VOLK_Store *store, const char *ns_str);
#define UNLIKELY(x)
Definition core.h:39
#define LIKELY(x)
Definition core.h:38
bool VOLK_graph_iter_is_add(VOLK_GraphIterator *it)
Definition graph.c:683
#define MALLOC_GUARD(var, rc)
Allocate one pointer with malloc and return rc if it fails.
Definition core.h:409
#define RCNL(exp)
Return NULL if exp returns a nonzero value.
Definition core.h:379
#define PCHECK(exp, marker)
Jump to marker if exp returns a negative value (skip warnings).
Definition core.h:324
#define PRCNL(exp)
Return NULL if exp returns a negative value (=error).
Definition core.h:390
#define CHECK(exp, marker)
Jump to marker if exp does not return VOLK_OK.
Definition core.h:311
#define NLNL(exp)
Log error and return NULL if exp is NULL.
Definition core.h:401
#define CALLOC_GUARD(var, rc)
Allocate one pointer with calloc and return rc if it fails.
Definition core.h:415
#define log_debug(...)
Definition core.h:294
#define RCCK(exp)
Return exp return value if it is of VOLK_rc type and nonzero.
Definition core.h:346
#define NLRCCK(exp, _rc)
Return rc return code if exp is NULL.
Definition core.h:370
#define PRCCK(exp)
Return exp return value if it is of VOLK_rc type and negative (=error).
Definition core.h:358
#define log_trace(...)
Definition core.h:296
#define VOLK_VALUE_ERR
An invalid input value was provided.
Definition core.h:141
#define VOLK_MEM_ERR
Memory allocation error.
Definition core.h:156
#define VOLK_NORESULT
No result yielded.
Definition core.h:112
#define VOLK_DB_ERR
Low-level database error.
Definition core.h:147
#define VOLK_END
Loop end.
Definition core.h:119
#define VOLK_OK
Generic success return code.
Definition core.h:95
#define VOLK_NOACTION
No action taken.
Definition core.h:105
int VOLK_rc
Return code.
Definition core.h:91
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 **ctx)
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 (so).
Definition term.h:96
@ VOLK_LINK_INBOUND
Inbound link (sp).
Definition term.h:94
@ VOLK_LINK_OUTBOUND
Outbound link (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:414
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:717
const VOLK_Graph * VOLK_graph_iter_graph(VOLK_GraphIterator *it)
Return the graph related to an iterator.
Definition graph.c:678
void VOLK_graph_print(const VOLK_Graph *gr)
Print graph information and triples to stdout.
Definition graph.c:733
size_t VOLK_graph_size_txn(void *txn, const VOLK_Graph *gr)
Number of triples in a graph.
Definition graph.c:328
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:763
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:885
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:518
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:549
void VOLK_graph_free(VOLK_Graph *gr)
Free a graph.
Definition graph.c:263
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:484
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:599
#define VOLK_graph_copy_contents(...)
Definition graph.h:157
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:287
VOLK_Store * VOLK_graph_store(const VOLK_Graph *gr)
Underlying graph store handle.
Definition graph.c:282
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:864
VOLK_GraphIterator * VOLK_graph_add_init_txn(void *txn, VOLK_Graph *gr)
Initialize an iterator to add triples.
Definition graph.c:410
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:658
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:829
VOLK_Term * VOLK_bnode_add_collection(VOLK_GraphIterator *it, VOLK_TermSet *ts)
Add triples for an anonymous collection to a graph.
Definition graph.c:904
bool VOLK_graph_equals_txn(void *txn, const VOLK_Graph *gr1, const VOLK_Graph *gr2)
Compare two graphs.
Definition graph.c:354
VOLK_rc VOLK_graph_add_iter(VOLK_GraphIterator *it, const VOLK_Triple *spo)
Add a single triple to the store.
Definition graph.c:427
void VOLK_graph_iter_free(VOLK_GraphIterator *it)
Free a graph iterator.
Definition graph.c:688
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:278
VOLK_bool_op
Boolean operations that can be performed on a graph.
Definition core.h:235
@ VOLK_BOOL_XOR
Boolean XOR.
Definition core.h:239
@ VOLK_BOOL_UNION
Boolean union.
Definition core.h:236
@ VOLK_BOOL_SUBTRACTION
Boolean subtraction.
Definition core.h:237
@ VOLK_BOOL_INTERSECTION
Boolean intersection.
Definition core.h:238
@ 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