Browse Source

Fix memory errors.

Stefano Cossu 3 years ago
parent
commit
7ac2f4ad1c
12 changed files with 204 additions and 42 deletions
  1. 5 3
      include/core.h
  2. 8 0
      include/graph.h
  3. 37 2
      include/store_mdb.h
  4. 15 14
      profile.c
  5. 10 4
      src/codec_nt.c
  6. 2 0
      src/core.c
  7. 7 1
      src/environment.c
  8. 5 3
      src/graph.c
  9. 2 2
      src/namespace.c
  10. 98 0
      src/store_mdb.c
  11. 2 0
      test/test_namespace.c
  12. 13 13
      test/test_term.c

+ 5 - 3
include/core.h

@@ -57,11 +57,12 @@ typedef int LSUP_rc;
 #define LSUP_NOACTION       88801
 #define LSUP_NORESULT       88802
 #define LSUP_END            88803
+#define LSUP_CONFLICT       88804
 // NOTE When adding new warning codes, use a value larger than the last one
-// in the list. Also change LSUP_MAX_WARN.
+// in the list. Also change LSUP_MAX_WARNING.
 
 #define LSUP_MIN_WARNING    LSUP_NOACTION
-#define LSUP_MAX_WARNING    LSUP_END
+#define LSUP_MAX_WARNING    LSUP_CONFLICT
 
 #define LSUP_ERROR          -88899
 #define LSUP_PARSE_ERR      -88898
@@ -71,11 +72,12 @@ typedef int LSUP_rc;
 #define LSUP_NOT_IMPL_ERR   -88894
 #define LSUP_IO_ERR         -88893
 #define LSUP_MEM_ERR        -88892
+#define LSUP_CONFLICT_ERR   -88891
 // NOTE When adding new error codes, use a value larger than the last one
 // in the list. Also change LSUP_MAX_ERR.
 
 #define LSUP_MIN_ERROR      LSUP_ERROR
-#define LSUP_MAX_ERROR      LSUP_MEM_ERR
+#define LSUP_MAX_ERROR      LSUP_CONFLICT_ERR
 
 extern char *warning_msg[], *error_msg[];
 

+ 8 - 0
include/graph.h

@@ -160,6 +160,14 @@ size_t
 LSUP_graph_size (const LSUP_Graph *gr);
 
 
+/** @brief Whether a graph contains a triple.
+ *
+ * @param[in] gr Graph to look up into.
+ *
+ * @param[in] spo Triple to look up.
+ *
+ * @return 1 if the triple is found, 0 if not found.
+ */
 bool
 LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo);
 

+ 37 - 2
include/store_mdb.h

@@ -24,9 +24,8 @@
 
 #include "lmdb.h"
 #include "triple.h"
+#include "namespace.h"
 
-// FIXME find a better cross-platform path.
-#define DEFAULT_ENV_PATH "./mdb_store"
 
 typedef char DbLabel[8];
 typedef struct MDBStore LSUP_MDBStore;
@@ -312,4 +311,40 @@ void LSUP_mdbiter_free (struct MDBIterator *it);
 LSUP_rc LSUP_mdbstore_triple_contexts(
         LSUP_MDBStore *store, LSUP_Key spok[], LSUP_Key **ck, size_t *ct);
 
+
+/** @brief Get all namespace prefixes in the store.
+ *
+ * @param[in] store MDB store to query.
+ *
+ * @param[out] nsm Pointer to namespace map to generate.
+ *
+ * @return LSUP_OK on success; LSUP_DB_ERR on MDB error.
+ */
+LSUP_rc
+LSUP_mdbstore_nsm_get (LSUP_MDBStore *store, LSUP_NSMap **nsm);
+
+
+/** @brief Store an in-memory namespace map into the permanent back end.
+ *
+ * Existing prefixes and namespaces are not updated. Thus, if the following are
+ * already stored:
+ *
+ * ns1: <urn:ns:a#>
+ * ns2: <urn:ns:b#>
+ *
+ * Neither of the following will be inserted:
+ *
+ * ns3: <urn:ns:a#>
+ * ns2: <urn:ns:c#>
+ *
+ * @param[in] store MDB store to update.
+ *
+ * @param[out] nsm Namespace map handle to store.
+ *
+ * @return LSUP_OK if all terms were updated; LSUP_CONFLICT if one or more
+ *  namespaces or terms were not updated because they already existed.
+ */
+LSUP_rc
+LSUP_mdbstore_nsm_store (LSUP_MDBStore *store, const LSUP_NSMap *nsm);
+
 #endif

