Browse Source

Pass htstore tests.

Stefano Cossu 4 years ago
parent
commit
02f4552a76
9 changed files with 150 additions and 100 deletions
  1. 5 1
      include/buffer.h
  2. 1 1
      include/store_htable.h
  3. 0 4
      include/term.h
  4. 44 44
      src/store_htable.c
  5. 0 41
      test/assets.h
  6. 0 3
      test/test_graph.c
  7. 94 0
      test/test_store_ht.c
  8. 1 1
      test/test_store_mdb.c
  9. 5 5
      test/test_term.c

+ 5 - 1
include/buffer.h

@@ -11,6 +11,10 @@
 #define HASH_SEED 0
 #endif
 
+// "NULL" key, a value that is never user-provided. Used to mark special
+// values (e.g. deleted records).
+#define NULL_KEY 0
+
 
 /** @brief General-purpose data buffer.
  *
@@ -96,7 +100,7 @@ void LSUP_buffer_free (LSUP_Buffer *buf);
  */
 inline LSUP_Key
 LSUP_buffer_hash (const LSUP_Buffer *buf)
-{ return XXH64(buf->addr, buf->size, HASH_SEED); }
+{ return (buf == NULL) ? NULL_KEY : XXH64(buf->addr, buf->size, HASH_SEED); }
 
 
 /** @brief Combine hash values.

+ 1 - 1
include/store_htable.h

@@ -93,7 +93,7 @@ LSUP_htstore_remove(
 
 LSUP_HTIterator *
 LSUP_htstore_lookup(
-        LSUP_HTStore *store, const LSUP_SerTriple *sspo, size_t *ct);
+        LSUP_HTStore *store, const LSUP_SerTriple *sspo);
 
 size_t
 LSUP_htstore_size (LSUP_HTStore *ht);

+ 0 - 4
include/term.h

@@ -11,10 +11,6 @@
     "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"
 #define LANG_SIZE 8 // Size in chars of lang tag
 
-// "NULL" key, a value that is never user-provided. Used to mark special
-// values (e.g. deleted records).
-#define NULL_KEY 0
-
 // "NULL" triple, a value that is never user-provided. Used to fill deleted
 // triples in a keyset.
 #define NULL_TRP {NULL_KEY, NULL_KEY, NULL_KEY}

+ 44 - 44
src/store_htable.c

@@ -28,11 +28,13 @@ typedef struct ht_store_t {
 
 typedef struct ht_iterator_t {
     HTStore *           store;      // Store being iterated.
-    size_t              i;          // Lookup cursor.
+    size_t              i;          // Number of records found at any point of
+                                    // a lookup iteration, or number of records
+                                    // added at any point of an add loop.
     LSUP_Key            luk[3];     // 0÷3 lookup keys.
     LSUP_key_eq_fn_t    eq_fn;      // Equality function to test triples.
     int                 rc;         // Return code for *next* result.
-    TripleEntry *       spok;       // Retrieved SPO key.
+    TripleEntry *       bucket;     // Retrieved SPO key bucket.
 } HTIterator;
 
 
@@ -97,7 +99,6 @@ static bool lookup_pok_eq_fn(
 
 /* * * Other prototypes. * * */
 
-static inline LSUP_rc htiter_next_key (HTIterator *it);
 static inline LSUP_rc tkey_to_strp (
         const HTStore *store, const LSUP_Key spok[], LSUP_SerTriple *sspo);
 
