diff --git a/mdbx/mdbx.c b/mdbx/mdbx.c index 15b73de..e72f31a 100644 --- a/mdbx/mdbx.c +++ b/mdbx/mdbx.c @@ -3,7 +3,7 @@ #define xMDBX_ALLOY 1 /* alloyed build */ -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS @@ -5103,6 +5103,9 @@ MDBX_INTERNAL int dbi_open(MDBX_txn *txn, const MDBX_val *const name, MDBX_INTERNAL int dbi_bind(MDBX_txn *txn, const size_t dbi, unsigned user_flags, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp); +MDBX_INTERNAL const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, + tree_t *fallback); + @@ -10355,28 +10358,24 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -__cold static tree_t *audit_db_dig(const MDBX_txn *txn, const size_t dbi, - tree_t *fallback) { - const MDBX_txn *dig = txn; - do { - tASSERT(txn, txn->n_dbi == dig->n_dbi); - const uint8_t state = dbi_state(dig, dbi); - if (state & DBI_LINDO) - switch (state & (DBI_VALID | DBI_STALE | DBI_OLDEN)) { - case DBI_VALID: - case DBI_OLDEN: - return dig->dbs + dbi; - case 0: - return nullptr; - case DBI_VALID | DBI_STALE: - case DBI_OLDEN | DBI_STALE: - break; - default: - tASSERT(txn, !!"unexpected dig->dbi_state[dbi]"); - } - dig = dig->parent; - } while (dig); - return fallback; +struct audit_ctx { + size_t used; + uint8_t *const done_bitmap; +}; + +static int audit_dbi(void *ctx, const MDBX_txn *txn, const MDBX_val *name, + MDBX_db_flags_t flags, const struct MDBX_stat *stat, + MDBX_dbi dbi) { + struct audit_ctx *audit_ctx = ctx; + (void)name; + (void)txn; + (void)flags; + audit_ctx->used += (size_t)stat->ms_branch_pages + + (size_t)stat->ms_leaf_pages + + (size_t)stat->ms_overflow_pages; + if (dbi) + audit_ctx->done_bitmap[dbi / CHAR_BIT] |= 1 << dbi % CHAR_BIT; + return MDBX_SUCCESS; } static size_t audit_db_used(const tree_t *db) { @@ -10423,8 +10422,6 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, tASSERT(txn, rc == MDBX_NOTFOUND); const size_t done_bitmap_size = (txn->n_dbi + CHAR_BIT - 1) / CHAR_BIT; - uint8_t *const done_bitmap = alloca(done_bitmap_size); - memset(done_bitmap, 0, done_bitmap_size); if (txn->parent) { tASSERT(txn, txn->n_dbi == txn->parent->n_dbi && txn->n_dbi == txn->env->txn->n_dbi); @@ -10434,51 +10431,20 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, #endif /* MDBX_ENABLE_DBI_SPARSE */ } - size_t used = NUM_METAS + - audit_db_used(audit_db_dig(txn, FREE_DBI, nullptr)) + - audit_db_used(audit_db_dig(txn, MAIN_DBI, nullptr)); - rc = cursor_init(&cx.outer, txn, MAIN_DBI); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - - rc = tree_search(&cx.outer, nullptr, Z_FIRST); - while (rc == MDBX_SUCCESS) { - page_t *mp = cx.outer.pg[cx.outer.top]; - for (size_t k = 0; k < page_numkeys(mp); k++) { - node_t *node = page_node(mp, k); - if (node_flags(node) != N_SUBDATA) - continue; - if (unlikely(node_ds(node) != sizeof(tree_t))) { - ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, - "invalid dupsort sub-tree node size", (unsigned)node_ds(node)); - return MDBX_CORRUPTED; - } - - tree_t reside; - const tree_t *db = memcpy(&reside, node_data(node), sizeof(reside)); - const MDBX_val name = {node_key(node), node_ks(node)}; - for (size_t dbi = CORE_DBS; dbi < env->n_dbi; ++dbi) { - if (dbi >= txn->n_dbi || !(env->dbs_flags[dbi] & DB_VALID)) - continue; - if (env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[dbi].name)) - continue; + struct audit_ctx ctx = {0, alloca(done_bitmap_size)}; + memset(ctx.done_bitmap, 0, done_bitmap_size); + ctx.used = NUM_METAS + audit_db_used(dbi_dig(txn, FREE_DBI, nullptr)) + + audit_db_used(dbi_dig(txn, MAIN_DBI, nullptr)); - done_bitmap[dbi / CHAR_BIT] |= 1 << dbi % CHAR_BIT; - db = audit_db_dig(txn, dbi, &reside); - break; - } - used += audit_db_used(db); - } - rc = cursor_sibling_right(&cx.outer); - } - tASSERT(txn, rc == MDBX_NOTFOUND); + rc = mdbx_enumerate_subdb(txn, audit_dbi, &ctx); + tASSERT(txn, rc == MDBX_SUCCESS); for (size_t dbi = CORE_DBS; dbi < txn->n_dbi; ++dbi) { - if (done_bitmap[dbi / CHAR_BIT] & (1 << dbi % CHAR_BIT)) + if (ctx.done_bitmap[dbi / CHAR_BIT] & (1 << dbi % CHAR_BIT)) continue; - const tree_t *db = audit_db_dig(txn, dbi, nullptr); + const tree_t *db = dbi_dig(txn, dbi, nullptr); if (db) - used += audit_db_used(db); + ctx.used += audit_db_used(db); else if (dbi_state(txn, dbi)) WARNING("audit %s@%" PRIaTXN ": unable account dbi %zd / \"%*s\", state 0x%02x", @@ -10487,7 +10453,7 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, (const char *)env->kvs[dbi].name.iov_base, dbi_state(txn, dbi)); } - if (pending + gc + used == txn->geo.first_unallocated) + if (pending + gc + ctx.used == txn->geo.first_unallocated) return MDBX_SUCCESS; if ((txn->flags & MDBX_TXN_RDONLY) == 0) @@ -10500,7 +10466,7 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, ERROR("audit @%" PRIaTXN ": %zu(pending) + %zu" "(gc) + %zu(count) = %zu(total) <> %zu" "(allocated)", - txn->txnid, pending, gc, used, pending + gc + used, + txn->txnid, pending, gc, ctx.used, pending + gc + ctx.used, (size_t)txn->geo.first_unallocated); return MDBX_PROBLEM; } @@ -18111,6 +18077,86 @@ __cold int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest, stat_get(&txn->dbs[dbi], dest, bytes); return MDBX_SUCCESS; } + +__cold const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, + tree_t *fallback) { + const MDBX_txn *dig = txn; + do { + tASSERT(txn, txn->n_dbi == dig->n_dbi); + const uint8_t state = dbi_state(dig, dbi); + if (state & DBI_LINDO) + switch (state & (DBI_VALID | DBI_STALE | DBI_OLDEN)) { + case DBI_VALID: + case DBI_OLDEN: + return dig->dbs + dbi; + case 0: + return nullptr; + case DBI_VALID | DBI_STALE: + case DBI_OLDEN | DBI_STALE: + break; + default: + tASSERT(txn, !!"unexpected dig->dbi_state[dbi]"); + } + dig = dig->parent; + } while (dig); + return fallback; +} + +__cold int mdbx_enumerate_subdb(const MDBX_txn *txn, MDBX_subdb_enum_func *func, + void *ctx) { + if (unlikely(!func)) + return MDBX_EINVAL; + + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + cursor_couple_t cx; + rc = cursor_init(&cx.outer, txn, MAIN_DBI); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + cx.outer.next = txn->cursors[MAIN_DBI]; + txn->cursors[MAIN_DBI] = &cx.outer; + for (rc = outer_first(&cx.outer, nullptr, nullptr); rc == MDBX_SUCCESS; + rc = outer_next(&cx.outer, nullptr, nullptr, MDBX_NEXT_NODUP)) { + node_t *node = + page_node(cx.outer.pg[cx.outer.top], cx.outer.ki[cx.outer.top]); + if (node_flags(node) != N_SUBDATA) + continue; + if (unlikely(node_ds(node) != sizeof(tree_t))) { + ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, + "invalid dupsort sub-tree node size", (unsigned)node_ds(node)); + rc = MDBX_CORRUPTED; + break; + } + + tree_t reside; + const tree_t *tree = memcpy(&reside, node_data(node), sizeof(reside)); + const MDBX_val name = {node_key(node), node_ks(node)}; + const MDBX_env *const env = txn->env; + MDBX_dbi dbi = 0; + for (size_t i = CORE_DBS; i < env->n_dbi; ++i) { + if (i >= txn->n_dbi || !(env->dbs_flags[i] & DB_VALID)) + continue; + if (env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[i].name)) + continue; + + tree = dbi_dig(txn, i, &reside); + dbi = (MDBX_dbi)i; + break; + } + + MDBX_stat stat; + stat_get(tree, &stat, sizeof(stat)); + rc = func(ctx, txn, &name, tree->flags, &stat, dbi); + if (rc != MDBX_SUCCESS) + break; + } + txn->cursors[MAIN_DBI] = cx.outer.next; + + return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc; +} /// \copyright SPDX-License-Identifier: Apache-2.0 /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 @@ -26912,7 +26958,7 @@ __cold int __must_check_result meta_override(MDBX_env *env, size_t target, osal_flush_incoherent_mmap(env->dxb_mmap.base, pgno2bytes(env, NUM_METAS), globals.sys_pagesize); } - eASSERT(env, (!env->txn && !env->basal_txn) || + eASSERT(env, (!env->txn && (env->flags & ENV_ACTIVE) == 0) || (env->stuck_meta == (int)target && (env->flags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) == MDBX_EXCLUSIVE)); @@ -39846,9 +39892,9 @@ __dll_export 0, 13, 0, - 64, - {"2024-06-26T09:44:42+03:00", "57d014f58b79279af6fbad3a3ffd19cdc5a174f2", "7abeac762f36276ad035546b7caa015838784f40", - "v0.13.0-64-g7abeac76"}, + 70, + {"2024-07-05T20:33:43+03:00", "cc833af0abd059cbcc23e32b7788554995d5c6ea", "3798d47a719a19b111896c22468abf139e333cee", + "v0.13.0-70-g3798d47a"}, sourcery}; __dll_export diff --git a/mdbx/mdbx.h b/mdbx/mdbx.h index cb3e2a5..1f4c2bc 100644 --- a/mdbx/mdbx.h +++ b/mdbx/mdbx.h @@ -3067,8 +3067,8 @@ LIBMDBX_INLINE_API(int, mdbx_env_close, (MDBX_env * env)) { * \param [in,out] env Экземпляр среды созданный функцией * \ref mdbx_env_create(). * - * \returns Ненулевое значение ошибки при сбое и 0 при успешном выполнении, - * некоторые возможные ошибки таковы: + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. + * Некоторые возможные ошибки таковы: * * \retval MDBX_BUSY В родительском процессе БД была открыта * в режиме \ref MDBX_EXCLUSIVE. @@ -4424,7 +4424,7 @@ MDBX_DEPRECATED LIBMDBX_API int mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags, MDBX_dbi *dbi, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp); -/** \brief Переименовает таблицу по DBI-хендлу. +/** \brief Переименовает таблицу по DBI-дескриптору. * \ingroup c_dbi * * Переименовывает пользовательскую именованную subDB связанную с передаваемым @@ -4437,12 +4437,52 @@ mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags, * * \param [in] name Новое имя для переименования. * - * \returns Ненулевое значение ошибки при сбое и 0 при успешном выполнении. */ + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. */ LIBMDBX_API int mdbx_dbi_rename(MDBX_txn *txn, MDBX_dbi dbi, const char *name); /** \copydoc mdbx_dbi_rename() */ LIBMDBX_API int mdbx_dbi_rename2(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *name); +/** \brief Функция обратного вызова для перечисления + * пользовательских именованных таблиц. + * + * \ingroup c_statinfo + * \see mdbx_enumerate_subdb() + * + * \param [in] ctx Указатель на контекст переданный аналогичным + * параметром в \ref mdbx_enumerate_subdb(). + * \param [in] txn Транзазакция. + * \param [in] name Имя таблицы. + * \param [in] flags Флаги \ref MDBX_db_flags_t. + * \param [in] stat Базовая информация \ref MDBX_stat о таблице. + * \param [in] dbi Отличное от 0 значение DBI-дескриптора, + * если таковой был открыт для этой таблицы. + * Либо 0 если такого открытого дескриптора нет. + * + * \returns Ноль при успехе и продолжении перечисления, при возвращении другого + * значения оно будет немедленно возвращено вызывающему + * без продолжения перечисления. */ +typedef int(MDBX_subdb_enum_func)(void *ctx, const MDBX_txn *txn, + const MDBX_val *name, MDBX_db_flags_t flags, + const struct MDBX_stat *stat, + MDBX_dbi dbi) MDBX_CXX17_NOEXCEPT; + +/** \brief Enumerate the entries in the reader lock table. + * \ingroup c_statinfo + * \see MDBX_subdb_enum_func + * + * \param [in] txn Транзакция запущенная посредством + * \ref mdbx_txn_begin(). + * \param [in] func Указатель на пользовательскую функцию-перечислитель + * с сигнатурой \ref MDBX_subdb_enum_func, + * которая будет вызвана для каждой таблицы. + * \param [in] ctx Указатель на некоторый контект, который будет передан + * в функцию-перечислитель как есть. + * + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. */ +LIBMDBX_API int mdbx_enumerate_subdb(const MDBX_txn *txn, + MDBX_subdb_enum_func *func, void *ctx); + /** \defgroup value2key Value-to-Key functions * \brief Value-to-Key functions to * \ref avoid_custom_comparators "avoid using custom comparators" @@ -4553,6 +4593,8 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_dbi_state) /** \brief Retrieve the DB flags and status for a database handle. * \ingroup c_statinfo + * \see MDBX_db_flags_t + * \see MDBX_dbi_state_t * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). * \param [in] dbi A database handle returned by \ref mdbx_dbi_open(). @@ -4564,7 +4606,8 @@ LIBMDBX_API int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags, unsigned *state); /** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL` * for discarding it result. - * \ingroup c_statinfo */ + * \ingroup c_statinfo + * \see MDBX_db_flags_t */ LIBMDBX_INLINE_API(int, mdbx_dbi_flags, (const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags)) { unsigned state; @@ -6135,7 +6178,7 @@ LIBMDBX_API int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target_meta); * нет препятствий к тому, чтобы другой процесс удалил БД и создал её заново с * другим размером страницы и/или изменением любых других параметров. * - * \returns Ненулевое значение ошибки при сбое и 0 при успешном выполнении. */ + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. */ LIBMDBX_API int mdbx_preopen_snapinfo(const char *pathname, MDBX_envinfo *info, size_t bytes); #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) diff --git a/mdbxdist/VERSION.txt b/mdbxdist/VERSION.txt index 2ee6b4b..3ed7a11 100644 --- a/mdbxdist/VERSION.txt +++ b/mdbxdist/VERSION.txt @@ -1 +1 @@ -0.13.0.64 +0.13.0.70 diff --git a/mdbxdist/mdbx.c b/mdbxdist/mdbx.c index 15b73de..e72f31a 100644 --- a/mdbxdist/mdbx.c +++ b/mdbxdist/mdbx.c @@ -3,7 +3,7 @@ #define xMDBX_ALLOY 1 /* alloyed build */ -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS @@ -5103,6 +5103,9 @@ MDBX_INTERNAL int dbi_open(MDBX_txn *txn, const MDBX_val *const name, MDBX_INTERNAL int dbi_bind(MDBX_txn *txn, const size_t dbi, unsigned user_flags, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp); +MDBX_INTERNAL const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, + tree_t *fallback); + @@ -10355,28 +10358,24 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -__cold static tree_t *audit_db_dig(const MDBX_txn *txn, const size_t dbi, - tree_t *fallback) { - const MDBX_txn *dig = txn; - do { - tASSERT(txn, txn->n_dbi == dig->n_dbi); - const uint8_t state = dbi_state(dig, dbi); - if (state & DBI_LINDO) - switch (state & (DBI_VALID | DBI_STALE | DBI_OLDEN)) { - case DBI_VALID: - case DBI_OLDEN: - return dig->dbs + dbi; - case 0: - return nullptr; - case DBI_VALID | DBI_STALE: - case DBI_OLDEN | DBI_STALE: - break; - default: - tASSERT(txn, !!"unexpected dig->dbi_state[dbi]"); - } - dig = dig->parent; - } while (dig); - return fallback; +struct audit_ctx { + size_t used; + uint8_t *const done_bitmap; +}; + +static int audit_dbi(void *ctx, const MDBX_txn *txn, const MDBX_val *name, + MDBX_db_flags_t flags, const struct MDBX_stat *stat, + MDBX_dbi dbi) { + struct audit_ctx *audit_ctx = ctx; + (void)name; + (void)txn; + (void)flags; + audit_ctx->used += (size_t)stat->ms_branch_pages + + (size_t)stat->ms_leaf_pages + + (size_t)stat->ms_overflow_pages; + if (dbi) + audit_ctx->done_bitmap[dbi / CHAR_BIT] |= 1 << dbi % CHAR_BIT; + return MDBX_SUCCESS; } static size_t audit_db_used(const tree_t *db) { @@ -10423,8 +10422,6 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, tASSERT(txn, rc == MDBX_NOTFOUND); const size_t done_bitmap_size = (txn->n_dbi + CHAR_BIT - 1) / CHAR_BIT; - uint8_t *const done_bitmap = alloca(done_bitmap_size); - memset(done_bitmap, 0, done_bitmap_size); if (txn->parent) { tASSERT(txn, txn->n_dbi == txn->parent->n_dbi && txn->n_dbi == txn->env->txn->n_dbi); @@ -10434,51 +10431,20 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, #endif /* MDBX_ENABLE_DBI_SPARSE */ } - size_t used = NUM_METAS + - audit_db_used(audit_db_dig(txn, FREE_DBI, nullptr)) + - audit_db_used(audit_db_dig(txn, MAIN_DBI, nullptr)); - rc = cursor_init(&cx.outer, txn, MAIN_DBI); - if (unlikely(rc != MDBX_SUCCESS)) - return rc; - - rc = tree_search(&cx.outer, nullptr, Z_FIRST); - while (rc == MDBX_SUCCESS) { - page_t *mp = cx.outer.pg[cx.outer.top]; - for (size_t k = 0; k < page_numkeys(mp); k++) { - node_t *node = page_node(mp, k); - if (node_flags(node) != N_SUBDATA) - continue; - if (unlikely(node_ds(node) != sizeof(tree_t))) { - ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, - "invalid dupsort sub-tree node size", (unsigned)node_ds(node)); - return MDBX_CORRUPTED; - } - - tree_t reside; - const tree_t *db = memcpy(&reside, node_data(node), sizeof(reside)); - const MDBX_val name = {node_key(node), node_ks(node)}; - for (size_t dbi = CORE_DBS; dbi < env->n_dbi; ++dbi) { - if (dbi >= txn->n_dbi || !(env->dbs_flags[dbi] & DB_VALID)) - continue; - if (env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[dbi].name)) - continue; + struct audit_ctx ctx = {0, alloca(done_bitmap_size)}; + memset(ctx.done_bitmap, 0, done_bitmap_size); + ctx.used = NUM_METAS + audit_db_used(dbi_dig(txn, FREE_DBI, nullptr)) + + audit_db_used(dbi_dig(txn, MAIN_DBI, nullptr)); - done_bitmap[dbi / CHAR_BIT] |= 1 << dbi % CHAR_BIT; - db = audit_db_dig(txn, dbi, &reside); - break; - } - used += audit_db_used(db); - } - rc = cursor_sibling_right(&cx.outer); - } - tASSERT(txn, rc == MDBX_NOTFOUND); + rc = mdbx_enumerate_subdb(txn, audit_dbi, &ctx); + tASSERT(txn, rc == MDBX_SUCCESS); for (size_t dbi = CORE_DBS; dbi < txn->n_dbi; ++dbi) { - if (done_bitmap[dbi / CHAR_BIT] & (1 << dbi % CHAR_BIT)) + if (ctx.done_bitmap[dbi / CHAR_BIT] & (1 << dbi % CHAR_BIT)) continue; - const tree_t *db = audit_db_dig(txn, dbi, nullptr); + const tree_t *db = dbi_dig(txn, dbi, nullptr); if (db) - used += audit_db_used(db); + ctx.used += audit_db_used(db); else if (dbi_state(txn, dbi)) WARNING("audit %s@%" PRIaTXN ": unable account dbi %zd / \"%*s\", state 0x%02x", @@ -10487,7 +10453,7 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, (const char *)env->kvs[dbi].name.iov_base, dbi_state(txn, dbi)); } - if (pending + gc + used == txn->geo.first_unallocated) + if (pending + gc + ctx.used == txn->geo.first_unallocated) return MDBX_SUCCESS; if ((txn->flags & MDBX_TXN_RDONLY) == 0) @@ -10500,7 +10466,7 @@ __cold static int audit_ex_locked(MDBX_txn *txn, size_t retired_stored, ERROR("audit @%" PRIaTXN ": %zu(pending) + %zu" "(gc) + %zu(count) = %zu(total) <> %zu" "(allocated)", - txn->txnid, pending, gc, used, pending + gc + used, + txn->txnid, pending, gc, ctx.used, pending + gc + ctx.used, (size_t)txn->geo.first_unallocated); return MDBX_PROBLEM; } @@ -18111,6 +18077,86 @@ __cold int mdbx_dbi_stat(const MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *dest, stat_get(&txn->dbs[dbi], dest, bytes); return MDBX_SUCCESS; } + +__cold const tree_t *dbi_dig(const MDBX_txn *txn, const size_t dbi, + tree_t *fallback) { + const MDBX_txn *dig = txn; + do { + tASSERT(txn, txn->n_dbi == dig->n_dbi); + const uint8_t state = dbi_state(dig, dbi); + if (state & DBI_LINDO) + switch (state & (DBI_VALID | DBI_STALE | DBI_OLDEN)) { + case DBI_VALID: + case DBI_OLDEN: + return dig->dbs + dbi; + case 0: + return nullptr; + case DBI_VALID | DBI_STALE: + case DBI_OLDEN | DBI_STALE: + break; + default: + tASSERT(txn, !!"unexpected dig->dbi_state[dbi]"); + } + dig = dig->parent; + } while (dig); + return fallback; +} + +__cold int mdbx_enumerate_subdb(const MDBX_txn *txn, MDBX_subdb_enum_func *func, + void *ctx) { + if (unlikely(!func)) + return MDBX_EINVAL; + + int rc = check_txn(txn, MDBX_TXN_BLOCKED); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + cursor_couple_t cx; + rc = cursor_init(&cx.outer, txn, MAIN_DBI); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + cx.outer.next = txn->cursors[MAIN_DBI]; + txn->cursors[MAIN_DBI] = &cx.outer; + for (rc = outer_first(&cx.outer, nullptr, nullptr); rc == MDBX_SUCCESS; + rc = outer_next(&cx.outer, nullptr, nullptr, MDBX_NEXT_NODUP)) { + node_t *node = + page_node(cx.outer.pg[cx.outer.top], cx.outer.ki[cx.outer.top]); + if (node_flags(node) != N_SUBDATA) + continue; + if (unlikely(node_ds(node) != sizeof(tree_t))) { + ERROR("%s/%d: %s %u", "MDBX_CORRUPTED", MDBX_CORRUPTED, + "invalid dupsort sub-tree node size", (unsigned)node_ds(node)); + rc = MDBX_CORRUPTED; + break; + } + + tree_t reside; + const tree_t *tree = memcpy(&reside, node_data(node), sizeof(reside)); + const MDBX_val name = {node_key(node), node_ks(node)}; + const MDBX_env *const env = txn->env; + MDBX_dbi dbi = 0; + for (size_t i = CORE_DBS; i < env->n_dbi; ++i) { + if (i >= txn->n_dbi || !(env->dbs_flags[i] & DB_VALID)) + continue; + if (env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[i].name)) + continue; + + tree = dbi_dig(txn, i, &reside); + dbi = (MDBX_dbi)i; + break; + } + + MDBX_stat stat; + stat_get(tree, &stat, sizeof(stat)); + rc = func(ctx, txn, &name, tree->flags, &stat, dbi); + if (rc != MDBX_SUCCESS) + break; + } + txn->cursors[MAIN_DBI] = cx.outer.next; + + return (rc == MDBX_NOTFOUND) ? MDBX_SUCCESS : rc; +} /// \copyright SPDX-License-Identifier: Apache-2.0 /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 @@ -26912,7 +26958,7 @@ __cold int __must_check_result meta_override(MDBX_env *env, size_t target, osal_flush_incoherent_mmap(env->dxb_mmap.base, pgno2bytes(env, NUM_METAS), globals.sys_pagesize); } - eASSERT(env, (!env->txn && !env->basal_txn) || + eASSERT(env, (!env->txn && (env->flags & ENV_ACTIVE) == 0) || (env->stuck_meta == (int)target && (env->flags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) == MDBX_EXCLUSIVE)); @@ -39846,9 +39892,9 @@ __dll_export 0, 13, 0, - 64, - {"2024-06-26T09:44:42+03:00", "57d014f58b79279af6fbad3a3ffd19cdc5a174f2", "7abeac762f36276ad035546b7caa015838784f40", - "v0.13.0-64-g7abeac76"}, + 70, + {"2024-07-05T20:33:43+03:00", "cc833af0abd059cbcc23e32b7788554995d5c6ea", "3798d47a719a19b111896c22468abf139e333cee", + "v0.13.0-70-g3798d47a"}, sourcery}; __dll_export diff --git a/mdbxdist/mdbx.c++ b/mdbxdist/mdbx.c++ index 9b55555..4cc541f 100644 --- a/mdbxdist/mdbx.c++ +++ b/mdbxdist/mdbx.c++ @@ -2,7 +2,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS @@ -5008,13 +5008,9 @@ __cold bool txn::rename_map(const char *old_name, const char *new_name, } } -#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L - -__cold bool txn::drop_map(const ::std::string_view &name, - bool throw_if_absent) { +__cold bool txn::drop_map(const ::mdbx::slice &name, bool throw_if_absent) { map_handle map; - const int err = - ::mdbx_dbi_open2(handle_, mdbx::slice(name), MDBX_DB_ACCEDE, &map.dbi); + const int err = ::mdbx_dbi_open2(handle_, name, MDBX_DB_ACCEDE, &map.dbi); switch (err) { case MDBX_SUCCESS: drop_map(map); @@ -5029,11 +5025,9 @@ __cold bool txn::drop_map(const ::std::string_view &name, } } -__cold bool txn::clear_map(const ::std::string_view &name, - bool throw_if_absent) { +__cold bool txn::clear_map(const ::mdbx::slice &name, bool throw_if_absent) { map_handle map; - const int err = - ::mdbx_dbi_open2(handle_, mdbx::slice(name), MDBX_DB_ACCEDE, &map.dbi); + const int err = ::mdbx_dbi_open2(handle_, name, MDBX_DB_ACCEDE, &map.dbi); switch (err) { case MDBX_SUCCESS: clear_map(map); @@ -5048,12 +5042,11 @@ __cold bool txn::clear_map(const ::std::string_view &name, } } -__cold bool txn::rename_map(const ::std::string_view &old_name, - const ::std::string_view &new_name, +__cold bool txn::rename_map(const ::mdbx::slice &old_name, + const ::mdbx::slice &new_name, bool throw_if_absent) { map_handle map; - const int err = ::mdbx_dbi_open2(handle_, mdbx::slice(old_name), - MDBX_DB_ACCEDE, &map.dbi); + const int err = ::mdbx_dbi_open2(handle_, old_name, MDBX_DB_ACCEDE, &map.dbi); switch (err) { case MDBX_SUCCESS: rename_map(map, new_name); @@ -5071,20 +5064,10 @@ __cold bool txn::rename_map(const ::std::string_view &old_name, __cold bool txn::rename_map(const ::std::string &old_name, const ::std::string &new_name, bool throw_if_absent) { - return rename_map(::std::string_view(old_name), ::std::string_view(new_name), + return rename_map(::mdbx::slice(old_name), ::mdbx::slice(new_name), throw_if_absent); } -#else - -__cold bool txn::rename_map(const ::std::string &old_name, - const ::std::string &new_name, - bool throw_if_absent) { - return rename_map(old_name.c_str(), new_name.c_str(), throw_if_absent); -} - -#endif /* __cpp_lib_string_view >= 201606L */ - //------------------------------------------------------------------------------ void cursor_managed::close() { diff --git a/mdbxdist/mdbx.h b/mdbxdist/mdbx.h index cb3e2a5..1f4c2bc 100644 --- a/mdbxdist/mdbx.h +++ b/mdbxdist/mdbx.h @@ -3067,8 +3067,8 @@ LIBMDBX_INLINE_API(int, mdbx_env_close, (MDBX_env * env)) { * \param [in,out] env Экземпляр среды созданный функцией * \ref mdbx_env_create(). * - * \returns Ненулевое значение ошибки при сбое и 0 при успешном выполнении, - * некоторые возможные ошибки таковы: + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. + * Некоторые возможные ошибки таковы: * * \retval MDBX_BUSY В родительском процессе БД была открыта * в режиме \ref MDBX_EXCLUSIVE. @@ -4424,7 +4424,7 @@ MDBX_DEPRECATED LIBMDBX_API int mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags, MDBX_dbi *dbi, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp); -/** \brief Переименовает таблицу по DBI-хендлу. +/** \brief Переименовает таблицу по DBI-дескриптору. * \ingroup c_dbi * * Переименовывает пользовательскую именованную subDB связанную с передаваемым @@ -4437,12 +4437,52 @@ mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags, * * \param [in] name Новое имя для переименования. * - * \returns Ненулевое значение ошибки при сбое и 0 при успешном выполнении. */ + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. */ LIBMDBX_API int mdbx_dbi_rename(MDBX_txn *txn, MDBX_dbi dbi, const char *name); /** \copydoc mdbx_dbi_rename() */ LIBMDBX_API int mdbx_dbi_rename2(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *name); +/** \brief Функция обратного вызова для перечисления + * пользовательских именованных таблиц. + * + * \ingroup c_statinfo + * \see mdbx_enumerate_subdb() + * + * \param [in] ctx Указатель на контекст переданный аналогичным + * параметром в \ref mdbx_enumerate_subdb(). + * \param [in] txn Транзазакция. + * \param [in] name Имя таблицы. + * \param [in] flags Флаги \ref MDBX_db_flags_t. + * \param [in] stat Базовая информация \ref MDBX_stat о таблице. + * \param [in] dbi Отличное от 0 значение DBI-дескриптора, + * если таковой был открыт для этой таблицы. + * Либо 0 если такого открытого дескриптора нет. + * + * \returns Ноль при успехе и продолжении перечисления, при возвращении другого + * значения оно будет немедленно возвращено вызывающему + * без продолжения перечисления. */ +typedef int(MDBX_subdb_enum_func)(void *ctx, const MDBX_txn *txn, + const MDBX_val *name, MDBX_db_flags_t flags, + const struct MDBX_stat *stat, + MDBX_dbi dbi) MDBX_CXX17_NOEXCEPT; + +/** \brief Enumerate the entries in the reader lock table. + * \ingroup c_statinfo + * \see MDBX_subdb_enum_func + * + * \param [in] txn Транзакция запущенная посредством + * \ref mdbx_txn_begin(). + * \param [in] func Указатель на пользовательскую функцию-перечислитель + * с сигнатурой \ref MDBX_subdb_enum_func, + * которая будет вызвана для каждой таблицы. + * \param [in] ctx Указатель на некоторый контект, который будет передан + * в функцию-перечислитель как есть. + * + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. */ +LIBMDBX_API int mdbx_enumerate_subdb(const MDBX_txn *txn, + MDBX_subdb_enum_func *func, void *ctx); + /** \defgroup value2key Value-to-Key functions * \brief Value-to-Key functions to * \ref avoid_custom_comparators "avoid using custom comparators" @@ -4553,6 +4593,8 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_dbi_state) /** \brief Retrieve the DB flags and status for a database handle. * \ingroup c_statinfo + * \see MDBX_db_flags_t + * \see MDBX_dbi_state_t * * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin(). * \param [in] dbi A database handle returned by \ref mdbx_dbi_open(). @@ -4564,7 +4606,8 @@ LIBMDBX_API int mdbx_dbi_flags_ex(const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags, unsigned *state); /** \brief The shortcut to calling \ref mdbx_dbi_flags_ex() with `state=NULL` * for discarding it result. - * \ingroup c_statinfo */ + * \ingroup c_statinfo + * \see MDBX_db_flags_t */ LIBMDBX_INLINE_API(int, mdbx_dbi_flags, (const MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags)) { unsigned state; @@ -6135,7 +6178,7 @@ LIBMDBX_API int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target_meta); * нет препятствий к тому, чтобы другой процесс удалил БД и создал её заново с * другим размером страницы и/или изменением любых других параметров. * - * \returns Ненулевое значение ошибки при сбое и 0 при успешном выполнении. */ + * \returns Ненулевое значение кода ошибки, либо 0 при успешном выполнении. */ LIBMDBX_API int mdbx_preopen_snapinfo(const char *pathname, MDBX_envinfo *info, size_t bytes); #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) diff --git a/mdbxdist/mdbx.h++ b/mdbxdist/mdbx.h++ index 2d98204..58a2b7c 100644 --- a/mdbxdist/mdbx.h++ +++ b/mdbxdist/mdbx.h++ @@ -3840,6 +3840,9 @@ public: /// \brief Returns the maximal write transaction size (i.e. limit for /// summary volume of dirty pages) in bytes for specified page size. static inline size_t transaction_size_max(intptr_t pagesize); + + /// \brief Returns the maximum opened map handles, aka DBI-handles. + static inline size_t max_map_handles(void); }; /// \brief Returns the minimal database size in bytes for the environment. @@ -4384,11 +4387,18 @@ public: const ::std::string &name, const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual, const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) const; + /// \brief Open existing key-value map. + inline map_handle open_map( + const ::mdbx::slice &name, + const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual, + const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) const; /// \brief Open existing key-value map. inline map_handle open_map_accede(const char *name) const; /// \brief Open existing key-value map. inline map_handle open_map_accede(const ::std::string &name) const; + /// \brief Open existing key-value map. + inline map_handle open_map_accede(const ::mdbx::slice &name) const; /// \brief Create new or open existing key-value map. inline map_handle @@ -4400,6 +4410,11 @@ public: create_map(const ::std::string &name, const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual, const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single); + /// \brief Create new or open existing key-value map. + inline map_handle + create_map(const ::mdbx::slice &name, + const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual, + const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single); /// \brief Drops key-value map using handle. inline void drop_map(map_handle map); @@ -4411,6 +4426,10 @@ public: /// \return `True` if the key-value map existed and was deleted, either /// `false` if the key-value map did not exist and there is nothing to delete. inline bool drop_map(const ::std::string &name, bool throw_if_absent = false); + /// \brief Drop key-value map. + /// \return `True` if the key-value map existed and was deleted, either + /// `false` if the key-value map did not exist and there is nothing to delete. + bool drop_map(const ::mdbx::slice &name, bool throw_if_absent = false); /// \brief Clear key-value map. inline void clear_map(map_handle map); @@ -4421,12 +4440,17 @@ public: /// `false` if the key-value map did not exist and there is nothing to clear. inline bool clear_map(const ::std::string &name, bool throw_if_absent = false); + /// \return `True` if the key-value map existed and was cleared, either + /// `false` if the key-value map did not exist and there is nothing to clear. + bool clear_map(const ::mdbx::slice &name, bool throw_if_absent = false); /// \brief Переименовывает таблицу ключ-значение. inline void rename_map(map_handle map, const char *new_name); /// \brief Переименовывает таблицу ключ-значение. inline void rename_map(map_handle map, const ::std::string &new_name); /// \brief Переименовывает таблицу ключ-значение. + inline void rename_map(map_handle map, const ::mdbx::slice &new_name); + /// \brief Переименовывает таблицу ключ-значение. /// \return `True` если таблица существует и была переименована, либо /// `false` в случае отсутствия исходной таблицы. bool rename_map(const char *old_name, const char *new_name, @@ -4436,6 +4460,11 @@ public: /// `false` в случае отсутствия исходной таблицы. bool rename_map(const ::std::string &old_name, const ::std::string &new_name, bool throw_if_absent = false); + /// \brief Переименовывает таблицу ключ-значение. + /// \return `True` если таблица существует и была переименована, либо + /// `false` в случае отсутствия исходной таблицы. + bool rename_map(const ::mdbx::slice &old_name, const ::mdbx::slice &new_name, + bool throw_if_absent = false); #if defined(DOXYGEN) || \ (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L) @@ -4444,21 +4473,29 @@ public: inline map_handle open_map( const ::std::string_view &name, const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual, - const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) const; + const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) const { + return open_map(::mdbx::slice(name), key_mode, value_mode); + } /// \brief Open existing key-value map. inline map_handle open_map_accede(const ::std::string_view &name) const; /// \brief Create new or open existing key-value map. inline map_handle create_map(const ::std::string_view &name, const ::mdbx::key_mode key_mode = ::mdbx::key_mode::usual, - const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single); + const ::mdbx::value_mode value_mode = ::mdbx::value_mode::single) { + return create_map(::mdbx::slice(name), key_mode, value_mode); + } /// \brief Drop key-value map. /// \return `True` if the key-value map existed and was deleted, either /// `false` if the key-value map did not exist and there is nothing to delete. - bool drop_map(const ::std::string_view &name, bool throw_if_absent = false); + bool drop_map(const ::std::string_view &name, bool throw_if_absent = false) { + return drop_map(::mdbx::slice(name), throw_if_absent); + } /// \return `True` if the key-value map existed and was cleared, either /// `false` if the key-value map did not exist and there is nothing to clear. - bool clear_map(const ::std::string_view &name, bool throw_if_absent = false); + bool clear_map(const ::std::string_view &name, bool throw_if_absent = false) { + return clear_map(::mdbx::slice(name), throw_if_absent); + } /// \brief Переименовывает таблицу ключ-значение. inline void rename_map(map_handle map, const ::std::string_view &new_name); /// \brief Переименовывает таблицу ключ-значение. @@ -4466,8 +4503,10 @@ public: /// `false` в случае отсутствия исходной таблицы. bool rename_map(const ::std::string_view &old_name, const ::std::string_view &new_name, - bool throw_if_absent = false); - + bool throw_if_absent = false) { + return rename_map(::mdbx::slice(old_name), ::mdbx::slice(new_name), + throw_if_absent); + } #endif /* __cpp_lib_string_view >= 201606L */ using map_stat = ::MDBX_stat; @@ -6089,6 +6128,8 @@ inline size_t env::limits::transaction_size_max(intptr_t pagesize) { return static_cast(result); } +inline size_t env::limits::max_map_handles(void) { return MDBX_MAX_DBI; } + inline env::operate_parameters env::get_operation_parameters() const { const auto flags = get_flags(); return operate_parameters(max_maps(), max_readers(), @@ -6428,151 +6469,113 @@ inline size_t txn::release_all_cursors(bool unbind) const { } inline ::mdbx::map_handle -txn::open_map(const char *name, const ::mdbx::key_mode key_mode, +txn::open_map(const ::mdbx::slice &name, const ::mdbx::key_mode key_mode, const ::mdbx::value_mode value_mode) const { ::mdbx::map_handle map; - error::success_or_throw(::mdbx_dbi_open( + error::success_or_throw(::mdbx_dbi_open2( handle_, name, MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode), &map.dbi)); assert(map.dbi != 0); return map; } -inline ::mdbx::map_handle txn::open_map_accede(const char *name) const { - ::mdbx::map_handle map; - error::success_or_throw( - ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi)); - assert(map.dbi != 0); - return map; -} - -inline ::mdbx::map_handle txn::create_map(const char *name, - const ::mdbx::key_mode key_mode, - const ::mdbx::value_mode value_mode) { +inline ::mdbx::map_handle +txn::open_map(const char *name, const ::mdbx::key_mode key_mode, + const ::mdbx::value_mode value_mode) const { ::mdbx::map_handle map; error::success_or_throw(::mdbx_dbi_open( - handle_, name, - MDBX_CREATE | MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode), + handle_, name, MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode), &map.dbi)); assert(map.dbi != 0); return map; } -inline void txn::drop_map(map_handle map) { - error::success_or_throw(::mdbx_drop(handle_, map.dbi, true)); -} - -inline void txn::clear_map(map_handle map) { - error::success_or_throw(::mdbx_drop(handle_, map.dbi, false)); -} - -inline void txn::rename_map(map_handle map, const char *new_name) { - error::success_or_throw(::mdbx_dbi_rename(handle_, map, new_name)); -} - -#if defined(DOXYGEN) || \ - (defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L) - inline ::mdbx::map_handle -txn::open_map(const ::std::string_view &name, const ::mdbx::key_mode key_mode, - const ::mdbx::value_mode value_mode) const { +txn::open_map_accede(const ::mdbx::slice &name) const { ::mdbx::map_handle map; - error::success_or_throw(::mdbx_dbi_open2( - handle_, ::mdbx::slice(name), - MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode), &map.dbi)); + error::success_or_throw( + ::mdbx_dbi_open2(handle_, name, MDBX_DB_ACCEDE, &map.dbi)); assert(map.dbi != 0); return map; } -inline ::mdbx::map_handle -txn::open_map_accede(const ::std::string_view &name) const { +inline ::mdbx::map_handle txn::open_map_accede(const char *name) const { ::mdbx::map_handle map; error::success_or_throw( - ::mdbx_dbi_open2(handle_, ::mdbx::slice(name), MDBX_DB_ACCEDE, &map.dbi)); + ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi)); assert(map.dbi != 0); return map; } -inline ::mdbx::map_handle txn::create_map(const ::std::string_view &name, +inline ::mdbx::map_handle txn::create_map(const ::mdbx::slice &name, const ::mdbx::key_mode key_mode, const ::mdbx::value_mode value_mode) { ::mdbx::map_handle map; error::success_or_throw(::mdbx_dbi_open2( - handle_, ::mdbx::slice(name), + handle_, name, MDBX_CREATE | MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode), &map.dbi)); assert(map.dbi != 0); return map; } -inline void txn::rename_map(map_handle map, - const ::std::string_view &new_name) { - error::success_or_throw( - ::mdbx_dbi_rename2(handle_, map, ::mdbx::slice(new_name))); -} - -inline ::mdbx::map_handle -txn::open_map(const ::std::string &name, const ::mdbx::key_mode key_mode, - const ::mdbx::value_mode value_mode) const { - return open_map(::std::string_view(name), key_mode, value_mode); -} - -inline ::mdbx::map_handle -txn::open_map_accede(const ::std::string &name) const { - return open_map_accede(::std::string_view(name)); -} - -inline ::mdbx::map_handle txn::create_map(const ::std::string &name, +inline ::mdbx::map_handle txn::create_map(const char *name, const ::mdbx::key_mode key_mode, const ::mdbx::value_mode value_mode) { - return create_map(::std::string_view(name), key_mode, value_mode); + ::mdbx::map_handle map; + error::success_or_throw(::mdbx_dbi_open( + handle_, name, + MDBX_CREATE | MDBX_db_flags_t(key_mode) | MDBX_db_flags_t(value_mode), + &map.dbi)); + assert(map.dbi != 0); + return map; } -inline bool txn::drop_map(const ::std::string &name, bool throw_if_absent) { - return drop_map(::std::string_view(name), throw_if_absent); +inline void txn::drop_map(map_handle map) { + error::success_or_throw(::mdbx_drop(handle_, map.dbi, true)); } -inline bool txn::clear_map(const ::std::string &name, bool throw_if_absent) { - return clear_map(::std::string_view(name), throw_if_absent); +inline void txn::clear_map(map_handle map) { + error::success_or_throw(::mdbx_drop(handle_, map.dbi, false)); } -inline void txn::rename_map(map_handle map, const ::std::string &new_name) { - return rename_map(map, ::std::string_view(new_name)); +inline void txn::rename_map(map_handle map, const char *new_name) { + error::success_or_throw(::mdbx_dbi_rename(handle_, map, new_name)); } -#else +inline void txn::rename_map(map_handle map, const ::mdbx::slice &new_name) { + error::success_or_throw(::mdbx_dbi_rename2(handle_, map, new_name)); +} inline ::mdbx::map_handle txn::open_map(const ::std::string &name, const ::mdbx::key_mode key_mode, const ::mdbx::value_mode value_mode) const { - return open_map(name.c_str(), key_mode, value_mode); + return open_map(::mdbx::slice(name), key_mode, value_mode); } inline ::mdbx::map_handle txn::open_map_accede(const ::std::string &name) const { - return open_map_accede(name.c_str()); + return open_map_accede(::mdbx::slice(name)); } inline ::mdbx::map_handle txn::create_map(const ::std::string &name, const ::mdbx::key_mode key_mode, const ::mdbx::value_mode value_mode) { - return create_map(name.c_str(), key_mode, value_mode); + return create_map(::mdbx::slice(name), key_mode, value_mode); } inline bool txn::drop_map(const ::std::string &name, bool throw_if_absent) { - return drop_map(name.c_str(), throw_if_absent); + return drop_map(::mdbx::slice(name), throw_if_absent); } inline bool txn::clear_map(const ::std::string &name, bool throw_if_absent) { - return clear_map(name.c_str(), throw_if_absent); + return clear_map(::mdbx::slice(name), throw_if_absent); } inline void txn::rename_map(map_handle map, const ::std::string &new_name) { - return rename_map(map, new_name.c_str()); + return rename_map(map, ::mdbx::slice(new_name)); } -#endif /* __cpp_lib_string_view >= 201606L */ - inline txn::map_stat txn::get_map_stat(map_handle map) const { txn::map_stat r; error::success_or_throw(::mdbx_dbi_stat(handle_, map.dbi, &r, sizeof(r))); diff --git a/mdbxdist/mdbx_chk.c b/mdbxdist/mdbx_chk.c index 6d7b4b3..94e5b6e 100644 --- a/mdbxdist/mdbx_chk.c +++ b/mdbxdist/mdbx_chk.c @@ -16,7 +16,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS diff --git a/mdbxdist/mdbx_copy.c b/mdbxdist/mdbx_copy.c index 225da9a..529ec4c 100644 --- a/mdbxdist/mdbx_copy.c +++ b/mdbxdist/mdbx_copy.c @@ -18,7 +18,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS diff --git a/mdbxdist/mdbx_drop.c b/mdbxdist/mdbx_drop.c index 1149bfe..79cc179 100644 --- a/mdbxdist/mdbx_drop.c +++ b/mdbxdist/mdbx_drop.c @@ -18,7 +18,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS diff --git a/mdbxdist/mdbx_dump.c b/mdbxdist/mdbx_dump.c index 02487d9..5a104ee 100644 --- a/mdbxdist/mdbx_dump.c +++ b/mdbxdist/mdbx_dump.c @@ -18,7 +18,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS diff --git a/mdbxdist/mdbx_load.c b/mdbxdist/mdbx_load.c index 96d94be..24ad1db 100644 --- a/mdbxdist/mdbx_load.c +++ b/mdbxdist/mdbx_load.c @@ -18,7 +18,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS diff --git a/mdbxdist/mdbx_stat.c b/mdbxdist/mdbx_stat.c index 1fc378f..18f7266 100644 --- a/mdbxdist/mdbx_stat.c +++ b/mdbxdist/mdbx_stat.c @@ -18,7 +18,7 @@ /// \author Леонид Юрьев aka Leonid Yuriev \date 2015-2024 -#define MDBX_BUILD_SOURCERY 84c5b5a6ebb00909e8a4d9736c054aac2e2abf8eca1b0620485c462bbed23474_v0_13_0_64_g7abeac76 +#define MDBX_BUILD_SOURCERY 9bf76fce8e3f74f34d482d7b2e9a6cc1bcabd797a6a4b4491ce5f6cd0ef29120_v0_13_0_70_g3798d47a #define LIBMDBX_INTERNALS