Переглянути джерело

Replace LookupArgs members with MDBIterator.

Stefano Cossu 4 роки тому
батько
коміт
06e282f820
1 змінених файлів з 165 додано та 261 видалено
  1. 165 261
      src/store_mdb.c

+ 165 - 261
src/store_mdb.c

@@ -40,27 +40,13 @@ typedef enum {
 
 struct MDBStore {
     MDB_env *           env;        // Environment handle.
-    MDB_txn *           txn;        // Current transaction. If RW, it may have
-                                    //  nested transactions.
+    MDB_txn *           txn;        // Current transaction.
     MDB_dbi             dbi[N_DB];  // DB handles. Refer to DbIdx enum.
     LSUP_Buffer *       default_ctx;// Default context as a serialized URI.
     StoreState          state;      // Store state (initialized, open etc.)
 };
 
 
-/** @brief Common match callback arguments.
- */
-typedef struct LookupArgs {
-    LSUP_Key luks[3];               // 0÷3 lookup keys.
-    uint8_t idx0, idx1;             // Which term in the triple the lookup keys
-                                    // represent, respectively.
-    LSUP_Key ck;                    // Context key to restrict results to.
-    size_t *ct;                     // Result count.
-    struct MDBIterator *it;         // Iterator returned on matches.
-    void *data;                     // Arbitrary data usable by the callback.
-} LookupArgs;
-
-
 /** @brief Iterator operation.
  *
  * Function executed for each iteration of a #MDBIterator.
@@ -72,13 +58,14 @@ typedef LSUP_rc (*iter_op_fn_t)(struct MDBIterator *it);
  */
 struct MDBIterator {
     struct MDBStore *store;     // MDB store pointer.
+    MDB_txn *txn;               // MDB transaction.
     MDB_cursor *cur;            // MDB cursor.
-    MDB_val *key, *data;        // Internal data handlers.
+    MDB_val key, data;          // Internal data handlers.
     LSUP_TripleKey *spok;       // Triple to be populated with match.
     LSUP_Key ck;                // Context key to filter by. May be NULL_TRP.
     iter_op_fn_t iter_op_fn;    // Function used to look up next match.
-    uint8_t term_order[3];      // Term order used in 1-2bound look-ups.
-    LSUP_Key luks[3];           // 0÷3 lookup keys.
+    const uint8_t *term_order;  // Term order used in 1-2bound look-ups.
+    LSUP_Key luk[3];            // 0÷3 lookup keys.
     size_t i;                   // Internal counter for paged lookups.
     int rc;                     // MDB_* return code for the next result.
 };
@@ -207,13 +194,15 @@ static int index_triple(
         LSUP_TripleKey spok, LSUP_Key ck);
 
 inline static LSUP_rc lookup_0bound(
-        struct MDBStore *store, LookupArgs *args);
+        struct MDBStore *store, struct MDBIterator *it, size_t *ct);
 inline static LSUP_rc lookup_1bound(
-        struct MDBStore *store, LookupArgs *args);
+        struct MDBStore *store, uint8_t idx0,
+        struct MDBIterator *it, size_t *ct);
 inline static LSUP_rc lookup_2bound(
-        struct MDBStore *store, LookupArgs *args);
+        struct MDBStore *store, uint8_t idx0, uint8_t idx1,
+        struct MDBIterator *it, size_t *ct);
 inline static LSUP_rc lookup_3bound(
-        struct MDBStore *store, LookupArgs *args);
+        struct MDBStore *store, struct MDBIterator *it, size_t *ct);
 /* TODO
 inline static int check_txn_open(MDB_txn *txn, bool write);
 */
