|
@@ -49,9 +49,15 @@ struct MDBStore {
|
|
|
|
|
|
/** @brief Iterator operation.
|
|
|
*
|
|
|
- * Function executed for each iteration of a #MDBIterator.
|
|
|
+ * Function executed for each iteration of a #MDBIterator. It assumes that a
|
|
|
+ * result triple has already been found and is ready to be composed and
|
|
|
+ * yielded.
|
|
|
+ *
|
|
|
+ * Upon call, the rc value of the iterator structure is set to the MDB_* rc
|
|
|
+ * value for the next result. It is up to the caller to evaluate this value
|
|
|
+ * and decide whether to call the function again.
|
|
|
*/
|
|
|
-typedef LSUP_rc (*iter_op_fn_t)(struct MDBIterator *it);
|
|
|
+typedef void (*iter_op_fn_t)(struct MDBIterator *it);
|
|
|
|
|
|
|
|
|
/** @brief Triple iterator.
|
|
@@ -91,7 +97,7 @@ struct MDBIterator {
|
|
|
#define MAIN_TABLE \
|
|
|
ENTRY( T_ST, "t:st", 0 ) /* Key to ser. term */ \
|
|
|
ENTRY( SPO_C, "spo:c", DUPFIXED_MASK ) /* Triple to context */ \
|
|
|
- ENTRY( C_, "c:", 0 ) /* Track empty contexts */\
|
|
|
+ ENTRY( C_, "c:", 0 ) /* Track empty ctx */ \
|
|
|
ENTRY( PFX_NS, "pfx:ns", 0 ) /* Prefix to NS */ \
|
|
|
|
|
|
/**
|
|
@@ -580,16 +586,24 @@ LSUP_store_lookup(
|
|
|
}
|
|
|
|
|
|
|
|
|
-/** @brief Yield the matching triples and advance the iterator.
|
|
|
- */
|
|
|
LSUP_rc
|
|
|
LSUP_store_it_next(LSUP_MDBIterator *it, LSUP_SerTerm **sspo)
|
|
|
{
|
|
|
- LSUP_rc rc = (
|
|
|
- it->rc == MDB_NOTFOUND ?
|
|
|
- LSUP_END : it->iter_op_fn(it));
|
|
|
+ // Only advance if the previous it->rc wasn't already at the end.
|
|
|
+ if(it->rc == MDB_NOTFOUND) return LSUP_END;
|
|
|
+
|
|
|
+ if(it->rc != MDB_SUCCESS) {
|
|
|
+ fprintf(stderr, mdb_strerror(it->rc));
|
|
|
+ return LSUP_DB_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ LSUP_rc rc;
|
|
|
+
|
|
|
+ it->iter_op_fn(it);
|
|
|
+
|
|
|
+ if (it->ck) {
|
|
|
+ rc = LSUP_NORESULT; // Intermediary value, will never be returned.
|
|
|
|
|
|
- if (it->ck && rc != LSUP_END) {
|
|
|
MDB_cursor *cur;
|
|
|
MDB_val key, data;
|
|
|
|
|
@@ -600,32 +614,47 @@ LSUP_store_it_next(LSUP_MDBIterator *it, LSUP_SerTerm **sspo)
|
|
|
data.mv_data = &it->ck;
|
|
|
data.mv_size = KLEN;
|
|
|
|
|
|
- do {
|
|
|
+ while (rc == LSUP_NORESULT) {
|
|
|
+ TRACE(STR, "begin ctx loop.");
|
|
|
// If ctx is specified, look if the matching triple is associated
|
|
|
// with it. If not, move on to the next triple.
|
|
|
// The loop normally exits when a triple with matching ctx is found
|
|
|
- // (LSUP_OK), or if there are no more triples (LSUP_END).
|
|
|
+ // (LSUP_OK), if there are no more triples (LSUP_END), or if there
|
|
|
+ // is an error (LSUPP_DB_ERR).
|
|
|
key.mv_data = it->spok;
|
|
|
|
|
|
- if (
|
|
|
- mdb_cursor_get(cur, &key, &data, MDB_GET_BOTH) == MDB_NOTFOUND
|
|
|
- ) {
|
|
|
- if (it->iter_op_fn(it) == LSUP_END) rc = LSUP_END;
|
|
|
- else rc = LSUP_NORESULT;
|
|
|
+ int db_rc = mdb_cursor_get(cur, &key, &data, MDB_GET_BOTH);
|
|
|
+
|
|
|
+ if (db_rc == MDB_SUCCESS) {
|
|
|
+ rc = LSUP_OK;
|
|
|
+ TRACE(STR, "Triple found for context.");
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (db_rc == MDB_NOTFOUND) {
|
|
|
+ TRACE(STR, "No triples found for context.");
|
|
|
+ if (it->rc == MDB_NOTFOUND) rc = LSUP_END;
|
|
|
+ else it->iter_op_fn(it);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ fprintf(stderr, mdb_strerror(it->rc));
|
|
|
+ rc = LSUP_DB_ERR;
|
|
|
}
|
|
|
|
|
|
- } while (rc == LSUP_NORESULT);
|
|
|
+ }
|
|
|
|
|
|
mdb_cursor_close(cur);
|
|
|
- }
|
|
|
|
|
|
- if (rc == LSUP_OK) {
|
|
|
- LSUP_store_key_to_sterm(it->store, *it->spok[0], *sspo);
|
|
|
- LSUP_store_key_to_sterm(it->store, *it->spok[1], *sspo + 1);
|
|
|
- LSUP_store_key_to_sterm(it->store, *it->spok[2], *sspo + 2);
|
|
|
+ } else rc = LSUP_OK;
|
|
|
|
|
|
- // TODO error handling.
|
|
|
- } else *sspo = NULL;
|
|
|
+ if (sspo) {
|
|
|
+ if (rc == LSUP_OK) {
|
|
|
+ LSUP_store_key_to_sterm(it->store, *it->spok[0], *sspo);
|
|
|
+ LSUP_store_key_to_sterm(it->store, *it->spok[1], *sspo + 1);
|
|
|
+ LSUP_store_key_to_sterm(it->store, *it->spok[2], *sspo + 2);
|
|
|
+
|
|
|
+ // TODO error handling.
|
|
|
+ } else *sspo = NULL;
|
|
|
+ }
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
@@ -861,18 +890,12 @@ index_triple(
|
|
|
*
|
|
|
* Cursor: spo:c
|
|
|
*/
|
|
|
-inline static LSUP_rc
|
|
|
+inline static void
|
|
|
it_next_0bound(struct MDBIterator *it)
|
|
|
{
|
|
|
- LSUP_Key *spok = (LSUP_Key*)it->data.mv_data;
|
|
|
-
|
|
|
- *it->spok[0] = spok[0];
|
|
|
- *it->spok[1] = spok[1];
|
|
|
- *it->spok[2] = spok[2];
|
|
|
+ it->spok = (LSUP_TripleKey*)&it->data.mv_data;
|
|
|
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, NULL, MDB_NEXT);
|
|
|
-
|
|
|
- return LSUP_OK;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -882,26 +905,33 @@ it_next_0bound(struct MDBIterator *it)
|
|
|
*
|
|
|
* Cursor: s:po, p:so, or o:sp.
|
|
|
*/
|
|
|
-inline static LSUP_rc
|
|
|
+inline static void
|
|
|
it_next_1bound(struct MDBIterator *it)
|
|
|
{
|
|
|
- LSUP_Key **lu_dset = it->data.mv_data;
|
|
|
+ LSUP_DoubleKey *lu_dset = it->data.mv_data;
|
|
|
|
|
|
- *it->spok[it->term_order[0]] = it->luk[0];
|
|
|
- *it->spok[it->term_order[1]] = lu_dset[it->i][0];
|
|
|
- *it->spok[it->term_order[2]] = lu_dset[it->i][1];
|
|
|
+ it->spok[0][it->term_order[0]] = it->luk[0];
|
|
|
+ it->spok[0][it->term_order[1]] = lu_dset[it->i][0];
|
|
|
+ it->spok[0][it->term_order[2]] = lu_dset[it->i][1];
|
|
|
+
|
|
|
+ TRACE(
|
|
|
+ "Composed triple: {%lu %lu %lu}",
|
|
|
+ it->spok[0][0], it->spok[0][1], it->spok[0][2]);
|
|
|
|
|
|
// Ensure next block within the same page is not beyond the last.
|
|
|
- if(it->i < it->data.mv_size / DBL_KLEN - 1)
|
|
|
+ if(it->i < it->data.mv_size / DBL_KLEN - 1) {
|
|
|
it->i ++;
|
|
|
- else {
|
|
|
+ TRACE("Increasing page cursor to %lu.", it->i);
|
|
|
+ TRACE("it->rc: %d", it->rc);
|
|
|
+
|
|
|
+ } else {
|
|
|
// If the last block in the page is being yielded,
|
|
|
// move cursor to beginning of next page.
|
|
|
it->i = 0;
|
|
|
+ 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);
|
|
|
}
|
|
|
-
|
|
|
- return LSUP_OK;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -911,17 +941,17 @@ it_next_1bound(struct MDBIterator *it)
|
|
|
*
|
|
|
* Cursor: po:s, so:p, or sp:o.
|
|
|
*/
|
|
|
-inline static LSUP_rc
|
|
|
+inline static void
|
|
|
it_next_2bound(struct MDBIterator *it)
|
|
|
{
|
|
|
LSUP_Key *lu_dset = it->data.mv_data;
|
|
|
|
|
|
- *it->spok[it->term_order[0]] = it->luk[0];
|
|
|
- *it->spok[it->term_order[1]] = it->luk[1];
|
|
|
- *it->spok[it->term_order[2]] = lu_dset[it->i];
|
|
|
+ it->spok[0][it->term_order[0]] = it->luk[0];
|
|
|
+ it->spok[0][it->term_order[1]] = it->luk[1];
|
|
|
+ it->spok[0][it->term_order[2]] = lu_dset[it->i];
|
|
|
|
|
|
// Ensure next block within the same page is not beyond the last.
|
|
|
- if(it->i < it->data.mv_size / DBL_KLEN - 1)
|
|
|
+ if(it->i < it->data.mv_size / KLEN - 1)
|
|
|
it->i ++;
|
|
|
else {
|
|
|
// If the last block in the page is being yielded,
|
|
@@ -929,8 +959,6 @@ it_next_2bound(struct MDBIterator *it)
|
|
|
it->i = 0;
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_NEXT_MULTIPLE);
|
|
|
}
|
|
|
-
|
|
|
- return LSUP_OK;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -940,11 +968,10 @@ it_next_2bound(struct MDBIterator *it)
|
|
|
* which was already set in the first result, or there was none, i.e. it->rc is
|
|
|
* already MDB_NOTFOUND and this function will not be called.
|
|
|
*/
|
|
|
-inline static LSUP_rc
|
|
|
+inline static void
|
|
|
it_next_3bound(struct MDBIterator *it)
|
|
|
{
|
|
|
it->rc = MDB_NOTFOUND;
|
|
|
- return LSUP_OK;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -986,7 +1013,12 @@ lookup_0bound(struct MDBStore *store, struct MDBIterator *it, size_t *ct)
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_FIRST);
|
|
|
it->iter_op_fn = it_next_0bound;
|
|
|
|
|
|
- return it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -997,26 +1029,47 @@ lookup_1bound(
|
|
|
{
|
|
|
it->term_order = (const uint8_t*)lookup_ordering_1bound[idx0];
|
|
|
|
|
|
- TRACE("Looking up 1 bound term: %lx\n", it->luk[0]);
|
|
|
+ TRACE("Looking up 1 bound term: %lu\n", it->luk[0]);
|
|
|
|
|
|
- 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->txn) {
|
|
|
+ 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();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-
|
|
|
mdb_cursor_open(it->txn, store->dbi[lookup_indices[idx0]], &it->cur);
|
|
|
|
|
|
it->key.mv_data = it->luk;
|
|
|
it->key.mv_size = KLEN;
|
|
|
|
|
|
if(ct) {
|
|
|
+ // If a context is specified, the only way to count triples matching
|
|
|
+ // the context is to loop over them.
|
|
|
if (it->ck != NULL_KEY) {
|
|
|
- it->rc = mdb_cursor_get(
|
|
|
- it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
|
|
|
- while (it->rc != MDB_NOTFOUND) {
|
|
|
+ struct MDBIterator *ct_it;
|
|
|
+ CRITICAL(ct_it = malloc(sizeof(struct MDBIterator)));
|
|
|
+
|
|
|
+ ct_it->luk[0] = it->luk[0];
|
|
|
+ LSUP_TripleKey ct_spok;
|
|
|
+ ct_it->spok = &ct_spok;
|
|
|
+ ct_it->ck = it->ck;
|
|
|
+ ct_it->store = it->store;
|
|
|
+ ct_it->txn = it->txn;
|
|
|
+ ct_it->key = it->key;
|
|
|
+ ct_it->data = it->data;
|
|
|
+ ct_it->i = 0;
|
|
|
+ lookup_1bound(store, idx0, ct_it, NULL);
|
|
|
+
|
|
|
+ while (LSUP_store_it_next(ct_it, NULL) != LSUP_END) {
|
|
|
+ ct[0] ++;
|
|
|
+ TRACE("Counter increased to %lu.", *ct);
|
|
|
}
|
|
|
+
|
|
|
+ mdb_cursor_close(ct_it->cur);
|
|
|
+ free(ct_it);
|
|
|
+
|
|
|
} else {
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
|
|
|
if (it->rc == MDB_SUCCESS) mdb_cursor_count(it->cur, ct);
|
|
@@ -1030,7 +1083,12 @@ lookup_1bound(
|
|
|
if (it->rc == MDB_SUCCESS)
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
|
|
|
|
|
|
- return it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1082,8 +1140,13 @@ lookup_2bound(
|
|
|
luk[luk1_offset] = it->luk[0];
|
|
|
luk[luk2_offset] = it->luk[1];
|
|
|
|
|
|
- if(store->txn) it->txn = store->txn;
|
|
|
- else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &it->txn);
|
|
|
+ if(!it->txn) {
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
it->key.mv_data = luk;
|
|
|
it->key.mv_size = DBL_KLEN;
|
|
@@ -1091,7 +1154,33 @@ lookup_2bound(
|
|
|
mdb_cursor_open(it->txn, dbi, &it->cur);
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
|
|
|
|
|
|
- if(ct && it->rc == MDB_SUCCESS) mdb_cursor_count(it->cur, ct);
|
|
|
+ if(ct) {
|
|
|
+ // If a context is specified, the only way to count triples matching
|
|
|
+ // the context is to loop over them.
|
|
|
+ if (it->ck != NULL_KEY) {
|
|
|
+ struct MDBIterator *ct_it;
|
|
|
+ CRITICAL(ct_it = malloc(sizeof(struct MDBIterator)));
|
|
|
+
|
|
|
+ ct_it->luk[0] = it->luk[0];
|
|
|
+ ct_it->luk[1] = it->luk[1];
|
|
|
+ LSUP_TripleKey ct_spok;
|
|
|
+ ct_it->spok = &ct_spok;
|
|
|
+ ct_it->ck = it->ck;
|
|
|
+ ct_it->store = it->store;
|
|
|
+ ct_it->txn = it->txn;
|
|
|
+ lookup_2bound(store, idx0, idx1, ct_it, NULL);
|
|
|
+
|
|
|
+ while (LSUP_store_it_next(ct_it, NULL) != LSUP_END) {
|
|
|
+ ct[0] ++;
|
|
|
+ }
|
|
|
+ if (ct_it->cur) mdb_cursor_close(ct_it->cur);
|
|
|
+ free(ct_it);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
|
|
|
+ if (it->rc == MDB_SUCCESS) mdb_cursor_count(it->cur, ct);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
it->i = 0;
|
|
|
it->iter_op_fn = it_next_2bound;
|
|
@@ -1100,7 +1189,12 @@ lookup_2bound(
|
|
|
if (it->rc == MDB_SUCCESS)
|
|
|
it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
|
|
|
|
|
|
- return it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1110,31 +1204,42 @@ lookup_3bound(struct MDBStore *store, struct MDBIterator *it, size_t *ct)
|
|
|
TRACE(
|
|
|
"Looking up 3 bound: {%lx, %lx, %lx}",
|
|
|
it->luk[0], it->luk[1], it->luk[2]);
|
|
|
- LSUP_rc rc = LSUP_NORESULT;
|
|
|
|
|
|
if(store->txn) it->txn = store->txn;
|
|
|
else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &it->txn);
|
|
|
|
|
|
- MDB_cursor *cur;
|
|
|
- it->rc = mdb_cursor_open(it->txn, store->dbi[IDX_S_PO], &cur);
|
|
|
-
|
|
|
it->key.mv_data = it->luk;
|
|
|
- it->key.mv_size = KLEN;
|
|
|
- it->data.mv_data = it->luk + 1;
|
|
|
- it->data.mv_size = DBL_KLEN;
|
|
|
|
|
|
- it->rc = mdb_cursor_get(cur, &it->key, &it->data, MDB_GET_BOTH);
|
|
|
- if(ct && it->rc == MDB_SUCCESS) *ct = 1;
|
|
|
+ if(it->ck != NULL_KEY) {
|
|
|
+ it->rc = mdb_cursor_open(it->txn, store->dbi[IDX_SPO_C], &it->cur);
|
|
|
+
|
|
|
+ it->key.mv_size = TRP_KLEN;
|
|
|
+ it->data.mv_data = &it->ck;
|
|
|
+ it->data.mv_size = KLEN;
|
|
|
|
|
|
- if (it->rc == MDB_NOTFOUND) {
|
|
|
- rc = LSUP_NORESULT;
|
|
|
} else {
|
|
|
- it->iter_op_fn = it_next_3bound;
|
|
|
- it->spok = &it->luk;
|
|
|
- rc = LSUP_OK;
|
|
|
+ it->rc = mdb_cursor_open(it->txn, store->dbi[IDX_S_PO], &it->cur);
|
|
|
+
|
|
|
+ it->key.mv_size = KLEN;
|
|
|
+ it->data.mv_data = it->luk + 1;
|
|
|
+ it->data.mv_size = DBL_KLEN;
|
|
|
}
|
|
|
|
|
|
- return rc;
|
|
|
+ it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_GET_BOTH);
|
|
|
+
|
|
|
+ mdb_cursor_close(it->cur);
|
|
|
+
|
|
|
+ if(ct && it->rc == MDB_SUCCESS) *ct = 1;
|
|
|
+
|
|
|
+ it->iter_op_fn = it_next_3bound;
|
|
|
+ it->spok = &it->luk;
|
|
|
+
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
|