|
@@ -28,10 +28,24 @@
|
|
typedef char DbLabel[8];
|
|
typedef char DbLabel[8];
|
|
typedef struct mdbstore_iter_t MDBIterator;
|
|
typedef struct mdbstore_iter_t MDBIterator;
|
|
|
|
|
|
|
|
+/// Store state flags.
|
|
typedef enum {
|
|
typedef enum {
|
|
LSSTORE_OPEN = 1<<0, ///< Env is open.
|
|
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 {
|
|
typedef enum {
|
|
OP_ADD,
|
|
OP_ADD,
|
|
@@ -40,10 +54,8 @@ typedef enum {
|
|
|
|
|
|
typedef struct mdbstore_t {
|
|
typedef struct mdbstore_t {
|
|
MDB_env * env; ///< Environment handle.
|
|
MDB_env * env; ///< Environment handle.
|
|
- MDB_txn * txn; ///< Current transaction.
|
|
|
|
MDB_dbi dbi[N_DB]; ///< DB handles. Refer to DbIdx enum.
|
|
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;
|
|
} MDBStore;
|
|
|
|
|
|
/** @brief Iterator operation.
|
|
/** @brief Iterator operation.
|
|
@@ -62,13 +74,17 @@ typedef void (*iter_op_fn_t)(MDBIterator *it);
|
|
/// Triple iterator.
|
|
/// Triple iterator.
|
|
typedef struct mdbstore_iter_t {
|
|
typedef struct mdbstore_iter_t {
|
|
MDBStore * store; ///< MDB store handle.
|
|
MDBStore * store; ///< MDB store handle.
|
|
|
|
+ IterFlags flags; ///< Iterator flags.
|
|
MDB_txn * txn; ///< MDB transaction.
|
|
MDB_txn * txn; ///< MDB transaction.
|
|
MDB_cursor * cur; ///< MDB cursor.
|
|
MDB_cursor * cur; ///< MDB cursor.
|
|
MDB_cursor * ctx_cur; ///< MDB c:spo index 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_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.
|
|
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.
|
|
const uint8_t * term_order; ///< Term order used in 1-2bound look-ups.
|
|
LSUP_Key luk[3]; ///< 0÷3 lookup keys.
|
|
LSUP_Key luk[3]; ///< 0÷3 lookup keys.
|
|
@@ -184,8 +200,9 @@ static const uint8_t lookup_ordering_2bound[3][3] = {
|
|
* Static prototypes.
|
|
* Static prototypes.
|
|
*/
|
|
*/
|
|
static int index_triple(
|
|
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_0bound (MDBIterator *it, size_t *ct);
|
|
inline static LSUP_rc lookup_1bound (
|
|
inline static LSUP_rc lookup_1bound (
|
|
@@ -240,11 +257,11 @@ finally:
|
|
|
|
|
|
|
|
|
|
static LSUP_rc
|
|
static LSUP_rc
|
|
-mdbstore_nsm_put (void *h, const LSUP_NSMap *nsm)
|
|
|
|
|
|
+mdbstore_nsm_put (void *h, const LSUP_NSMap *nsm, void *th)
|
|
{
|
|
{
|
|
MDBStore *store = h;
|
|
MDBStore *store = h;
|
|
MDB_txn *txn;
|
|
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;
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
int db_rc;
|
|
int db_rc;
|
|
@@ -403,31 +420,32 @@ mdbstore_new (const char *id, size_t _unused)
|
|
CHECK (mdb_env_open (store->env, path, 0, ENV_FILE_MODE), fail);
|
|
CHECK (mdb_env_open (store->env, path, 0, ENV_FILE_MODE), fail);
|
|
|
|
|
|
// Assign DB handles to store->dbi.
|
|
// 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++)
|
|
for (int i = 0; i < N_DB; i++)
|
|
CHECK (mdb_dbi_open (
|
|
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.
|
|
// Bootstrap the permanent store with initial data.
|
|
MDB_stat stat;
|
|
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) {
|
|
if (stat.ms_entries == 0) {
|
|
log_debug ("Loading initial data into %s", path);
|
|
log_debug ("Loading initial data into %s", path);
|
|
// Load initial NS map.
|
|
// Load initial NS map.
|
|
- mdbstore_nsm_put (store, LSUP_default_nsm);
|
|
|
|
|
|
+ mdbstore_nsm_put (store, LSUP_default_nsm, txn);
|
|
|
|
|
|
// Index default context.
|
|
// 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;
|
|
return store;
|
|
|
|
|
|
fail:
|
|
fail:
|
|
- if (store->txn) mdb_txn_abort (store->txn);
|
|
|
|
|
|
+ if (txn) mdb_txn_abort (txn);
|
|
mdb_env_close (store->env);
|
|
mdb_env_close (store->env);
|
|
|
|
|
|
return NULL;
|
|
return NULL;
|
|
@@ -438,7 +456,7 @@ static void
|
|
mdbstore_free (void *h)
|
|
mdbstore_free (void *h)
|
|
{
|
|
{
|
|
MDBStore *store = h;
|
|
MDBStore *store = h;
|
|
- if (store->state & LSSTORE_OPEN) {
|
|
|
|
|
|
+ if (store->flags & LSSTORE_OPEN) {
|
|
const char *path;
|
|
const char *path;
|
|
mdb_env_get_path (store->env, &path);
|
|
mdb_env_get_path (store->env, &path);
|
|
log_info ("Closing MDB env at %s.", path);
|
|
log_info ("Closing MDB env at %s.", path);
|
|
@@ -463,7 +481,7 @@ mdbstore_id (const void *h)
|
|
static LSUP_rc
|
|
static LSUP_rc
|
|
mdbstore_stat (const MDBStore *store, MDB_stat *stat)
|
|
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 *txn;
|
|
mdb_txn_begin (store->env, NULL, MDB_RDONLY, &txn);
|
|
mdb_txn_begin (store->env, NULL, MDB_RDONLY, &txn);
|
|
@@ -489,8 +507,43 @@ mdbstore_size (const void *h)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+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); }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/** @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 *
|
|
static void *
|
|
-mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
|
|
|
|
+mdbstore_add_init (void *h, const LSUP_Buffer *sc, void *th)
|
|
{
|
|
{
|
|
MDBStore *store = h;
|
|
MDBStore *store = h;
|
|
/* An iterator is used here. Some members are a bit misused but it does
|
|
/* An iterator is used here. Some members are a bit misused but it does
|
|
@@ -502,12 +555,7 @@ mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
it->store = store;
|
|
it->store = store;
|
|
it->i = 0;
|
|
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) {
|
|
if (sc) {
|
|
// Store context if it's not the default one.
|
|
// Store context if it's not the default one.
|
|
@@ -521,11 +569,11 @@ mdbstore_add_init (void *h, const LSUP_Buffer *sc)
|
|
it->data.mv_size = sc->size;
|
|
it->data.mv_size = sc->size;
|
|
|
|
|
|
int db_rc = mdb_put(
|
|
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);
|
|
&it->key, &it->data, MDB_NOOVERWRITE);
|
|
if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
|
|
if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
|
|
LOG_RC (db_rc);
|
|
LOG_RC (db_rc);
|
|
- mdb_txn_abort (it->store->txn);
|
|
|
|
|
|
+ mdb_txn_abort (it->txn);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
@@ -564,7 +612,7 @@ mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
it->data.mv_size = st->size;
|
|
it->data.mv_size = st->size;
|
|
|
|
|
|
db_rc = mdb_put(
|
|
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);
|
|
&it->key, &it->data, MDB_NOOVERWRITE);
|
|
if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
|
|
if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
|
|
LOG_RC (db_rc);
|
|
LOG_RC (db_rc);
|
|
@@ -584,7 +632,7 @@ mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
it->data.mv_size = it->luc == NULL_KEY ? 0 : KLEN;
|
|
it->data.mv_size = it->luc == NULL_KEY ? 0 : KLEN;
|
|
|
|
|
|
db_rc = mdb_put(
|
|
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);
|
|
&it->key, &it->data, MDB_NODUPDATA);
|
|
|
|
|
|
if (db_rc == MDB_KEYEXIST) return LSUP_NOACTION;
|
|
if (db_rc == MDB_KEYEXIST) return LSUP_NOACTION;
|
|
@@ -595,7 +643,7 @@ mdbstore_add_iter (void *h, const LSUP_BufferTriple *sspo)
|
|
}
|
|
}
|
|
|
|
|
|
// Index.
|
|
// 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++;
|
|
if (rc == LSUP_OK) it->i++;
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -608,13 +656,11 @@ mdbstore_add_done (void *h)
|
|
MDBIterator *it = h;
|
|
MDBIterator *it = h;
|
|
LSUP_rc rc = LSUP_OK;
|
|
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);
|
|
free (it);
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
@@ -625,9 +671,7 @@ static void
|
|
mdbstore_add_abort (void *h)
|
|
mdbstore_add_abort (void *h)
|
|
{
|
|
{
|
|
MDBIterator *it = h;
|
|
MDBIterator *it = h;
|
|
- mdb_txn_abort (it->store->txn);
|
|
|
|
-
|
|
|
|
- it->store->txn = NULL;
|
|
|
|
|
|
+ mdb_txn_abort (it->txn);
|
|
|
|
|
|
free (it);
|
|
free (it);
|
|
}
|
|
}
|
|
@@ -686,9 +730,8 @@ key_to_sterm (MDBIterator *it, const LSUP_Key key, LSUP_Buffer *sterm)
|
|
static void *
|
|
static void *
|
|
mdbstore_lookup (
|
|
mdbstore_lookup (
|
|
void *h, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
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_TripleKey spok = {
|
|
LSUP_buffer_hash (ss),
|
|
LSUP_buffer_hash (ss),
|
|
LSUP_buffer_hash (sp),
|
|
LSUP_buffer_hash (sp),
|
|
@@ -698,7 +741,7 @@ mdbstore_lookup (
|
|
MDBIterator *it;
|
|
MDBIterator *it;
|
|
CALLOC_GUARD (it, NULL);
|
|
CALLOC_GUARD (it, NULL);
|
|
|
|
|
|
- it->store = store;
|
|
|
|
|
|
+ it->store = h;
|
|
it->luc = LSUP_buffer_hash (sc);
|
|
it->luc = LSUP_buffer_hash (sc);
|
|
log_debug ("Lookup context: %lx", it->luc);
|
|
log_debug ("Lookup context: %lx", it->luc);
|
|
|
|
|
|
@@ -707,13 +750,14 @@ mdbstore_lookup (
|
|
uint8_t idx0, idx1;
|
|
uint8_t idx0, idx1;
|
|
|
|
|
|
// Start RO transaction if not in a write txn already.
|
|
// 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 {
|
|
else {
|
|
it->rc = mdb_txn_begin (it->store->env, NULL, MDB_RDONLY, &it->txn);
|
|
it->rc = mdb_txn_begin (it->store->env, NULL, MDB_RDONLY, &it->txn);
|
|
if (it->rc != MDB_SUCCESS) {
|
|
if (it->rc != MDB_SUCCESS) {
|
|
log_error ("Database error: %s", LSUP_strerror (it->rc));
|
|
log_error ("Database error: %s", LSUP_strerror (it->rc));
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
+ it->flags |= ITER_OPEN_TXN;
|
|
}
|
|
}
|
|
|
|
|
|
// Context index loop.
|
|
// Context index loop.
|
|
@@ -920,7 +964,7 @@ mdbiter_free (void *h)
|
|
|
|
|
|
if (it->cur) mdb_cursor_close (it->cur);
|
|
if (it->cur) mdb_cursor_close (it->cur);
|
|
if (it->ctx_cur) mdb_cursor_close (it->ctx_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->ck);
|
|
|
|
|
|
free (it);
|
|
free (it);
|
|
@@ -928,9 +972,9 @@ mdbiter_free (void *h)
|
|
|
|
|
|
|
|
|
|
static LSUP_rc
|
|
static LSUP_rc
|
|
-mdbstore_remove(
|
|
|
|
|
|
+mdbstore_remove (
|
|
void *h, const LSUP_Buffer *ss, const LSUP_Buffer *sp,
|
|
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, size_t *ct, void *th)
|
|
{
|
|
{
|
|
MDBStore *store = h;
|
|
MDBStore *store = h;
|
|
LSUP_rc rc = LSUP_NOACTION, db_rc;
|
|
LSUP_rc rc = LSUP_NOACTION, db_rc;
|
|
@@ -940,13 +984,12 @@ mdbstore_remove(
|
|
if (sc == NULL) sc = LSUP_default_ctx_buf;
|
|
if (sc == NULL) sc = LSUP_default_ctx_buf;
|
|
ck = LSUP_buffer_hash (sc);
|
|
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 *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;
|
|
MDB_val spok_v, ck_v;
|
|
|
|
|
|
@@ -954,7 +997,8 @@ mdbstore_remove(
|
|
ck_v.mv_size = KLEN;
|
|
ck_v.mv_size = KLEN;
|
|
ck_v.mv_data = &ck;
|
|
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 (UNLIKELY (!it)) return LSUP_DB_ERR;
|
|
if (ct) log_debug ("Found %lu triples to remove.", *ct);
|
|
if (ct) log_debug ("Found %lu triples to remove.", *ct);
|
|
|
|
|
|
@@ -994,22 +1038,20 @@ mdbstore_remove(
|
|
if (db_rc == MDB_SUCCESS) continue;
|
|
if (db_rc == MDB_SUCCESS) continue;
|
|
if (UNLIKELY (db_rc != MDB_NOTFOUND)) goto fail;
|
|
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);
|
|
mdbiter_free (it);
|
|
|
|
|
|
- if (UNLIKELY (mdb_txn_commit (store->txn) != MDB_SUCCESS)) {
|
|
|
|
|
|
+ if (UNLIKELY (mdb_txn_commit (txn) != MDB_SUCCESS)) {
|
|
rc = LSUP_TXN_ERR;
|
|
rc = LSUP_TXN_ERR;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
- store->txn = NULL;
|
|
|
|
|
|
|
|
return rc;
|
|
return rc;
|
|
|
|
|
|
fail:
|
|
fail:
|
|
- mdb_txn_abort (store->txn);
|
|
|
|
- store->txn = NULL;
|
|
|
|
|
|
+ mdb_txn_abort (txn);
|
|
|
|
|
|
log_error ("Database error: %s", LSUP_strerror (db_rc));
|
|
log_error ("Database error: %s", LSUP_strerror (db_rc));
|
|
|
|
|
|
@@ -1048,19 +1090,19 @@ mdbstore_tkey_exists (MDBStore *store, LSUP_Key tkey)
|
|
|
|
|
|
|
|
|
|
static LSUP_rc
|
|
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;
|
|
MDBStore *store = h;
|
|
int db_rc;
|
|
int db_rc;
|
|
MDB_val key, data;
|
|
MDB_val key, data;
|
|
|
|
|
|
MDB_txn *txn;
|
|
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;
|
|
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);
|
|
LSUP_Key k = LSUP_buffer_hash (sterm);
|
|
key.mv_data = &k;
|
|
key.mv_data = &k;
|
|
@@ -1072,17 +1114,12 @@ mdbstore_add_term (void *h, const LSUP_Buffer *sterm)
|
|
db_rc = mdb_cursor_put (cur, &key, &data, MDB_NOOVERWRITE);
|
|
db_rc = mdb_cursor_put (cur, &key, &data, MDB_NOOVERWRITE);
|
|
if (db_rc != MDB_KEYEXIST) CHECK (db_rc, fail);
|
|
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;
|
|
return LSUP_OK;
|
|
|
|
|
|
fail:
|
|
fail:
|
|
- log_error (mdb_strerror (db_rc));
|
|
|
|
- if (txn) mdb_txn_abort (txn);
|
|
|
|
|
|
+ if (!th) mdb_txn_abort (txn);
|
|
return LSUP_DB_ERR;
|
|
return LSUP_DB_ERR;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1098,6 +1135,10 @@ const LSUP_StoreInt mdbstore_int = {
|
|
|
|
|
|
.size_fn = mdbstore_size,
|
|
.size_fn = mdbstore_size,
|
|
|
|
|
|
|
|
+ .txn_begin_fn = mdbstore_txn_begin,
|
|
|
|
+ .txn_commit_fn = mdbstore_txn_commit,
|
|
|
|
+ .txn_abort_fn = mdbstore_txn_abort,
|
|
|
|
+
|
|
.add_init_fn = mdbstore_add_init,
|
|
.add_init_fn = mdbstore_add_init,
|
|
.add_iter_fn = mdbstore_add_iter,
|
|
.add_iter_fn = mdbstore_add_iter,
|
|
.add_abort_fn = mdbstore_add_abort,
|
|
.add_abort_fn = mdbstore_add_abort,
|
|
@@ -1123,9 +1164,13 @@ const LSUP_StoreInt mdbstore_int = {
|
|
* @param op[in] Store operation. One of OP_ADD or OP_REMOVE.
|
|
* @param op[in] Store operation. One of OP_ADD or OP_REMOVE.
|
|
* @param spok[in] Triple key to index.
|
|
* @param spok[in] Triple key to index.
|
|
* @param ck[in] Context to index, may be NULL.
|
|
* @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
|
|
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;
|
|
int db_rc;
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
LSUP_rc rc = LSUP_NOACTION;
|
|
@@ -1144,7 +1189,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
v2.mv_data = spok;
|
|
v2.mv_data = spok;
|
|
v2.mv_size = TRP_KLEN;
|
|
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) {
|
|
if (mdb_cursor_get (cur, &v1, &v2, MDB_GET_BOTH) == MDB_SUCCESS) {
|
|
db_rc = mdb_cursor_del (cur, 0);
|
|
db_rc = mdb_cursor_del (cur, 0);
|
|
if (db_rc != MDB_SUCCESS) return LSUP_DB_ERR;
|
|
if (db_rc != MDB_SUCCESS) return LSUP_DB_ERR;
|
|
@@ -1164,7 +1209,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
v2.mv_size = TRP_KLEN;
|
|
v2.mv_size = TRP_KLEN;
|
|
|
|
|
|
db_rc = mdb_put(
|
|
db_rc = mdb_put(
|
|
- store->txn, store->dbi[IDX_C_SPO],
|
|
|
|
|
|
+ txn, store->dbi[IDX_C_SPO],
|
|
&v1, &v2, MDB_NODUPDATA);
|
|
&v1, &v2, MDB_NODUPDATA);
|
|
if (db_rc != MDB_SUCCESS) return LSUP_DB_ERR;
|
|
if (db_rc != MDB_SUCCESS) return LSUP_DB_ERR;
|
|
if (db_rc != MDB_KEYEXIST) rc = LSUP_OK;
|
|
if (db_rc != MDB_KEYEXIST) rc = LSUP_OK;
|
|
@@ -1191,8 +1236,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
|
|
|
|
if (op == OP_REMOVE) {
|
|
if (op == OP_REMOVE) {
|
|
MDB_cursor *cur1, *cur2;
|
|
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);
|
|
db_rc = mdb_cursor_get (cur1, &v1, &v2, MDB_GET_BOTH);
|
|
if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur1, 0);
|
|
if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur1, 0);
|
|
@@ -1203,8 +1247,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
v1.mv_data = spok + i;
|
|
v1.mv_data = spok + i;
|
|
v2.mv_data = dbl_keys[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);
|
|
db_rc = mdb_cursor_get (cur2, &v2, &v1, MDB_GET_BOTH);
|
|
if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur2, 0);
|
|
if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur2, 0);
|
|
@@ -1220,7 +1263,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
"%lx: %lx %lx", *(size_t*)(v1.mv_data),
|
|
"%lx: %lx %lx", *(size_t*)(v1.mv_data),
|
|
*(size_t*)(v2.mv_data), *(size_t*)(v2.mv_data) + 1);
|
|
*(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;
|
|
if (db_rc == MDB_SUCCESS) rc = LSUP_OK;
|
|
else if (db_rc != MDB_KEYEXIST) return LSUP_DB_ERR;
|
|
else if (db_rc != MDB_KEYEXIST) return LSUP_DB_ERR;
|
|
@@ -1231,7 +1274,7 @@ index_triple(MDBStore *store, StoreOp op, LSUP_TripleKey spok, LSUP_Key ck)
|
|
"%lx %lx: %lx", *(size_t*)(v2.mv_data),
|
|
"%lx %lx: %lx", *(size_t*)(v2.mv_data),
|
|
*(size_t*)(v2.mv_data) + 1, *(size_t*)(v1.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;
|
|
if (db_rc == MDB_SUCCESS) rc = LSUP_OK;
|
|
else if (db_rc != MDB_KEYEXIST) return LSUP_DB_ERR;
|
|
else if (db_rc != MDB_KEYEXIST) return LSUP_DB_ERR;
|