|
@@ -1,5 +1,3 @@
|
|
|
-#include <ftw.h>
|
|
|
-
|
|
|
#include "store_mdb.h"
|
|
|
|
|
|
/**
|
|
@@ -11,12 +9,12 @@
|
|
|
* Memory map size.
|
|
|
*/
|
|
|
#if (defined DEBUG || defined TESTING)
|
|
|
- #define DEFAULT_MAPSIZE 1<<24 // 16Mb (limit for Valgrind)
|
|
|
+#define DEFAULT_MAPSIZE 1<<24 // 16Mb (limit for Valgrind)
|
|
|
#elif !(defined __LP64__ || defined __LLP64__) || \
|
|
|
defined _WIN32 && !defined _WIN64
|
|
|
- #define DEFAULT_MAPSIZE 1<<31 // 2Gb (limit for 32-bit systems)
|
|
|
+#define DEFAULT_MAPSIZE 1<<31 // 2Gb (limit for 32-bit systems)
|
|
|
#else
|
|
|
- #define DEFAULT_MAPSIZE 1UL<<40 // 1Tb
|
|
|
+#define DEFAULT_MAPSIZE 1UL<<40 // 1Tb
|
|
|
#endif
|
|
|
|
|
|
#define ENV_DIR_MODE 0750
|
|
@@ -30,10 +28,24 @@
|
|
|
typedef char DbLabel[8];
|
|
|
typedef struct mdbstore_iter_t MDBIterator;
|
|
|
|
|
|
+/// Store state flags.
|
|
|
typedef enum {
|
|
|
LSSTORE_OPEN = 1<<0, ///< Env is open.
|
|
|
- LSSTORE_DIRTY_TXN = LSSTORE_OPEN + (1<<1), ///< Main txn is open.
|
|
|
-} StoreState;
|
|
|
+} StoreFlags;
|
|
|
+
|
|
|
+/// Iterator state flags.
|
|
|
+typedef enum {
|
|
|
+ ITER_OPEN_TXN = 1<<0, /**< A transaction is open.
|
|
|
+ *
|
|
|
+ * The iterator has begun a new
|
|
|
+ * transaction on initialization
|
|
|
+ * which needs to be closed. If
|
|
|
+ * false, the iterator is using an
|
|
|
+ * existing transaction which will
|
|
|
+ * not be closed with
|
|
|
+ * #mdbiter_free().
|
|
|
+ */
|
|
|
+} IterFlags;
|
|
|
|
|
|
typedef enum {
|
|
|
OP_ADD,
|
|
@@ -42,10 +54,8 @@ typedef enum {
|
|
|
|
|
|
typedef struct mdbstore_t {
|
|
|
MDB_env * env; ///< Environment handle.
|
|
|
- MDB_txn * txn; ///< Current transaction.
|
|
|
MDB_dbi dbi[N_DB]; ///< DB handles. Refer to DbIdx enum.
|
|
|
- StoreState state; ///< Store state.
|
|
|
- int features; ///< Store feature flags.
|
|
|
+ StoreFlags flags; ///< Store state flags.
|
|
|
} MDBStore;
|
|
|
|
|
|
/** @brief Iterator operation.
|
|
@@ -64,13 +74,17 @@ typedef void (*iter_op_fn_t)(MDBIterator *it);
|
|
|
/// Triple iterator.
|
|
|
typedef struct mdbstore_iter_t {
|
|
|
MDBStore * store; ///< MDB store handle.
|
|
|
+ IterFlags flags; ///< Iterator flags.
|
|
|
MDB_txn * txn; ///< MDB transaction.
|
|
|
MDB_cursor * cur; ///< MDB cursor.
|
|
|
MDB_cursor * ctx_cur; ///< MDB c:spo index cursor.
|
|
|
- MDB_val key, data; ///< Internal data handlers.
|
|
|
+ MDB_val key; ///< Internal data handler.
|
|
|
+ MDB_val data; ///< Internal data handler.
|
|
|
LSUP_TripleKey spok; ///< Triple to be populated with match.
|
|
|
- LSUP_Key * ck; ///< Context array to be populated for each
|
|
|
- ///< matching triple if requested.
|
|
|
+ LSUP_Key * ck; /**< Context array.
|
|
|
+ *
|
|
|
+ * This shall be populated for each
|
|
|
+ * matching triple if requested. */
|
|
|
iter_op_fn_t iter_op_fn; ///< Function used to look up next match.
|
|
|
const uint8_t * term_order; ///< Term order used in 1-2bound look-ups.
|
|
|
LSUP_Key luk[3]; ///< 0÷3 lookup keys.
|
|
@@ -186,8 +200,9 @@ static const uint8_t lookup_ordering_2bound[3][3] = {
|
|
|
* Static prototypes.
|
|
|
*/
|
|
|
static int index_triple(
|
|
|
- MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck);
|
|
|
-static LSUP_rc mdbstore_add_term (void *h, const LSUP_Buffer *sterm);
|
|
|
+ MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck,
|
|
|
+ MDB_txn *txn);
|
|
|
+static LSUP_rc mdbstore_add_term (void *h, const LSUP_Buffer *sterm, void *th);
|
|
|
|
|
|
inline static LSUP_rc lookup_0bound (MDBIterator *it, size_t *ct);
|
|
|
inline static LSUP_rc lookup_1bound (
|
|
@@ -201,7 +216,7 @@ inline static LSUP_rc lookup_3bound(MDBIterator *it, size_t *ct);
|
|
|
* Store interface.
|
|
|
*/
|
|
|
|
|
|
-LSUP_NSMap *
|
|
|
+static LSUP_NSMap *
|
|
|
mdbstore_nsm_get (void *h)
|
|
|
{
|
|
|
MDBStore *store = h;
|
|
@@ -241,12 +256,12 @@ finally:
|
|
|
}
|
|
|
|
|
|
|
|
|
-LSUP_rc
|
|
|
-mdbstore_nsm_put (void *h, const LSUP_NSMap *nsm)
|
|
|
+static LSUP_rc
|
|
|
+mdbstore_nsm_put (void *h, const LSUP_NSMap *nsm, void *th)
|
|
|
{
|
|
|
MDBStore *store = h;
|
|
|
MDB_txn *txn;
|
|
|
- RCCK (mdb_txn_begin (store->env, store->txn, 0, &txn));
|
|
|
+ RCCK (mdb_txn_begin (store->env, (MDB_txn *) th, 0, &txn));
|
|
|
|
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
|
int db_rc;
|
|
@@ -332,7 +347,7 @@ mdbstore_path_from_id (const char *id)
|
|
|
* and checking that it's a writable directory. If the path is not specified
|
|
|
* in the LSUP_MDB_STORE_URN environment variable, a default directory is used.
|
|
|
*/
|
|
|
-LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbstore_setup (const char *id, bool clear)
|
|
|
{
|
|
|
const char *path = mdbstore_path_from_id (id);
|
|
@@ -380,7 +395,7 @@ mdbstore_setup (const char *id, bool clear)
|
|
|
* it is not necessary to modify this, unless one is operating under memory
|
|
|
* and disk constraints. The default map size is 1Tb.
|
|
|
*/
|
|
|
-void *
|
|
|
+static void *
|
|
|
mdbstore_new (const char *id, size_t _unused)
|
|
|
{
|
|
|
(void) _unused;
|
|
@@ -405,42 +420,43 @@ mdbstore_new (const char *id, size_t _unused)
|
|
|
CHECK (mdb_env_open (store->env, path, 0, ENV_FILE_MODE), fail);
|
|
|
|
|
|
// Assign DB handles to store->dbi.
|
|
|
- mdb_txn_begin (store->env, NULL, 0, &store->txn);
|
|
|
+ MDB_txn *txn = NULL;
|
|
|
+ CHECK (mdb_txn_begin (store->env, NULL, 0, &txn), fail);
|
|
|
for (int i = 0; i < N_DB; i++)
|
|
|
CHECK (mdb_dbi_open (
|
|
|
- store->txn, db_labels[i], db_flags[i], store->dbi + i), fail);
|
|
|
+ txn, db_labels[i], db_flags[i], store->dbi + i), fail);
|
|
|
|
|
|
// Bootstrap the permanent store with initial data.
|
|
|
MDB_stat stat;
|
|
|
- CHECK (mdb_stat (store->txn, store->dbi[IDX_PFX_NS], &stat), fail);
|
|
|
+ CHECK (mdb_stat (txn, store->dbi[IDX_PFX_NS], &stat), fail);
|
|
|
if (stat.ms_entries == 0) {
|
|
|
log_debug ("Loading initial data into %s", path);
|
|
|
// Load initial NS map.
|
|
|
- mdbstore_nsm_put (store, LSUP_default_nsm);
|
|
|
+ mdbstore_nsm_put (store, LSUP_default_nsm, txn);
|
|
|
|
|
|
// Index default context.
|
|
|
- mdbstore_add_term (store, LSUP_default_ctx_buf);
|
|
|
+ mdbstore_add_term (store, LSUP_default_ctx_buf, txn);
|
|
|
}
|
|
|
|
|
|
- store->state |= LSSTORE_OPEN;
|
|
|
- mdb_txn_commit (store->txn);
|
|
|
- store->txn = NULL;
|
|
|
+ store->flags |= LSSTORE_OPEN;
|
|
|
+ mdb_txn_commit (txn);
|
|
|
+ txn = NULL;
|
|
|
|
|
|
return store;
|
|
|
|
|
|
fail:
|
|
|
- if (store->txn) mdb_txn_abort (store->txn);
|
|
|
+ if (txn) mdb_txn_abort (txn);
|
|
|
mdb_env_close (store->env);
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
|
|
|
-void
|
|
|
+static void
|
|
|
mdbstore_free (void *h)
|
|
|
{
|
|
|
MDBStore *store = h;
|
|
|
- if (store->state & LSSTORE_OPEN) {
|
|
|
+ if (store->flags & LSSTORE_OPEN) {
|
|
|
const char *path;
|
|
|
mdb_env_get_path (store->env, &path);
|
|
|
log_info ("Closing MDB env at %s.", path);
|
|
@@ -451,7 +467,9 @@ mdbstore_free (void *h)
|
|
|
}
|
|
|
|
|
|
|
|
|
-char *mdbstore_id (const void *h)
|
|
|
+#if 0
|
|
|
+static char *
|
|
|
+mdbstore_id (const void *h)
|
|
|
{
|
|
|
const MDBStore *store = h;
|
|
|
const char *path;
|
|
@@ -459,12 +477,13 @@ char *mdbstore_id (const void *h)
|
|
|
|
|
|
return strcat ("file://", path);
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
-LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbstore_stat (const MDBStore *store, MDB_stat *stat)
|
|
|
{
|
|
|
- if (!(store->state & LSSTORE_OPEN)) return 0;
|
|
|
+ if (!(store->flags & LSSTORE_OPEN)) return 0;
|
|
|
|
|
|
MDB_txn *txn;
|
|
|
mdb_txn_begin (store->env, NULL, MDB_RDONLY, &txn);
|
|
@@ -477,7 +496,7 @@ mdbstore_stat (const MDBStore *store, MDB_stat *stat)
|
|
|
}
|
|
|
|
|
|
|
|
|
-size_t
|
|
|
+static size_t
|
|
|
mdbstore_size (const void *h)
|
|
|
{
|
|
|
const MDBStore *store = h;
|
|
@@ -490,8 +509,48 @@ mdbstore_size (const void *h)
|
|
|
}
|
|
|
|
|
|
|
|
|
-void *
|
|
|
-mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
|
+static LSUP_rc
|
|
|
+mdbstore_txn_begin (void *h, int flags, void **th)
|
|
|
+{
|
|
|
+ MDBStore *store = h;
|
|
|
+
|
|
|
+ RCCK (mdb_txn_begin (store->env, NULL, flags, (MDB_txn **) th));
|
|
|
+
|
|
|
+ return LSUP_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static LSUP_rc
|
|
|
+mdbstore_txn_commit (void *th)
|
|
|
+{
|
|
|
+ RCCK (mdb_txn_commit ((MDB_txn *) th));
|
|
|
+
|
|
|
+ return LSUP_OK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+mdbstore_txn_abort (void *th)
|
|
|
+{ mdb_txn_abort ((MDB_txn *) th); }
|
|
|
+
|
|
|
+
|
|
|
+static void *
|
|
|
+mdbiter_txn (void *h)
|
|
|
+{ return ((MDBIterator *) h)->txn; }
|
|
|
+
|
|
|
+
|
|
|
+/** @brief Begin an add loop.
|
|
|
+ *
|
|
|
+ * @sa #store_add_init_fn_t
|
|
|
+ *
|
|
|
+ * @param[in] th Previously opened MDB_txn handle, if the add loop shall be
|
|
|
+ * run within a broader transaction. The transaction must be read-write. The
|
|
|
+ * operation will always open a new transaction that is closed with
|
|
|
+ * #mdbstore_add_done() or #mdbstore_add_abort(). If this parameter is not
|
|
|
+ * NULL, the loop transaction will have the passed txn set as its parent.
|
|
|
+ */
|
|
|
+static void *
|
|
|
+mdbstore_add_init (void *h, const LSUP_Buffer *sc, void *th)
|
|
|
{
|
|
|
MDBStore *store = h;
|
|
|
/* An iterator is used here. Some members are a bit misused but it does
|
|
@@ -503,12 +562,7 @@ mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
|
it->store = store;
|
|
|
it->i = 0;
|
|
|
|
|
|
- // No other write transaction may be open.
|
|
|
- if (UNLIKELY (it->store->txn)) {
|
|
|
- log_error ("A write transaction is already open.");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- mdb_txn_begin (store->env, NULL, 0, &it->store->txn);
|
|
|
+ mdb_txn_begin (store->env, (MDB_txn *) th, 0, &it->txn);
|
|
|
|
|
|
if (sc) {
|
|
|
// Store context if it's not the default one.
|
|
@@ -522,11 +576,11 @@ mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
|
it->data.mv_size = sc->size;
|
|
|
|
|
|
int db_rc = mdb_put(
|
|
|
- it->store->txn, it->store->dbi[IDX_T_ST],
|
|
|
+ it->txn, it->store->dbi[IDX_T_ST],
|
|
|
&it->key, &it->data, MDB_NOOVERWRITE);
|
|
|
if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
|
|
|
LOG_RC (db_rc);
|
|
|
- mdb_txn_abort (it->store->txn);
|
|
|
+ mdb_txn_abort (it->txn);
|
|
|
return NULL;
|
|
|
}
|
|
|
} else {
|
|
@@ -544,7 +598,7 @@ mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
|
* #mdbstore_add_abort or #mdbstore_add_done. FIXME
|
|
|
*
|
|
|
*/
|
|
|
-LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
|
{
|
|
|
if (UNLIKELY (!h)) return LSUP_VALUE_ERR;
|
|
@@ -565,7 +619,7 @@ mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
|
it->data.mv_size = st->size;
|
|
|
|
|
|
db_rc = mdb_put(
|
|
|
- it->store->txn, it->store->dbi[IDX_T_ST],
|
|
|
+ it->txn, it->store->dbi[IDX_T_ST],
|
|
|
&it->key, &it->data, MDB_NOOVERWRITE);
|
|
|
if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
|
|
|
LOG_RC (db_rc);
|
|
@@ -585,7 +639,7 @@ mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
|
it->data.mv_size = it->luc == NULL_KEY ? 0 : KLEN;
|
|
|
|
|
|
db_rc = mdb_put(
|
|
|
- it->store->txn, it->store->dbi[IDX_SPO_C],
|
|
|
+ it->txn, it->store->dbi[IDX_SPO_C],
|
|
|
&it->key, &it->data, MDB_NODUPDATA);
|
|
|
|
|
|
if (db_rc == MDB_KEYEXIST) return LSUP_NOACTION;
|
|
@@ -596,46 +650,43 @@ mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
|
}
|
|
|
|
|
|
// Index.
|
|
|
- LSUP_rc rc = index_triple (it->store, OP_ADD, spok, it->luc);
|
|
|
+ LSUP_rc rc = index_triple (it->store, OP_ADD, spok, it->luc, it->txn);
|
|
|
if (rc == LSUP_OK) it->i++;
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
|
|
|
-LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbstore_add_done (void *h)
|
|
|
{
|
|
|
MDBIterator *it = h;
|
|
|
LSUP_rc rc = LSUP_OK;
|
|
|
|
|
|
- if (mdb_txn_commit (it->store->txn) != MDB_SUCCESS) {
|
|
|
- mdb_txn_abort (it->store->txn);
|
|
|
- rc = LSUP_DB_ERR;
|
|
|
+ if (mdb_txn_commit (it->txn) != MDB_SUCCESS) {
|
|
|
+ mdb_txn_abort (it->txn);
|
|
|
+ rc = LSUP_TXN_ERR;
|
|
|
}
|
|
|
|
|
|
- it->store->txn = NULL;
|
|
|
-
|
|
|
free (it);
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
|
|
|
-void
|
|
|
+static void
|
|
|
mdbstore_add_abort (void *h)
|
|
|
{
|
|
|
MDBIterator *it = h;
|
|
|
- mdb_txn_abort (it->store->txn);
|
|
|
-
|
|
|
- it->store->txn = NULL;
|
|
|
+ mdb_txn_abort (it->txn);
|
|
|
|
|
|
free (it);
|
|
|
}
|
|
|
|
|
|
|
|
|
+#if 0
|
|
|
/* TODO deprecate. Use low-level instead and abstract at graph level. */
|
|
|
-LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbstore_add (
|
|
|
void *h, const LSUP_Buffer *sc,
|
|
|
const LSUP_BufferTriple strp[], const size_t ct, size_t *inserted)
|
|
@@ -655,6 +706,7 @@ mdbstore_add (
|
|
|
|
|
|
return mdbstore_add_done (it);
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
static LSUP_rc
|
|
@@ -682,12 +734,11 @@ key_to_sterm (MDBIterator *it, const LSUP_Key key, LSUP_Buffer *sterm)
|
|
|
}
|
|
|
|
|
|
|
|
|
-void *
|
|
|
+static void *
|
|
|
mdbstore_lookup (
|
|
|
void *h, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
|
- const LSUP_Buffer *so, const LSUP_Buffer *sc, size_t *ct)
|
|
|
+ const LSUP_Buffer *so, const LSUP_Buffer *sc, void *th, size_t *ct)
|
|
|
{
|
|
|
- MDBStore *store = h;
|
|
|
LSUP_TripleKey spok = {
|
|
|
LSUP_buffer_hash (ss),
|
|
|
LSUP_buffer_hash (sp),
|
|
@@ -697,7 +748,7 @@ mdbstore_lookup (
|
|
|
MDBIterator *it;
|
|
|
CALLOC_GUARD (it, NULL);
|
|
|
|
|
|
- it->store = store;
|
|
|
+ it->store = h;
|
|
|
it->luc = LSUP_buffer_hash (sc);
|
|
|
log_debug ("Lookup context: %lx", it->luc);
|
|
|
|
|
@@ -706,13 +757,14 @@ mdbstore_lookup (
|
|
|
uint8_t idx0, idx1;
|
|
|
|
|
|
// Start RO transaction if not in a write txn already.
|
|
|
- if (it->store->txn) it->txn = it->store->txn;
|
|
|
+ if (th) it->txn = th;
|
|
|
else {
|
|
|
it->rc = mdb_txn_begin (it->store->env, NULL, MDB_RDONLY, &it->txn);
|
|
|
if (it->rc != MDB_SUCCESS) {
|
|
|
log_error ("Database error: %s", LSUP_strerror (it->rc));
|
|
|
return NULL;
|
|
|
}
|
|
|
+ it->flags |= ITER_OPEN_TXN;
|
|
|
}
|
|
|
|
|
|
// Context index loop.
|
|
@@ -780,7 +832,7 @@ mdbstore_lookup (
|
|
|
* ckset is filled with an array of contexts that the triple appears
|
|
|
* in, if not NULL.
|
|
|
*/
|
|
|
-inline static LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbiter_next_key (MDBIterator *it)
|
|
|
{
|
|
|
if (UNLIKELY (!it)) return LSUP_VALUE_ERR;
|
|
@@ -872,7 +924,7 @@ mdbiter_next_key (MDBIterator *it)
|
|
|
}
|
|
|
|
|
|
|
|
|
-LSUP_rc
|
|
|
+static LSUP_rc
|
|
|
mdbiter_next (
|
|
|
void *h, LSUP_BufferTriple *sspo, LSUP_Buffer **ctx_p)
|
|
|
{
|
|
@@ -911,7 +963,7 @@ mdbiter_next (
|
|
|
}
|
|
|
|
|
|
|
|
|
-void
|
|
|
+static void
|
|
|
mdbiter_free (void *h)
|
|
|
{
|
|
|
MDBIterator *it = h;
|
|
@@ -919,17 +971,17 @@ mdbiter_free (void *h)
|
|
|
|
|
|
if (it->cur) mdb_cursor_close (it->cur);
|
|
|
if (it->ctx_cur) mdb_cursor_close (it->ctx_cur);
|
|
|
- if (it->store->txn != it->txn) mdb_txn_abort (it->txn);
|
|
|
+ if (it->flags & ITER_OPEN_TXN) mdb_txn_abort (it->txn);
|
|
|
free (it->ck);
|
|
|
|
|
|
free (it);
|
|
|
}
|
|
|
|
|
|
|
|
|
-LSUP_rc
|
|
|
-mdbstore_remove(
|
|
|
+static LSUP_rc
|
|
|
+mdbstore_remove (
|
|
|
void *h, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
|
- const LSUP_Buffer *so, const LSUP_Buffer *sc, size_t *ct)
|
|
|
+ const LSUP_Buffer *so, const LSUP_Buffer *sc, void *th, size_t *ct)
|
|
|
{
|
|
|
MDBStore *store = h;
|
|
|
LSUP_rc rc = LSUP_NOACTION, db_rc;
|
|
@@ -939,13 +991,12 @@ mdbstore_remove(
|
|
|
if (sc == NULL) sc = LSUP_default_ctx_buf;
|
|
|
ck = LSUP_buffer_hash (sc);
|
|
|
|
|
|
- // No other write transaction may be open.
|
|
|
- if (UNLIKELY (store->txn)) return LSUP_TXN_ERR;
|
|
|
- mdb_txn_begin (store->env, NULL, 0, &store->txn);
|
|
|
+ MDB_txn *txn;
|
|
|
+ mdb_txn_begin (store->env, (MDB_txn *) th, 0, &txn);
|
|
|
|
|
|
MDB_cursor *dcur, *icur;
|
|
|
- mdb_cursor_open (store->txn, store->dbi[IDX_SPO_C], &dcur);
|
|
|
- mdb_cursor_open (store->txn, store->dbi[IDX_C_SPO], &icur);
|
|
|
+ mdb_cursor_open (txn, store->dbi[IDX_SPO_C], &dcur);
|
|
|
+ mdb_cursor_open (txn, store->dbi[IDX_C_SPO], &icur);
|
|
|
|
|
|
MDB_val spok_v, ck_v;
|
|
|
|
|
@@ -953,7 +1004,8 @@ mdbstore_remove(
|
|
|
ck_v.mv_size = KLEN;
|
|
|
ck_v.mv_data = &ck;
|
|
|
|
|
|
- MDBIterator *it = mdbstore_lookup (store, ss, sp, so, sc, ct);
|
|
|
+ // The lookup operates within the current (bottom) write transaction.
|
|
|
+ MDBIterator *it = mdbstore_lookup (store, ss, sp, so, sc, txn, ct);
|
|
|
if (UNLIKELY (!it)) return LSUP_DB_ERR;
|
|
|
if (ct) log_debug ("Found %lu triples to remove.", *ct);
|
|
|
|
|
@@ -993,22 +1045,20 @@ mdbstore_remove(
|
|
|
if (db_rc == MDB_SUCCESS) continue;
|
|
|
if (UNLIKELY (db_rc != MDB_NOTFOUND)) goto fail;
|
|
|
|
|
|
- rc = index_triple (store, OP_REMOVE, it->spok, ck);
|
|
|
+ rc = index_triple (store, OP_REMOVE, it->spok, ck, txn);
|
|
|
}
|
|
|
|
|
|
mdbiter_free (it);
|
|
|
|
|
|
- if (UNLIKELY (mdb_txn_commit (store->txn) != MDB_SUCCESS)) {
|
|
|
+ if (UNLIKELY (mdb_txn_commit (txn) != MDB_SUCCESS)) {
|
|
|
rc = LSUP_TXN_ERR;
|
|
|
goto fail;
|
|
|
}
|
|
|
- store->txn = NULL;
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
fail:
|
|
|
- mdb_txn_abort (store->txn);
|
|
|
- store->txn = NULL;
|
|
|
+ mdb_txn_abort (txn);
|
|
|
|
|
|
log_error ("Database error: %s", LSUP_strerror (db_rc));
|
|
|
|
|
@@ -1016,7 +1066,8 @@ fail:
|
|
|
}
|
|
|
|
|
|
|
|
|
-int
|
|
|
+#if 0
|
|
|
+static int
|
|
|
mdbstore_tkey_exists (MDBStore *store, LSUP_Key tkey)
|
|
|
{
|
|
|
int db_rc, rc;
|
|
@@ -1044,22 +1095,23 @@ mdbstore_tkey_exists (MDBStore *store, LSUP_Key tkey)
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
static LSUP_rc
|
|
|
-mdbstore_add_term (void *h, const LSUP_Buffer *sterm)
|
|
|
+mdbstore_add_term (void *h, const LSUP_Buffer *sterm, void *th)
|
|
|
{
|
|
|
MDBStore *store = h;
|
|
|
int db_rc;
|
|
|
MDB_val key, data;
|
|
|
|
|
|
MDB_txn *txn;
|
|
|
- // If store->txn exists, open a child txn, otherwise parent should be NULL.
|
|
|
- RCCK (mdb_txn_begin (store->env, store->txn, 0, &txn));
|
|
|
+ // If store->txn exists, open a child txn, otherwise reuse the same txn.
|
|
|
+ if (th) txn = th;
|
|
|
+ else RCCK (mdb_txn_begin (store->env, NULL, 0, &txn));
|
|
|
|
|
|
MDB_cursor *cur;
|
|
|
- db_rc = mdb_cursor_open (txn, store->dbi[IDX_T_ST], &cur);
|
|
|
- if (UNLIKELY (db_rc != MDB_SUCCESS)) goto fail;
|
|
|
+ CHECK (mdb_cursor_open (txn, store->dbi[IDX_T_ST], &cur), fail);
|
|
|
|
|
|
LSUP_Key k = LSUP_buffer_hash (sterm);
|
|
|
key.mv_data = &k;
|
|
@@ -1071,17 +1123,12 @@ mdbstore_add_term (void *h, const LSUP_Buffer *sterm)
|
|
|
db_rc = mdb_cursor_put (cur, &key, &data, MDB_NOOVERWRITE);
|
|
|
if (db_rc != MDB_KEYEXIST) CHECK (db_rc, fail);
|
|
|
|
|
|
- if (txn != store->txn) {
|
|
|
- db_rc = mdb_txn_commit (txn);
|
|
|
- txn = NULL;
|
|
|
- CHECK (db_rc, fail);
|
|
|
- }
|
|
|
+ if (!th) CHECK (db_rc = mdb_txn_commit (txn), fail);
|
|
|
|
|
|
return LSUP_OK;
|
|
|
|
|
|
fail:
|
|
|
- log_error (mdb_strerror (db_rc));
|
|
|
- if (txn) mdb_txn_abort (txn);
|
|
|
+ if (!th) mdb_txn_abort (txn);
|
|
|
return LSUP_DB_ERR;
|
|
|
}
|
|
|
|
|
@@ -1097,6 +1144,11 @@ const LSUP_StoreInt mdbstore_int = {
|
|
|
|
|
|
.size_fn = mdbstore_size,
|
|
|
|
|
|
+ .txn_begin_fn = mdbstore_txn_begin,
|
|
|
+ .txn_commit_fn = mdbstore_txn_commit,
|
|
|
+ .txn_abort_fn = mdbstore_txn_abort,
|
|
|
+ .iter_txn_fn = mdbiter_txn,
|
|
|
+
|
|
|
.add_init_fn = mdbstore_add_init,
|
|
|
.add_iter_fn = mdbstore_add_iter,
|
|
|
.add_abort_fn = mdbstore_add_abort,
|
|
@@ -1122,9 +1174,13 @@ const LSUP_StoreInt mdbstore_int = {
|
|
|
* @param op[in] Store operation. One of OP_ADD or OP_REMOVE.
|
|
|
* @param spok[in] Triple key to index.
|
|
|
* @param ck[in] Context to index, may be NULL.
|
|
|
+ * @param[in] th Transaction handle. This MUST be a valid pointer to an open
|
|
|
+ * RW transaction.
|
|
|
*/
|
|
|
static LSUP_rc
|
|
|
-index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
+index_triple(
|
|
|
+ MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck,
|
|
|
+ MDB_txn *txn)
|
|
|
{
|
|
|
int db_rc;
|
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
@@ -1143,7 +1199,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
v2.mv_data = spok;
|
|
|
v2.mv_size = TRP_KLEN;
|
|
|
|
|
|
- mdb_cursor_open (store->txn, store->dbi[IDX_C_SPO], &cur);
|
|
|
+ mdb_cursor_open (txn, store->dbi[IDX_C_SPO], &cur);
|
|
|
if (mdb_cursor_get (cur, &v1, &v2, MDB_GET_BOTH) == MDB_SUCCESS) {
|
|
|
db_rc = mdb_cursor_del (cur, 0);
|
|
|
if (db_rc != MDB_SUCCESS) return LSUP_DB_ERR;
|
|
@@ -1163,7 +1219,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
v2.mv_size = TRP_KLEN;
|
|
|
|
|
|
db_rc = mdb_put(
|
|
|
- store->txn, store->dbi[IDX_C_SPO],
|
|
|
+ txn, store->dbi[IDX_C_SPO],
|
|
|
&v1, &v2, MDB_NODUPDATA);
|
|
|
if (db_rc != MDB_SUCCESS) return LSUP_DB_ERR;
|
|
|
if (db_rc != MDB_KEYEXIST) rc = LSUP_OK;
|
|
@@ -1190,8 +1246,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
|
|
|
if (op == OP_REMOVE) {
|
|
|
MDB_cursor *cur1, *cur2;
|
|
|
- mdb_cursor_open(
|
|
|
- store->txn, store->dbi[lookup_indices[i]], &cur1);
|
|
|
+ mdb_cursor_open(txn, store->dbi[lookup_indices[i]], &cur1);
|
|
|
|
|
|
db_rc = mdb_cursor_get (cur1, &v1, &v2, MDB_GET_BOTH);
|
|
|
if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur1, 0);
|
|
@@ -1202,8 +1257,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
v1.mv_data = spok + i;
|
|
|
v2.mv_data = dbl_keys[i];
|
|
|
|
|
|
- mdb_cursor_open(
|
|
|
- store->txn, store->dbi[lookup_indices[i + 3]], &cur2);
|
|
|
+ mdb_cursor_open(txn, store->dbi[lookup_indices[i + 3]], &cur2);
|
|
|
|
|
|
db_rc = mdb_cursor_get (cur2, &v2, &v1, MDB_GET_BOTH);
|
|
|
if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur2, 0);
|
|
@@ -1219,7 +1273,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
"%lx: %lx %lx", *(size_t*)(v1.mv_data),
|
|
|
*(size_t*)(v2.mv_data), *(size_t*)(v2.mv_data) + 1);
|
|
|
|
|
|
- db_rc = mdb_put (store->txn, db1, &v1, &v2, MDB_NODUPDATA);
|
|
|
+ db_rc = mdb_put (txn, db1, &v1, &v2, MDB_NODUPDATA);
|
|
|
|
|
|
if (db_rc == MDB_SUCCESS) rc = LSUP_OK;
|
|
|
else if (db_rc != MDB_KEYEXIST) return LSUP_DB_ERR;
|
|
@@ -1230,7 +1284,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
"%lx %lx: %lx", *(size_t*)(v2.mv_data),
|
|
|
*(size_t*)(v2.mv_data) + 1, *(size_t*)(v1.mv_data));
|
|
|
|
|
|
- db_rc = mdb_put (store->txn, db2, &v2, &v1, MDB_NODUPDATA);
|
|
|
+ db_rc = mdb_put (txn, db2, &v2, &v1, MDB_NODUPDATA);
|
|
|
|
|
|
if (db_rc == MDB_SUCCESS) rc = LSUP_OK;
|
|
|
else if (db_rc != MDB_KEYEXIST) return LSUP_DB_ERR;
|