|
@@ -1,29 +1,21 @@
|
|
-#include "store_htable.h"
|
|
|
|
-#include "store_mdb.h"
|
|
|
|
#include "graph.h"
|
|
#include "graph.h"
|
|
|
|
|
|
/*
|
|
/*
|
|
* Data types.
|
|
* Data types.
|
|
*/
|
|
*/
|
|
|
|
|
|
-typedef struct Graph {
|
|
|
|
- const LSUP_Env * env; ///> LSUP environment.
|
|
|
|
- LSUP_Term *uri; ///> Graph "name" (URI)
|
|
|
|
- const LSUP_StoreInt * interface; ///> Store interface.
|
|
|
|
- void * backend; ///> Store back end struct.
|
|
|
|
- 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.
|
|
|
|
- const LSUP_StoreIteratorInt * interface; ///> Iterator interface.
|
|
|
|
- void * backend; ///> Iterator back end struct.
|
|
|
|
- size_t ct; ///> Total matches.
|
|
|
|
-} GraphIterator;
|
|
|
|
|
|
+struct graph_t {
|
|
|
|
+ LSUP_Term *uri; ///< Graph "name" (URI).
|
|
|
|
+ LSUP_Store * store; ///< Store handle.
|
|
|
|
+ LSUP_NSMap * nsm; /**< Namespace map. NOTE: This is
|
|
|
|
+ * NULL for permanent stores. */
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct graph_iter_t {
|
|
|
|
+ LSUP_Store * store; ///< Store tied to the iterator.
|
|
|
|
+ void * data; ///< Iterator state.
|
|
|
|
+ size_t ct; ///< Total lookup matches.
|
|
|
|
+};
|
|
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -31,14 +23,11 @@ typedef struct GraphIterator {
|
|
*/
|
|
*/
|
|
|
|
|
|
inline static LSUP_rc
|
|
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);
|
|
|
|
|
|
+graph_iter_next_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo);
|
|
|
|
|
|
-#define ENTRY(a, b, c) (be) == (LSUP_STORE_##a) ||
|
|
|
|
|
|
+#define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
|
|
static inline bool
|
|
static inline bool
|
|
-check_backend (LSUP_store_type be)
|
|
|
|
|
|
+check_backend (LSUP_StoreType be)
|
|
{ return (BACKEND_TBL false); }
|
|
{ return (BACKEND_TBL false); }
|
|
#undef ENTRY
|
|
#undef ENTRY
|
|
|
|
|
|
@@ -47,12 +36,14 @@ check_backend (LSUP_store_type be)
|
|
* Graph API.
|
|
* Graph API.
|
|
*/
|
|
*/
|
|
|
|
|
|
-Graph *
|
|
|
|
-LSUP_graph_new_env (
|
|
|
|
- const LSUP_Env *env, LSUP_Term *uri, const LSUP_store_type store_type)
|
|
|
|
|
|
+LSUP_Graph *
|
|
|
|
+LSUP_graph_new (
|
|
|
|
+ LSUP_Term *uri, const LSUP_StoreType store_type, const char *store_id,
|
|
|
|
+ LSUP_NSMap *nsm, size_t size)
|
|
{
|
|
{
|
|
- if (UNLIKELY (!env)) {
|
|
|
|
- log_error ("No valid environment passed. Did you call LSUP_init()?");
|
|
|
|
|
|
+ if (UNLIKELY (!LSUP_is_init)) {
|
|
|
|
+ log_error (
|
|
|
|
+ "Environment is not initialized. Did you call LSUP_init()?");
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
if (UNLIKELY (!check_backend (store_type))) return NULL;
|
|
if (UNLIKELY (!check_backend (store_type))) return NULL;
|
|
@@ -61,32 +52,40 @@ LSUP_graph_new_env (
|
|
MALLOC_GUARD (gr, NULL);
|
|
MALLOC_GUARD (gr, NULL);
|
|
|
|
|
|
gr->uri = uri;
|
|
gr->uri = uri;
|
|
- gr->env = env;
|
|
|
|
- gr->nsm = env->nsm;
|
|
|
|
|
|
+ MALLOC_GUARD (gr->store, NULL);
|
|
|
|
|
|
- switch (store_type) {
|
|
|
|
-#define ENTRY(a, b, c) case LSUP_STORE_##a: gr->interface = &b; break;
|
|
|
|
|
|
+ gr->store->type = store_type;
|
|
|
|
+ gr->store->id = strdup (store_id);
|
|
|
|
+ if (UNLIKELY (!gr->store->id)) return NULL;
|
|
|
|
+
|
|
|
|
+ switch (gr->store->type) {
|
|
|
|
+#define ENTRY(a, b) \
|
|
|
|
+ case LSUP_STORE_##a: gr->store->sif = &b; break;
|
|
BACKEND_TBL
|
|
BACKEND_TBL
|
|
#undef ENTRY
|
|
#undef ENTRY
|
|
default:
|
|
default:
|
|
log_error ("Not a valid store type: %d", store_type); return NULL;
|
|
log_error ("Not a valid store type: %d", store_type); return NULL;
|
|
};
|
|
};
|
|
|
|
|
|
- gr->backend = gr->interface->new_fn();
|
|
|
|
|
|
+ // TODO implement custom default context.
|
|
|
|
+ gr->store->data = gr->store->sif->new_fn (store_id, size);
|
|
|
|
+
|
|
|
|
+ if (gr->store->sif->features & LSUP_STORE_PERM) gr->nsm = NULL;
|
|
|
|
+ else gr->nsm = nsm ? nsm : LSUP_default_nsm;
|
|
|
|
|
|
log_debug ("Graph created.");
|
|
log_debug ("Graph created.");
|
|
return gr;
|
|
return gr;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+#if 0
|
|
LSUP_Graph *
|
|
LSUP_Graph *
|
|
-LSUP_graph_copy (const Graph *src)
|
|
|
|
|
|
+LSUP_graph_copy (const LSUP_Graph *src, LSUP_Term *uri)
|
|
{
|
|
{
|
|
- LSUP_Graph *dest = LSUP_graph_new_env (
|
|
|
|
- src->env, LSUP_iriref_new (NULL, NULL), src->store_type);
|
|
|
|
|
|
+ LSUP_Graph *dest = LSUP_graph_new (uri, src->store_type, src->nsm);
|
|
if (UNLIKELY (!dest)) return NULL;
|
|
if (UNLIKELY (!dest)) return NULL;
|
|
|
|
|
|
- LSUP_rc rc = graph_copy_contents (src, dest);
|
|
|
|
|
|
+ LSUP_rc rc = LSUP_graph_copy_contents (src, dest);
|
|
if (UNLIKELY (rc != LSUP_OK)) return NULL;
|
|
if (UNLIKELY (rc != LSUP_OK)) return NULL;
|
|
|
|
|
|
return dest;
|
|
return dest;
|
|
@@ -107,7 +106,7 @@ LSUP_graph_store (
|
|
if (UNLIKELY (!dest)) return LSUP_DB_ERR;
|
|
if (UNLIKELY (!dest)) return LSUP_DB_ERR;
|
|
|
|
|
|
LSUP_rc rc;
|
|
LSUP_rc rc;
|
|
- rc = graph_copy_contents (src, dest);
|
|
|
|
|
|
+ rc = LSUP_graph_copy_contents (src, dest);
|
|
if (UNLIKELY (rc < 0)) return LSUP_DB_ERR;
|
|
if (UNLIKELY (rc < 0)) return LSUP_DB_ERR;
|
|
|
|
|
|
if (src->store_type == LSUP_STORE_MEM) {
|
|
if (src->store_type == LSUP_STORE_MEM) {
|
|
@@ -120,49 +119,95 @@ LSUP_graph_store (
|
|
|
|
|
|
return LSUP_OK;
|
|
return LSUP_OK;
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
|
-// TODO support boolean ops between any types of graphs.
|
|
|
|
-Graph *
|
|
|
|
|
|
+LSUP_rc
|
|
LSUP_graph_bool_op(
|
|
LSUP_graph_bool_op(
|
|
- const LSUP_bool_op op, const Graph *gr1, const Graph *gr2)
|
|
|
|
|
|
+ const LSUP_bool_op op, const LSUP_Graph *gr1, const LSUP_Graph *gr2,
|
|
|
|
+ LSUP_Graph *res)
|
|
{
|
|
{
|
|
- 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;
|
|
|
|
|
|
+ LSUP_rc rc;
|
|
|
|
+ if (UNLIKELY (
|
|
|
|
+ op != LSUP_BOOL_UNION
|
|
|
|
+ && op != LSUP_BOOL_SUBTRACTION
|
|
|
|
+ && op != LSUP_BOOL_INTERSECTION
|
|
|
|
+ && op != LSUP_BOOL_XOR)) {
|
|
|
|
+ log_error ("Invalid boolean operation: %d.", op);
|
|
|
|
+
|
|
|
|
+ rc = LSUP_VALUE_ERR;
|
|
|
|
+ goto fail;
|
|
}
|
|
}
|
|
- 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;
|
|
|
|
|
|
+
|
|
|
|
+ if (op == LSUP_BOOL_UNION) {
|
|
|
|
+ PCHECK (LSUP_graph_copy_contents (gr1, res), fail);
|
|
|
|
+ PCHECK (LSUP_graph_copy_contents (gr2, res), fail);
|
|
|
|
+
|
|
|
|
+ return LSUP_OK;
|
|
}
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
+ LSUP_Buffer
|
|
|
|
+ *res_sc = LSUP_term_serialize (res->uri),
|
|
|
|
+ *gr1_sc = LSUP_term_serialize (gr1->uri),
|
|
|
|
+ *gr2_sc = LSUP_term_serialize (gr2->uri);
|
|
|
|
+ void *lu1_it, *lu2_it, *add_it;
|
|
|
|
+ LSUP_BufferTriple *sspo;
|
|
|
|
+ size_t ct;
|
|
|
|
+
|
|
|
|
+ add_it = res->store->sif->add_init_fn (res->store->data, res_sc);
|
|
|
|
+
|
|
|
|
+ size_t i = 0;
|
|
|
|
+ if (op == LSUP_BOOL_XOR) {
|
|
|
|
+ // Add triples from gr2 if not found in gr1.
|
|
|
|
+ lu2_it = gr2->store->sif->lookup_fn (
|
|
|
|
+ gr2->store->data, NULL, NULL, NULL, gr2_sc, NULL);
|
|
|
|
+ while (gr2->store->sif->lu_next_fn (lu2_it, sspo, NULL) == LSUP_OK) {
|
|
|
|
+ lu1_it = gr1->store->sif->lookup_fn (
|
|
|
|
+ gr1->store->data, sspo->s, sspo->p, sspo->o, gr1_sc, &ct);
|
|
|
|
+ if (ct > 0)
|
|
|
|
+ res->store->sif->add_iter_fn (add_it, sspo);
|
|
|
|
+ gr1->store->sif->lu_free_fn (lu1_it);
|
|
|
|
+ }
|
|
|
|
+ gr2->store->sif->lu_free_fn (lu2_it);
|
|
|
|
+ }
|
|
|
|
|
|
- return res;
|
|
|
|
|
|
+ lu1_it = gr1->store->sif->lookup_fn (
|
|
|
|
+ gr1->store->data, NULL, NULL, NULL, gr1_sc, NULL);
|
|
|
|
+ while (gr1->store->sif->lu_next_fn (lu1_it, sspo, NULL) == LSUP_OK) {
|
|
|
|
+ lu2_it = gr2->store->sif->lookup_fn (
|
|
|
|
+ gr2->store->data, sspo->s, sspo->p, sspo->o, gr2_sc, &ct);
|
|
|
|
+ // For XOR and subtraction, add if not found.
|
|
|
|
+ // For intersection, add if found.
|
|
|
|
+ if (ct == 0 ^ op == LSUP_BOOL_INTERSECTION)
|
|
|
|
+ res->store->sif->add_iter_fn (add_it, sspo);
|
|
|
|
+ gr2->store->sif->lu_free_fn (lu2_it);
|
|
|
|
+ }
|
|
|
|
+ gr1->store->sif->lu_free_fn (lu1_it);
|
|
|
|
+
|
|
|
|
+ res->store->sif->add_done_fn (add_it);
|
|
|
|
+ LSUP_buffer_free (res_sc);
|
|
|
|
+ LSUP_buffer_free (gr1_sc);
|
|
|
|
+ LSUP_buffer_free (gr2_sc);
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+
|
|
|
|
+fail:
|
|
|
|
+ LSUP_graph_free (res);
|
|
|
|
+ return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
void
|
|
LSUP_graph_free (LSUP_Graph *gr)
|
|
LSUP_graph_free (LSUP_Graph *gr)
|
|
{
|
|
{
|
|
- if (LIKELY (gr != NULL)) {
|
|
|
|
- LSUP_term_free (gr->uri);
|
|
|
|
|
|
+ if (UNLIKELY (!gr)) return;
|
|
|
|
|
|
- if (gr->store_type == LSUP_STORE_MEM)
|
|
|
|
- LSUP_htstore_free (gr->ht_store);
|
|
|
|
|
|
+ LSUP_term_free (gr->uri);
|
|
|
|
+ free (gr->store->id);
|
|
|
|
+ gr->store->sif->free_fn (gr->store->data);
|
|
|
|
+ free (gr->store);
|
|
|
|
|
|
- free (gr);
|
|
|
|
- }
|
|
|
|
|
|
+ free (gr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -186,61 +231,53 @@ LSUP_graph_set_uri (LSUP_Graph *gr, LSUP_Term *uri)
|
|
|
|
|
|
|
|
|
|
LSUP_NSMap *
|
|
LSUP_NSMap *
|
|
-LSUP_graph_namespace (const Graph *gr)
|
|
|
|
|
|
+LSUP_graph_namespace (const LSUP_Graph *gr)
|
|
{
|
|
{
|
|
- if (gr->store_type == LSUP_STORE_MEM) return gr->nsm;
|
|
|
|
|
|
+ // If nsm_get_fn is not defined, the store has no own NS map.
|
|
|
|
+ if (!gr->store->sif->nsm_get_fn) return gr->nsm;
|
|
|
|
|
|
- LSUP_NSMap *nsm;
|
|
|
|
- if (LSUP_mdbstore_nsm_get (gr->mdb_store, &nsm) < 0) return NULL;
|
|
|
|
- return nsm;
|
|
|
|
|
|
+ return gr->store->sif->nsm_get_fn (gr->store->data);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
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)
|
|
|
|
|
|
+LSUP_graph_set_namespace (LSUP_Graph *gr, LSUP_NSMap *nsm)
|
|
{
|
|
{
|
|
- 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);
|
|
|
|
|
|
+ if (!gr->store->sif->nsm_get_fn) gr->nsm = nsm;
|
|
|
|
+ else log_warn ("Graph back end has a stored NS map.");
|
|
|
|
+}
|
|
|
|
|
|
- LSUP_graph_iter_free (it);
|
|
|
|
|
|
|
|
- return ct;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
+size_t
|
|
|
|
+LSUP_graph_size (const LSUP_Graph *gr)
|
|
|
|
+{ return gr->store->sif->size_fn (gr->store->data); }
|
|
|
|
|
|
|
|
|
|
bool
|
|
bool
|
|
-LSUP_graph_equals (const Graph *gr1, const Graph *gr2)
|
|
|
|
|
|
+LSUP_graph_equals (const LSUP_Graph *gr1, const LSUP_Graph *gr2)
|
|
{
|
|
{
|
|
- LSUP_Graph *res = LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2);
|
|
|
|
|
|
+ LSUP_Graph *res = LSUP_graph_new (NULL, LSUP_STORE_HTABLE, NULL, NULL, 0);
|
|
|
|
+ LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2, res);
|
|
|
|
+ bool ret = (LSUP_graph_size (res) == 0);
|
|
|
|
|
|
- return (LSUP_graph_size (res) == 0);
|
|
|
|
|
|
+ LSUP_graph_free (res);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-GraphIterator *
|
|
|
|
|
|
+LSUP_GraphIterator *
|
|
LSUP_graph_add_init (LSUP_Graph *gr)
|
|
LSUP_graph_add_init (LSUP_Graph *gr)
|
|
{
|
|
{
|
|
- GraphIterator *it;
|
|
|
|
|
|
+ LSUP_GraphIterator *it;
|
|
CALLOC_GUARD (it, NULL);
|
|
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);
|
|
|
|
- }
|
|
|
|
|
|
+ LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
|
|
|
|
+
|
|
|
|
+ it->data = gr->store->sif->add_init_fn (gr->store->data, sc);
|
|
|
|
+ LSUP_buffer_free (sc);
|
|
|
|
|
|
- it->graph = gr;
|
|
|
|
|
|
+ it->store = gr->store;
|
|
|
|
|
|
return it;
|
|
return it;
|
|
}
|
|
}
|
|
@@ -254,35 +291,22 @@ LSUP_graph_add_iter (LSUP_GraphIterator *it, const LSUP_Triple *spo)
|
|
LSUP_BufferTriple *sspo = LSUP_triple_serialize (spo);
|
|
LSUP_BufferTriple *sspo = LSUP_triple_serialize (spo);
|
|
if (UNLIKELY (!sspo)) return LSUP_MEM_ERR;
|
|
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);
|
|
|
|
|
|
+ PCHECK (it->store->sif->add_iter_fn (it->data, sspo), finally);
|
|
|
|
|
|
|
|
+ // Store datatype term permanently if the store supports it.
|
|
|
|
+ if (it->store->sif->add_term_fn) {
|
|
for (int i = 0; i < 3; i++) {
|
|
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);
|
|
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))
|
|
|
|
- ) {
|
|
|
|
|
|
+ if (term->type == LSUP_TERM_LITERAL) {
|
|
LSUP_Buffer *ser_dtype = LSUP_term_serialize (term->datatype);
|
|
LSUP_Buffer *ser_dtype = LSUP_term_serialize (term->datatype);
|
|
- LSUP_mdbstore_add_term (it->graph->mdb_store, ser_dtype);
|
|
|
|
|
|
+ it->store->sif->add_term_fn (it->store->data, ser_dtype);
|
|
LSUP_buffer_free (ser_dtype);
|
|
LSUP_buffer_free (ser_dtype);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+finally:
|
|
LSUP_btriple_free (sspo);
|
|
LSUP_btriple_free (sspo);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -291,18 +315,11 @@ LSUP_graph_add_iter (LSUP_GraphIterator *it, const LSUP_Triple *spo)
|
|
|
|
|
|
void
|
|
void
|
|
LSUP_graph_add_done (LSUP_GraphIterator *it)
|
|
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.");
|
|
|
|
-}
|
|
|
|
|
|
+{ it->store->sif->add_done_fn (it->data); }
|
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
LSUP_rc
|
|
-LSUP_graph_add (Graph *gr, const LSUP_Triple trp[], size_t *ct)
|
|
|
|
|
|
+LSUP_graph_add (LSUP_Graph *gr, const LSUP_Triple trp[], size_t *ct)
|
|
{
|
|
{
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
|
|
|
|
@@ -322,9 +339,13 @@ LSUP_graph_add (Graph *gr, const LSUP_Triple trp[], size_t *ct)
|
|
// A duplicate will return LSUP_NOACTION and not increment the
|
|
// A duplicate will return LSUP_NOACTION and not increment the
|
|
// counter.
|
|
// counter.
|
|
}
|
|
}
|
|
- if (UNLIKELY (db_rc < 0)) return db_rc;
|
|
|
|
|
|
+ if (UNLIKELY (db_rc < 0)) {
|
|
|
|
+ rc = db_rc;
|
|
|
|
+ goto finally;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+finally:
|
|
LSUP_graph_add_done (it);
|
|
LSUP_graph_add_done (it);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -344,10 +365,7 @@ LSUP_graph_remove (
|
|
*so = LSUP_term_serialize (o),
|
|
*so = LSUP_term_serialize (o),
|
|
*sc = LSUP_term_serialize (gr->uri);
|
|
*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);
|
|
|
|
|
|
+ rc = gr->store->sif->remove_fn (gr->store->data, ss, sp, so, sc, ct);
|
|
|
|
|
|
LSUP_buffer_free (ss);
|
|
LSUP_buffer_free (ss);
|
|
LSUP_buffer_free (sp);
|
|
LSUP_buffer_free (sp);
|
|
@@ -358,26 +376,59 @@ LSUP_graph_remove (
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-GraphIterator *
|
|
|
|
-LSUP_graph_lookup (const Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
|
|
|
|
|
|
+/**
|
|
|
|
+ * Copy triples from a source graph into a destination one.
|
|
|
|
+ *
|
|
|
|
+ * The destination graph is not initialized here, so the copy is cumulative.
|
|
|
|
+ */
|
|
|
|
+LSUP_rc
|
|
|
|
+LSUP_graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest)
|
|
|
|
+{
|
|
|
|
+ LSUP_rc rc = LSUP_NOACTION;
|
|
|
|
+
|
|
|
|
+ LSUP_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;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+LSUP_GraphIterator *
|
|
|
|
+LSUP_graph_lookup (
|
|
|
|
+ const LSUP_Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
|
|
const LSUP_Term *o, size_t *ct)
|
|
const LSUP_Term *o, size_t *ct)
|
|
{
|
|
{
|
|
- GraphIterator *it;
|
|
|
|
|
|
+ LSUP_GraphIterator *it;
|
|
MALLOC_GUARD (it, NULL);
|
|
MALLOC_GUARD (it, NULL);
|
|
|
|
|
|
- it->graph = gr;
|
|
|
|
|
|
+ it->store = gr->store;
|
|
|
|
|
|
- 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, ct);
|
|
|
|
|
|
+ LSUP_Buffer
|
|
|
|
+ *ss = LSUP_term_serialize (s),
|
|
|
|
+ *sp = LSUP_term_serialize (p),
|
|
|
|
+ *so = LSUP_term_serialize (o),
|
|
|
|
+ *sc = LSUP_term_serialize (gr->uri);
|
|
|
|
|
|
- else it->mdb_iter = LSUP_mdbstore_lookup (
|
|
|
|
- it->graph->mdb_store, ss, sp, so, sc, ct);
|
|
|
|
|
|
+ it->data = it->store->sif->lookup_fn (it->store, ss, sp, so, sc, ct);
|
|
|
|
+ if (UNLIKELY (!it->data)) {
|
|
|
|
+ free (it);
|
|
|
|
+ it = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
LSUP_buffer_free (ss);
|
|
LSUP_buffer_free (ss);
|
|
LSUP_buffer_free (sp);
|
|
LSUP_buffer_free (sp);
|
|
@@ -389,27 +440,18 @@ LSUP_graph_lookup (const Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
|
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
LSUP_rc
|
|
-LSUP_graph_iter_next (GraphIterator *it, LSUP_Triple *spo)
|
|
|
|
|
|
+LSUP_graph_iter_next (LSUP_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;
|
|
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.
|
|
|
|
|
|
+ LSUP_BufferTriple *sspo;
|
|
|
|
+ if (it->store->sif->features & LSUP_STORE_COW) {
|
|
CALLOC_GUARD (ss, LSUP_MEM_ERR);
|
|
CALLOC_GUARD (ss, LSUP_MEM_ERR);
|
|
CALLOC_GUARD (sp, LSUP_MEM_ERR);
|
|
CALLOC_GUARD (sp, LSUP_MEM_ERR);
|
|
CALLOC_GUARD (so, LSUP_MEM_ERR);
|
|
CALLOC_GUARD (so, LSUP_MEM_ERR);
|
|
|
|
+ sspo = LSUP_btriple_new (ss, sp, so);
|
|
|
|
+ } else {
|
|
|
|
+ // TODO copy-on-retrieval stores. None yet.
|
|
}
|
|
}
|
|
- sspo = LSUP_btriple_new (ss, sp, so);
|
|
|
|
|
|
|
|
LSUP_rc rc = graph_iter_next_buffer (it, sspo);
|
|
LSUP_rc rc = graph_iter_next_buffer (it, sspo);
|
|
|
|
|
|
@@ -422,21 +464,20 @@ LSUP_graph_iter_next (GraphIterator *it, LSUP_Triple *spo)
|
|
if (!spo->o) return LSUP_ERROR;
|
|
if (!spo->o) return LSUP_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
- if (it->graph->store_type == LSUP_STORE_MEM) free (sspo);
|
|
|
|
- else LSUP_btriple_free_shallow (sspo);
|
|
|
|
|
|
+ if (it->store->sif->features & LSUP_STORE_COW) {
|
|
|
|
+ LSUP_btriple_free_shallow (sspo);
|
|
|
|
+ } else {
|
|
|
|
+ // TODO copy-on-retrieval stores. None yet.
|
|
|
|
+ }
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
void
|
|
-LSUP_graph_iter_free (GraphIterator *it)
|
|
|
|
|
|
+LSUP_graph_iter_free (LSUP_GraphIterator *it)
|
|
{
|
|
{
|
|
- if (it->graph->store_type == LSUP_STORE_MEM)
|
|
|
|
- LSUP_htiter_free (it->ht_iter);
|
|
|
|
- else
|
|
|
|
- LSUP_mdbiter_free (it->mdb_iter);
|
|
|
|
-
|
|
|
|
|
|
+ it->store->sif->lu_free_fn (it->data);
|
|
free (it);
|
|
free (it);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -444,7 +485,7 @@ LSUP_graph_iter_free (GraphIterator *it)
|
|
bool
|
|
bool
|
|
LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
|
|
LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
|
|
{
|
|
{
|
|
- GraphIterator *it = LSUP_graph_lookup (
|
|
|
|
|
|
+ LSUP_GraphIterator *it = LSUP_graph_lookup (
|
|
gr, spo->s, spo->p, spo->o, NULL);
|
|
gr, spo->s, spo->p, spo->o, NULL);
|
|
LSUP_Triple *tmp_spo = TRP_DUMMY;
|
|
LSUP_Triple *tmp_spo = TRP_DUMMY;
|
|
bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
|
|
bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
|
|
@@ -460,54 +501,14 @@ LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
|
|
* Static functions.
|
|
* Static functions.
|
|
*/
|
|
*/
|
|
|
|
|
|
-/** @brief Advance iterator and return serialized triple.
|
|
|
|
|
|
+/** @brief Advance an iterator and return a serialized triple.
|
|
*
|
|
*
|
|
* This is an internal function to pass raw buffers between higher-level
|
|
* This is an internal function to pass raw buffers between higher-level
|
|
* functions without serializing and deserializing triples.
|
|
* functions without serializing and deserializing triples.
|
|
*/
|
|
*/
|
|
inline static LSUP_rc
|
|
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;
|
|
|
|
-}
|
|
|
|
|
|
+graph_iter_next_buffer (LSUP_GraphIterator *it, LSUP_BufferTriple *sspo)
|
|
|
|
+{ return it->store->sif->lu_next_fn (it->data, sspo, NULL); }
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|