1
0

4 Коміти 0001c8ab00 ... 4b203e5de1

Автор SHA1 Опис Дата
  scossu 4b203e5de1 Fix memory leaks. 9 місяців тому
  scossu 98f1d9f46f Add LSUP_graph_get(); fix LSUP_graph_size(). 9 місяців тому
  scossu 64cdc9c263 Change storage of BTRP_DUMMY. 9 місяців тому
  scossu 78064ee6d6 Fix graph boolean XOR op. 9 місяців тому
5 змінених файлів з 189 додано та 38 видалено
  1. 11 3
      include/buffer.h
  2. 27 3
      include/graph.h
  3. 14 5
      src/buffer.c
  4. 68 27
      src/graph.c
  5. 69 0
      test/test_graph.c

+ 11 - 3
include/buffer.h

@@ -228,8 +228,9 @@ LSUP_btriple_free (LSUP_BufferTriple *sspo);
 
 /** @brief Free a buffer triple and its buffer handles but not the buffer data.
  *
- * This is useful when freeing a "dummy" triple whose buffers are owned by the
- * caller but the data the terms point to are owned by the store.
+ * This is useful when freeing a dummy triple (#LSUP_BTRP_DUMMY) or a triple
+ * whose buffers are owned by the caller but the data the terms point to are
+ * owned by the store.
  *
  */
 void
@@ -279,6 +280,13 @@ LSUP_btriple_hash (const LSUP_BufferTriple *strp)
 }
 
 
-#define BTRP_DUMMY LSUP_btriple_new (NULL, NULL, NULL)
+/** @brief Dummy buffer triple.
+ *
+ * Triple of dummy buffer, with #LSUP_Buffer size space allocated, but no
+ * contents.
+ *
+ * Free with #LSUP_btriple_free_shallow().
+ */
+#define BTRP_DUMMY LSUP_btriple_new (BUF_DUMMY, BUF_DUMMY, BUF_DUMMY)
 
 #endif

+ 27 - 3
include/graph.h

@@ -40,6 +40,30 @@ LSUP_Graph *
 LSUP_graph_new (LSUP_Store *store, LSUP_Term *uri, LSUP_NSMap *nsm);
 
 
+/** @brief Create a temp graph from stored triples.
+ *
+ * The new graph is stored in a hash map and is made up of all the triples
+ * found in the store with the given context URI. The new graph URI is the
+ * same as the given context.
+ *
+ * @param[in] store Back end store handle. The store must exist.
+ *
+ * @param[in] uri URI of the graph to retrieve.
+ *
+ * @param[out] ct If not NULL, it will be populated with the number of triples
+ * found.
+ *
+ * @return New graph handle. It must be freed by the caller. If no matching
+ * context URI was found, NULL is returned.
+ */
+LSUP_Graph *
+LSUP_graph_get_txn (void *txn, LSUP_Store *store, LSUP_Term *uri, size_t *ct);
+
+
+/// Non-transactional version of #LSUP_graph_get_txn().
+#define LSUP_graph_get(...) LSUP_graph_get_txn (NULL, __VA_ARGS__)
+
+
 /** @brief Copy triples from a source graph into a destination one.
  *
  * The destination graph is not initialized here, so the copy is cumulative.
@@ -244,11 +268,11 @@ LSUP_graph_add_txn (
  *
  * @param[in] txn Transaction handle. It may be NULL.
  *
- * @param gr[in] Graph to delete triples from.
+ * @param[in] gr[in] Graph to delete triples from.
  *
- * @param ptn[in] Matching pattern. Any and all of s, p, o can be NULL.
+ * @param[in] s, p, o Matching pattern. Any and all of s, p, o can be NULL.
  *
- * @param ct[out] If not NULL it is populated with the number of triples
+ * @param[out] ct If not NULL it is populated with the number of triples
  *  deleted.
  */
 LSUP_rc

+ 14 - 5
src/buffer.c

