Browse Source

Merge branch 'graph_txn' of scossu/lsup_rdf into master

scossu 1 year ago
parent
commit
9559777694
11 changed files with 162 additions and 79 deletions
  1. 5 13
      include/graph.h
  2. 40 5
      include/store.h
  3. 0 1
      include/store_interface.h
  4. 1 2
      src/codec/lexer_nt.re
  5. 1 2
      src/codec/lexer_ttl.re
  6. 12 34
      src/graph.c
  7. 47 0
      src/store.c
  8. 2 2
      src/store_mdb.c
  9. 1 2
      test/test_codec_nt.c
  10. 1 2
      test/test_codec_ttl.c
  11. 52 16
      test/test_graph.c

+ 5 - 13
include/graph.h

@@ -20,20 +20,14 @@ typedef struct graph_iter_t LSUP_GraphIterator;
 
 
 /** @brief Create an empty graph.
+ *
+ * @param[in] store Back end store handle. It may be the result of
+ * #LSUP_store_new(), or NULL; in the latter case, it defaults to a temporary
+ * HTable store that is freed together with the graph.
  *
  * @param[in] uri URI of the new graph. If NULL, a UUID4 URN is generated. The
  *  graph owns the handle.
  *
- * @param store_type[in] Type of store backing the graph. One of the values of
- *  #LSUP_StoreType.
- *
- * @param[in] store_id Identifier for the back end store. This may be
- *  interpreted differently by each store implementation. For the MDB store,
- *  this is the file path where the store is located. It is ignored by volatile
- *  stores (with LSUP_STORE_PERM feature flag set to false). If a store
- *  does not exist for the given identifier, a new one is initialized. If this
- *  parameter is NULL, the default store for the selected type is used.
- *
  * @param[in] nsm Namespace map to use for an in-memory graph. This is ignored
  *  by graphs backed by permanent stores, which handle their own namespace map.
  *  If this is NULL, the graph is assigned a global namespace map that lives
@@ -42,9 +36,7 @@ typedef struct graph_iter_t LSUP_GraphIterator;
  * @return New graph, or NULL on error. Must be freed with #LSUP_graph_free().
  */
 LSUP_Graph *
-LSUP_graph_new (
-        LSUP_Term *uri, const LSUP_StoreType store_type, const char *store_id,
-        LSUP_NSMap *nsm, size_t size);
+LSUP_graph_new (LSUP_Store *store, LSUP_Term *uri, LSUP_NSMap *nsm);
 
 
 /** @brief Copy triples from a source graph into a destination one.

+ 40 - 5
include/store.h

@@ -41,11 +41,6 @@ BACKEND_TBL
 } LSUP_StoreType;
 
 
-/** @brief Return store interface for a specific type.
- */
-const LSUP_StoreInt *LSUP_store_int (LSUP_StoreType type);
-
-
 /** @brief Store structure.
  *
  * Code using the store interface should create an instance of this structure
@@ -69,4 +64,44 @@ typedef struct store_t {
     void *                          data;   ///< Store back end data.
 } LSUP_Store;
 
+
+/** @brief Return store interface for a specific type.
+ */
+const LSUP_StoreInt *LSUP_store_int (LSUP_StoreType type);
+
+
+/** @brief Create a new store.
+ *
+ * The life cycle of a store may normally outspan the one of one or multiple
+ * graphs with the same back end, hence it is managed independently.
+ *
+ * @param store_type[in] Type of store backing the graph. One of the values of
+ *  #LSUP_StoreType.
+ *
+ * @param[in] store_id Identifier for the store. This may be
+ *  interpreted differently by each store implementation. For the MDB store,
+ *  this is the file path where the store is located. It is ignored by volatile
+ *  stores (with LSUP_STORE_PERM feature flag set to false). If a store
+ *  does not exist for the given identifier, a new one is initialized. If this
+ *  parameter is NULL, the default store for the selected type is used.
+ *
+ *  @param[in] size Initial size of the store. Only used for optimization
+ *  purposes. It may be ignored by some implementations and it is always safe
+ *  to set to 0.
+ *
+ *  @return Store handle that should be passed to #LSUP_store_new(). It must be
+ *  freed with #LSUP_store_free().
+ */
+LSUP_Store *
+LSUP_store_new (
+        const LSUP_StoreType store_type, const char *store_id, size_t size);
+
+
+/** @brief Free a store created with #LSUP_store_new().
+ *
+ * @param[in] store Store handle.
+ */
+void
+LSUP_store_free (LSUP_Store *store);
+
 #endif  /* LSUP_STORE_H */

