11#if (defined DEBUG || defined TESTING)
12#define DEFAULT_MAPSIZE 1<<24
13#elif !(defined __LP64__ || defined __LLP64__) || \
14 defined _WIN32 && !defined _WIN64
15#define DEFAULT_MAPSIZE 1<<31
17#define DEFAULT_MAPSIZE 1UL<<40
20#define ENV_DIR_MODE 0750
21#define ENV_FILE_MODE 0640
54typedef struct mdbstore_t {
74typedef struct mdbstore_iter_t {
102#define DUPSORT_MASK MDB_DUPSORT
103#define DUPFIXED_MASK MDB_DUPSORT | MDB_DUPFIXED
112 ENTRY( T_ST, "t:st", 0 ) \
113 ENTRY( SPO_C, "spo:c", DUPFIXED_MASK ) \
114 ENTRY( IDK_ID, "idk:id", 0 ) \
119#define LOOKUP_TABLE \
121 ENTRY( S_PO, "s:po", DUPFIXED_MASK ) \
122 ENTRY( P_SO, "p:so", DUPFIXED_MASK ) \
123 ENTRY( O_SP, "o:sp", DUPFIXED_MASK ) \
124 ENTRY( PO_S, "po:s", DUPFIXED_MASK ) \
125 ENTRY( SO_P, "so:p", DUPFIXED_MASK ) \
126 ENTRY( SP_O, "sp:o", DUPFIXED_MASK ) \
127 ENTRY( C_SPO, "c:spo", DUPFIXED_MASK ) \
132#define ENTRY(a, b, c) static const DbLabel DB_##a = b;
144#define ENTRY(a, b, c) IDX_##a,
153static const char *db_labels[
N_DB] = {
154#define ENTRY(a, b, c) DB_##a,
163static const unsigned int db_flags[
N_DB] = {
164#define ENTRY(a, b, c) c,
176static DBIdx lookup_indices[9] = {
177#define ENTRY(a, b, c) IDX_##a,
182static const uint8_t lookup_ordering_1bound[3][3] = {
188static const uint8_t lookup_ordering_2bound[3][3] = {
198static int index_triple(
204inline static VOLK_rc lookup_1bound (
206inline static VOLK_rc lookup_2bound (
207 uint8_t idx0, uint8_t idx1,
MDBIterator *it,
size_t *ct);
212mdbstore_path_from_id (
const char *
id)
215 if (!
id)
id = getenv (
"VOLK_MDB_STORE_URN");
219 "`VOLK_MDB_STORE_URN' environment variable is not "
220 "set. The default URN %s has been set as the store ID.",
id
222 }
else if (strncmp (
"file://",
id, 7) != 0) {
223 log_error (
"MDB store ID must be in the `file://<abs_path>` format.");
237txn_begin (MDB_env *env, MDB_txn *p,
unsigned int f, MDB_txn **tp) {
238 VOLK_rc rc = mdb_txn_begin (env, p, f, tp);
240 mdb_env_get_path (env, &path);
242 "BEGIN %s transaction %p child of %p in env %s",
243 f == 0 ?
"RW" :
"RO", *tp, p, path);
249txn_commit (MDB_txn *t) {
251 return mdb_txn_commit (t);
266mdbstore_setup (
const char *
id,
bool clear)
270 const char *path = mdbstore_path_from_id (
id);
274 if (clear)
rm_r (path);
281 RCCK (mdb_env_create (&env));
283 RCCK (mdb_env_set_maxdbs (env,
N_DB));
285 LOG_DEBUG(
"Environment opened at %s.", path);
288 RCCK (txn_begin (env, NULL, 0, &txn));
290 for (
int i = 0; i <
N_DB; i++) {
291 LOG_TRACE(
"Creating DB %s", db_labels[i]);
293 mdb_dbi_open (txn, db_labels[i], db_flags[i] | MDB_CREATE, &dbi)
299 CHECK (mdb_dbi_open (
300 txn, db_labels[IDX_T_ST], db_flags[IDX_T_ST], &dbi), fail);
301 CHECK (mdb_stat (txn, dbi, &stat), fail);
303 if (stat.ms_entries == 0) {
304 LOG_DEBUG (
"Loading initial data into %s", path);
307 CHECK (mdb_cursor_open (txn, dbi, &cur), fail);
311 key.mv_size =
sizeof (k);
316 VOLK_rc db_rc = mdb_cursor_put (cur, &key, &data, 0);
320 CHECK (txn_commit (txn), fail);
343mdbstore_new (
const char *
id,
size_t _unused)
351 const char *path = mdbstore_path_from_id (
id);
352 if (!path)
return NULL;
357 RCNL (mdb_env_create (&store->
env));
362 char *env_mapsize = getenv (
"VOLK_MDB_MAPSIZE");
364 else sscanf (env_mapsize,
"%zu", &mapsize);
366 "Setting environment map size at %s to %zu Mb.",
367 path, mapsize / 1024 / 1024);
368 CHECK (mdb_env_set_mapsize (store->
env, mapsize), fail);
373 CHECK (txn_begin (store->
env, NULL, 0, &txn), fail);
374 for (
int i = 0; i <
N_DB; i++)
375 CHECK (mdb_dbi_open (
376 txn, db_labels[i], db_flags[i], store->
dbi + i), fail);
379 CHECK (txn_commit(txn), fail);
382 log_info (
"Created environment at %s", path);
387 if (txn) mdb_txn_abort (txn);
388 mdb_env_close (store->
env);
395mdbstore_free (
void *h)
400 mdb_env_get_path (store->
env, &path);
401 log_info (
"Closing MDB env at %s.", path);
402 mdb_env_close (store->
env);
410mdbstore_stat (
const MDBStore *store, MDB_stat *stat)
415 RCCK (txn_begin (store->
env, NULL, MDB_RDONLY, &txn));
417 if (mdb_stat (txn, store->
dbi[IDX_SPO_C], stat) != MDB_SUCCESS)
426mdbstore_size (
const void *h)
432 if (mdbstore_stat (store, &stat) !=
VOLK_OK)
return 0;
434 return stat.ms_entries;
444 RCNL (mdb_env_get_path (store->
env, &path));
446 char *
id = malloc (strlen (path) + 8);
447 sprintf (
id,
"file://%s", path);
454mdbstore_txn_begin (
void *h,
int flags,
void **th)
458 RCCK (txn_begin (store->
env, NULL, flags, (MDB_txn **) th));
465mdbstore_txn_commit (
void *th)
467 RCCK (txn_commit ((MDB_txn *) th));
474mdbstore_txn_abort (
void *th)
475{ mdb_txn_abort ((MDB_txn *) th); }
494mdbstore_add_init (
void *h,
const VOLK_Buffer *sc,
void *th)
506 CHECK (txn_begin (store->
env, (MDB_txn *) th, 0, &it->
txn), fail);
514 it->
key.mv_data = &it->
luc;
519 int db_rc = mdb_put (
521 &it->
key, &it->
data, MDB_NOOVERWRITE);
522 if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
524 mdb_txn_abort (it->
txn);
528 LOG_DEBUG(
"No context passed to iterator, using default.");
557 for (
int i = 0; i < 3; i++) {
562 it->
key.mv_data = spok + i;
569 &it->
key, &it->
data, MDB_NOOVERWRITE);
570 if (db_rc != MDB_SUCCESS && db_rc != MDB_KEYEXIST) {
576 LOG_TRACE(
"Inserting spok: {%lx, %lx, %lx}", spok[0], spok[1], spok[2]);
580 it->
key.mv_data = spok;
589 &it->
key, &it->
data, MDB_NODUPDATA);
592 if (db_rc != MDB_SUCCESS) {
594 "MDB error while inserting triple: %s",
VOLK_strerror(db_rc));
607mdbstore_add_done (
void *h)
611 log_debug (
"Committing add transaction.");
613 if (txn_commit (it->
txn) != MDB_SUCCESS) {
614 mdb_txn_abort (it->
txn);
626mdbstore_add_abort (
void *h)
629 mdb_txn_abort (it->
txn);
642 MDB_val key_v, data_v;
643 key_v.mv_data = (
void*)&key;
644 key_v.mv_size =
KLEN;
646 db_rc = mdb_get (txn, store->
dbi[IDX_T_ST], &key_v, &data_v);
649 if (db_rc == MDB_SUCCESS) {
650 sterm->
addr = data_v.mv_data;
651 sterm->
size = data_v.mv_size;
653 }
else if (db_rc == MDB_NOTFOUND) {
684 if (th) it->
txn = th;
687 it->
rc = txn_begin (it->
store->
env, NULL, MDB_RDONLY, &it->
txn);
688 if (it->
rc != MDB_SUCCESS) {
706 it->
luk[0] = spok[0];
707 it->
luk[1] = spok[1];
708 it->
luk[2] = spok[2];
709 PRCNL (lookup_3bound (it, ct));
712 it->
luk[0] = spok[0];
717 it->
luk[1] = spok[1];
719 PRCNL (lookup_2bound (idx0, idx1, it, ct));
723 it->
luk[1] = spok[2];
725 PRCNL (lookup_2bound (idx0, idx1, it, ct));
728 }
else PRCNL (lookup_1bound (idx0, it, ct));
731 it->
luk[0] = spok[1];
736 it->
luk[1] = spok[2];
738 PRCNL (lookup_2bound (idx0, idx1, it, ct));
741 }
else PRCNL (lookup_1bound (idx0, it, ct));
745 it->
luk[0] = spok[2];
747 PRCNL (lookup_1bound (idx0, it, ct));
750 }
else PRCNL (lookup_0bound (it, ct));
784 data.mv_data = &it->
luc;
798 "Found spok: {%lx, %lx, %lx}",
801 key.mv_data = it->
spok;
803 db_rc = mdb_cursor_get (it->
ctx_cur, &key, &data, MDB_GET_BOTH);
805 if (db_rc == MDB_SUCCESS) {
809 }
else if (db_rc == MDB_NOTFOUND) {
822 "Found spok in any context: {%lx, %lx, %lx}",
829 key.mv_data = it->
spok;
830 db_rc = mdb_cursor_get (it->
ctx_cur, &key, &data, MDB_SET_KEY);
831 if (db_rc != MDB_SUCCESS) {
832 log_error (
"No context found for triple!");
837 db_rc = mdb_cursor_count (it->
ctx_cur, &ct);
840 VOLK_Key *tmp_ck = realloc (it->
ck, sizeof (*it->
ck) * (ct + 1));
847 memcpy (it->
ck + i++, data.mv_data, sizeof (*it->
ck));
849 mdb_cursor_get (it->
ctx_cur, &key, &data, MDB_NEXT_DUP)
863 VOLK_rc rc = mdbiter_next_key (it);
880 LOG_TRACE(
"Allocating %lu context buffers + sentinel.", i - 1);
881 ctx = malloc(i *
sizeof (*ctx));
884 for (i = 0; it->
ck[i]; i++)
885 key_to_sterm (it->
store, it->
txn, it->
ck[i], ctx + i);
886 memset (ctx + i, 0,
sizeof (*ctx));
898mdbiter_free (
void *h)
903 if (it->
cur) mdb_cursor_close (it->
cur);
918 unsigned char *trp_data = NULL;
928 CHECK (rc = txn_begin (store->
env, p_txn, 0, &txn),
finally);
930 MDB_cursor *i_cur, *d_cur;
932 rc = mdb_cursor_open (txn, store->
dbi[IDX_C_SPO], &i_cur),
939 key.mv_data = &new_ck;
941 rc = mdb_cursor_get (i_cur, &key, &data, MDB_FIRST_DUP);
942 if (rc == MDB_SUCCESS) {
944 "Context key %lu already exists. Not replacing old graph.",
951 CHECK (rc = mdbstore_add_term (store, new_c, txn), close_i);
953 key.mv_data = &old_ck;
955 rc = mdb_cursor_get (i_cur, &key, &data, MDB_SET);
956 if (rc == MDB_NOTFOUND) {
957 log_info (
"No triples found associated with old context.");
961 if (rc != MDB_SUCCESS) {
969 CHECK (rc = mdb_cursor_count (i_cur, &trp_ct), close_i);
970 trp_data = malloc (trp_ct *
TRP_KLEN);
978 rc = mdb_cursor_get (i_cur, &key, &data, MDB_GET_MULTIPLE);
979 if (rc != MDB_SUCCESS) {
985 memcpy (trp_data + loc_cur, data.mv_data, data.mv_size);
986 loc_cur += data.mv_size;
987 }
while (mdb_cursor_get (
988 i_cur, &key, &data, MDB_NEXT_MULTIPLE) == MDB_SUCCESS);
991 key.mv_data = &old_ck;
994 CHECK (rc = mdb_cursor_get (i_cur, &key, NULL, MDB_SET), close_i);
995 CHECK (rc = mdb_cursor_del (i_cur, MDB_NODUPDATA), close_i);
998 key.mv_data = &new_ck;
999 for (
size_t i = 0; i < trp_ct; i++) {
1000 data.mv_data = trp_data + i * data.mv_size;
1002 rc = mdb_cursor_put (i_cur, &key, &data, MDB_APPENDDUP),
1017 CHECK (rc = mdb_cursor_open (txn, store->
dbi[IDX_SPO_C], &d_cur), close_i);
1019 data.mv_size =
KLEN;
1020 for (
size_t i = 0; i < trp_ct; i++) {
1021 key.mv_data = trp_data + i * key.mv_size;
1022 data.mv_data = &old_ck;
1024 rc = mdb_cursor_get (d_cur, &key, &data, MDB_GET_BOTH),
1026 CHECK (rc = mdb_cursor_del (d_cur, 0), close_d);
1027 data.mv_data = &new_ck;
1029 rc = mdb_cursor_put (d_cur, &key, &data, MDB_NOOVERWRITE),
1034 mdb_cursor_close (d_cur);
1036 mdb_cursor_close (i_cur);
1039 else mdb_txn_abort (txn);
1041 if (trp_data) free (trp_data);
1064 RCCK (txn_begin (store->
env, (MDB_txn *) th, 0, &txn));
1066 MDB_cursor *dcur, *icur;
1067 mdb_cursor_open (txn, store->
dbi[IDX_SPO_C], &dcur);
1068 mdb_cursor_open (txn, store->
dbi[IDX_C_SPO], &icur);
1070 MDB_val spok_v, ck_v;
1073 ck_v.mv_size =
KLEN;
1077 MDBIterator *it = mdbstore_lookup (store, ss, sp, so, sc, txn, ct);
1079 if (ct) {
LOG_DEBUG(
"Found %lu triples to remove.", *ct);}
1081 while (mdbiter_next_key (it) ==
VOLK_OK) {
1082 spok_v.mv_data = it->
spok;
1084 db_rc = mdb_cursor_get (dcur, &spok_v, &ck_v, MDB_GET_BOTH);
1085 if (db_rc == MDB_NOTFOUND)
continue;
1086 if (
UNLIKELY (db_rc != MDB_SUCCESS))
goto fail;
1089 "Removing {%lx, %lx, %lx}",
1093 db_rc = mdb_cursor_del (dcur, 0);
1094 if (
UNLIKELY (db_rc != MDB_SUCCESS))
goto fail;
1097 spok_v.mv_data = it->
spok;
1101 db_rc = mdb_cursor_get (icur, &ck_v, &spok_v, MDB_GET_BOTH);
1102 if (db_rc == MDB_NOTFOUND)
continue;
1103 if (
UNLIKELY (db_rc != MDB_SUCCESS))
goto fail;
1105 db_rc = mdb_cursor_del (icur, 0);
1106 if (
UNLIKELY (db_rc != MDB_SUCCESS))
goto fail;
1108 spok_v.mv_data = it->
spok;
1113 db_rc = mdb_cursor_get (dcur, &spok_v, NULL, MDB_SET);
1114 if (db_rc == MDB_SUCCESS)
continue;
1115 if (
UNLIKELY (db_rc != MDB_NOTFOUND))
goto fail;
1122 if (
UNLIKELY (txn_commit (txn) != MDB_SUCCESS)) {
1130 mdb_txn_abort (txn);
1144 key.mv_data = &tkey;
1147 MDB_txn *txn = NULL;
1148 txn_begin (store->
env, NULL, MDB_RDONLY, &txn);
1150 MDB_cursor *cur = NULL;
1151 mdb_cursor_open (txn, store->
dbi[IDX_T_ST], &cur);
1153 db_rc = mdb_cursor_get (cur, &key, &data, MDB_SET);
1155 if (db_rc == MDB_SUCCESS) rc = 1;
1156 else if (db_rc == MDB_NOTFOUND) rc = 0;
1162 if (cur) mdb_cursor_close (cur);
1163 if (txn) mdb_txn_abort (txn);
1182mdbstore_add_term (
void *h,
const VOLK_Buffer *sterm,
void *th)
1192 bool borrowed_txn = (th != NULL);
1193 if (borrowed_txn) txn = th;
1194 else RCCK (txn_begin (store->
env, NULL, 0, &txn));
1197 CHECK (mdb_cursor_open (txn, store->
dbi[IDX_T_ST], &cur), fail);
1201 key.mv_size =
sizeof (k);
1203 data.mv_data = sterm->
addr;
1204 data.mv_size = sterm->
size;
1206 db_rc = mdb_cursor_put (cur, &key, &data, MDB_NOOVERWRITE);
1207 if (db_rc != MDB_KEYEXIST)
CHECK (db_rc, fail);
1209 if (!borrowed_txn)
CHECK (db_rc = txn_commit (txn), fail);
1214 if (!borrowed_txn) mdb_txn_abort (txn);
1215 LOG_TRACE(
"Aborted txn for adding term.");
1228 else CHECK (txn_begin (store->
env, NULL, MDB_RDONLY, &txn), fail);
1232 CHECK (mdb_cursor_open (txn, store->
dbi[IDX_C_SPO], &cur), fail);
1234 db_rc = mdb_cursor_get (cur, &key, &data, MDB_FIRST);
1237 while (db_rc == MDB_SUCCESS) {
1238 tdata = realloc (tdata, (i + 1) *
sizeof (*tdata));
1242 CHECK (key_to_sterm (store, txn, tkey, tdata[i]), fail);
1243 db_rc = mdb_cursor_get (cur, &key, &data, MDB_NEXT_NODUP);
1247 tdata = realloc (tdata, i *
sizeof (data));
1249 mdb_cursor_close (cur);
1250 if (txn != th && txn != NULL) mdb_txn_abort (txn);
1255 if (txn != th && txn != NULL) mdb_txn_abort (txn);
1256 if (tdata) free (tdata);
1262 .name =
"MDB Store",
1266 .setup_fn = mdbstore_setup,
1267 .new_fn = mdbstore_new,
1268 .free_fn = mdbstore_free,
1270 .size_fn = mdbstore_size,
1273 .txn_begin_fn = mdbstore_txn_begin,
1274 .txn_commit_fn = mdbstore_txn_commit,
1275 .txn_abort_fn = mdbstore_txn_abort,
1276 .iter_txn_fn = mdbiter_txn,
1278 .add_init_fn = mdbstore_add_init,
1279 .add_iter_fn = mdbstore_add_iter,
1280 .add_abort_fn = mdbstore_add_abort,
1281 .add_done_fn = mdbstore_add_done,
1282 .add_term_fn = mdbstore_add_term,
1284 .update_ctx_fn = mdbstore_update_ctx,
1286 .lookup_fn = mdbstore_lookup,
1287 .lu_next_fn = mdbiter_next,
1288 .lu_free_fn = mdbiter_free,
1290 .remove_fn = mdbstore_remove,
1316 LOG_TRACE(
"Indexing triple: {%lx %lx %lx}", spok[0], spok[1], spok[2]);
1329 mdb_cursor_open (txn, store->
dbi[IDX_C_SPO], &cur);
1330 if (mdb_cursor_get (cur, &v1, &v2, MDB_GET_BOTH) == MDB_SUCCESS) {
1331 db_rc = mdb_cursor_del (cur, 0);
1337 mdb_cursor_close (cur);
1340 }
else if (op ==
OP_ADD) {
1349 txn, store->
dbi[IDX_C_SPO],
1350 &v1, &v2, MDB_NODUPDATA);
1352 if (db_rc != MDB_KEYEXIST) rc =
VOLK_OK;
1367 for (
int i = 0; i < 3; i++) {
1368 MDB_dbi db1 = store->
dbi[lookup_indices[i]];
1369 MDB_dbi db2 = store->
dbi[lookup_indices[i + 3]];
1371 v1.mv_data = spok + i;
1372 v2.mv_data = dbl_keys[i];
1375 MDB_cursor *cur1, *cur2;
1376 mdb_cursor_open(txn, store->
dbi[lookup_indices[i]], &cur1);
1378 db_rc = mdb_cursor_get (cur1, &v1, &v2, MDB_GET_BOTH);
1379 if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur1, 0);
1381 mdb_cursor_close (cur1);
1384 v1.mv_data = spok + i;
1385 v2.mv_data = dbl_keys[i];
1387 mdb_cursor_open(txn, store->
dbi[lookup_indices[i + 3]], &cur2);
1389 db_rc = mdb_cursor_get (cur2, &v2, &v1, MDB_GET_BOTH);
1390 if (db_rc == MDB_SUCCESS) mdb_cursor_del (cur2, 0);
1394 mdb_cursor_close (cur2);
1398 LOG_TRACE(
"Indexing in %s: ", db_labels[lookup_indices[i]]);
1400 "%lx: %lx %lx", *(
size_t*)(v1.mv_data),
1401 *(
size_t*)(v2.mv_data), *(
size_t*)(v2.mv_data) + 1);
1403 db_rc = mdb_put (txn, db1, &v1, &v2, MDB_NODUPDATA);
1405 if (db_rc == MDB_SUCCESS) rc =
VOLK_OK;
1406 else if (db_rc != MDB_KEYEXIST)
return VOLK_DB_ERR;
1409 LOG_TRACE(
"Indexing in %s: ", db_labels[lookup_indices[i + 3]]);
1411 "%lx %lx: %lx", *(
size_t*)(v2.mv_data),
1412 *(
size_t*)(v2.mv_data) + 1, *(
size_t*)(v1.mv_data));
1414 db_rc = mdb_put (txn, db2, &v2, &v1, MDB_NODUPDATA);
1416 if (db_rc == MDB_SUCCESS) rc =
VOLK_OK;
1417 else if (db_rc != MDB_KEYEXIST)
return VOLK_DB_ERR;
1436 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_NEXT);
1456 "Composed triple: {%lx %lx %lx}",
1470 it->
rc = mdb_cursor_get (
1471 it->
cur, &it->
key, &it->
data, MDB_NEXT_MULTIPLE);
1492 if (it->
i < it->
data.mv_size /
KLEN - 1)
1498 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_NEXT_MULTIPLE);
1511{ it->
rc = MDB_NOTFOUND; }
1524 it->
rc = mdb_cursor_open (
1527 it->
key.mv_data = &it->
luc;
1530 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_SET);
1531 if (it->
rc == MDB_SUCCESS) mdb_cursor_count (it->
cur, ct);
1533 mdb_cursor_close (it->
cur);
1539 mdb_stat (it->
txn, it->
store->
dbi[IDX_S_PO], &stat);
1541 *ct = stat.ms_entries;
1547 if (it->
rc != MDB_SUCCESS) {
1552 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_FIRST);
1560 if (it->
rc != MDB_SUCCESS && it->
rc != MDB_NOTFOUND) {
1570lookup_1bound (uint8_t idx0,
MDBIterator *it,
size_t *ct)
1572 it->
term_order = (
const uint8_t*)lookup_ordering_1bound[idx0];
1576 mdb_cursor_open (it->
txn, it->
store->
dbi[lookup_indices[idx0]], &it->
cur);
1578 it->
key.mv_data = it->
luk;
1598 ct_it->
luk[0] = it->
luk[0];
1602 VOLK_rc rc = lookup_1bound (idx0, ct_it, NULL);
1603 if (rc < 0)
return rc;
1606 while (
VOLK_END != (db_rc = mdbiter_next_key (ct_it))) {
1607 if (
UNLIKELY (db_rc < 0))
return db_rc;
1612 if (ct_it->
cur) mdb_cursor_close (ct_it->
cur);
1617 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_SET);
1618 if (it->
rc == MDB_SUCCESS) mdb_cursor_count (it->
cur, ct);
1626 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_SET);
1627 if (it->
rc == MDB_SUCCESS)
1628 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_GET_MULTIPLE);
1630 if (it->
rc != MDB_SUCCESS && it->
rc != MDB_NOTFOUND) {
1640lookup_2bound(uint8_t idx0, uint8_t idx1,
MDBIterator *it,
size_t *ct)
1642 uint8_t luk1_offset, luk2_offset;
1646 for (
int i = 0; i < 3; i++) {
1649 idx0 == lookup_ordering_2bound[i][0] &&
1650 idx1 == lookup_ordering_2bound[i][1]
1652 idx0 == lookup_ordering_2bound[i][1] &&
1653 idx1 == lookup_ordering_2bound[i][0]
1656 it->
term_order = (
const uint8_t*)lookup_ordering_2bound[i];
1664 dbi = it->
store->
dbi[lookup_indices[i + 3]];
1666 "Looking up 2 bound in %s",
1667 db_labels[lookup_indices[i + 3]]);
1675 "Values %d and %d not found in lookup keys.",
1682 luk[luk1_offset] = it->
luk[0];
1683 luk[luk2_offset] = it->
luk[1];
1685 it->
key.mv_data = luk;
1688 mdb_cursor_open (it->
txn, dbi, &it->
cur);
1689 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_SET);
1702 ct_it->
luk[0] = it->
luk[0];
1703 ct_it->
luk[1] = it->
luk[1];
1707 lookup_2bound (idx0, idx1, ct_it, NULL);
1709 while (mdbiter_next_key (ct_it) !=
VOLK_END) (*ct) ++;
1712 if (ct_it->
cur) mdb_cursor_close (ct_it->
cur);
1717 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_SET);
1718 if (it->
rc == MDB_SUCCESS) mdb_cursor_count (it->
cur, ct);
1726 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_SET);
1727 if (it->
rc == MDB_SUCCESS)
1728 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_GET_MULTIPLE);
1730 if (it->
rc != MDB_SUCCESS && it->
rc != MDB_NOTFOUND) {
1743 "Looking up 3 bound: {%lx, %lx, %lx}",
1746 it->
key.mv_data = it->
luk;
1749 it->
rc = mdb_cursor_open (
1760 it->
data.mv_data = it->
luk + 1;
1764 it->
rc = mdb_cursor_get (it->
cur, &it->
key, &it->
data, MDB_GET_BOTH);
1766 if (it->
rc != MDB_SUCCESS && it->
rc != MDB_NOTFOUND) {
1771 mdb_cursor_close (it->
cur);
1774 if (ct && it->
rc == MDB_SUCCESS) *ct = 1;
#define NULL_KEY
"NULL" key, a value that is never user-provided.
VOLK_Key VOLK_buffer_hash(const VOLK_Buffer *buf)
Hash a buffer.
VOLK_Buffer * VOLK_btriple_pos(const VOLK_BufferTriple *trp, VOLK_TriplePos n)
Get serialized triple by term position.
VOLK_Buffer * VOLK_default_ctx_buf
Serialized default context.
#define BUF_DUMMY
Dummy buffer to be used with VOLK_buffer_init.
#define NULL_TRP
"NULL" triple, a value that is never user-provided.
bool VOLK_env_is_init
Whether the environment is initialized.
#define MALLOC_GUARD(var, rc)
Allocate one pointer with malloc and return rc if it fails.
#define RCNL(exp)
Return NULL if exp returns a nonzero value.
#define PRCNL(exp)
Return NULL if exp returns a negative value (=error).
#define CHECK(exp, marker)
Jump to marker if exp does not return VOLK_OK.
#define CALLOC_GUARD(var, rc)
Allocate one pointer with calloc and return rc if it fails.
VOLK_rc rm_r(const char *path)
Remove a directory recursively (POSIX compatible).
#define RCCK(exp)
Return exp return value if it is of VOLK_rc type and nonzero.
VOLK_rc mkdir_p(const char *_path, mode_t mode)
Make recursive directories.
#define LOG_RC(rc)
Log an error or warning for return codes that are not VOLK_OK.
#define PRCCK(exp)
Return exp return value if it is of VOLK_rc type and negative (=error).
size_t VOLK_Key
Term key, i.e., hash of a serialized term.
VOLK_Key VOLK_TripleKey[3]
Array of three VOLK_Key values, representing a triple.
VOLK_Key VOLK_DoubleKey[2]
Array of two VOLK_Key values.
#define VOLK_VALUE_ERR
An invalid input value was provided.
#define VOLK_MEM_ERR
Memory allocation error.
#define VOLK_NORESULT
No result yielded.
#define VOLK_DB_ERR
Low-level database error.
#define VOLK_CONFLICT
Conflict warning.
#define VOLK_END
Loop end.
#define VOLK_OK
Generic success return code.
#define VOLK_NOACTION
No action taken.
#define VOLK_ENV_ERR
Error while handling environment setup; or environment not initialized.
#define VOLK_TXN_ERR
Error handling a store transaction.
const char * VOLK_strerror(VOLK_rc rc)
Return an error message for a return code.
@ VOLK_STORE_TXN
Supports transaction handling.
@ VOLK_STORE_COW
Copy on write.
@ VOLK_STORE_IDX
Store is fully SPO(C)-indexed.
VOLK_Buffer ** mdbstore_ctx_list(void *h, void *th)
StoreFlags
Store state flags.
@ LSSTORE_OPEN
Env is open.
const VOLK_StoreInt mdbstore_int
MDB store interface.
char * mdbstore_id(const void *h)
void(* iter_op_fn_t)(MDBIterator *it)
Iterator operation.
IterFlags
Iterator state flags.
LMDB graph store backend.
#define VOLK_MDB_STORE_URN
Default MDB store identifier and location.
MDB_cursor * ctx_cur
MDB c:spo index cursor.
VOLK_TripleKey spok
Triple to be populated with match.
VOLK_Key luk[3]
0รท3 lookup keys.
MDB_cursor * cur
MDB cursor.
const uint8_t * term_order
Term order used in 1-2bound look-ups.
MDBStore * store
MDB store handle.
IterFlags flags
Iterator flags.
MDB_txn * txn
MDB transaction.
VOLK_Key luc
Ctx key to filter by. May be NULL_KEY.
size_t i
Internal counter for paged lookups.
iter_op_fn_t iter_op_fn
Function used to look up next match.
MDB_val key
Internal data handler.
int rc
MDB_* return code for the next result.
MDB_val data
Internal data handler.
StoreFlags flags
Store state flags.
MDB_env * env
Environment handle.
MDB_dbi dbi[N_DB]
DB handles. Refer to DbIdx enum.
General-purpose data buffer.