@@ -16,14 +16,23 @@ LSUP_rc
 LSUP_buffer_init (
         LSUP_Buffer *buf, const size_t size, const unsigned char *data)
 {
-    // If size is zero, addr becomes NULL.
-    unsigned char *tmp = realloc (buf->addr, size);
-    if (UNLIKELY (size > 0 && tmp == NULL)) return LSUP_MEM_ERR;
+    // Do not rely on glibc realloc to handle zero size. See man 3 realloc -
+    // Nonportable behavior.
+    if (size == 0) {
+        if (buf->addr) {
+            free (buf->addr);
+            buf->addr = NULL;
+        }
+    } else {
+        // If buf->addr is NULL, realloc == malloc. This is portable.
+        unsigned char *tmp = realloc (buf->addr, size);
+        if (UNLIKELY (size > 0 && tmp == NULL)) return LSUP_MEM_ERR;
 
-    buf->addr = tmp;
+        buf->addr = tmp;
+    }
     buf->size = size;
 
-    if (data) memcpy (buf->addr, data, buf->size);
+    if (data && buf->addr) memcpy (buf->addr, data, buf->size);
 
     return LSUP_OK;
 }

+ 68 - 27
src/graph.c

@@ -29,9 +29,6 @@ struct graph_iter_t {
 inline static LSUP_rc
 graph_iter_next_buffer (LSUP_GraphIterator *it);
 
-inline static LSUP_rc
-graph_iter_alloc_buffers (LSUP_GraphIterator *it);
-
 
 #define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
 static inline bool
@@ -64,6 +61,42 @@ LSUP_graph_new (LSUP_Store *store, LSUP_Term *uri, LSUP_NSMap *nsm)
 }
 
 