@@ -522,7 +511,7 @@ LSUP_store_key_to_sterm(
 LSUP_rc
 LSUP_store_lookup(
         LSUP_MDBStore *store, LSUP_SerTerm *sspoc[],
-        struct MDBIterator **it, size_t *ct)
+        struct MDBIterator **itp, size_t *ct)
 {
     LSUP_TripleKey spok = {
         LSUP_sterm_to_key(sspoc[0]),
@@ -530,64 +519,64 @@ LSUP_store_lookup(
         LSUP_sterm_to_key(sspoc[2]),
     };
 
-    LookupArgs args_s;
-    LookupArgs *args = &args_s;
+    LSUP_MDBIterator *it;
+    CRITICAL(it = malloc(sizeof(struct MDBIterator)));
+    *itp = it;
 
-    args->ck = store->default_ctx ? LSUP_sterm_to_key(sspoc[3]) : NULL_KEY;
+    it->store = store;
+    it->ck = store->default_ctx ? LSUP_sterm_to_key(sspoc[3]) : NULL_KEY;
 
-    args->ct = ct;
-    *args->ct = 0;
+    if(ct) *ct = 0;
 
-    CRITICAL(args->it = *it = malloc(sizeof(struct MDBIterator)));
-    args->it->store = store;
+    uint8_t idx0, idx1;
 
     // s p o (all terms bound)
     if (spok[0] != NULL_KEY && spok[1] != NULL_KEY && spok[2] != NULL_KEY) {
-        args->luks[0] = spok[0];
-        args->luks[1] = spok[1];
-        args->luks[2] = spok[2];
-        return lookup_3bound(store, args);
-    }
-
-    else if (spok[0] != NULL_KEY) {
-        args->luks[0] = spok[0];
-        args->idx0 = 0;
-
-        if (spok[1] != NULL_KEY) { // s p ?
-            args->luks[1] = spok[1];
-            args->idx1 = 1;
-            return lookup_2bound(store, args);
-
-        } else if (spok[2] != NULL_KEY) { // s ? o
-            args->luks[1] = spok[2];
-            args->idx1 = 2;
-            return lookup_2bound(store, args);
-
-        } else { // s ? ?
-            return lookup_1bound(store, args);
-        }
+        it->luk[0] = spok[0];
+        it->luk[1] = spok[1];
+        it->luk[2] = spok[2];
+        return lookup_3bound(store, it, ct);
+
+    } else if (spok[0] != NULL_KEY) {
+        it->luk[0] = spok[0];
+        idx0 = 0;
+
+        // s p ?
+        if (spok[1] != NULL_KEY) {
+            it->luk[1] = spok[1];
+            idx1 = 1;
+            return lookup_2bound(store, idx0, idx1, it, ct);
+
+        // s ? o
+        } else if (spok[2] != NULL_KEY) {
+            it->luk[1] = spok[2];
+            idx1 = 2;
+            return lookup_2bound(store, idx0, idx1, it, ct);
+
+        // s ? ?
+        } else return lookup_1bound(store, idx0, it, ct);
 
     } else if (spok[1] != NULL_KEY) {
-        args->luks[0] = spok[1];
-        args->idx0 = 1;
-
-        if (spok[2] != NULL_KEY) { // ? p o
-            args->luks[1] = spok[2];
-            args->idx1 = 2;
-            return lookup_2bound(store, args);
-
-        } else { // ? p ?
-            return lookup_1bound(store, args);
-        }
-
-    } else if (spok[2] != NULL_KEY) { // ? ? o
-        args->luks[0] = spok[2];
-        args->idx0 = 2;
-        return lookup_1bound(store, args);
-
-    } else { // ? ? ? (all terms unbound)
-        return lookup_0bound(store, args);
-    }
+        it->luk[0] = spok[1];
+        idx0 = 1;
+
+        // ? p o
+        if (spok[2] != NULL_KEY) {
+            it->luk[1] = spok[2];
+            idx1 = 2;
+            return lookup_2bound(store, idx0, idx1, it, ct);
+
+        // ? p ?
+        } else return lookup_1bound(store, idx0, it, ct);
+
+    // ? ? o
+    } else if (spok[2] != NULL_KEY) {
+        it->luk[0] = spok[2];
+        idx0 = 2;
+        return lookup_1bound(store, idx0, it, ct);
+
+    // ? ? ? (all terms unbound)
+    } else return lookup_0bound(store, it, ct);
 }
 
 
