Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
AskAlexSharov committed Jul 12, 2024
1 parent 8158a71 commit 11cda1b
Show file tree
Hide file tree
Showing 13 changed files with 431 additions and 267 deletions.
188 changes: 117 additions & 71 deletions mdbx/mdbx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);




Expand Down Expand Up @@ -10355,28 +10358,24 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key,
/// \author Леонид Юрьев aka Leonid Yuriev <[email protected]> \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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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",
Expand All @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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 <[email protected]> \date 2015-2024

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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
Expand Down
55 changes: 49 additions & 6 deletions mdbx/mdbx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 связанную с передаваемым
Expand All @@ -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"
Expand Down Expand Up @@ -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().
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion mdbxdist/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.13.0.64
0.13.0.70
Loading

0 comments on commit 11cda1b

Please sign in to comment.