+ 0 - 1
include/store_interface.h

@@ -53,7 +53,6 @@ typedef enum {
     LSUP_STORE_IDX      = 1<<2,   ///< Store is fully SPO(C)-indexed.
     LSUP_STORE_TXN      = 1<<3,   ///< Supports transaction handling.
     LSUP_STORE_COW      = 1<<4,   ///< Copy on write. @sa #iter_next_fn_t()
-    //LSUP_STORE_NET      = 1<<5,   ///< Store is over a network protocol.
 } LSUP_StoreFeature;
 
 

+ 1 - 2
src/codec/lexer_nt.re

@@ -267,8 +267,7 @@ LSUP_nt_parse_doc (FILE *fh, LSUP_Graph **gr_p, size_t *ct, char **err_p)
 
     LSUP_rc rc;
 
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *gr = LSUP_graph_new (NULL, LSUP_iriref_new (NULL, NULL), NULL);
     if (UNLIKELY (!gr)) return LSUP_MEM_ERR;
 
     LSUP_GraphIterator *it = LSUP_graph_add_init (gr);

+ 1 - 2
src/codec/lexer_ttl.re

@@ -376,8 +376,7 @@ LSUP_ttl_parse_doc (FILE *fh, LSUP_Graph **gr_p, size_t *ct, char **err_p)
     void *parser = TTLParseAlloc (malloc);
 
     // TODO add basic NS, critically xsd: and rdf:
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *gr = LSUP_graph_new (NULL, LSUP_iriref_new (NULL, NULL), NULL);
     if (UNLIKELY (!gr)) return LSUP_MEM_ERR;
 
     state->it = LSUP_graph_add_init (gr);

+ 12 - 34
src/graph.c

@@ -40,48 +40,22 @@ check_backend (LSUP_StoreType be)
 #undef ENTRY
 
 
-#define ENTRY(a, b) case LSUP_STORE_##a: return &b;
-static inline const LSUP_StoreInt *
-select_interface (LSUP_StoreType be) {
-    switch (be) {
-        BACKEND_TBL
-        default: return NULL;
-    }
-}
-#undef ENTRY
-
-
 /*
  * Graph API.
  */
 
 LSUP_Graph *
-LSUP_graph_new (
-        LSUP_Term *uri, const LSUP_StoreType store_type, const char *store_id,
-        LSUP_NSMap *nsm, size_t size)
+LSUP_graph_new (LSUP_Store *store, LSUP_Term *uri, LSUP_NSMap *nsm)
 {
-    if (UNLIKELY (!LSUP_IS_INIT)) {
-        log_error (
-                "Environment is not initialized. Did you call LSUP_init()?");
-        return NULL;
-    }
-    const LSUP_StoreInt *sif = select_interface (store_type);
-    if (UNLIKELY (!sif)) {
-        log_error ("Not a valid store type: %d", store_type);
-        return NULL;
-    }
+    // Create a HTable graph by default.
+    if (!store) store = LSUP_store_new (LSUP_STORE_HTABLE, NULL, 0);
 
     LSUP_Graph *gr;
     MALLOC_GUARD (gr, NULL);
 
+    if (!uri) uri = LSUP_iriref_new (NULL, NULL);
     gr->uri = uri;
-    MALLOC_GUARD (gr->store, NULL);
-
-    gr->store->type = store_type;
-    gr->store->sif = sif;
-    gr->store->id = store_id ? strdup (store_id) : NULL;
-    // TODO implement custom default context.
-    gr->store->data = gr->store->sif->new_fn (store_id, size);
+    gr->store = store;
 
     if (gr->store->sif->features & LSUP_STORE_PERM) gr->nsm = NULL;
     else gr->nsm = nsm ? nsm : LSUP_default_nsm;
@@ -175,8 +149,12 @@ LSUP_graph_free (LSUP_Graph *gr)
 
     LSUP_term_free (gr->uri);
     free (gr->store->id);
-    gr->store->sif->free_fn (gr->store->data);
-    free (gr->store);
+    // If the store is a HTable, it means it has been created with the graph
+    // and must go with it.
+    if (gr->store->type == LSUP_STORE_HTABLE) {
+        gr->store->sif->free_fn (gr->store->data);
+        free (gr->store);
+    }
 
     free (gr);
 }
