Browse Source

Implement graph size for MDB back end; add remove tests.

Stefano Cossu 4 years ago
parent
commit
726c23f011
5 changed files with 160 additions and 74 deletions
  1. 16 8
      src/graph.c
  2. 7 4
      src/store_htable.c
  3. 86 22
      src/store_mdb.c
  4. 49 40
      test/test_graph.c
  5. 2 0
      test/test_store_mdb.c

+ 16 - 8
src/graph.c

@@ -258,8 +258,16 @@ LSUP_graph_size (const Graph *gr)
 {
     if (gr->store_type == LSUP_STORE_MEM)
         return LSUP_htstore_size (gr->ht_store);
+    else {
+        LSUP_Triple *spo = TRP_DUMMY;
+        size_t ct;
+        LSUP_GraphIterator *it = LSUP_graph_lookup (gr, spo, &ct);
 
-    return LSUP_mdbstore_size (gr->mdb_store);
+        LSUP_graph_iter_free (it);
+        LSUP_triple_free (spo);
+
+        return ct;
+    }
 }
 
 
@@ -519,6 +527,13 @@ mdbstore_init()
 {
     char *path;
 
+    if (UNLIKELY (!default_ctx)) {
+        LSUP_Term *default_ctx_uri = LSUP_uri_new (default_ctx_label);
+        default_ctx = LSUP_buffer_new_from_term (default_ctx_uri);
+        LSUP_term_free (default_ctx_uri);
+        atexit (ctx_cleanup);
+    }
+
     // RAM disk store.
     if (UNLIKELY (!default_tmp_store)) {
         printf ("Initializing RAM disk back end.\n");
@@ -548,12 +563,5 @@ mdbstore_init()
         if (UNLIKELY (!default_store)) return LSUP_DB_ERR;
     }
 
-    if (UNLIKELY (!default_ctx)) {
-        LSUP_Term *default_ctx_uri = LSUP_uri_new (default_ctx_label);
-        default_ctx = LSUP_buffer_new_from_term (default_ctx_uri);
-        LSUP_term_free (default_ctx_uri);
-        atexit (ctx_cleanup);
-    }
-
     return LSUP_OK;
 }

+ 7 - 4
src/store_htable.c