+ 15 - 14
profile.c

@@ -23,7 +23,7 @@ generate_triples()
                 LSUP_uri_new (pstr), LSUP_uri_new (ostr));
     }
     LSUP_triple_init (trp + NT, NULL, NULL, NULL);
-    TRACE(STR, "Triples generated.");
+    log_info ("Triples generated.");
 
     return trp;
 }
@@ -33,8 +33,8 @@ insert_triples (LSUP_Graph *gr, LSUP_Triple *trp)
 {
     size_t ct;
     LSUP_rc rc = LSUP_graph_add_trp(gr, trp, &ct);
-    if (rc != LSUP_OK) printf ("Graph loading interrupted: %d.\n", rc);
-    else printf ("Graph populated with %lu triples.\n", ct);
+    if (rc != LSUP_OK) log_warn ("Graph loading interrupted: %d.", rc);
+    else log_info ("Graph populated with %lu triples.", ct);
 
     return rc;
 }
@@ -46,22 +46,23 @@ int main()
     putenv ("LSUP_MDB_STORE_PATH=" TMPDIR "/lsup_profile_mdb");
     // Clear out database from previous test.
     rm_r (getenv ("LSUP_MDB_STORE_PATH"));
+    LSUP_init();
 
     int rc;
     clock_t start, tc1, tc2, end;
     double wallclock, rate;
 
-    printf ("Generating triples.\n");
+    log_info ("Generating triples.");
     start = clock();
     LSUP_Triple *trp = generate_triples();
     tc1 = clock();
     wallclock = (tc1 - start) / CLOCKS_PER_SEC;
-    printf("Time elapsed: %lf s\n", wallclock);
+    log_info ("Time elapsed: %lf s", wallclock);
 
-    printf("Inserting triples.\n");
+    log_info ("Inserting triples.");
     LSUP_Graph *gr = LSUP_graph_new (LSUP_STORE_MDB);
     if (!gr) {
-        fprintf (stderr, "Error creating graph!\n");
+        log_error ("Error creating graph!");
         return -1;
     }
     rc = insert_triples (gr, trp);
@@ -75,10 +76,10 @@ int main()
 
     tc2 = clock();
     wallclock = (tc2 - tc1) / CLOCKS_PER_SEC;
-    printf("Time elapsed: %lf s\n", wallclock);
-    printf ("Graph size: %lu\n", LSUP_graph_size (gr));
+    log_info ("Time elapsed: %lf s", wallclock);
+    log_info ("Graph size: %lu", LSUP_graph_size (gr));
 
-    printf("Lookup...\n");
+    log_info ("Lookup...");
     size_t ct = 0;
     LSUP_Triple *spo = TRP_DUMMY;
     LSUP_Term *s = LSUP_uri_new ("urn:s:0");
@@ -87,16 +88,16 @@ int main()
     LSUP_GraphIterator *it = LSUP_graph_lookup(gr, NULL, NULL, NULL, NULL);
     while (LSUP_graph_iter_next (it, spo) != LSUP_END)
         ct ++;
-    printf("Found triples per subject: %lu\n", ct);
+    log_info ("Found triples per subject: %lu", ct);
     LSUP_graph_iter_free (it);
     end = clock();
     wallclock = (end - tc2) / CLOCKS_PER_SEC;
-    printf("Time elapsed: %lf s\n", wallclock);
+    log_info ("Time elapsed: %lf s", wallclock);
 
     wallclock = (end - start) / CLOCKS_PER_SEC;
     rate = NT / wallclock;