@@ -646,10 +635,8 @@ void
 LSUP_store_it_free(struct MDBIterator *it)
 {
     if (it) {
-        MDB_txn *cur_txn = mdb_cursor_txn(it->cur);
-
         mdb_cursor_close(it->cur);
-        if(it->store->txn != cur_txn) mdb_txn_abort(cur_txn);
+        if(it->store->txn != it->txn) mdb_txn_abort(it->txn);
 
         free(it);
         it = NULL;
@@ -877,13 +864,13 @@ index_triple(
 inline static LSUP_rc
 it_next_0bound(struct MDBIterator *it)
 {
-    LSUP_Key *spok = (LSUP_Key*)it->data->mv_data;
+    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->rc = mdb_cursor_get(it->cur, it->key, NULL, MDB_NEXT);
+    it->rc = mdb_cursor_get(it->cur, &it->key, NULL, MDB_NEXT);
 
     return LSUP_OK;
 }
@@ -898,20 +885,20 @@ it_next_0bound(struct MDBIterator *it)
 inline static LSUP_rc
 it_next_1bound(struct MDBIterator *it)
 {
-    LSUP_Key **lu_dset = it->data->mv_data;
+    LSUP_Key **lu_dset = it->data.mv_data;
 
-    *it->spok[it->term_order[0]] = it->luks[0];
+    *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];
 
     // 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 {
         // If the last block in the page is being yielded,
         // move cursor to beginning of next page.
         it->i = 0;
-        it->rc = mdb_cursor_get(it->cur, it->key, it->data, MDB_NEXT_MULTIPLE);
+        it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_NEXT_MULTIPLE);
     }
 
     return LSUP_OK;
@@ -927,20 +914,20 @@ it_next_1bound(struct MDBIterator *it)
 inline static LSUP_rc
 it_next_2bound(struct MDBIterator *it)
 {
-    LSUP_Key *lu_dset = it->data->mv_data;
+    LSUP_Key *lu_dset = it->data.mv_data;
 
-    *it->spok[it->term_order[0]] = it->luks[0];
-    *it->spok[it->term_order[1]] = it->luks[1];
+    *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];
 
     // 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 {
         // If the last block in the page is being yielded,
         // move cursor to beginning of next page.
         it->i = 0;
-        it->rc = mdb_cursor_get(it->cur, it->key, it->data, MDB_NEXT_MULTIPLE);
+        it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_NEXT_MULTIPLE);
     }
 
     return LSUP_OK;
@@ -964,149 +951,110 @@ it_next_3bound(struct MDBIterator *it)
 /* * * Term-specific lookups. * * */
 
 inline static LSUP_rc