@@ -354,7 +354,7 @@ LSUP_htstore_remove(
     LSUP_HTIterator *it = LSUP_htstore_lookup (store, sspo);
     if (UNLIKELY (!it)) return LSUP_DB_ERR;
 
-    *ct = 0;
+    if (ct) *ct = 0;
 
     TripleEntry *tmp = malloc (sizeof (*tmp));
     HASH_ITER (hh, store->keys, it->entry, tmp) {
@@ -362,7 +362,7 @@ LSUP_htstore_remove(
             HASH_DEL (store->keys, it->entry);
             free (it->entry);
 
-            (*ct)++;
+            if (ct) (*ct)++;
         }
     }
 
@@ -454,12 +454,14 @@ LSUP_htiter_cur (LSUP_HTIterator *it)
 LSUP_rc
 LSUP_htiter_next (HTIterator *it, LSUP_SerTriple *sspo)
 {
+    if (UNLIKELY (!it)) return LSUP_VALUE_ERR;
+
     // If the previous iteration hit the end, return.
     if (it->rc != LSUP_OK) return it->rc;
 
     it->rc = LSUP_NORESULT;
 
-    while (it->rc == LSUP_NORESULT) {
+    do {
         if (!it->entry) it->rc = LSUP_END;
 
         else {
@@ -478,7 +480,8 @@ LSUP_htiter_next (HTIterator *it, LSUP_SerTriple *sspo)
 
             it->entry = it->entry->hh.next;
         }
-    }
+    } while (it->rc == LSUP_NORESULT);
+
     return it->rc;
 }
 

+ 86 - 22
src/store_mdb.c

@@ -614,19 +614,27 @@ LSUP_mdbstore_lookup(
 inline static LSUP_rc
 mdbiter_next_key (LSUP_MDBIterator *it)
 {
-    if (UNLIKELY (!it)) return LSUP_DB_ERR;
+    if (UNLIKELY (!it)) return LSUP_VALUE_ERR;
 
     // Only advance if the previous it->rc wasn't already at the end.
     if (it->rc == MDB_NOTFOUND) return LSUP_END;
 
     if (UNLIKELY (it->rc != MDB_SUCCESS)) {
-        fprintf (stderr, mdb_strerror (it->rc));
+        fprintf (
+                stderr, "%s:%d [%s]: Database error: %s\n",
+                __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
         return LSUP_DB_ERR;
     }
 
     LSUP_rc rc;
 
+    /* Retrieve current value and advance cursor to the next result.
+     * it->rc is set to the result of the next iteration.
+     */
     it->iter_op_fn (it);
+    TRACE (
+            "Found  spok: {%lx, %lx, %lx}",
+            it->spok[0], it->spok[1], it->spok[2]);
 
     if (it->ck) {
         rc = LSUP_NORESULT;  // Intermediary value, will never be returned.
@@ -634,8 +642,15 @@ mdbiter_next_key (LSUP_MDBIterator *it)
         MDB_cursor *cur;
         MDB_val key, data;
 
-        mdb_cursor_open
+        int db_rc;
+        db_rc = mdb_cursor_open
             (mdb_cursor_txn (it->cur), it->store->dbi[IDX_SPO_C], &cur);
+        if (UNLIKELY (db_rc != MDB_SUCCESS)) {
+            fprintf (
+                    stderr, "%s:%d [%s]: Database error: %s\n",
+                    __FILE__, __LINE__, __func__, mdb_strerror (db_rc));
+            return LSUP_DB_ERR;
+        }
 
         key.mv_size = TRP_KLEN;
         data.mv_data = &it->ck;
@@ -647,10 +662,10 @@ mdbiter_next_key (LSUP_MDBIterator *it)
             // with it. If not, move on to the next triple.
             // The loop normally exits when a triple with matching ctx is found
             // (LSUP_OK), if there are no more triples (LSUP_END), or if there
-            // is an error (LSUPP_DB_ERR).
+            // is an error (LSUP_DB_ERR).
             key.mv_data = it->spok;
 
-            int db_rc = mdb_cursor_get (cur, &key, &data, MDB_GET_BOTH);
+            db_rc = mdb_cursor_get (cur, &key, &data, MDB_GET_BOTH);
 
             if (db_rc == MDB_SUCCESS) {
                 rc = LSUP_OK;
@@ -737,30 +752,41 @@ LSUP_mdbstore_remove(
 
     spok_v.mv_size = TRP_KLEN;
     ck_v.mv_size = KLEN;
+    ck_v.mv_data = &ck;
 
     LSUP_MDBIterator *it = LSUP_mdbstore_lookup (store, sspo, sc, ct);
     if (UNLIKELY (!it)) return LSUP_DB_ERR;
+    if (ct) TRACE ("Found %lu triples to remove.", *ct);
 
-    while (mdbiter_next_key (it)) {
+    while (mdbiter_next_key (it) == LSUP_OK) {
         spok_v.mv_data = it->spok;
 
         rc = mdb_cursor_get (dcur, &spok_v, &ck_v, MDB_GET_BOTH);
         if (rc == MDB_NOTFOUND) continue;
         if (UNLIKELY (rc != MDB_SUCCESS)) goto _remove_abort;
 
+        TRACE (
+                "Removing {%lx, %lx, %lx}",
+                it->spok[0], it->spok[1], it->spok[2]);
+
         // Delete spo:c entry.
-        mdb_cursor_del (dcur, 0);
+        rc = mdb_cursor_del (dcur, 0);
+        if (UNLIKELY (rc != MDB_SUCCESS)) goto _remove_abort;
 
         // Restore ck address after each delete.
+        spok_v.mv_data = it->spok;
         ck_v.mv_data = &ck;
 
-        // Delete c::spo entry.
+        // Delete c:spo entry.
         rc = mdb_cursor_get (icur, &ck_v, &spok_v, MDB_GET_BOTH);
         if (rc == MDB_NOTFOUND) continue;
         if (UNLIKELY (rc != MDB_SUCCESS)) goto _remove_abort;
 
-        mdb_cursor_del (icur, 0);
+        rc = mdb_cursor_del (icur, 0);
+        if (UNLIKELY (rc != MDB_SUCCESS)) goto _remove_abort;
+
         spok_v.mv_data = it->spok;
+        ck_v.mv_data = &ck;
 
         // If there are no more contexts associated with this triple,
         // remove from indices.
@@ -771,6 +797,8 @@ LSUP_mdbstore_remove(
         index_triple (store, OP_REMOVE, it->spok, ck);
     }
 
+    LSUP_mdbiter_free (it);
+
     if (UNLIKELY (mdb_txn_commit (txn) != MDB_SUCCESS)) {
         rc = LSUP_TXN_ERR;
         goto _remove_abort;
@@ -780,6 +808,9 @@ LSUP_mdbstore_remove(
 
 _remove_abort:
     mdb_txn_abort (txn);
+    fprintf (
+            stderr, "%s:%d [%s]: Database error: %s\n",
+            __FILE__, __LINE__, __func__, mdb_strerror (rc));
 
     return rc;
 }
@@ -807,6 +838,7 @@ index_triple(
 
     // Index c:spo.
     if (op == OP_REMOVE) {
+        TRACE (STR, "Indexing op: REMOVE");
         if (ck != NULL_KEY) {
             MDB_cursor *cur;
 
@@ -827,6 +859,7 @@ index_triple(
         }
 
     } else if (op == OP_ADD) {
+        TRACE (STR, "Indexing op: ADD");
         if (ck != NULL_KEY) {
             v1.mv_data = &ck;
             v1.mv_size = KLEN;
@@ -963,7 +996,6 @@ it_next_1bound (MDBIterator *it)
         //TRACE ("Reset page cursor to %lu.", it->i);
         it->rc = mdb_cursor_get (
                 it->cur, &it->key, &it->data, MDB_NEXT_MULTIPLE);
-        TRACE ("it->rc: %d", it->rc);
     }
 }
 
@@ -1016,7 +1048,12 @@ lookup_0bound (MDBStore *store, MDBIterator *it, size_t *ct)
     if (store->txn) it->txn = store->txn;
     else {
         it->rc = mdb_txn_begin (store->env, NULL, MDB_RDONLY, &it->txn);
-        if (it->rc != MDB_SUCCESS) abort(); // TODO handle error
+        if (it->rc != MDB_SUCCESS) {
+            fprintf (
+                    stderr, "%s:%d [%s]: Database error: %s\n",
+                    __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
+            return LSUP_DB_ERR;
+        }
     }
 
     if (ct) {
@@ -1040,6 +1077,7 @@ lookup_0bound (MDBStore *store, MDBIterator *it, size_t *ct)
 
             *ct = stat.ms_entries;
         }
+        TRACE ("Found %lu keys.", *ct);
     }
 
     mdb_cursor_open (it->txn, store->dbi[IDX_SPO_C], &it->cur);
@@ -1051,7 +1089,9 @@ lookup_0bound (MDBStore *store, MDBIterator *it, size_t *ct)
     it->iter_op_fn = it_next_0bound;
 
     if (it->rc != MDB_SUCCESS && it->rc != MDB_NOTFOUND) {
-        fprintf (stderr, "Database error: %s", mdb_strerror (it->rc));
+        fprintf (
+                stderr, "%s:%d [%s]: Database error: %s\n",
+                __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
         return LSUP_DB_ERR;
     }
 
@@ -1070,7 +1110,12 @@ lookup_1bound (MDBStore *store, uint8_t idx0, MDBIterator *it, size_t *ct)
         if (store->txn) it->txn = store->txn;
         else {
             it->rc = mdb_txn_begin (store->env, NULL, MDB_RDONLY, &it->txn);
-            if (it->rc != MDB_SUCCESS) abort();
+            if (it->rc != MDB_SUCCESS) {
+                fprintf (
+                        stderr, "%s:%d [%s]: Database error: %s",
+                        __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
+                return LSUP_DB_ERR;
+            }
         }
     }
 
@@ -1125,7 +1170,9 @@ lookup_1bound (MDBStore *store, uint8_t idx0, MDBIterator *it, size_t *ct)
         it->rc = mdb_cursor_get (it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
 
     if (it->rc != MDB_SUCCESS && it->rc != MDB_NOTFOUND) {
-        fprintf (stderr, "Database error: %s", mdb_strerror (it->rc));
+        fprintf (
+                stderr, "%s:%d [%s]: Database error: %s",
+                __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
         return LSUP_DB_ERR;
     }
 
@@ -1185,7 +1232,12 @@ lookup_2bound(
         if (store->txn) it->txn = store->txn;
         else {
             it->rc = mdb_txn_begin (store->env, NULL, MDB_RDONLY, &it->txn);
-            if (it->rc != MDB_SUCCESS) abort();
+            if (it->rc != MDB_SUCCESS) {
+                fprintf (
+                        stderr, "%s:%d [%s]: Database error: %s",
+                        __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
+                return LSUP_DB_ERR;
+            }
         }
     }
 
@@ -1235,7 +1287,9 @@ lookup_2bound(
         it->rc = mdb_cursor_get (it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
 
     if (it->rc != MDB_SUCCESS && it->rc != MDB_NOTFOUND) {
-        fprintf (stderr, "Database error: %s", mdb_strerror (it->rc));
+        fprintf (
+                stderr, "%s:%d [%s]: Database error: %s\n",
+                __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
         return LSUP_DB_ERR;
     }
 
@@ -1251,7 +1305,15 @@ lookup_3bound (MDBStore *store, MDBIterator *it, size_t *ct)
             it->luk[0], it->luk[1], it->luk[2]);
 
     if (store->txn) it->txn = store->txn;
-    else mdb_txn_begin (store->env, NULL, MDB_RDONLY, &it->txn);
+    else {
+        it->rc = mdb_txn_begin (store->env, NULL, MDB_RDONLY, &it->txn);
+        if (it->rc != MDB_SUCCESS) {
+            fprintf (
+                    stderr, "%s:%d [%s]: Database error: %s\n",
+                    __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
+            return LSUP_DB_ERR;
+        }
+    }
 
     it->key.mv_data = it->luk;
 
@@ -1272,6 +1334,13 @@ lookup_3bound (MDBStore *store, MDBIterator *it, size_t *ct)
 
     it->rc = mdb_cursor_get (it->cur, &it->key, &it->data, MDB_GET_BOTH);
 
+    if (it->rc != MDB_SUCCESS && it->rc != MDB_NOTFOUND) {
+        fprintf (
+                stderr, "%s:%d [%s]: Database error: %s\n",
+                __FILE__, __LINE__, __func__, mdb_strerror (it->rc));
+        return LSUP_DB_ERR;
+    }
+
     mdb_cursor_close (it->cur);
     it->cur = NULL;
 
@@ -1280,11 +1349,6 @@ lookup_3bound (MDBStore *store, MDBIterator *it, size_t *ct)
     it->iter_op_fn = it_next_3bound;
     memcpy (it->spok, it->luk, sizeof (LSUP_TripleKey));
 
-    if (it->rc != MDB_SUCCESS && it->rc != MDB_NOTFOUND) {
-        fprintf (stderr, "Database error: %s", mdb_strerror (it->rc));
-        return LSUP_DB_ERR;
-    }
-
     return LSUP_OK;
 }
 

+ 49 - 40
test/test_graph.c

@@ -3,15 +3,18 @@
 #include "assets/triples.h"
 
 static int
-test_graph_mem_new ()
+_graph_new (LSUP_store_type type)
 {
     LSUP_Graph *gr;
-    gr = LSUP_graph_new (LSUP_STORE_MEM);
+    gr = LSUP_graph_new (type);
+    ASSERT (gr != NULL, "Error creating graph!");
 
     EXPECT_PASS (LSUP_graph_set_uri (gr, "urn:gr:1"));
     EXPECT_STR_EQ (LSUP_graph_uri (gr)->data, "urn:gr:1");
 
-    ASSERT (strcmp (LSUP_graph_uri (gr)->data, "urn:gr:1") == 0, "Graph URI mismatch!");
+    ASSERT (
+            strcmp (LSUP_graph_uri (gr)->data, "urn:gr:1") == 0,
+            "Graph URI mismatch!");
     EXPECT_INT_EQ (LSUP_graph_size (gr), 0);
 
     LSUP_graph_free (gr);
@@ -21,11 +24,11 @@ test_graph_mem_new ()
 
 
 static int
-test_graph_mem_add()
+_graph_add (LSUP_store_type type)
 {
     LSUP_Triple *trp = create_triples();
 
-    LSUP_Graph *gr = LSUP_graph_new (LSUP_STORE_MEM);
+    LSUP_Graph *gr = LSUP_graph_new (type);
     ASSERT (gr != NULL, "Error creating graph!");
 
     size_t ct;
@@ -53,19 +56,33 @@ test_graph_mem_add()
 
 
 static int
-test_graph_mdb_new ()
+_graph_remove (LSUP_store_type type)
 {
-    LSUP_Graph *gr;
-    gr = LSUP_graph_new (LSUP_STORE_MDB);
-    ASSERT (gr != NULL, "Error creating graph!");
+    LSUP_Triple *trp = create_triples();
 
-    EXPECT_PASS (LSUP_graph_set_uri (gr, "urn:gr:1"));
-    EXPECT_STR_EQ (LSUP_graph_uri (gr)->data, "urn:gr:1");
+    LSUP_Graph *gr = LSUP_graph_new (type);
 
-    ASSERT (
-            strcmp (LSUP_graph_uri (gr)->data, "urn:gr:1") == 0,
-            "Graph URI mismatch!");
-    EXPECT_INT_EQ (LSUP_graph_size (gr), 0);
+    size_t ct;
+    LSUP_graph_add_trp (gr, trp, &ct);
+
+    EXPECT_INT_EQ (ct, 8);
+    EXPECT_INT_EQ (LSUP_graph_size (gr), 8);
+
+    LSUP_Triple *spo = LSUP_triple_new (trp[0].s, NULL, NULL);
+    LSUP_graph_remove (gr, spo, &ct);
+
+    ASSERT (!LSUP_graph_contains (gr, trp + 0), "Unexpected triple found!");
+    ASSERT (LSUP_graph_contains (gr, trp + 1), "Triple not in graph!");
+    ASSERT (LSUP_graph_contains (gr, trp + 2), "Triple not in graph!");
+    ASSERT (!LSUP_graph_contains (gr, trp + 3), "Unexpected triple found!");
+    ASSERT (!LSUP_graph_contains (gr, trp + 4), "Unexpected triple found!");
+    ASSERT (!LSUP_graph_contains (gr, trp + 5), "Unexpected triple found!");
+    ASSERT (LSUP_graph_contains (gr, trp + 6), "Triple not in graph!");
+    ASSERT (!LSUP_graph_contains (gr, trp + 7), "Unexpected triple found!");
+    EXPECT_INT_EQ (LSUP_graph_size (gr), 3);
+
+    LSUP_triple_free (spo);
+    free_triples (trp); // gr copied data.
 
     LSUP_graph_free (gr);
 
@@ -73,33 +90,25 @@ test_graph_mdb_new ()
 }
 
 
-static int
-test_graph_mdb_add()
-{
-    LSUP_Triple *trp = create_triples();
-
-    LSUP_Graph *gr = LSUP_graph_new (LSUP_STORE_MDB);
-    ASSERT (gr != NULL, "Error creating graph!");
+static int test_graph_new() {
+    if (_graph_new (LSUP_STORE_MEM) != 0) return -1;
+    if (_graph_new (LSUP_STORE_MDB_TMP) != 0) return -1;
 
-    size_t ct;
-    LSUP_graph_add_trp (gr, trp, &ct);
+    return 0;
+}
 
-    EXPECT_INT_EQ (ct, 8);
-    EXPECT_INT_EQ (LSUP_graph_size (gr), 8);
 
-    for (int i = 0; i < sizeof (trp); i++) {
-        printf ("checking triple #%d... ", i);
-        ASSERT (LSUP_graph_contains (gr, trp + i), "Triple not in graph!");
-        printf ("OK.\n");
-    }
+static int test_graph_add() {
+    if (_graph_add (LSUP_STORE_MEM) != 0) return -1;
+    if (_graph_add (LSUP_STORE_MDB_TMP) != 0) return -1;
 
-    LSUP_Triple *missing_trp = LSUP_triple_new (trp[1].s, trp[6].p, trp[4].o);
-    ASSERT (! LSUP_graph_contains (gr, missing_trp), "Triple in graph!");
-    free (missing_trp);
+    return 0;
+}
 
-    free_triples (trp); // gr copied data.
 
-    LSUP_graph_free (gr);
+static int test_graph_remove() {
+    if (_graph_remove (LSUP_STORE_MEM) != 0) return -1;
+    if (_graph_remove (LSUP_STORE_MDB_TMP) != 0) return -1;
 
     return 0;
 }
@@ -107,10 +116,10 @@ test_graph_mdb_add()
 
 int graph_tests()
 {
-    RUN (test_graph_mem_new);
-    RUN (test_graph_mem_add);
-    RUN (test_graph_mdb_new);
-    RUN (test_graph_mdb_add);
+    RUN (test_graph_new);
+    RUN (test_graph_add);
+    RUN (test_graph_remove);
+
     return 0;
 }
 

+ 2 - 0
test/test_store_mdb.c

@@ -279,10 +279,12 @@ static int test_quad_store()
         printf ("}\n");
         */
 
+        printf ("Checking triple #%d...", i);
         LSUP_MDBIterator *it = LSUP_mdbstore_lookup(
                 store, lut + i, luc[i], &ct);
         ASSERT (it != NULL, "Lookup error!");
         EXPECT_INT_EQ (ct, results[i]);
+        printf ("OK.\n");
 
         LSUP_mdbiter_free (it);
     }