@@ -285,7 +286,11 @@ LSUP_htstore_add_init (HTStore *store)
 LSUP_rc
 LSUP_htstore_add_iter (HTIterator *it, const LSUP_SerTriple *sspo)
 {
-    LSUP_TripleKey spok = NULL_TRP;
+    LSUP_TripleKey spok = {
+        LSUP_buffer_hash (sspo->s),
+        LSUP_buffer_hash (sspo->p),
+        LSUP_buffer_hash (sspo->o),
+    };
 
     // Add triple.
     TRACE ("Inserting spok: {%lx, %lx, %lx}", spok[0], spok[1], spok[2]);
@@ -335,17 +340,21 @@ LSUP_rc
 LSUP_htstore_remove(
         LSUP_HTStore *store, const LSUP_SerTriple *sspo, size_t *ct)
 {
-    LSUP_HTIterator *it = LSUP_htstore_lookup (store, sspo, ct);
+    LSUP_HTIterator *it = LSUP_htstore_lookup (store, sspo);
     if (UNLIKELY (!it)) return LSUP_DB_ERR;
 
     *ct = 0;
-    while (htiter_next_key (it)) {
-        HASH_DEL (store->keys, it->spok);
-        free (it->spok);
-        //if (UNLIKELY (rc < 0)) return rc;
 
-        (*ct) ++;
+    TripleEntry *tmp = malloc (sizeof (*tmp));
+    HASH_ITER (hh, store->keys, it->bucket, tmp) {
+        if (it->eq_fn (it->bucket->key, it->luk)) {
+            HASH_DEL (store->keys, it->bucket);
+            free (it->bucket);
+
+            (*ct)++;
+        }
     }
+
     // TODO clean up orphan indices in separate (async, scheduled) function.
 
     return LSUP_OK;
@@ -353,7 +362,7 @@ LSUP_htstore_remove(
 
 
 HTIterator *
-LSUP_htstore_lookup (HTStore *store, const LSUP_SerTriple *sspo, size_t *ct)
+LSUP_htstore_lookup (HTStore *store, const LSUP_SerTriple *sspo)
 {
     HTIterator *it = malloc (sizeof (*it));
     if (UNLIKELY (!it)) return NULL;
@@ -413,8 +422,9 @@ LSUP_htstore_lookup (HTStore *store, const LSUP_SerTriple *sspo, size_t *ct)
     // ? ? ?
     } else it->eq_fn = lookup_none_eq_fn;
 
-    it->spok = it->store->keys->hh.next;
-    it->rc = it->spok == NULL ? LSUP_END : LSUP_OK;
+    it->bucket = it->store->keys; // First record in hash table.
+    it->rc = it->bucket == NULL ? LSUP_END : LSUP_OK;
+    it->i = 0;
 
     return it;
 }
@@ -433,47 +443,37 @@ LSUP_htiter_cur (LSUP_HTIterator *it)
 LSUP_rc
 LSUP_htiter_next (HTIterator *it, LSUP_SerTriple *sspo)
 {
-    LSUP_rc rc = htiter_next_key (it);
-    if (UNLIKELY (rc != LSUP_OK)) return rc;
+    // If the previous iteration hit the end, return.
+    if (it->rc != LSUP_OK) return it->rc;
 
-    IndexEntry *cur;
+    it->rc = LSUP_NORESULT;
 
-    HASH_FIND (hh, it->store->idx, it->spok + 0, KLEN, cur);
-    sspo->s = cur->sterm;
-    HASH_FIND (hh, it->store->idx, it->spok + 1, KLEN, cur);
-    sspo->p = cur->sterm;
-    HASH_FIND (hh, it->store->idx, it->spok + 2, KLEN, cur);
-    sspo->o = cur->sterm;
+    while (it->rc == LSUP_NORESULT) {
+        if (!it->bucket) it->rc = LSUP_END;
 
-    if (!sspo->s || !sspo->p || !sspo->o) {
-        sspo = NULL;
-        return LSUP_DB_ERR;
-    }
-
-    return LSUP_OK;
-}
+        else {
+            if (it->eq_fn (it->bucket->key, it->luk)) {
+                tkey_to_strp (it->store, it->bucket->key, sspo);
+                if (!sspo->s || !sspo->p || !sspo->o) return LSUP_DB_ERR;
 
+                TRACE (
+                    "Found spok: {%lx, %lx, %lx}",
+                    it->bucket->key[0], it->bucket->key[1], it->bucket->key[2]
+                );
 
-/* * * Statics * * */
+                it->rc = LSUP_OK;
+                it->i++;
+            }
 
-static inline LSUP_rc
-htiter_next_key (HTIterator *it)
-{
-    // Loop as long as there are entries, and until a match is found.
-    for (;;) {
-        if (it->rc != LSUP_OK) return it->rc;
-        if (it->eq_fn (it->spok->key, it->luk)) return LSUP_OK;
-
-        TripleEntry *cur = NULL, *tmp = NULL;
-        HASH_ITER (hh, it->store->keys, cur, tmp);
-        if (cur != NULL) {
-            it->spok = cur;
-            it->rc = LSUP_OK;
-        } else it->rc = LSUP_NORESULT;
+            it->bucket = it->bucket->hh.next;
+        }
     }
+    return it->rc;
 }
 
 
+/* * * Statics * * */
+
 inline static LSUP_rc
 tkey_to_strp (
         const HTStore *store, const LSUP_Key spok[], LSUP_SerTriple *sspo)

+ 0 - 41
test/assets.h

@@ -11,47 +11,6 @@ LSUP_Triple *create_triples()
     trp = malloc (NUM_TRP * sizeof (LSUP_Triple));
     if (!trp) abort();
 
-    // These constitute overall 10 individual triples, 8 unique.
-
-    /*
-    LSUP_uri_init (&terms[0][0], "urn:s:0");
-    LSUP_uri_init (&terms[0][1], "urn:p:0");
-    LSUP_uri_init (&terms[0][2], "urn:o:0");
-    trp[0] = {terms[1][0], terms[1][1], terms[1][2]};
-
-    LSUP_uri_init (&terms[1][0], "urn:s:1");
-    LSUP_uri_init (&terms[1][1], "urn:p:1");
-    LSUP_uri_init (&terms[1][2], "urn:o:1");
-    trp[1] = {terms[1][0], terms[1][1], terms[1][2]};
-
-    LSUP_uri_init (&terms[2][0], "urn:s:2");
-    LSUP_uri_init (&terms[2][1], "urn:p:2");
-    LSUP_uri_init (&terms[2][2], "urn:o:2");
-    trp[2] = {terms[2][0], terms[2][1], terms[2][2]};
-
-    LSUP_uri_init (&terms[3][0], "urn:s:0");
-    LSUP_uri_init (&terms[3][1], "urn:p:1");
-    LSUP_uri_init (&terms[3][2], "urn:o:2");
-    trp[3] = {terms[3][0], terms[3][1], terms[3][2]};
-
-    LSUP_uri_init (&terms[4][0], "urn:s:0");
-    LSUP_uri_init (&terms[4][1], "urn:p:2");
-    LSUP_term_init (&terms[4][2], LSUP_TERM_LITERAL, "String 1", NULL, NULL);
-    trp[4] = {terms[4][0], terms[4][1], terms[4][2]};
-
-    LSUP_uri_init (&terms[5][0], "urn:s:0");
-    LSUP_uri_init (&terms[5][1], "urn:p:5");
-    LSUP_term_init(
-            &terms[5][2], LSUP_TERM_LITERAL, "String 1", "xsd:string", NULL);
-    trp[5] = {terms[5][0], terms[5][1], terms[5][2]};
-
-    LSUP_uri_init (&terms[6][0], "urn:s:1");
-    LSUP_uri_init (&terms[6][1], "urn:p:6");
-    LSUP_term_init(
-            &terms[6][2], LSUP_TERM_LITERAL, "String 1", "xsd:string", "es-ES");
-    trp[6] = {terms[6][0], terms[6][1], terms[6][2]};
-    */
-
     trp[0].s = LSUP_uri_new ("urn:s:0");
     trp[0].p = LSUP_uri_new ("urn:p:0");
     trp[0].o = LSUP_uri_new ("urn:o:0");

+ 0 - 3
test/test_graph.c

@@ -12,9 +12,6 @@ test_graph_mem_new ()
     EXPECT_PASS (LSUP_graph_set_uri (gr, "urn:gr:1"));
     EXPECT_STR_EQ (LSUP_graph_uri (gr)->data, "urn:gr:1");
 
-    EXPECT_PASS (LSUP_graph_resize (gr, 10));
-    EXPECT_INT_EQ (LSUP_graph_capacity (gr), 10);
-
     ASSERT (strcmp (LSUP_graph_uri (gr)->data, "urn:gr:1") == 0, "Graph URI mismatch!");
     EXPECT_INT_EQ (LSUP_graph_size (gr), 0);
 

+ 94 - 0
test/test_store_ht.c

@@ -0,0 +1,94 @@
+#include "test.h"
+#include "store_htable.h"
+#include "assets.h"
+
+/** @brief Test hash table store.
+ */
+static int test_htstore()
+{
+    LSUP_HTStore *store = LSUP_htstore_new();
+    ASSERT (store != NULL, "Error initializing store!");
+
+    LSUP_Triple *trp = create_triples();
+    LSUP_SerTriple ser_trp[NUM_TRP];
+
+    for (int i = 0; i < NUM_TRP; i++) {
+        LSUP_striple_init (ser_trp + i, BUF_DUMMY, BUF_DUMMY, BUF_DUMMY);
+        LSUP_triple_serialize (trp + i, ser_trp + i);
+    }
+
+    // Test adding.
+    LSUP_HTIterator *it = LSUP_htstore_add_init (store);
+    for (size_t i = 0; i < NUM_TRP; i++) {
+        LSUP_rc rc = LSUP_htstore_add_iter (it, ser_trp + i);
+        ASSERT (
+                (i < 8 && rc == LSUP_OK) || rc == LSUP_NOACTION,
+                "Wrong return code on insert!");
+    }
+
+    EXPECT_INT_EQ (LSUP_htiter_cur (it), 8);
+    EXPECT_INT_EQ (LSUP_htstore_size (store), 8);
+
+    LSUP_htstore_add_done (it);
+
+    // Test lookups.
+    LSUP_SerTriple lut[12] = {
+        {NULL, NULL, NULL},
+
+        {ser_trp[0].s, NULL, NULL},
+        {ser_trp[2].s, NULL, NULL},
+        {NULL, ser_trp[0].p, NULL},
+        {NULL, ser_trp[0].s, NULL},
+        {NULL, NULL, ser_trp[6].o},
+
+        {ser_trp[4].s, ser_trp[4].p, NULL},
+        {NULL, ser_trp[7].p, ser_trp[7].o},
+        {ser_trp[5].s, NULL, ser_trp[5].o},
+        {ser_trp[5].s, NULL, ser_trp[5].o},
+
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[4].o},
+        {ser_trp[4].s, ser_trp[4].p, ser_trp[6].o},
+    };
+
+    size_t results[12] = {
+        8,
+        5, 1, 1, 0, 1,
+        2, 1, 2, 2,
+        1, 0,
+    };
+
+    for (int i = 0; i < NUM_TRP; i++) {
+        size_t ct = 0;
+        TRACE ("Testing triple lookup #%d.\n", i);
+
+        LSUP_HTIterator *it = LSUP_htstore_lookup(store, lut + i);
+        LSUP_SerTriple *sspo = STRP_DUMMY;
+        while (LSUP_htiter_next (it, sspo) != LSUP_END) {
+            // Verify that the internal counter aligns with an external one.
+            ct ++;
+            EXPECT_INT_EQ (ct, LSUP_htiter_cur(it));
+        }
+        EXPECT_INT_EQ (ct, results[i]);
+
+        LSUP_htiter_free (it);
+    }
+
+    for (int i = 0; i < NUM_TRP; i++) {
+        LSUP_buffer_free (ser_trp[i].s);
+        LSUP_buffer_free (ser_trp[i].p);
+        LSUP_buffer_free (ser_trp[i].o);
+    }
+
+    LSUP_htstore_free (store);
+    free_triples (trp);
+
+    return 0;
+}
+
+
+int store_ht_tests()
+{
+    RUN(test_htstore);
+
+    return 0;
+}

+ 1 - 1
test/test_store_mdb.c

@@ -305,7 +305,7 @@ static int test_quad_store()
 }
 
 
-int store_mdb_test()
+int store_mdb_tests()
 {
     RUN (test_triple_store);
     RUN (test_quad_store);

+ 5 - 5
test/test_term.c

@@ -86,11 +86,11 @@ static int test_term_to_key()
     LSUP_Term *tllit2 = LSUP_term_new(
             LSUP_TERM_LITERAL, "hello", "xsd:string", "en-GB");
 
-    LSUP_Key uri_key = LSUP_term_to_key (uri);
-    LSUP_Key lit_key = LSUP_term_to_key (lit);
-    LSUP_Key tlit_key = LSUP_term_to_key (tlit);
-    LSUP_Key tllit1_key = LSUP_term_to_key (tllit1);
-    LSUP_Key tllit2_key = LSUP_term_to_key (tllit2);
+    LSUP_Key uri_key = LSUP_term_hash (uri);
+    LSUP_Key lit_key = LSUP_term_hash (lit);
+    LSUP_Key tlit_key = LSUP_term_hash (tlit);
+    LSUP_Key tllit1_key = LSUP_term_hash (tllit1);
+    LSUP_Key tllit2_key = LSUP_term_hash (tllit2);
 
     ASSERT (uri_key != lit_key, "URI key conflict!");
     ASSERT (lit_key != tlit_key, "URI key conflict!");