-lookup_0bound(struct MDBStore *store, LookupArgs *args)
+lookup_0bound(struct MDBStore *store, struct MDBIterator *it, size_t *ct)
 {
-    int rc = LSUP_NORESULT, db_rc;
-
-    MDB_txn *txn;
-    if(store->txn) txn = store->txn;
-    else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &txn);
-
-    MDB_val key_v;
-
-    MDB_cursor *cur;
+    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(args->ct) {
-        if(args->ck != NULL_KEY) {
+    if(ct) {
+        if(it->ck != NULL_KEY) {
             // Look up by given context.
-            db_rc = mdb_cursor_open(txn, store->dbi[IDX_C_SPO], &cur);
+            it->rc = mdb_cursor_open(it->txn, store->dbi[IDX_C_SPO], &it->cur);
 
-            key_v.mv_data = &args->ck;
-            key_v.mv_size = KLEN;
+            it->key.mv_data = &it->ck;
+            it->key.mv_size = KLEN;
 
-            db_rc = mdb_cursor_get(cur, &key_v, NULL, MDB_SET);
-            if (db_rc != MDB_SUCCESS) return rc;
+            it->rc = mdb_cursor_get(it->cur, &it->key, NULL, MDB_SET);
+            if (it->rc == MDB_SUCCESS) mdb_cursor_count(it->cur, ct);
 
-            db_rc = mdb_cursor_count(cur, args->ct);
+            mdb_cursor_close(it->cur);
 
         } else {
             // Look up all contexts.
             MDB_stat stat;
-            mdb_stat(txn, store->dbi[IDX_S_PO], &stat);
+            mdb_stat(it->txn, store->dbi[IDX_S_PO], &stat);
 
-            *args->ct = stat.ms_entries;
+            *ct = stat.ms_entries;
         }
     }
 
-    args->it->ck = args->ck;
-    memcpy(args->it->key, &key_v, sizeof(MDB_val));
-
-    mdb_cursor_open(txn, store->dbi[IDX_SPO_C], &args->it->cur);
+    mdb_cursor_open(it->txn, store->dbi[IDX_SPO_C], &it->cur);
 
-    args->it->rc = mdb_cursor_get(
-            args->it->cur, args->it->key, args->it->data, MDB_FIRST);
+    it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_FIRST);
+    it->iter_op_fn = it_next_0bound;
 
-    args->it->iter_op_fn = it_next_0bound;
-
-    return args->it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
-
-    mdb_cursor_close(cur);
-    if (txn != store->txn) mdb_txn_abort(txn);
-
-    return rc;
+    return it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
 }
 
 
 inline static LSUP_rc
