123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- #include "store_htable.h"
- #include "store_mdb.h"
- #include "graph.h"
- /*
- * Data types.
- */
- typedef struct Graph {
- const LSUP_Env * env; // LSUP environment.
- LSUP_store_type store_type; // Back end type: in-memory or MDB.
- LSUP_Term *uri; // Graph "name" (URI)
- union {
- LSUP_HTStore * ht_store;
- LSUP_MDBStore * mdb_store;
- }; // Back end, defined by store_type.
- LSUP_NSMap * nsm; // Namespace map. NOTE: This is
- // NULL for MDB* stores. To get a
- // proper NSMap, always call
- // #LSUP_graph_namespace() for all
- // types of graphs.
- } Graph;
- typedef struct GraphIterator {
- const Graph * graph; // Parent graph.
- union { // Internal store iterator.
- LSUP_HTIterator * ht_iter;
- LSUP_MDBIterator * mdb_iter;
- };
- size_t ct; // Total matches.
- } GraphIterator;
- /*
- * Static prototypes.
- */
- inline static LSUP_rc
- graph_iter_next_buffer (GraphIterator *it, LSUP_BufferTriple *sspo);
- static LSUP_rc
- graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest);
- #define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
- static inline bool
- check_backend (LSUP_store_type be)
- { return (BACKEND_TBL false); }
- #undef ENTRY
- /*
- * Graph API.
- */
- Graph *
- LSUP_graph_new_env (
- const LSUP_Env *env, LSUP_Term *uri, const LSUP_store_type store_type)
- {
- if (UNLIKELY (!env)) {
- log_error ("No valid environment passed. Did you call LSUP_init()?");
- return NULL;
- }
- if (UNLIKELY (!check_backend (store_type))) return NULL;
- LSUP_Graph *gr;
- MALLOC_GUARD (gr, NULL);
- gr->uri = uri;
- gr->store_type = store_type;
- gr->env = env;
- gr->nsm = env->nsm;
- if (gr->store_type == LSUP_STORE_MEM) {
- gr->ht_store = LSUP_htstore_new();
- if (UNLIKELY (!gr->ht_store)) return NULL;
- } else if (gr->store_type == LSUP_STORE_MDB) {
- gr->mdb_store = env->mdb_store;
- } else { // LSUP_STORE_MDB_TMP
- gr->mdb_store = env->mdb_store_ramdisk;
- }
- log_debug ("Graph created.");
- return gr;
- }
- LSUP_Graph **
- LSUP_graph_new_lookup_env (
- const LSUP_Env *env, const LSUP_Term *s,
- const LSUP_Term *p, const LSUP_Term *o)
- {
- if (UNLIKELY (!env)) {
- log_error ("No valid environment passed. Did you call LSUP_init()?");
- return NULL;
- }
- LSUP_Buffer *ss = LSUP_term_serialize (s);
- LSUP_Buffer *sp = LSUP_term_serialize (p);
- LSUP_Buffer *so = LSUP_term_serialize (o);
- LSUP_Buffer **ctx_a = LSUP_mdbstore_lookup_contexts (
- env->mdb_store, ss, sp, so);
- if (UNLIKELY (!ctx_a)) return NULL;
- LSUP_buffer_free (ss);
- LSUP_buffer_free (sp);
- LSUP_buffer_free (so);
- // Count for allocation.
- size_t i;
- for (i = 0; ctx_a[i] != NULL; i++) {}
- LSUP_Graph **gr_a = calloc (i + 1, sizeof (*gr_a));
- if (UNLIKELY (!gr_a)) return NULL;
- for (i = 0; ctx_a[i] != NULL; i++) {
- gr_a[i] = LSUP_graph_new (
- LSUP_iriref_new (NULL, NULL), LSUP_STORE_MDB);
- LSUP_Term *uri = LSUP_term_new_from_buffer (ctx_a[i]);
- gr_a[i]->uri = uri;
- LSUP_buffer_free (ctx_a[i]);
- }
- free (ctx_a);
- return gr_a;
- }
- LSUP_Graph *
- LSUP_graph_copy (const Graph *src)
- {
- LSUP_Graph *dest = LSUP_graph_new_env (
- src->env, LSUP_iriref_new (NULL, NULL), src->store_type);
- if (UNLIKELY (!dest)) return NULL;
- LSUP_rc rc = graph_copy_contents (src, dest);
- if (UNLIKELY (rc != LSUP_OK)) return NULL;
- return dest;
- }
- LSUP_rc
- LSUP_graph_store (
- const LSUP_Graph *src, LSUP_Graph **dest_p, const LSUP_Env *env)
- {
- if (!env) env = LSUP_default_env;
- if (src->store_type == LSUP_STORE_MDB && src->env == env)
- return LSUP_NOACTION;
- LSUP_Graph *dest = LSUP_graph_new_env (
- env, LSUP_iriref_new (src->uri->data, LSUP_iriref_nsm (src->uri)),
- LSUP_STORE_MDB);
- if (UNLIKELY (!dest)) return LSUP_DB_ERR;
- LSUP_rc rc;
- rc = graph_copy_contents (src, dest);
- if (UNLIKELY (rc < 0)) return LSUP_DB_ERR;
- if (src->store_type == LSUP_STORE_MEM) {
- rc = LSUP_mdbstore_nsm_store (dest->mdb_store, src->nsm);
- if (UNLIKELY (rc < 0)) return LSUP_DB_ERR;
- }
- *dest_p = dest;
- return LSUP_OK;
- }
- // TODO support boolean ops between any types of graphs.
- Graph *
- LSUP_graph_bool_op(
- const LSUP_bool_op op, const Graph *gr1, const Graph *gr2)
- {
- if (UNLIKELY (gr1->store_type != LSUP_STORE_MEM)) {
- fprintf(
- stderr,
- "First operand %s is not an in-memory graph. "
- "Cannot perform boolean operation.",
- gr1->uri->data);
- return NULL;
- }
- if (UNLIKELY (gr2->store_type != LSUP_STORE_MEM)) {
- fprintf(
- stderr,
- "Second operand %s is not an in-memory graph. "
- "Cannot perform boolean operation.",
- gr2->uri->data);
- return NULL;
- }
- LSUP_Graph *res = LSUP_graph_new (
- LSUP_iriref_new (NULL, NULL), LSUP_STORE_MEM);
- res->ht_store = LSUP_htstore_bool_op (op, gr1->ht_store, gr2->ht_store);
- return res;
- }
- void
- LSUP_graph_free (LSUP_Graph *gr)
- {
- if (LIKELY (gr != NULL)) {
- LSUP_term_free (gr->uri);
- if (gr->store_type == LSUP_STORE_MEM)
- LSUP_htstore_free (gr->ht_store);
- free (gr);
- }
- }
- LSUP_Term *
- LSUP_graph_uri (const LSUP_Graph *gr) { return gr->uri; }
- LSUP_rc
- LSUP_graph_set_uri (LSUP_Graph *gr, LSUP_Term *uri)
- {
- if (!LSUP_IS_IRI (uri)) {
- log_error ("Term provided is not a IRI.");
- return LSUP_VALUE_ERR;
- }
- LSUP_term_free (gr->uri);
- gr->uri = LSUP_iriref_new (uri->data, LSUP_iriref_nsm (uri));
- return LSUP_OK;
- }
- LSUP_NSMap *
- LSUP_graph_namespace (const Graph *gr)
- {
- if (gr->store_type == LSUP_STORE_MEM) return gr->nsm;
- LSUP_NSMap *nsm;
- if (LSUP_mdbstore_nsm_get (gr->mdb_store, &nsm) < 0) return NULL;
- return nsm;
- }
- void
- LSUP_graph_set_namespace (Graph *gr, LSUP_NSMap *nsm)
- { if (gr->store_type == LSUP_STORE_MEM) gr->nsm = nsm; }
- size_t
- LSUP_graph_size (const Graph *gr)
- {
- if (gr->store_type == LSUP_STORE_MEM)
- return LSUP_htstore_size (gr->ht_store);
- else {
- size_t ct;
- LSUP_GraphIterator *it = LSUP_graph_lookup (gr, NULL, NULL, NULL, &ct);
- LSUP_graph_iter_free (it);
- return ct;
- }
- }
- bool
- LSUP_graph_equals (const Graph *gr1, const Graph *gr2)
- {
- LSUP_Graph *res = LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2);
- return (LSUP_graph_size (res) == 0);
- }
- GraphIterator *
- LSUP_graph_add_init (LSUP_Graph *gr)
- {
- GraphIterator *it;
- CALLOC_GUARD (it, NULL);
- if (gr->store_type == LSUP_STORE_MEM) {
- it->ht_iter = LSUP_htstore_add_init (gr->ht_store);
- } else {
- LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
- it->mdb_iter = LSUP_mdbstore_add_init (gr->mdb_store, sc);
- LSUP_buffer_free (sc);
- }
- it->graph = gr;
- return it;
- }
- LSUP_rc
- LSUP_graph_add_iter (LSUP_GraphIterator *it, const LSUP_Triple *spo)
- {
- LSUP_rc rc;
- LSUP_BufferTriple *sspo = LSUP_triple_serialize (spo);
- if (UNLIKELY (!sspo)) return LSUP_MEM_ERR;
- if (it->graph->store_type == LSUP_STORE_MEM) {
- rc = LSUP_htstore_add_iter (it->ht_iter, sspo);
- for (int i = 0; i < 3; i++) {
- LSUP_htstore_add_term (
- it->graph->ht_store, LSUP_btriple_pos (sspo, i));
- // HT store uses term keys from tcache.
- }
- } else {
- rc = LSUP_mdbstore_add_iter (it->mdb_iter, sspo);
- for (int i = 0; i < 3; i++) {
- LSUP_mdbstore_add_term (
- it->graph->mdb_store, LSUP_btriple_pos (sspo, i));
- // Store datatype term permanently.
- LSUP_Term *term = LSUP_triple_pos (spo, i);
- if (
- term->type == LSUP_TERM_LITERAL
- && !LSUP_mdbstore_tkey_exists (
- it->graph->mdb_store, LSUP_term_hash (term->datatype))
- ) {
- LSUP_Buffer *ser_dtype = LSUP_term_serialize (term->datatype);
- LSUP_mdbstore_add_term (it->graph->mdb_store, ser_dtype);
- LSUP_buffer_free (ser_dtype);
- }
- }
- }
- LSUP_btriple_free (sspo);
- return rc;
- }
- void
- LSUP_graph_add_done (LSUP_GraphIterator *it)
- {
- if (it->graph->store_type == LSUP_STORE_MEM)
- LSUP_htstore_add_done (it->ht_iter);
- else LSUP_mdbstore_add_done (it->mdb_iter);
- free (it);
- log_trace ("Done adding.");
- }
- LSUP_rc
- LSUP_graph_add (Graph *gr, const LSUP_Triple trp[], size_t *inserted)
- {
- LSUP_rc rc = LSUP_NOACTION;
- // Initialize iterator.
- LSUP_GraphIterator *it = LSUP_graph_add_init (gr);
- // Serialize and insert RDF triples.
- for (size_t i = 0; trp[i].s != NULL; i++) {
- log_trace ("Inserting triple #%lu", i);
- LSUP_rc db_rc = LSUP_graph_add_iter (it, trp + i);
- if (db_rc == LSUP_OK) rc = LSUP_OK;
- if (UNLIKELY (db_rc < 0)) return db_rc;
- }
- if (inserted) {
- if (gr->store_type == LSUP_STORE_MEM) {
- *inserted = LSUP_htiter_cur (it->ht_iter);
- } else {
- *inserted = LSUP_mdbiter_cur (it->mdb_iter);
- }
- }
- LSUP_graph_add_done (it);
- return rc;
- }
- LSUP_rc
- LSUP_graph_remove (
- LSUP_Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
- const LSUP_Term *o, size_t *ct)
- {
- LSUP_rc rc;
- LSUP_Buffer *ss = LSUP_term_serialize (s);
- LSUP_Buffer *sp = LSUP_term_serialize (p);
- LSUP_Buffer *so = LSUP_term_serialize (o);
- LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
- if (gr->store_type == LSUP_STORE_MEM)
- rc = LSUP_htstore_remove (gr->ht_store, ss, sp, so, ct);
- else
- rc = LSUP_mdbstore_remove (gr->mdb_store, ss, sp, so, sc, ct);
- LSUP_buffer_free (ss);
- LSUP_buffer_free (sp);
- LSUP_buffer_free (so);
- LSUP_buffer_free (sc);
- return rc;
- }
- GraphIterator *
- LSUP_graph_lookup (const Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
- const LSUP_Term *o, size_t *ct)
- {
- GraphIterator *it;
- MALLOC_GUARD (it, NULL);
- it->graph = gr;
- LSUP_Buffer *ss = LSUP_term_serialize (s);
- LSUP_Buffer *sp = LSUP_term_serialize (p);
- LSUP_Buffer *so = LSUP_term_serialize (o);
- LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
- if (it->graph->store_type == LSUP_STORE_MEM) {
- it->ht_iter = LSUP_htstore_lookup (it->graph->ht_store, ss, sp, so);
- if (ct) *ct = it->ct;
- } else it->mdb_iter = LSUP_mdbstore_lookup (
- it->graph->mdb_store, ss, sp, so, sc, ct);
- LSUP_buffer_free (ss);
- LSUP_buffer_free (sp);
- LSUP_buffer_free (so);
- LSUP_buffer_free (sc);
- return it;
- }
- LSUP_rc
- LSUP_graph_iter_next (GraphIterator *it, LSUP_Triple *spo)
- {
- /*
- * NOTE: Memory and MDB back ends treat sspo differently, whereas the
- * memory one owns the whole buffer structure, while the MDB one owns only
- * the data. Therefore they must be initialized and freed differently.
- */
- LSUP_BufferTriple *sspo;
- LSUP_Buffer *ss, *sp, *so;
- if (it->graph->store_type == LSUP_STORE_MEM) {
- ss = sp = so = NULL;
- } else {
- // Craft buffers manually so that their addresses are NULL and need not
- // be freed.
- CALLOC_GUARD (ss, LSUP_MEM_ERR);
- CALLOC_GUARD (sp, LSUP_MEM_ERR);
- CALLOC_GUARD (so, LSUP_MEM_ERR);
- }
- sspo = LSUP_btriple_new (ss, sp, so);
- LSUP_rc rc = graph_iter_next_buffer (it, sspo);
- if (rc == LSUP_OK) {
- spo->s = LSUP_term_new_from_buffer (sspo->s);
- if (!spo->s) return LSUP_ERROR;
- spo->p = LSUP_term_new_from_buffer (sspo->p);
- if (!spo->p) return LSUP_ERROR;
- spo->o = LSUP_term_new_from_buffer (sspo->o);
- if (!spo->o) return LSUP_ERROR;
- }
- if (it->graph->store_type == LSUP_STORE_MEM) free (sspo);
- else LSUP_btriple_free_shallow (sspo);
- return rc;
- }
- void
- LSUP_graph_iter_free (GraphIterator *it)
- {
- if (it->graph->store_type == LSUP_STORE_MEM)
- LSUP_htiter_free (it->ht_iter);
- else
- LSUP_mdbiter_free (it->mdb_iter);
- free (it);
- }
- size_t
- LSUP_graph_iter_cur (GraphIterator *it)
- { return LSUP_mdbiter_cur (it->mdb_iter); }
- bool
- LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
- {
- GraphIterator *it = LSUP_graph_lookup (
- gr, spo->s, spo->p, spo->o, NULL);
- LSUP_Triple *tmp_spo = TRP_DUMMY;
- bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
- LSUP_triple_free (tmp_spo);
- LSUP_graph_iter_free (it);
- return rc;
- }
- /*
- * Static functions.
- */
- /** @brief Advance iterator and return serialized triple.
- *
- * This is an internal function to pass raw buffers between higher-level
- * functions without serializing and deserializing triples.
- */
- inline static LSUP_rc
- graph_iter_next_buffer (GraphIterator *it, LSUP_BufferTriple *sspo)
- {
- LSUP_rc rc;
- if (it->graph->store_type == LSUP_STORE_MEM)
- rc = LSUP_htiter_next (it->ht_iter, sspo);
- else rc = LSUP_mdbiter_next (it->mdb_iter, sspo, NULL);
- return rc;
- }
- /**
- * Copy triples from a source graph into a destination one.
- *
- * The destination graph is not initialized here, so the copy is cumulative.
- */
- static LSUP_rc
- graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest)
- {
- LSUP_rc rc = LSUP_NOACTION;
- GraphIterator *it = LSUP_graph_lookup (src, NULL, NULL, NULL, NULL);
- LSUP_Triple spo;
- LSUP_GraphIterator *add_it = LSUP_graph_add_init (dest);
- while (LSUP_graph_iter_next (it, &spo) != LSUP_END) {
- LSUP_rc add_rc = LSUP_graph_add_iter (add_it, &spo);
- LSUP_triple_done (&spo);
- if (LIKELY (add_rc == LSUP_OK)) rc = LSUP_OK;
- else if (add_rc < 0) {
- rc = add_rc;
- break;
- }
- }
- LSUP_graph_add_done (add_it);
- LSUP_graph_iter_free (it);
- return rc;
- }
- /**
- * Extern inline definitions.
- */
- size_t LSUP_graph_size (const LSUP_Graph *gr);
|