@@ -232,7 +210,7 @@ LSUP_graph_size (const LSUP_Graph *gr)
 bool
 LSUP_graph_equals (const LSUP_Graph *gr1, const LSUP_Graph *gr2)
 {
-    LSUP_Graph *res = LSUP_graph_new (NULL, LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *res = LSUP_graph_new (NULL, NULL, NULL);
     LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2, res);
     bool ret = (LSUP_graph_size (res) == 0);
 

+ 47 - 0
src/store.c

@@ -1,6 +1,17 @@
 #include "store.h"
 
 
+#define ENTRY(a, b) case LSUP_STORE_##a: return &b;
+static inline const LSUP_StoreInt *
+select_interface (LSUP_StoreType be) {
+    switch (be) {
+        BACKEND_TBL
+        default: return NULL;
+    }
+}
+#undef ENTRY
+
+
 const LSUP_StoreInt *
 LSUP_store_int (LSUP_StoreType type) {
     switch (type) {
@@ -11,3 +22,39 @@ BACKEND_TBL
         default: return NULL;
     }
 }
+
+
+LSUP_Store *
+LSUP_store_new (
+        const LSUP_StoreType store_type, const char *store_id, size_t size)
+{
+    if (UNLIKELY (!LSUP_IS_INIT)) {
+        log_error (
+                "Environment is not initialized. Did you call LSUP_init()?");
+        return NULL;
+    }
+    const LSUP_StoreInt *sif = select_interface (store_type);
+    if (UNLIKELY (!sif)) {
+        log_error ("Not a valid store type: %d", store_type);
+        return NULL;
+    }
+
+    LSUP_Store *store;
+    MALLOC_GUARD (store, NULL);
+
+    store->type = store_type;
+    store->sif = sif;
+    store->id = store_id ? strdup (store_id) : NULL;
+    // TODO implement custom default context.
+    store->data = store->sif->new_fn (store_id, size);
+
+    return store;
+}
+
+
+void
+LSUP_store_free (LSUP_Store *store)
+{
+    store->sif->free_fn (store->data);
+    free (store);
+}

+ 2 - 2
src/store_mdb.c

@@ -580,11 +580,11 @@ mdbstore_add_init (void *h, const LSUP_Buffer *sc, void *th)
         it->data.mv_data = sc->addr;
         it->data.mv_size = sc->size;
 
-        int db_rc = mdb_put(
+        int db_rc = mdb_put (
                 it->txn, it->store->dbi[IDX_T_ST],
                 &it->key, &it->data, MDB_NOOVERWRITE);
         if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
-            LOG_RC (db_rc);
+            log_error (LSUP_strerror (db_rc));
             mdb_txn_abort (it->txn);
             return NULL;
         }

+ 1 - 2
test/test_codec_nt.c

@@ -164,8 +164,7 @@ int
 test_encode_nt_graph()
 {
     log_info ("Test encoding graph document.");
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *gr = LSUP_graph_new (NULL, NULL, NULL);
     if (!gr) return LSUP_MEM_ERR;
 
     size_t ins;

+ 1 - 2
test/test_codec_ttl.c

@@ -14,8 +14,7 @@ int
 test_encode_ttl_graph()
 {
     log_info ("Test encoding graph document.");
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *gr = LSUP_graph_new (NULL, NULL, NULL);
     if (!gr) return LSUP_MEM_ERR;
 
     size_t ins;

+ 52 - 16
test/test_graph.c

@@ -10,8 +10,14 @@ _graph_new (LSUP_StoreType type)
     const LSUP_StoreInt *sif = LSUP_store_int (type);
     if (sif->setup_fn) sif->setup_fn (NULL, true);
 
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), type, NULL, NULL, 0);
+    LSUP_Graph *gr;
+    LSUP_Store *store;
+    if (type == LSUP_STORE_HTABLE) {
+        gr = LSUP_graph_new (NULL, NULL, NULL);
+    } else {
+        store = LSUP_store_new (type, NULL, 0);
+        gr = LSUP_graph_new (store, NULL, NULL);
+    }
     ASSERT (gr != NULL, "Error creating graph!");
 
     EXPECT_PASS (LSUP_graph_set_uri (gr, LSUP_iriref_new ("urn:gr:1", NULL)));
@@ -27,6 +33,7 @@ _graph_new (LSUP_StoreType type)
     EXPECT_INT_EQ (LSUP_graph_size (gr), 0);
 
     LSUP_graph_free (gr);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
 
     return 0;
 }
@@ -40,8 +47,14 @@ _graph_add (LSUP_StoreType type)
 
     LSUP_Triple *trp = create_triples();
 
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), type, NULL, NULL, 0);
+    LSUP_Graph *gr;
+    LSUP_Store *store;
+    if (type == LSUP_STORE_HTABLE) {
+        gr = LSUP_graph_new (NULL, NULL, NULL);
+    } else {
+        store = LSUP_store_new (type, NULL, 0);
+        gr = LSUP_graph_new (store, NULL, NULL);
+    }
     ASSERT (gr != NULL, "Error creating graph!");
 
     size_t ct;