-lookup_1bound(struct MDBStore *store, LookupArgs *args)
+lookup_1bound(
+        struct MDBStore *store, uint8_t idx0,
+        struct MDBIterator *it, size_t *ct)
 {
-    int rc = LSUP_NORESULT, db_rc;
-
-    const uint8_t *term_order = lookup_ordering_1bound[args->idx0];
+    it->term_order = (const uint8_t*)lookup_ordering_1bound[idx0];
 
-    TRACE("Looking up 1 bound term: %lx\n", args->luks[0]);
+    TRACE("Looking up 1 bound term: %lx\n", it->luk[0]);
 
-    MDB_txn *txn;
-    if(store->txn) txn = store->txn;
+    if(store->txn) it->txn = store->txn;
     else {
-        db_rc = mdb_txn_begin(store->env, NULL, MDB_RDONLY, &txn);
-        if (db_rc != MDB_SUCCESS) abort();
+        it->rc = mdb_txn_begin(store->env, NULL, MDB_RDONLY, &it->txn);
+        if (it->rc != MDB_SUCCESS) abort();
     }
 
 
-    MDB_cursor *cur;
-    mdb_cursor_open(txn, store->dbi[lookup_indices[args->idx0]], &cur);
+    mdb_cursor_open(it->txn, store->dbi[lookup_indices[idx0]], &it->cur);
 
-    MDB_val key_v, data_v;
-    key_v.mv_data = args->luks;
-    key_v.mv_size = KLEN;
+    it->key.mv_data = it->luk;
+    it->key.mv_size = KLEN;
 
-    if(args->ct) {
-        if (args->ck != NULL_KEY) {
-            db_rc = mdb_cursor_get(cur, &key_v, &data_v, MDB_GET_MULTIPLE);
-            while (db_rc != MDB_NOTFOUND) {
+    if(ct) {
+        if (it->ck != NULL_KEY) {
+            it->rc = mdb_cursor_get(
+                    it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
+            while (it->rc != MDB_NOTFOUND) {
             }
         } else {
-            db_rc = mdb_cursor_get(cur, &key_v, &data_v, MDB_SET);
-            if (db_rc != MDB_SUCCESS) return rc;
-
-            db_rc = mdb_cursor_count(cur, args->ct);
+            it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
+            if (it->rc == MDB_SUCCESS) mdb_cursor_count(it->cur, ct);
         }
-
-        if (!args->it && *args->ct > 0) rc = LSUP_OK;
     }
 
-    if(args->it) {
-        args->it->ck = args->ck;
-        args->it->cur = cur;
-        memcpy(args->it->key, &key_v, sizeof(MDB_val));
-        memcpy(args->it->data, &data_v, sizeof(MDB_val));
-        args->it->term_order[0] = term_order[0];
-        args->it->term_order[1] = term_order[1];
-        args->it->term_order[2] = term_order[2];
-        args->it->luks[0] = args->luks[0];
-        args->it->i = 0;
-        args->it->iter_op_fn = it_next_1bound;
-
-        args->it->rc = mdb_cursor_get(
-                args->it->cur, args->it->key, args->it->data, MDB_SET);
-        if (args->it->rc == MDB_SUCCESS)
-            args->it->rc = mdb_cursor_get(
-                    args->it->cur, args->it->key, args->it->data,
-                    MDB_GET_MULTIPLE);
-
-        return args->it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
-    }
+    it->i = 0;
+    it->iter_op_fn = it_next_1bound;
 
-    mdb_cursor_close(cur);
-    if (txn != store->txn) mdb_txn_abort(txn);
+    it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
+    if (it->rc == MDB_SUCCESS)
+        it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
 
-    return rc;
+    return it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
 }
 
 
 inline static LSUP_rc
-lookup_2bound(struct MDBStore *store, LookupArgs *args)
+lookup_2bound(
+        struct MDBStore *store, uint8_t idx0, uint8_t idx1,
+        struct MDBIterator *it, size_t *ct)
 {
-    int rc = LSUP_NORESULT;
-
     uint8_t luk1_offset, luk2_offset;
-    const uint8_t *term_order;
     MDB_dbi dbi = 0;
 
     // Establish lookup ordering with some awkward offset math.
     for(int i = 0; i < 3; i++) {
         if (
             (
-                args->idx0 == lookup_ordering_2bound[i][0] &&
-                args->idx1 == lookup_ordering_2bound[i][1]
+                idx0 == lookup_ordering_2bound[i][0] &&
+                idx1 == lookup_ordering_2bound[i][1]
             ) || (
-                args->idx0 == lookup_ordering_2bound[i][1] &&
-                args->idx1 == lookup_ordering_2bound[i][0]
+                idx0 == lookup_ordering_2bound[i][1] &&
+                idx1 == lookup_ordering_2bound[i][0]
             )
         ) {
-            term_order = lookup_ordering_2bound[i];
-            if (term_order[0] == args->idx0) {
+            it->term_order = (const uint8_t*)lookup_ordering_2bound[i];
+            if (it->term_order[0] == idx0) {
                 luk1_offset = 0;
                 luk2_offset = 1;
             } else {
@@ -1125,113 +1073,69 @@ lookup_2bound(struct MDBStore *store, LookupArgs *args)
     if (dbi == 0) {
         TRACE(
                 "Values %d and %d not found in lookup keys.",
-                args->idx0, args->idx1);
+                idx0, idx1);
         return LSUP_VALUE_ERR;
     }
 
     // Compose term keys in lookup key.
     LSUP_DoubleKey luk;
-    luk[luk1_offset] = args->luks[0];
-    luk[luk2_offset] = args->luks[1];
+    luk[luk1_offset] = it->luk[0];
+    luk[luk2_offset] = it->luk[1];
 
-    MDB_txn *txn;
-    if(store->txn) txn = store->txn;
-    else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &txn);
-
-    MDB_cursor *cur;
-    mdb_cursor_open(txn, dbi, &cur);
+    if(store->txn) it->txn = store->txn;
+    else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &it->txn);
 
-    MDB_val key_v, data_v;
-    key_v.mv_data = luk;
-    key_v.mv_size = DBL_KLEN;
+    it->key.mv_data = luk;
+    it->key.mv_size = DBL_KLEN;
 
-    if(args->ct) {
-        mdb_cursor_get(cur, &key_v, &data_v, MDB_SET);
-        mdb_cursor_count(cur, args->ct);
+    mdb_cursor_open(it->txn, dbi, &it->cur);
+    it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
 
-        if (!args->it && *args->ct > 0) rc = LSUP_OK;
-    }
+    if(ct && it->rc == MDB_SUCCESS) mdb_cursor_count(it->cur, ct);
 
-    if(args->it) {
-        args->it->ck = args->ck;
-        args->it->cur = cur;
-        memcpy(args->it->key, &key_v, sizeof(MDB_val));
-        memcpy(args->it->data, &data_v, sizeof(MDB_val));
-        args->it->term_order[0] = term_order[0];
-        args->it->term_order[1] = term_order[1];
-        args->it->term_order[2] = term_order[2];
-        args->it->luks[0] = args->luks[0];
-        args->it->luks[1] = args->luks[1];
-        args->it->i = 0;
-        args->it->iter_op_fn = it_next_2bound;
-
-        args->it->rc = mdb_cursor_get(
-                args->it->cur, args->it->key, args->it->data, MDB_SET);
-        if (args->it->rc == MDB_SUCCESS)
-            args->it->rc = mdb_cursor_get(
-                    args->it->cur, args->it->key, args->it->data,
-                    MDB_GET_MULTIPLE);
-
-        return args->it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
-    }
+    it->i = 0;
+    it->iter_op_fn = it_next_2bound;
 
-    mdb_cursor_close(cur);
-    if (txn != store->txn) mdb_txn_abort(txn);
+    it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_SET);
+    if (it->rc == MDB_SUCCESS)
+        it->rc = mdb_cursor_get(it->cur, &it->key, &it->data, MDB_GET_MULTIPLE);
 
-    return rc;
+    return it->rc == MDB_SUCCESS ? LSUP_OK : LSUP_NORESULT;
 }
 
 
 inline static LSUP_rc
-lookup_3bound(struct MDBStore *store, LookupArgs *args)
+lookup_3bound(struct MDBStore *store, struct MDBIterator *it, size_t *ct)
 {
     TRACE(
             "Looking up 3 bound: {%lx, %lx, %lx}",
-            args->luks[0], args->luks[1], args->luks[2]);
+            it->luk[0], it->luk[1], it->luk[2]);
     LSUP_rc rc = LSUP_NORESULT;
 
-    MDB_txn *txn;
-    if(store->txn) txn = store->txn;
-    else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &txn);
+    if(store->txn) it->txn = store->txn;
+    else mdb_txn_begin(store->env, NULL, MDB_RDONLY, &it->txn);
 
     MDB_cursor *cur;
-    int db_rc = mdb_cursor_open(txn, store->dbi[IDX_S_PO], &cur);
-
-    MDB_val key_v, data_v;
-    key_v.mv_data = args->luks;
-    key_v.mv_size = KLEN;
-    data_v.mv_data = args->luks + 1;
-    data_v.mv_size = DBL_KLEN;
-
-    db_rc = mdb_cursor_get(cur, &key_v, &data_v, MDB_GET_BOTH);
-
-    if(args->ct) {
-        if (db_rc == MDB_SUCCESS) {
-            *args->ct = 1;
-            if (!args->it) rc = LSUP_OK;
-        }
-    }
-
-    if(args->it) {
-        args->it->rc = db_rc;
-        if (args->it->rc == MDB_NOTFOUND) {
-            rc = LSUP_NORESULT;
-        } else {
-            args->it->ck = args->ck;
-            args->it->iter_op_fn = it_next_3bound;
-            *args->it->spok[0] = args->luks[0];
-            *args->it->spok[1] = args->luks[1];
-            *args->it->spok[2] = args->luks[2];
-            args->it->rc = LSUP_OK;
-            rc = LSUP_OK;
-        }
-
-        return rc;
+    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->rc == MDB_NOTFOUND) {
+        rc = LSUP_NORESULT;
+    } else {
+        it->iter_op_fn = it_next_3bound;
+        *it->spok[0] = it->luk[0];
+        *it->spok[1] = it->luk[1];
+        *it->spok[2] = it->luk[2];
+        rc = LSUP_OK;
     }
 
-    mdb_cursor_close(cur);
-    if (txn != store->txn) mdb_txn_abort(txn);
-
     return rc;
 }