+LSUP_Graph *
+LSUP_graph_get_txn (void *txn, LSUP_Store *store, LSUP_Term *uri, size_t *ct)
+{
+    LSUP_Buffer *sc = LSUP_term_serialize (uri);
+    void *it = store->sif->lookup_fn (
+            store->data, NULL, NULL, NULL, sc, NULL, NULL);
+
+    LSUP_Graph *gr = LSUP_graph_new (NULL, uri, NULL);
+    LSUP_BufferTriple *sspo = BTRP_DUMMY;
+    void *add_it = LSUP_graph_add_init_txn (txn, gr);
+
+    size_t _ct = 0;
+    while (store->sif->lu_next_fn (it, sspo, NULL) == LSUP_OK) {
+        // TODO This is inefficient, it's deserializing a buffer triple that
+        // will be re-serialized by LSUP_graph_add_iter.
+        LSUP_Triple *spo = LSUP_triple_new_from_btriple (sspo);
+        LSUP_graph_add_iter (add_it, spo);
+        LSUP_triple_free (spo);
+        _ct++;
+    }
+    LSUP_graph_add_done (add_it);
+    store->sif->lu_free_fn(it);
+    LSUP_buffer_free (sc);
+    LSUP_btriple_free_shallow (sspo);
+
+    // Do not create a new graph if no results were found.
+    if (_ct == 0) {
+        LSUP_graph_free (gr);
+        gr = NULL;
+    }
+    if (ct) *ct = _ct;
+
+    return gr;
+}
+
+
 LSUP_rc
 LSUP_graph_bool_op_txn (
         void *txn, const LSUP_bool_op op,
@@ -80,6 +113,8 @@ LSUP_graph_bool_op_txn (
         return LSUP_VALUE_ERR;
     }
 
+    /* BEGIN union block. */
+
     if (op == LSUP_BOOL_UNION) {
         rc = LSUP_graph_copy_contents (gr1, res);
         PCHECK (rc, fail);
@@ -89,6 +124,10 @@ LSUP_graph_bool_op_txn (
         return LSUP_OK;
     }
 
+    /* END union block. */
+
+    /* BEGIN subtraction, intersection, XOR block. */
+
     LSUP_Buffer
         *res_sc = LSUP_term_serialize (res->uri),
         *gr1_sc = LSUP_term_serialize (gr1->uri),
@@ -107,7 +146,7 @@ LSUP_graph_bool_op_txn (
             lu1_it = gr1->store->sif->lookup_fn (
                     gr1->store->data, sspo->s, sspo->p, sspo->o, gr1_sc,
                     txn, &ct);
-            if (ct > 0)
+            if (ct == 0)
                 res->store->sif->add_iter_fn (add_it, sspo);
             gr1->store->sif->lu_free_fn (lu1_it);
         }
@@ -129,10 +168,13 @@ LSUP_graph_bool_op_txn (
     gr1->store->sif->lu_free_fn (lu1_it);
 
     res->store->sif->add_done_fn (add_it);
+    LSUP_btriple_free_shallow (sspo);
     LSUP_buffer_free (res_sc);
     LSUP_buffer_free (gr1_sc);
     LSUP_buffer_free (gr2_sc);
 
+    /* END subtraction, intersection, XOR block. */
+
     return rc;
 
 fail:
@@ -203,7 +245,17 @@ LSUP_graph_set_namespace (LSUP_Graph *gr, LSUP_NSMap *nsm)
 
 size_t
 LSUP_graph_size (const LSUP_Graph *gr)
-{ return gr->store->sif->size_fn (gr->store->data); }
+{
+    size_t ct = 0;
+    LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
+    void *it = gr->store->sif->lookup_fn (
+        gr->store->data, NULL, NULL, NULL, sc, NULL, &ct);
+    gr->store->sif->lu_free_fn (it);
+
+    LSUP_buffer_free (sc);
+
+    return ct;
+}
 
 
 bool
@@ -321,15 +373,13 @@ LSUP_graph_remove_txn (
         const LSUP_Term *s, const LSUP_Term *p, const LSUP_Term *o,
         size_t *ct)
 {
-    LSUP_rc rc;
-
     LSUP_Buffer
         *ss = LSUP_term_serialize (s),
         *sp = LSUP_term_serialize (p),
         *so = LSUP_term_serialize (o),
         *sc = LSUP_term_serialize (gr->uri);
 
-    rc = gr->store->sif->remove_fn (
+    LSUP_rc rc = gr->store->sif->remove_fn (
             gr->store->data, ss, sp, so, sc, txn, ct);
 
     LSUP_buffer_free (ss);
@@ -403,7 +453,15 @@ LSUP_graph_lookup_txn (
     }
 
     it->graph = gr;
-    RCNL (graph_iter_alloc_buffers (it));
+
+    if (it->graph->store->sif->features & LSUP_STORE_COW) {
+        // Copy-on-wite store.
+        it->sspo = BTRP_DUMMY;
+
+        if (UNLIKELY (it->sspo == NULL)) return NULL;
+    } else {
+        // TODO copy-on-retrieval store. No implementations yet.
+    }
 
     return it;
 }
@@ -444,6 +502,7 @@ LSUP_graph_iter_free (LSUP_GraphIterator *it)
      */
     if (it->graph->store->sif->features & LSUP_STORE_COW) {
         LSUP_btriple_free_shallow (it->sspo);
+        log_debug ("Freeing dummy triple @ %p", it->sspo);
     } else {
         // TODO copy-on-retrieval stores. None yet.
     }
@@ -662,24 +721,6 @@ graph_iter_next_buffer (LSUP_GraphIterator *it)
 { return it->graph->store->sif->lu_next_fn (it->data, it->sspo, NULL); }
 
 
-/** @brief Properly allocate temporary byte buffers in advance of iteration.
- */
-inline LSUP_rc
-graph_iter_alloc_buffers (LSUP_GraphIterator *it)
-{
-    if (it->graph->store->sif->features & LSUP_STORE_COW) {
-        it->sspo = BTRP_DUMMY;
-        CALLOC_GUARD (it->sspo->s, LSUP_MEM_ERR);
-        CALLOC_GUARD (it->sspo->p, LSUP_MEM_ERR);
-        CALLOC_GUARD (it->sspo->o, LSUP_MEM_ERR);
-    } else {
-        // TODO copy-on-retrieval stores. None yet.
-    }
-
-    return LSUP_OK;
-}
-
-
 /**
  * Extern inline definitions.
  */

+ 69 - 0
test/test_graph.c

@@ -82,6 +82,64 @@ _graph_add (LSUP_StoreType type)
 }
 
 
+static int
+_graph_get (LSUP_StoreType type)
+{
+    const LSUP_StoreInt *sif = LSUP_store_int (type);
+    // Skip if the store doesn't support contexts.
+    if (!(sif->features & LSUP_STORE_CTX)) return 0;
+
+    if (sif->setup_fn) sif->setup_fn (NULL, true);
+
+    LSUP_Triple **trp = create_triples();
+
+    LSUP_Store *store = LSUP_store_new (type, NULL, 0);
+    LSUP_Graph
+        *gr1 = LSUP_graph_new (store, NULL, NULL),
+        *gr2 = LSUP_graph_new (store, NULL, NULL);
+
+    ASSERT (gr1 != NULL, "Error creating graph!");
+    ASSERT (gr2 != NULL, "Error creating graph!");
+
+
+    // Add 2 groups of triples to different graphs.
+    void *it1 = LSUP_graph_add_init (gr1);
+    for (size_t i = 0; i < 5; i++) {
+        LSUP_graph_add_iter(it1, trp[i]);
+    }
+    LSUP_graph_add_done (it1);
+
+    void *it2 = LSUP_graph_add_init (gr2);
+    for (size_t i = 5; i < NUM_TRP; i++) {
+        LSUP_graph_add_iter(it2, trp[i]);
+    }
+    LSUP_graph_add_done (it2);
+
+    EXPECT_INT_EQ (LSUP_graph_size (gr1), 5);
+    EXPECT_INT_EQ (LSUP_graph_size (gr2), 3);
+
+    size_t ct3, ct4;
+    LSUP_Graph
+        *gr3 = LSUP_graph_get (store, LSUP_graph_uri (gr1), &ct3),
+        *gr4 = LSUP_graph_get (store, LSUP_graph_uri (gr2), &ct4);
+
+    EXPECT_INT_EQ (LSUP_graph_size (gr3), LSUP_graph_size (gr1));
+    EXPECT_INT_EQ (LSUP_graph_size (gr4), LSUP_graph_size (gr2));
+
+    ASSERT (LSUP_graph_equals (gr1, gr3), "Graphs 1 and 3 are not equal!");
+    ASSERT (LSUP_graph_equals (gr2, gr4), "Graphs 2 and 4 are not equal!");
+
+    LSUP_graph_free (gr1);
+    LSUP_graph_free (gr2);
+    LSUP_graph_free (gr3);
+    LSUP_graph_free (gr4);
+    free_triples (trp);
+    if (type != LSUP_STORE_HTABLE) LSUP_store_free (store);
+
+    return 0;
+}
+
+
 static int
 _graph_lookup (LSUP_StoreType type)
 {
@@ -330,6 +388,16 @@ BACKEND_TBL
 }
 
 
+static int test_graph_get() {
+#define ENTRY(a, b) \
+    if (_graph_get (LSUP_STORE_##a) != 0) return -1;
+BACKEND_TBL
+#undef ENTRY
+
+    return 0;
+}
+
+
 static int test_graph_lookup() {
 #define ENTRY(a, b) \
     if (_graph_lookup (LSUP_STORE_##a) != 0) return -1;
@@ -411,6 +479,7 @@ int graph_tests()
     RUN (test_environment);
     RUN (test_graph_new);
     RUN (test_graph_add);
+    RUN (test_graph_get);
     RUN (test_graph_lookup);
     RUN (test_graph_remove);
     RUN (test_graph_copy);