@@ -62,6 +75,7 @@ _graph_add (LSUP_StoreType type)
     free_triples (trp); // gr copied data.
 
     LSUP_graph_free (gr);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
 
     return 0;
 }
@@ -121,8 +135,14 @@ _graph_lookup (LSUP_StoreType type)
 
     if (sif->setup_fn) sif->setup_fn (NULL, true);
 
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), type, NULL, NULL, 0);
+    LSUP_Graph *gr;
+    LSUP_Store *store;
+    if (type == LSUP_STORE_HTABLE) {
+        gr = LSUP_graph_new (NULL, NULL, NULL);
+    } else {
+        store = LSUP_store_new (type, NULL, 0);
+        gr = LSUP_graph_new (store, NULL, NULL);
+    }
 
     size_t ct;
     LSUP_graph_add (gr, trp, &ct);
@@ -166,6 +186,7 @@ _graph_lookup (LSUP_StoreType type)
 
     free_triples (trp);
     LSUP_graph_free (gr);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
 
     return 0;
 }
@@ -179,8 +200,14 @@ _graph_remove (LSUP_StoreType type)
 
     LSUP_Triple *trp = create_triples();
 
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), type, NULL, NULL, 0);
+    LSUP_Graph *gr;
+    LSUP_Store *store;
+    if (type == LSUP_STORE_HTABLE) {
+        gr = LSUP_graph_new (NULL, NULL, NULL);
+    } else {
+        store = LSUP_store_new (type, NULL, 0);
+        gr = LSUP_graph_new (store, NULL, NULL);
+    }
 
     size_t ct;
     LSUP_graph_add (gr, trp, &ct);
@@ -205,6 +232,7 @@ _graph_remove (LSUP_StoreType type)
     free_triples (trp); // gr copied data.
 
     LSUP_graph_free (gr);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
 
     // TODO Test complete removal of triples from index when they are not
     // in another context.
@@ -223,8 +251,14 @@ _graph_txn (LSUP_StoreType type)
 
     LSUP_Triple *trp = create_triples();
 
-    LSUP_Graph *gr = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), type, NULL, NULL, 0);
+    LSUP_Graph *gr;
+    LSUP_Store *store;
+    if (type == LSUP_STORE_HTABLE) {
+        gr = LSUP_graph_new (NULL, NULL, NULL);
+    } else {
+        store = LSUP_store_new (type, NULL, 0);
+        gr = LSUP_graph_new (store, NULL, NULL);
+    }
 
     void *txn;
     size_t ct;
@@ -245,6 +279,11 @@ _graph_txn (LSUP_StoreType type)
     EXPECT_INT_EQ (ct, 8);
     EXPECT_INT_EQ (LSUP_graph_size (gr), 8);
 
+    LSUP_graph_free (gr);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
+
+    free_triples (trp); // gr copied data.
+
     return 0;
 }
 
@@ -330,15 +369,13 @@ static int test_graph_copy()
 {
     LSUP_Triple *trp = create_triples();
 
-    LSUP_Graph *gr1 = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *gr1 = LSUP_graph_new (NULL, NULL, NULL);
     ASSERT (gr1 != NULL, "Error creating graph!");
 
     LSUP_graph_add (gr1, trp, NULL);
 
     // Copy to graph with same store type.
-    LSUP_Graph *gr2 = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_HTABLE, NULL, NULL, 0);
+    LSUP_Graph *gr2 = LSUP_graph_new (NULL, NULL, NULL);
     EXPECT_PASS (LSUP_graph_copy_contents (gr1, gr2));
     EXPECT_INT_EQ (LSUP_graph_size (gr1), LSUP_graph_size (gr2));
 
@@ -350,8 +387,7 @@ static int test_graph_copy()
     }
 
     // Copy to graph with a different store type.
-    LSUP_Graph *gr3 = LSUP_graph_new (
-            LSUP_iriref_new (NULL, NULL), LSUP_STORE_MDB, NULL, NULL, 0);
+    LSUP_Graph *gr3 = LSUP_graph_new (NULL, NULL, NULL);
     EXPECT_PASS (LSUP_graph_copy_contents (gr1, gr3));
     EXPECT_INT_EQ (LSUP_graph_size (gr1), LSUP_graph_size (gr2));