|
@@ -1,7 +1,6 @@
|
|
|
#include <ftw.h>
|
|
|
|
|
|
#include "store_mdb.h"
|
|
|
-#include "data/bootstrap.h"
|
|
|
|
|
|
/**
|
|
|
* Number of DBs defined. See MAIN_TABLE and LOOKUP_TABLE defines below.
|
|
@@ -29,6 +28,8 @@
|
|
|
*/
|
|
|
|
|
|
typedef char DbLabel[8];
|
|
|
+typedef struct mdbstore_t MDBStore;
|
|
|
+typedef struct mdbstore_iter_t MDBIterator;
|
|
|
|
|
|
typedef enum {
|
|
|
LSSTORE_INIT = 1, // Is the store environment set up on disk?
|
|
@@ -41,14 +42,14 @@ typedef enum {
|
|
|
OP_REMOVE,
|
|
|
} StoreOp;
|
|
|
|
|
|
-typedef struct mdbstore_t {
|
|
|
+struct mdbstore_t {
|
|
|
MDB_env * env; // Environment handle.
|
|
|
MDB_txn * txn; // Current transaction.
|
|
|
MDB_dbi dbi[N_DB]; // DB handles. Refer to DbIdx enum.
|
|
|
LSUP_Buffer * default_ctx; // Default ctx as a serialized URI.
|
|
|
StoreState state; // Store state.
|
|
|
int features; // Store feature flags.
|
|
|
-} MDBStore;
|
|
|
+};
|
|
|
|
|
|
/** @brief Iterator operation.
|
|
|
*
|
|
@@ -60,11 +61,11 @@ typedef struct mdbstore_t {
|
|
|
* value for the next result. It is up to the caller to evaluate this value
|
|
|
* and decide whether to call the function again.
|
|
|
*/
|
|
|
-typedef void (*iter_op_fn_t)(LSUP_MDBIterator *it);
|
|
|
+typedef void (*iter_op_fn_t)(MDBIterator *it);
|
|
|
|
|
|
|
|
|
/// Triple iterator.
|
|
|
-typedef struct mdbstore_iter_t {
|
|
|
+struct mdbstore_iter_t {
|
|
|
MDBStore * store; ///< MDB store handle.
|
|
|
MDB_txn * txn; ///< MDB transaction.
|
|
|
MDB_cursor * cur; ///< MDB cursor.
|
|
@@ -81,7 +82,7 @@ typedef struct mdbstore_iter_t {
|
|
|
size_t ct; ///< Current count of records inserted or
|
|
|
///< results found.
|
|
|
int rc; ///< MDB_* return code for the next result.
|
|
|
-} MDBIterator;
|
|
|
+};
|
|
|
|
|
|
|
|
|
/*
|
|
@@ -94,29 +95,29 @@ typedef struct mdbstore_iter_t {
|
|
|
/**
|
|
|
* Main DBs. These are the master information containers.
|
|
|
*
|
|
|
- * Data columns are: identifier prefix, DB label, flags.
|
|
|
- *
|
|
|
* The number of entries must match the N_DB constant defined above.
|
|
|
*/
|
|
|
#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 ctx */ \
|
|
|
- ENTRY( PFX_NS, "pfx:ns", 0 ) /* Prefix to NS */ \
|
|
|
- ENTRY( IDK_ID, "idk:id", 0 ) /* ID key to ID */ \
|
|
|
+/* #ID pfx #DB label #Flags */ \
|
|
|
+ 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 ctx */ \
|
|
|
+ ENTRY( PFX_NS, "pfx:ns", 0 ) /* Prefix to NS */ \
|
|
|
+ ENTRY( IDK_ID, "idk:id", 0 ) /* ID key to ID */ \
|
|
|
|
|
|
/**
|
|
|
* Lookup DBs. These are indices and may be destroyed and rebuilt.
|
|
|
*/
|
|
|
#define LOOKUP_TABLE \
|
|
|
- ENTRY( S_PO, "s:po", DUPFIXED_MASK ) /* 1-bound lookup */ \
|
|
|
- ENTRY( P_SO, "p:so", DUPFIXED_MASK ) /* 1-bound lookup */ \
|
|
|
- ENTRY( O_SP, "o:sp", DUPFIXED_MASK ) /* 1-bound lookup */ \
|
|
|
- ENTRY( PO_S, "po:s", DUPFIXED_MASK ) /* 2-bound lookup */ \
|
|
|
- ENTRY( SO_P, "so:p", DUPFIXED_MASK ) /* 2-bound lookup */ \
|
|
|
- ENTRY( SP_O, "sp:o", DUPFIXED_MASK ) /* 2-bound lookup */ \
|
|
|
- ENTRY( C_SPO, "c:spo", DUPFIXED_MASK ) /* Context lookup */ \
|
|
|
- ENTRY( NS_PFX, "ns:pfx", DUPSORT_MASK ) /* NS to prefix */ \
|
|
|
+/* #ID pfx #DB label #Flags */ \
|
|
|
+ ENTRY( S_PO, "s:po", DUPFIXED_MASK ) /* 1-bound lookup */ \
|
|
|
+ ENTRY( P_SO, "p:so", DUPFIXED_MASK ) /* 1-bound lookup */ \
|
|
|
+ ENTRY( O_SP, "o:sp", DUPFIXED_MASK ) /* 1-bound lookup */ \
|
|
|
+ ENTRY( PO_S, "po:s", DUPFIXED_MASK ) /* 2-bound lookup */ \
|
|
|
+ ENTRY( SO_P, "so:p", DUPFIXED_MASK ) /* 2-bound lookup */ \
|
|
|
+ ENTRY( SP_O, "sp:o", DUPFIXED_MASK ) /* 2-bound lookup */ \
|
|
|
+ ENTRY( C_SPO, "c:spo", DUPFIXED_MASK ) /* Context lookup */ \
|
|
|
+ ENTRY( NS_PFX, "ns:pfx", DUPSORT_MASK ) /* NS to prefix */ \
|
|
|
|
|
|
/**
|
|
|
* DB labels. They are prefixed with DB_
|
|
@@ -188,7 +189,7 @@ static const uint8_t lookup_ordering_2bound[3][3] = {
|
|
|
* Static prototypes.
|
|
|
*/
|
|
|
static int index_triple(
|
|
|
- LSUP_MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck);
|
|
|
+ MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck);
|
|
|
|
|
|
inline static LSUP_rc lookup_0bound (MDBIterator *it, size_t *ct);
|
|
|
inline static LSUP_rc lookup_1bound (
|
|
@@ -202,8 +203,119 @@ inline static LSUP_rc lookup_3bound(MDBIterator *it, size_t *ct);
|
|
|
* API.
|
|
|
*/
|
|
|
|
|
|
+LSUP_NSMap *
|
|
|
+mdbstore_nsm_get (void *h)
|
|
|
+{
|
|
|
+ MDBStore *store = h;
|
|
|
+ LSUP_NSMap *nsm = LSUP_nsmap_new();
|
|
|
+ if (UNLIKELY (!nsm)) return NULL;
|
|
|
+
|
|
|
+ MDB_txn *txn;
|
|
|
+ mdb_txn_begin (store->env, NULL, MDB_RDONLY, &txn);
|
|
|
+
|
|
|
+ MDB_cursor *cur;
|
|
|
+ if (mdb_cursor_open (txn, store->dbi[IDX_PFX_NS], &cur) != MDB_SUCCESS) {
|
|
|
+ mdb_txn_abort (txn);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ MDB_val ns_v, pfx_v;
|
|
|
+ if (mdb_cursor_get (cur, &pfx_v, &ns_v, MDB_FIRST) != MDB_SUCCESS)
|
|
|
+ goto finally;
|
|
|
+
|
|
|
+ do {
|
|
|
+ ns_pfx pfx;
|
|
|
+ char *ns = malloc (ns_v.mv_size);
|
|
|
+
|
|
|
+ strncpy (pfx, pfx_v.mv_data, pfx_v.mv_size);
|
|
|
+ strncpy (ns, ns_v.mv_data, ns_v.mv_size);
|
|
|
+ LSUP_nsmap_add (nsm, pfx, ns);
|
|
|
+
|
|
|
+ free (ns);
|
|
|
+ } while (mdb_cursor_get (
|
|
|
+ cur, &pfx_v, &ns_v, MDB_NEXT_NODUP) == MDB_SUCCESS);
|
|
|
+
|
|
|
+finally:
|
|
|
+ mdb_cursor_close (cur);
|
|
|
+ mdb_txn_abort (txn);
|
|
|
+
|
|
|
+ return nsm;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_setup (const char *path, bool clear)
|
|
|
+mdbstore_nsm_put (void *h, const LSUP_NSMap *nsm)
|
|
|
+{
|
|
|
+ MDBStore *store = h;
|
|
|
+ MDB_txn *txn;
|
|
|
+ RCCK (mdb_txn_begin (store->env, store->txn, 0, &txn));
|
|
|
+
|
|
|
+ LSUP_rc rc = LSUP_NOACTION;
|
|
|
+ int db_rc;
|
|
|
+
|
|
|
+ MDB_cursor *dcur = NULL, *icur = NULL;
|
|
|
+ if (
|
|
|
+ mdb_cursor_open (txn, store->dbi[IDX_PFX_NS], &dcur) != MDB_SUCCESS
|
|
|
+ ||
|
|
|
+ mdb_cursor_open (txn, store->dbi[IDX_NS_PFX], &icur) != MDB_SUCCESS
|
|
|
+ ) {
|
|
|
+ mdb_txn_abort (txn);
|
|
|
+ return LSUP_DB_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ MDB_val pfx_v, ns_v;
|
|
|
+ const char ***nsm_data = LSUP_nsmap_dump (nsm);
|
|
|
+
|
|
|
+ for (size_t i = 0; nsm_data[i] != NULL; i++) {
|
|
|
+ // At least 1 action. If not OK, it will change during the iteration.
|
|
|
+ if (i == 0) rc = LSUP_OK;
|
|
|
+ // On previous error, just clean up the NSM data array.
|
|
|
+ if (rc < 0) goto loop_end;
|
|
|
+
|
|
|
+ pfx_v.mv_data = (void *) nsm_data[i][0];
|
|
|
+ pfx_v.mv_size = strlen (nsm_data[i][0]) + 1;
|
|
|
+ ns_v.mv_data = (void *) nsm_data[i][1];
|
|
|
+ ns_v.mv_size = strlen (nsm_data[i][1]) + 1;
|
|
|
+
|
|
|
+ // If either ns or pfx exist, skip.
|
|
|
+ if (
|
|
|
+ mdb_cursor_get (dcur, &pfx_v, &ns_v, MDB_SET) != MDB_NOTFOUND
|
|
|
+ ||
|
|
|
+ mdb_cursor_get (icur, &ns_v, &pfx_v, MDB_SET) != MDB_NOTFOUND
|
|
|
+ ) {
|
|
|
+ rc = LSUP_CONFLICT;
|
|
|
+ goto loop_end;
|
|
|
+ }
|
|
|
+
|
|
|
+ db_rc = mdb_cursor_put (dcur, &pfx_v, &ns_v, 0);
|
|
|
+ db_rc |= mdb_cursor_put (icur, &ns_v, &pfx_v, 0);
|
|
|
+ if (db_rc != MDB_SUCCESS) {
|
|
|
+ log_error ("DB error: %s", LSUP_strerror (db_rc));
|
|
|
+ rc = LSUP_DB_ERR;
|
|
|
+ }
|
|
|
+loop_end:
|
|
|
+ free (nsm_data[i]);
|
|
|
+ }
|
|
|
+ free (nsm_data);
|
|
|
+
|
|
|
+ if (UNLIKELY (rc != LSUP_OK)) mdb_txn_abort (txn);
|
|
|
+ else if (UNLIKELY (mdb_txn_commit (txn) != MDB_SUCCESS)) {
|
|
|
+ mdb_txn_abort (txn);
|
|
|
+ rc = LSUP_TXN_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/** @brief Create the MDB environment and databases on disk.
|
|
|
+ *
|
|
|
+ * This function takes care of creaating the environment path if not existing,
|
|
|
+ * and checking that it's a writable directory. If the path is not specified
|
|
|
+ * in the LSUP_STORE_PATH environment variable, a default directory is used.
|
|
|
+ */
|
|
|
+LSUP_rc
|
|
|
+mdbstore_setup (const char *path, bool clear)
|
|
|
{
|
|
|
int rc;
|
|
|
|
|
@@ -243,15 +355,22 @@ LSUP_mdbstore_setup (const char *path, bool clear)
|
|
|
}
|
|
|
|
|
|
|
|
|
-MDBStore *
|
|
|
-LSUP_mdbstore_new (const char *path, const LSUP_Buffer *default_ctx)
|
|
|
+/** @brief Open an MDB store.
|
|
|
+ *
|
|
|
+ * The store must have been set up with #mdbstore_setup.
|
|
|
+ *
|
|
|
+ * Some environment variables affect various store parameters:
|
|
|
+ *
|
|
|
+ * - LSUP_MDB_MAPSIZE Long int specifying the size of the memory map. Usually
|
|
|
+ * it is not necessary to modify this, unless one is operating under memory
|
|
|
+ * and disk constraints. The default map size is 1Tb.
|
|
|
+ */
|
|
|
+void *
|
|
|
+mdbstore_new (const char *path, const LSUP_Buffer *default_ctx)
|
|
|
{
|
|
|
int db_rc;
|
|
|
- LSUP_MDBStore *store;
|
|
|
+ MDBStore *store;
|
|
|
MALLOC_GUARD (store, NULL);
|
|
|
- store->features = LSUP_STORE_CTX | LSUP_STORE_IDX;
|
|
|
- if (strcmp (path, LSUP_MDB_RAMDISK_PATH) != 0)
|
|
|
- store->features |= LSUP_STORE_PERM;
|
|
|
|
|
|
db_rc = mdb_env_create (&store->env);
|
|
|
log_trace ("create rc: %d", db_rc);
|
|
@@ -298,7 +417,7 @@ LSUP_mdbstore_new (const char *path, const LSUP_Buffer *default_ctx)
|
|
|
for (int i = 0; init_nsmap[i][0] != NULL; i++)
|
|
|
LSUP_nsmap_add (nsm, init_nsmap[i][0], init_nsmap[i][1]);
|
|
|
|
|
|
- LSUP_mdbstore_nsm_store (store, nsm);
|
|
|
+ mdbstore_nsm_put (store, nsm);
|
|
|
|
|
|
LSUP_nsmap_free (nsm);
|
|
|
}
|
|
@@ -318,8 +437,9 @@ fail:
|
|
|
|
|
|
|
|
|
void
|
|
|
-LSUP_mdbstore_free (LSUP_MDBStore *store)
|
|
|
+mdbstore_free (void *h)
|
|
|
{
|
|
|
+ MDBStore *store = h;
|
|
|
if (store->state & LSSTORE_OPEN) {
|
|
|
const char *path;
|
|
|
mdb_env_get_path (store->env, &path);
|
|
@@ -336,12 +456,12 @@ LSUP_mdbstore_free (LSUP_MDBStore *store)
|
|
|
}
|
|
|
|
|
|
|
|
|
-int LSUP_mdbstore_features (LSUP_MDBStore *store)
|
|
|
+int mdbstore_features (MDBStore *store)
|
|
|
{ return store->features; }
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_stat (LSUP_MDBStore *store, MDB_stat *stat)
|
|
|
+mdbstore_stat (MDBStore *store, MDB_stat *stat)
|
|
|
{
|
|
|
if (!(store->state & LSSTORE_INIT)) return 0;
|
|
|
|
|
@@ -357,20 +477,22 @@ LSUP_mdbstore_stat (LSUP_MDBStore *store, MDB_stat *stat)
|
|
|
|
|
|
|
|
|
size_t
|
|
|
-LSUP_mdbstore_size (LSUP_MDBStore *store)
|
|
|
+mdbstore_size (void *h)
|
|
|
{
|
|
|
+ MDBStore *store = h;
|
|
|
// Size is calculated outside of any pending write txn.
|
|
|
|
|
|
MDB_stat stat;
|
|
|
- if (LSUP_mdbstore_stat (store, &stat) != LSUP_OK) return 0;
|
|
|
+ if (mdbstore_stat (store, &stat) != LSUP_OK) return 0;
|
|
|
|
|
|
return stat.ms_entries;
|
|
|
}
|
|
|
|
|
|
|
|
|
-MDBIterator *
|
|
|
-LSUP_mdbstore_add_init (LSUP_MDBStore *store, const LSUP_Buffer *sc)
|
|
|
+void *
|
|
|
+mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
|
{
|
|
|
+ MDBStore *store = h;
|
|
|
/* An iterator is used here. Some members are a bit misused but it does
|
|
|
* its job without having to define a very similar struct.
|
|
|
*/
|
|
@@ -413,9 +535,16 @@ LSUP_mdbstore_add_init (LSUP_MDBStore *store, const LSUP_Buffer *sc)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/*
|
|
|
+ * NOTE: at the moment #mdbstore_remove() or another
|
|
|
+ * #mdbstore_init() cannot be called between #mdbstore_add_init and
|
|
|
+ * #mdbstore_add_abort or #mdbstore_add_done. FIXME
|
|
|
+ *
|
|
|
+ */
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_add_iter (MDBIterator *it, const LSUP_BufferTriple *sspo)
|
|
|
+mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
|
{
|
|
|
+ MDBIterator *it = h;
|
|
|
int db_rc;
|
|
|
LSUP_TripleKey spok = NULL_TRP;
|
|
|
|
|
@@ -472,8 +601,9 @@ LSUP_mdbstore_add_iter (MDBIterator *it, const LSUP_BufferTriple *sspo)
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_add_done (MDBIterator *it)
|
|
|
+mdbstore_add_done (void *h)
|
|
|
{
|
|
|
+ MDBIterator *it = h;
|
|
|
LSUP_rc rc = LSUP_OK;
|
|
|
|
|
|
if (mdb_txn_commit (it->store->txn) != MDB_SUCCESS) {
|
|
@@ -490,8 +620,9 @@ LSUP_mdbstore_add_done (MDBIterator *it)
|
|
|
|
|
|
|
|
|
void
|
|
|
-LSUP_mdbstore_add_abort (MDBIterator *it)
|
|
|
+mdbstore_add_abort (void *h)
|
|
|
{
|
|
|
+ MDBIterator *it = h;
|
|
|
mdb_txn_abort (it->store->txn);
|
|
|
|
|
|
it->store->txn = NULL;
|
|
@@ -500,29 +631,31 @@ LSUP_mdbstore_add_abort (MDBIterator *it)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/* TODO deprecate. Use low-level instead and abstract at graph level. */
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_add (
|
|
|
- LSUP_MDBStore *store, const LSUP_Buffer *sc,
|
|
|
+mdbstore_add (
|
|
|
+ void *h, const LSUP_Buffer *sc,
|
|
|
const LSUP_BufferTriple strp[], const size_t ct, size_t *inserted)
|
|
|
{
|
|
|
- MDBIterator *it = LSUP_mdbstore_add_init (store, sc);
|
|
|
+ MDBStore *store = h;
|
|
|
+ MDBIterator *it = mdbstore_add_init (store, sc);
|
|
|
if (UNLIKELY (!it)) return LSUP_DB_ERR;
|
|
|
|
|
|
for (size_t i = 0; i < ct; i++) {
|
|
|
- LSUP_rc rc = LSUP_mdbstore_add_iter (it, strp + i);
|
|
|
+ LSUP_rc rc = mdbstore_add_iter (it, strp + i);
|
|
|
if (UNLIKELY (rc < 0)) {
|
|
|
- LSUP_mdbstore_add_abort (it);
|
|
|
+ mdbstore_add_abort (it);
|
|
|
return rc;
|
|
|
}
|
|
|
}
|
|
|
*inserted = it->i;
|
|
|
|
|
|
- return LSUP_mdbstore_add_done (it);
|
|
|
+ return mdbstore_add_done (it);
|
|
|
}
|
|
|
|
|
|
|
|
|
static LSUP_rc
|
|
|
-key_to_sterm (LSUP_MDBIterator *it, const LSUP_Key key, LSUP_Buffer *sterm)
|
|
|
+key_to_sterm (MDBIterator *it, const LSUP_Key key, LSUP_Buffer *sterm)
|
|
|
{
|
|
|
LSUP_rc rc = LSUP_NORESULT;
|
|
|
int db_rc;
|
|
@@ -546,18 +679,19 @@ key_to_sterm (LSUP_MDBIterator *it, const LSUP_Key key, LSUP_Buffer *sterm)
|
|
|
}
|
|
|
|
|
|
|
|
|
-MDBIterator *
|
|
|
-LSUP_mdbstore_lookup(
|
|
|
- LSUP_MDBStore *store, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
|
+void *
|
|
|
+mdbstore_lookup(
|
|
|
+ void *h, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
|
const LSUP_Buffer *so, const LSUP_Buffer *sc, size_t *ct)
|
|
|
{
|
|
|
+ MDBStore *store = h;
|
|
|
LSUP_TripleKey spok = {
|
|
|
LSUP_buffer_hash (ss),
|
|
|
LSUP_buffer_hash (sp),
|
|
|
LSUP_buffer_hash (so),
|
|
|
};
|
|
|
|
|
|
- LSUP_MDBIterator *it;
|
|
|
+ MDBIterator *it;
|
|
|
CALLOC_GUARD (it, NULL);
|
|
|
|
|
|
it->store = store;
|
|
@@ -644,7 +778,7 @@ LSUP_mdbstore_lookup(
|
|
|
* in, if not NULL.
|
|
|
*/
|
|
|
inline static LSUP_rc
|
|
|
-mdbiter_next_key (LSUP_MDBIterator *it)
|
|
|
+mdbiter_next_key (MDBIterator *it)
|
|
|
{
|
|
|
if (UNLIKELY (!it)) return LSUP_VALUE_ERR;
|
|
|
|
|
@@ -736,9 +870,10 @@ mdbiter_next_key (LSUP_MDBIterator *it)
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbiter_next (
|
|
|
- LSUP_MDBIterator *it, LSUP_BufferTriple *sspo, LSUP_Buffer **ctx_p)
|
|
|
+mdbiter_next (
|
|
|
+ void *h, LSUP_BufferTriple *sspo, LSUP_Buffer **ctx_p)
|
|
|
{
|
|
|
+ MDBIterator *it = h;
|
|
|
LSUP_rc rc = mdbiter_next_key (it);
|
|
|
|
|
|
if (rc == LSUP_OK) {
|
|
@@ -774,8 +909,9 @@ LSUP_mdbiter_next (
|
|
|
|
|
|
|
|
|
void
|
|
|
-LSUP_mdbiter_free (MDBIterator *it)
|
|
|
+mdbiter_free (void *h)
|
|
|
{
|
|
|
+ MDBIterator *it = h;
|
|
|
if (!it) return;
|
|
|
|
|
|
if (it->cur) mdb_cursor_close (it->cur);
|
|
@@ -788,10 +924,11 @@ LSUP_mdbiter_free (MDBIterator *it)
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_remove(
|
|
|
- LSUP_MDBStore *store, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
|
+mdbstore_remove(
|
|
|
+ void *h, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
|
const LSUP_Buffer *so, const LSUP_Buffer *sc, size_t *ct)
|
|
|
{
|
|
|
+ MDBStore *store = h;
|
|
|
LSUP_rc rc = LSUP_NOACTION, db_rc;
|
|
|
|
|
|
LSUP_Key ck = NULL_KEY;
|
|
@@ -815,7 +952,7 @@ LSUP_mdbstore_remove(
|
|
|
ck_v.mv_size = KLEN;
|
|
|
ck_v.mv_data = &ck;
|
|
|
|
|
|
- LSUP_MDBIterator *it = LSUP_mdbstore_lookup (store, ss, sp, so, sc, ct);
|
|
|
+ MDBIterator *it = mdbstore_lookup (store, ss, sp, so, sc, ct);
|
|
|
if (UNLIKELY (!it)) return LSUP_DB_ERR;
|
|
|
if (ct) log_debug ("Found %lu triples to remove.", *ct);
|
|
|
|
|
@@ -858,7 +995,7 @@ LSUP_mdbstore_remove(
|
|
|
rc = index_triple (store, OP_REMOVE, it->spok, ck);
|
|
|
}
|
|
|
|
|
|
- LSUP_mdbiter_free (it);
|
|
|
+ mdbiter_free (it);
|
|
|
|
|
|
if (UNLIKELY (mdb_txn_commit (store->txn) != MDB_SUCCESS)) {
|
|
|
rc = LSUP_TXN_ERR;
|
|
@@ -878,114 +1015,8 @@ fail:
|
|
|
}
|
|
|
|
|
|
|
|
|
-LSUP_rc
|
|
|
-LSUP_mdbstore_nsm_get (LSUP_MDBStore *store, LSUP_NSMap **nsm_p)
|
|
|
-{
|
|
|
- LSUP_rc rc = LSUP_NORESULT;
|
|
|
- LSUP_NSMap *nsm = LSUP_nsmap_new();
|
|
|
- if (UNLIKELY (!nsm)) return LSUP_MEM_ERR;
|
|
|
-
|
|
|
- *nsm_p = nsm;
|
|
|
-
|
|
|
- MDB_txn *txn;
|
|
|
- mdb_txn_begin (store->env, NULL, MDB_RDONLY, &txn);
|
|
|
-
|
|
|
- MDB_cursor *cur;
|
|
|
- if (mdb_cursor_open (txn, store->dbi[IDX_PFX_NS], &cur) != MDB_SUCCESS) {
|
|
|
- mdb_txn_abort (txn);
|
|
|
- return LSUP_DB_ERR;
|
|
|
- }
|
|
|
-
|
|
|
- MDB_val ns_v, pfx_v;
|
|
|
- if (mdb_cursor_get (cur, &pfx_v, &ns_v, MDB_FIRST) != MDB_SUCCESS)
|
|
|
- goto finally;
|
|
|
-
|
|
|
- do {
|
|
|
- ns_pfx pfx;
|
|
|
- char *ns = malloc (ns_v.mv_size);
|
|
|
-
|
|
|
- strncpy (pfx, pfx_v.mv_data, pfx_v.mv_size);
|
|
|
- strncpy (ns, ns_v.mv_data, ns_v.mv_size);
|
|
|
- LSUP_nsmap_add (nsm, pfx, ns);
|
|
|
-
|
|
|
- free (ns);
|
|
|
- } while (mdb_cursor_get (
|
|
|
- cur, &pfx_v, &ns_v, MDB_NEXT_NODUP) == MDB_SUCCESS);
|
|
|
-
|
|
|
-finally:
|
|
|
- mdb_cursor_close (cur);
|
|
|
- mdb_txn_abort (txn);
|
|
|
-
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-LSUP_rc
|
|
|
-LSUP_mdbstore_nsm_store (LSUP_MDBStore *store, const LSUP_NSMap *nsm)
|
|
|
-{
|
|
|
- MDB_txn *txn;
|
|
|
- RCCK (mdb_txn_begin (store->env, store->txn, 0, &txn));
|
|
|
-
|
|
|
- LSUP_rc rc = LSUP_NOACTION;
|
|
|
- int db_rc;
|
|
|
-
|
|
|
- MDB_cursor *dcur = NULL, *icur = NULL;
|
|
|
- if (
|
|
|
- mdb_cursor_open (txn, store->dbi[IDX_PFX_NS], &dcur) != MDB_SUCCESS
|
|
|
- ||
|
|
|
- mdb_cursor_open (txn, store->dbi[IDX_NS_PFX], &icur) != MDB_SUCCESS
|
|
|
- ) {
|
|
|
- mdb_txn_abort (txn);
|
|
|
- return LSUP_DB_ERR;
|
|
|
- }
|
|
|
-
|
|
|
- MDB_val pfx_v, ns_v;
|
|
|
- const char ***nsm_data = LSUP_nsmap_dump (nsm);
|
|
|
-
|
|
|
- for (size_t i = 0; nsm_data[i] != NULL; i++) {
|
|
|
- // At least 1 action. If not OK, it will change during the iteration.
|
|
|
- if (i == 0) rc = LSUP_OK;
|
|
|
- // On previous error, just clean up the NSM data array.
|
|
|
- if (rc < 0) goto loop_end;
|
|
|
-
|
|
|
- pfx_v.mv_data = (void *) nsm_data[i][0];
|
|
|
- pfx_v.mv_size = strlen (nsm_data[i][0]) + 1;
|
|
|
- ns_v.mv_data = (void *) nsm_data[i][1];
|
|
|
- ns_v.mv_size = strlen (nsm_data[i][1]) + 1;
|
|
|
-
|
|
|
- // If either ns or pfx exist, skip.
|
|
|
- if (
|
|
|
- mdb_cursor_get (dcur, &pfx_v, &ns_v, MDB_SET) != MDB_NOTFOUND
|
|
|
- ||
|
|
|
- mdb_cursor_get (icur, &ns_v, &pfx_v, MDB_SET) != MDB_NOTFOUND
|
|
|
- ) {
|
|
|
- rc = LSUP_CONFLICT;
|
|
|
- goto loop_end;
|
|
|
- }
|
|
|
-
|
|
|
- db_rc = mdb_cursor_put (dcur, &pfx_v, &ns_v, 0);
|
|
|
- db_rc |= mdb_cursor_put (icur, &ns_v, &pfx_v, 0);
|
|
|
- if (db_rc != MDB_SUCCESS) {
|
|
|
- log_error ("DB error: %s", LSUP_strerror (db_rc));
|
|
|
- rc = LSUP_DB_ERR;
|
|
|
- }
|
|
|
-loop_end:
|
|
|
- free (nsm_data[i]);
|
|
|
- }
|
|
|
- free (nsm_data);
|
|
|
-
|
|
|
- if (UNLIKELY (rc != LSUP_OK)) mdb_txn_abort (txn);
|
|
|
- else if (UNLIKELY (mdb_txn_commit (txn) != MDB_SUCCESS)) {
|
|
|
- mdb_txn_abort (txn);
|
|
|
- rc = LSUP_TXN_ERR;
|
|
|
- }
|
|
|
-
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
int
|
|
|
-LSUP_mdbstore_tkey_exists (LSUP_MDBStore *store, LSUP_Key tkey)
|
|
|
+mdbstore_tkey_exists (MDBStore *store, LSUP_Key tkey)
|
|
|
{
|
|
|
int db_rc, rc;
|
|
|
MDB_val key, data;
|
|
@@ -1015,8 +1046,9 @@ LSUP_mdbstore_tkey_exists (LSUP_MDBStore *store, LSUP_Key tkey)
|
|
|
|
|
|
|
|
|
LSUP_rc
|
|
|
-LSUP_mdbstore_add_term (LSUP_MDBStore *store, const LSUP_Buffer *sterm)
|
|
|
+mdbstore_add_term (void *h, const LSUP_Buffer *sterm)
|
|
|
{
|
|
|
+ MDBStore *store = h;
|
|
|
int db_rc;
|
|
|
MDB_val key, data;
|
|
|
|
|
@@ -1053,8 +1085,39 @@ fail:
|
|
|
}
|
|
|
|
|
|
|
|
|
-/* * * Static functions. * * */
|
|
|
+const LSUP_StoreInt mdbstore_int = {
|
|
|
+ .name = "MDB Store",
|
|
|
+ .features = LSUP_STORE_PERM | LSUP_STORE_CTX | LSUP_STORE_IDX
|
|
|
+ | LSUP_STORE_TXN,
|
|
|
+
|
|
|
+ .setup_fn = mdbstore_setup,
|
|
|
+ .new_fn = mdbstore_new,
|
|
|
+ .free_fn = mdbstore_free,
|
|
|
+
|
|
|
+ .size_fn = mdbstore_size,
|
|
|
+
|
|
|
+ .add_init_fn = mdbstore_add_init,
|
|
|
+ .add_iter_fn = mdbstore_add_iter,
|
|
|
+ .add_abort_fn = mdbstore_add_abort,
|
|
|
+ .add_done_fn = mdbstore_add_done,
|
|
|
+ .add_term_fn = mdbstore_add_term,
|
|
|
+
|
|
|
+ .lookup_fn = mdbstore_lookup,
|
|
|
|
|
|
+ .remove_fn = mdbstore_remove,
|
|
|
+
|
|
|
+ .nsm_put_fn = mdbstore_nsm_put,
|
|
|
+ .nsm_get_fn = mdbstore_nsm_get,
|
|
|
+};
|
|
|
+
|
|
|
+const LSUP_StoreIteratorInt mdbiter_int = {
|
|
|
+ .name = "MDB Iterator",
|
|
|
+ .iter_fn = mdbiter_next,
|
|
|
+ .free_fn = mdbiter_free,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/* * * Static functions. * * */
|
|
|
|
|
|
/** @brief Index an added or removed triple.
|
|
|
*
|
|
@@ -1064,8 +1127,7 @@ fail:
|
|
|
* @param ck[in] Context to index, may be NULL.
|
|
|
*/
|
|
|
static LSUP_rc
|
|
|
-index_triple(
|
|
|
- LSUP_MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
+index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
{
|
|
|
int db_rc;
|
|
|
LSUP_rc rc = LSUP_NOACTION;
|