217 #include <sys/stat.h>
258 #if MDB_VERSION_FULL < MDB_VERINT(0, 9, 11)
259 #error "This Postfix version requires LMDB version 0.9.11 or later"
285 #define SLMDB_DEF_API_RETRY_LIMIT 30
286 #define SLMDB_DEF_BULK_RETRY_LIMIT \
287 (2 * sizeof(size_t) * CHAR_BIT)
294 #define SLMDB_API_RETURN(slmdb, status) do { \
295 (slmdb)->api_retry_count = 0; \
308 static void slmdb_cursor_close(
SLMDB *slmdb)
316 txn = mdb_cursor_txn(slmdb->
cursor);
317 mdb_cursor_close(slmdb->
cursor);
324 static void slmdb_saved_key_init(
SLMDB *slmdb)
333 static void slmdb_saved_key_free(
SLMDB *slmdb)
336 slmdb_saved_key_init(slmdb);
339 #define HAVE_SLMDB_SAVED_KEY(s) ((s)->saved_key.mv_data != 0)
343 static int slmdb_saved_key_assign(
SLMDB *slmdb, MDB_val *key_val)
352 slmdb->
saved_key.mv_data = malloc(key_val->mv_size);
355 realloc(slmdb->
saved_key.mv_data, key_val->mv_size);
357 slmdb_saved_key_init(slmdb);
367 memcpy(slmdb->
saved_key.mv_data, key_val->mv_data, key_val->mv_size);
368 slmdb->
saved_key.mv_size = key_val->mv_size;
374 static int slmdb_prepare(
SLMDB *slmdb)
389 if ((status = mdb_drop(slmdb->
txn, slmdb->
dbi, 0)) != 0)
392 if ((status = mdb_txn_commit(slmdb->
txn)) != 0)
396 }
else if ((slmdb->
lmdb_flags & MDB_RDONLY) != 0
398 mdb_txn_abort(slmdb->
txn);
407 static int slmdb_recover(
SLMDB *slmdb,
int status)
416 slmdb_cursor_close(slmdb);
468 case MDB_MAP_RESIZED:
469 if ((status = mdb_env_set_mapsize(slmdb->
env, 0)) == 0) {
471 mdb_env_info(slmdb->
env, &info);
484 case MDB_READERS_FULL:
508 if ((status = mdb_txn_begin(slmdb->
env, (MDB_txn *) 0,
511 && (status = slmdb_prepare(slmdb)) == 0)
519 static int slmdb_txn_begin(
SLMDB *slmdb,
int rdonly, MDB_txn **txn)
523 if ((status = mdb_txn_begin(slmdb->
env, (MDB_txn *) 0, rdonly, txn)) != 0
524 && (status = slmdb_recover(slmdb, status)) == 0)
525 status = slmdb_txn_begin(slmdb, rdonly, txn);
542 else if ((status = slmdb_txn_begin(slmdb, MDB_RDONLY, &txn)) != 0)
543 SLMDB_API_RETURN(slmdb, status);
548 if ((status = mdb_get(txn, slmdb->
dbi, mdb_key, mdb_value)) != 0
549 && status != MDB_NOTFOUND) {
551 if ((status = slmdb_recover(slmdb, status)) == 0)
552 status =
slmdb_get(slmdb, mdb_key, mdb_value);
553 SLMDB_API_RETURN(slmdb, status);
562 SLMDB_API_RETURN(slmdb, status);
568 MDB_val *mdb_value,
int flags)
578 else if ((status = slmdb_txn_begin(slmdb, 0, &txn)) != 0)
579 SLMDB_API_RETURN(slmdb, status);
584 if ((status = mdb_put(txn, slmdb->
dbi, mdb_key, mdb_value, flags)) != 0) {
586 if (status != MDB_KEYEXIST) {
587 if ((status = slmdb_recover(slmdb, status)) == 0)
588 status =
slmdb_put(slmdb, mdb_key, mdb_value, flags);
589 SLMDB_API_RETURN(slmdb, status);
596 if (status == 0 && slmdb->
txn == 0 && (status = mdb_txn_commit(txn)) != 0
597 && (status = slmdb_recover(slmdb, status)) == 0)
598 status =
slmdb_put(slmdb, mdb_key, mdb_value, flags);
600 SLMDB_API_RETURN(slmdb, status);
615 else if ((status = slmdb_txn_begin(slmdb, 0, &txn)) != 0)
616 SLMDB_API_RETURN(slmdb, status);
621 if ((status = mdb_del(txn, slmdb->
dbi, mdb_key, (MDB_val *) 0)) != 0) {
623 if (status != MDB_NOTFOUND) {
624 if ((status = slmdb_recover(slmdb, status)) == 0)
626 SLMDB_API_RETURN(slmdb, status);
633 if (status == 0 && slmdb->
txn == 0 && (status = mdb_txn_commit(txn)) != 0
634 && (status = slmdb_recover(slmdb, status)) == 0)
637 SLMDB_API_RETURN(slmdb, status);
643 MDB_val *mdb_value, MDB_cursor_op op)
652 if ((status = slmdb_txn_begin(slmdb, MDB_RDONLY, &txn)) != 0)
653 SLMDB_API_RETURN(slmdb, status);
654 if ((status = mdb_cursor_open(txn, slmdb->
dbi, &slmdb->
cursor)) != 0) {
656 if ((status = slmdb_recover(slmdb, status)) == 0)
658 SLMDB_API_RETURN(slmdb, status);
664 if (HAVE_SLMDB_SAVED_KEY(slmdb) && op != MDB_FIRST)
666 (MDB_val *) 0, MDB_SET);
673 status = mdb_cursor_get(slmdb->
cursor, mdb_key, mdb_value, op);
683 status = slmdb_saved_key_assign(slmdb, mdb_key);
685 slmdb_cursor_close(slmdb);
693 if (status == MDB_NOTFOUND) {
694 slmdb_cursor_close(slmdb);
695 if (HAVE_SLMDB_SAVED_KEY(slmdb))
696 slmdb_saved_key_free(slmdb);
698 slmdb_cursor_close(slmdb);
699 if ((status = slmdb_recover(slmdb, status)) == 0)
701 SLMDB_API_RETURN(slmdb, status);
705 SLMDB_API_RETURN(slmdb, status);
710 static void slmdb_assert_cb(MDB_env *env,
const char *text)
712 SLMDB *slmdb = (
SLMDB *) mdb_env_get_userctx(env);
728 for (reqno = first; status == 0 && reqno !=
SLMDB_CTL_END; reqno = va_arg(ap,
int)) {
738 if ((rc = mdb_env_set_userctx(slmdb->
env, (
void *) slmdb)) != 0
739 || (rc = mdb_env_set_assert(slmdb->
env, slmdb_assert_cb)) != 0)
752 status = errno = EINVAL;
771 && (status = mdb_txn_commit(slmdb->
txn)) != 0)
772 status = slmdb_recover(slmdb, status);
778 slmdb_cursor_close(slmdb);
780 mdb_env_close(slmdb->
env);
785 if (HAVE_SLMDB_SAVED_KEY(slmdb))
786 slmdb_saved_key_free(slmdb);
788 SLMDB_API_RETURN(slmdb, status);
805 return (MDB_SUCCESS);
811 int lmdb_flags,
int slmdb_flags)
823 if ((status = mdb_env_create(&env)) != 0)
831 #define SLMDB_FUDGE 10240
835 if (
stat(path, &st) == 0
836 && st.st_size > slmdb->
curr_limit - SLMDB_FUDGE) {
839 if (st.st_size < slmdb->
hard_limit - SLMDB_FUDGE)
850 if ((status = mdb_env_set_mapsize(env, slmdb->
curr_limit)) != 0
851 || (status = mdb_env_open(env, path, lmdb_flags, 0644)) != 0
852 || (status = mdb_txn_begin(env, (MDB_txn *) 0,
853 lmdb_flags & MDB_RDONLY, &txn)) != 0
854 || (status = mdb_open(txn, (
const char *) 0, 0, &dbi)) != 0
855 || (status = mdb_env_get_fd(env, &db_fd)) != 0) {
868 slmdb->
db_fd = db_fd;
870 slmdb_saved_key_init(slmdb);
881 if ((status = slmdb_prepare(slmdb)) != 0)
void(* SLMDB_NOTIFY_FN)(void *, int,...)
int slmdb_del(SLMDB *, MDB_val *)
int slmdb_init(SLMDB *, size_t, int, size_t)
int slmdb_get(SLMDB *, MDB_val *, MDB_val *)
#define SLMDB_CTL_ASSERT_FN
void(* longjmp_fn)(void *, int)
#define SLMDB_CTL_API_RETRY_LIMIT
#define SLMDB_CTL_NOTIFY_FN
#define SLMDB_CTL_BULK_RETRY_LIMIT
void(* notify_fn)(void *, int,...)
#define SLMDB_CTL_CB_CONTEXT
void(* SLMDB_LONGJMP_FN)(void *, int)
int slmdb_cursor_get(SLMDB *, MDB_val *, MDB_val *, MDB_cursor_op)
void(* assert_fn)(void *, const char *)
#define SLMDB_CTL_LONGJMP_FN
int slmdb_open(SLMDB *, const char *, int, int, int)
void(* SLMDB_ASSERT_FN)(void *, const char *)
int slmdb_control(SLMDB *, int,...)
int slmdb_put(SLMDB *, MDB_val *, MDB_val *, int)