-    printf(
-            "%d triples created and inserted in %lf s (%lf triples/s)\n",
+    log_info (
+            "%d triples created and inserted in %lf s (%lf triples/s)",
             NT, wallclock, rate);
 
     LSUP_term_free (s);

+ 10 - 4
src/codec_nt.c

@@ -104,7 +104,7 @@ gr_to_nt_init (const LSUP_Graph *gr);
 static LSUP_rc
 gr_to_nt_iter (LSUP_CodecIterator *it, unsigned char **res) {
     LSUP_rc rc = LSUP_graph_iter_next (it->gr_it, it->trp);
-    if (rc != LSUP_OK) return rc;
+    if (rc != LSUP_OK) goto finally;
 
     term_to_nt (it->trp->s, it->nsm, &it->str_s);
     term_to_nt (it->trp->p, it->nsm, &it->str_p);
@@ -116,7 +116,8 @@ gr_to_nt_iter (LSUP_CodecIterator *it, unsigned char **res) {
             + strlen (it->str_o) + 6);
     if (UNLIKELY (!tmp)) {
         *res = NULL;
-        return LSUP_MEM_ERR;
+        rc = LSUP_MEM_ERR;
+        goto finally;
     }
 
     sprintf ((char*)tmp, "%s %s %s .\n", it->str_s, it->str_p, it->str_o);
@@ -124,7 +125,12 @@ gr_to_nt_iter (LSUP_CodecIterator *it, unsigned char **res) {
 
     it->cur++;
 
-    return LSUP_OK;
+finally:
+    LSUP_term_free (it->trp->s); it->trp->s = NULL;
+    LSUP_term_free (it->trp->p); it->trp->p = NULL;
+    LSUP_term_free (it->trp->o); it->trp->o = NULL;
+
+    return rc;
 }
 
 
@@ -185,7 +191,7 @@ gr_to_nt_init (const LSUP_Graph *gr)
     it->gr_it = LSUP_graph_lookup(gr, NULL, NULL, NULL, &it->cur);
     it->nsm = LSUP_graph_namespace (gr);
     it->cur = 0;
-    it->trp = LSUP_triple_new (TERM_DUMMY, TERM_DUMMY, TERM_DUMMY);
+    it->trp = TRP_DUMMY;
     it->rep = NULL;
     it->str_s = NULL;
     it->str_p = NULL;

+ 2 - 0
src/core.c

@@ -12,6 +12,7 @@ char *warning_msg[] = {
     "No action or change of state occurred.",
     "No result.",
     "End of the loop reached.",
+    "A resource conflict prevented some actions from being completed.",
 };
 
 /*
@@ -27,6 +28,7 @@ char *err_msg[] = {
     "Not implemented.",
     "Input/Output error.",
     "Memory error.",
+    "A resource conflict resulted in an invalid state.",
 };
 
 

+ 7 - 1
src/environment.c

@@ -1,6 +1,9 @@
 #include "environment.h"
 
 
+// FIXME find a better cross-platform path.
+#define DEFAULT_ENV_PATH "./mdb_store"
+
 // RAMdisk path for MDB volatile store.
 #define MDB_RAMDISK_PATH TMPDIR "/lsup_mem_graph"
 
@@ -22,7 +25,7 @@ LSUP_env_new (
         const char *mdb_ramdisk_path, const LSUP_NSMap *nsmap)
 {
     LSUP_Env *env;
-    MALLOC_GUARD (env, NULL);
+    CALLOC_GUARD (env, NULL);
 
     // Default store context.
     LSUP_Term *default_ctx_uri = LSUP_uri_new (default_ctx);
@@ -44,6 +47,9 @@ LSUP_env_new (
     if (UNLIKELY (!env->mdbstore_ramdisk)) return NULL;
     log_info ("Initialized RAM disk back end at %s.", mdb_ramdisk_path);
 
+    // Get default namespace from store.
+    RCNL (LSUP_mdbstore_nsm_get (env->mdbstore, &env->nsm));
+
     return env;
 }
 

+ 5 - 3
src/graph.c

@@ -83,7 +83,10 @@ check_backend (LSUP_store_type be)
 Graph *
 LSUP_graph_new_env (const LSUP_Env *env, const LSUP_store_type store_type)
 {
-    if (UNLIKELY (!env)) return NULL;
+    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;
@@ -447,7 +450,6 @@ LSUP_graph_iter_next (GraphIterator *it, LSUP_Triple *spo)
         spo->s = LSUP_term_new_from_buffer (sspo->s);
         spo->p = LSUP_term_new_from_buffer (sspo->p);
         spo->o = LSUP_term_new_from_buffer (sspo->o);
-
     }
 
     if (it->graph->store_type == LSUP_STORE_MEM) free (sspo);
@@ -479,7 +481,7 @@ 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 = LSUP_triple_new (TERM_DUMMY, TERM_DUMMY, TERM_DUMMY);
+    LSUP_Triple *tmp_spo = TRP_DUMMY;
     bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
 
     LSUP_triple_free (tmp_spo);

+ 2 - 2
src/namespace.c

@@ -146,7 +146,6 @@ LSUP_nsmap_normalize_uri (
     char *pfx_uri = NULL;
 
     NSIndex *entry;
-    HASH_FIND_STR (map->np, fq_uri, entry);
     for (entry = map->np; entry != NULL; entry = entry->hh.next) {
         if (memcmp (entry->ns->ns, fq_uri, strlen (entry->ns->ns)) == 0)
             break;
@@ -193,7 +192,8 @@ LSUP_nsmap_denormalize_uri (
     }
 
     if (entry) {
-        size_t fq_size = strlen (entry->ns) + strlen (pfx_uri) - pfx_len - 1;
+        // -1 for :, +1 for terminator.
+        size_t fq_size = strlen (entry->ns) + strlen (pfx_uri) - pfx_len;
         fq_uri = malloc (fq_size);
         if (UNLIKELY (! (fq_uri))) return LSUP_MEM_ERR;
 

+ 98 - 0
src/store_mdb.c

@@ -806,6 +806,104 @@ _remove_abort:
 }
 
 
+LSUP_rc
+LSUP_mdbstore_nsm_get (LSUP_MDBStore *store, LSUP_NSMap **nsm_p)
+{
+    LSUP_rc rc = LSUP_NORESULT;
+    LSUP_NSMap *nsm = LSUP_nsmap_new();
+    if (UNLIKELY (!nsm)) return LSUP_MEM_ERR;
+
+    *nsm_p = nsm;
+
+    MDB_txn *txn;
+    mdb_txn_begin (store->env, NULL, MDB_RDONLY, &txn);
+
+    MDB_cursor *cur;
+    if (mdb_cursor_open (txn, store->dbi[IDX_PFX_NS], &cur) != MDB_SUCCESS) {
+        mdb_txn_abort (txn);
+        return LSUP_DB_ERR;
+    }
+
+    MDB_val ns_v, pfx_v;
+    if (mdb_cursor_get (cur, &ns_v, &pfx_v, MDB_FIRST) != MDB_SUCCESS)
+        goto finally;
+
+    do {
+        ns_pfx pfx;
+        char *ns = malloc (ns_v.mv_size);
+
+        strncpy (pfx, pfx_v.mv_data, pfx_v.mv_size);
+        strncpy (ns, ns_v.mv_data, ns_v.mv_size);
+        LSUP_nsmap_add (nsm, pfx, ns);
+
+        free (ns);
+    } while (mdb_cursor_get (
+                cur, &ns_v, &pfx_v, MDB_NEXT_NODUP) == MDB_SUCCESS);
+
+finally:
+    mdb_cursor_close (cur);
+    mdb_txn_abort (txn);
+
+    return rc;
+}
+
+
+LSUP_rc
+LSUP_mdbstore_nsm_store (LSUP_MDBStore *store, const LSUP_NSMap *nsm)
+{
+    LSUP_rc rc = LSUP_NOACTION;
+    int db_rc;
+
+    MDB_cursor *dcur = NULL, *icur = NULL;
+    if (
+        mdb_cursor_open (
+                store->txn, store->dbi[IDX_PFX_NS], &dcur) != MDB_SUCCESS
+        ||
+        mdb_cursor_open (
+                store->txn, store->dbi[IDX_NS_PFX], &icur) != MDB_SUCCESS
+    ) {
+        rc = LSUP_DB_ERR;
+        goto finally;
+    }
+
+    MDB_val pfx_v, ns_v;
+    const char ***nsm_data = LSUP_nsmap_dump (nsm);
+
+    for (size_t i = 0; nsm_data[i] != NULL; i++) {
+        // At least 1 action. If not OK, it will change during the iteration.
+        if (i == 0) rc = LSUP_OK;
+
+        pfx_v.mv_data = (void *)nsm_data[i][0];
+        pfx_v.mv_size = strlen (nsm_data[i][0]) + 1;
+        ns_v.mv_data = (void *)nsm_data[i][1];
+        ns_v.mv_size = strlen (nsm_data[i][1]) + 1;
+
+        // If either ns or pfx exist, quit.
+        if (
+            mdb_cursor_get (dcur, &pfx_v, &ns_v, MDB_SET) != MDB_NOTFOUND
+            ||
+            mdb_cursor_get (icur, &ns_v, &pfx_v, MDB_SET) != MDB_NOTFOUND
+        ) {
+            rc = LSUP_CONFLICT;
+            goto finally;
+        }
+
+        db_rc = mdb_cursor_put (dcur, &pfx_v, &ns_v, 0);
+        if (db_rc != MDB_SUCCESS) {
+            log_error ("DB error: %s", LSUP_strerror (db_rc));
+            rc = LSUP_DB_ERR;
+            goto finally;
+        }
+    }
+
+finally:
+    if (icur) mdb_cursor_close (icur);
+    if (dcur) mdb_cursor_close (dcur);
+
+    return rc;
+}
+
+
 /* * * Static functions. * * */
 
 

+ 2 - 0
test/test_namespace.c

@@ -38,6 +38,8 @@ test_namespace()
     ASSERT (LSUP_nsmap_get (nsm, "dc") == NULL, "Deleted NS found!");
 
     LSUP_nsmap_free (nsm);
+    free (fq_uri);
+    free (pfx_uri);
 
     return 0;
 }

+ 13 - 13
test/test_term.c

@@ -15,7 +15,7 @@ static int test_term_new()
     EXPECT_STR_EQ (term->datatype, datatype);
     EXPECT_STR_EQ (term->lang, lang);
 
-    log_info ("Reset term.\n");
+    log_info ("Reset term.");
 
     char *uri_data = "urn:id:2144564356";
     LSUP_term_init (term, LSUP_TERM_URI, uri_data, NULL, NULL);
@@ -37,33 +37,33 @@ static int test_term_serialize_deserialize()
     LSUP_Term *dsterm = TERM_DUMMY;
 
     LSUP_term_serialize (uri, sterm);
-    log_info ("%s", "Serialized URI: ");
-    LSUP_buffer_print (sterm);
-    log_info ("%s", "\n");
+    //log_info ("%s", "Serialized URI: ");
+    //LSUP_buffer_print (sterm);
+    //log_info ("%s", "\n");
     LSUP_term_deserialize (sterm, dsterm);
     ASSERT (LSUP_term_equals (dsterm, uri), "URI serialization error!");
     LSUP_term_free (uri);
 
     LSUP_term_serialize (lit, sterm);
-    log_info ("%s", "Serialized literal: ");
-    LSUP_buffer_print (sterm);
-    log_info ("%s", "\n");
+    //log_info ("%s", "Serialized literal: ");
+    //LSUP_buffer_print (sterm);
+    //log_info ("%s", "\n");
     LSUP_term_deserialize (sterm, dsterm);
     ASSERT (LSUP_term_equals (dsterm, lit), "lit serialization error!");
     LSUP_term_free (lit);
 
     LSUP_term_serialize (tlit, sterm);
-    log_info ("%s", "Serialized typed literal: ");
-    LSUP_buffer_print (sterm);
-    log_info ("%s", "\n");
+    //log_info ("%s", "Serialized typed literal: ");
+    //LSUP_buffer_print (sterm);
+    //log_info ("%s", "\n");
     LSUP_term_deserialize (sterm, dsterm);
     ASSERT (LSUP_term_equals (dsterm, tlit), "tlit serialization error!");
     LSUP_term_free (tlit);
 
     LSUP_term_serialize (tllit, sterm);
-    log_info ("%s", "Serialized typed and language-tagged URI: ");
-    LSUP_buffer_print (sterm);
-    log_info ("%s", "\n");
+    //log_info ("%s", "Serialized typed and language-tagged URI: ");
+    //LSUP_buffer_print (sterm);
+    //log_info ("%s", "\n");
     LSUP_term_deserialize (sterm, dsterm);
     ASSERT (LSUP_term_equals (dsterm, tllit), "URI serialization error!");
     LSUP_term_free (tllit);