mdbx: доработка chk-функционала с устранением ошибок и недочетов.

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2024-02-20 23:52:09 +03:00
parent fb5dbbdf20
commit 164d112507
2 changed files with 60 additions and 43 deletions

View File

@ -24529,32 +24529,35 @@ __cold static int walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno,
(mp ? page_room(mp) : pagesize - header_size) - payload_size; (mp ? page_room(mp) : pagesize - header_size) - payload_size;
size_t align_bytes = 0; size_t align_bytes = 0;
for (size_t i = 0; err == MDBX_SUCCESS && i < nentries; for (size_t i = 0; err == MDBX_SUCCESS && i < nentries; ++i) {
align_bytes += ((payload_size + align_bytes) & 1), ++i) {
if (type == MDBX_page_dupfixed_leaf) { if (type == MDBX_page_dupfixed_leaf) {
/* LEAF2 pages have no mp_ptrs[] or node headers */ /* LEAF2 pages have no mp_ptrs[] or node headers */
payload_size += mp->mp_leaf2_ksize; payload_size += mp->mp_leaf2_ksize;
continue; continue;
} }
MDBX_node *node = page_node(mp, i); const MDBX_node *node = page_node(mp, i);
payload_size += NODESIZE + node_ks(node); header_size += NODESIZE;
const size_t node_key_size = node_ks(node);
payload_size += node_key_size;
if (type == MDBX_page_branch) { if (type == MDBX_page_branch) {
assert(i > 0 || node_ks(node) == 0); assert(i > 0 || node_ks(node) == 0);
align_bytes += node_key_size & 1;
continue; continue;
} }
const size_t node_data_size = node_ds(node);
assert(type == MDBX_page_leaf); assert(type == MDBX_page_leaf);
switch (node_flags(node)) { switch (node_flags(node)) {
case 0 /* usual node */: case 0 /* usual node */:
payload_size += node_ds(node); payload_size += node_data_size;
align_bytes += (node_key_size + node_data_size) & 1;
break; break;
case F_BIGDATA /* long data on the large/overflow page */: { case F_BIGDATA /* long data on the large/overflow page */: {
payload_size += sizeof(pgno_t);
const pgno_t large_pgno = node_largedata_pgno(node); const pgno_t large_pgno = node_largedata_pgno(node);
const size_t over_payload = node_ds(node); const size_t over_payload = node_data_size;
const size_t over_header = PAGEHDRSZ; const size_t over_header = PAGEHDRSZ;
npages = 1; npages = 1;
@ -24573,27 +24576,31 @@ __cold static int walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno,
over_payload, over_header, over_unused); over_payload, over_header, over_unused);
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc; return (rc == MDBX_RESULT_TRUE) ? MDBX_SUCCESS : rc;
payload_size += sizeof(pgno_t);
align_bytes += node_key_size & 1;
} break; } break;
case F_SUBDATA /* sub-db */: { case F_SUBDATA /* sub-db */: {
const size_t namelen = node_ks(node); const size_t namelen = node_key_size;
payload_size += node_ds(node); if (unlikely(namelen == 0 || node_data_size != sizeof(MDBX_db))) {
if (unlikely(namelen == 0 || node_ds(node) != sizeof(MDBX_db))) {
assert(err == MDBX_CORRUPTED); assert(err == MDBX_CORRUPTED);
err = MDBX_CORRUPTED; err = MDBX_CORRUPTED;
} }
header_size += node_data_size;
align_bytes += (node_key_size + node_data_size) & 1;
} break; } break;
case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */: case F_SUBDATA | F_DUPDATA /* dupsorted sub-tree */:
payload_size += sizeof(MDBX_db); if (unlikely(node_data_size != sizeof(MDBX_db))) {
if (unlikely(node_ds(node) != sizeof(MDBX_db))) {
assert(err == MDBX_CORRUPTED); assert(err == MDBX_CORRUPTED);
err = MDBX_CORRUPTED; err = MDBX_CORRUPTED;
} }
header_size += node_data_size;
align_bytes += (node_key_size + node_data_size) & 1;
break; break;
case F_DUPDATA /* short sub-page */: { case F_DUPDATA /* short sub-page */: {
if (unlikely(node_ds(node) <= PAGEHDRSZ)) { if (unlikely(node_data_size <= PAGEHDRSZ || (node_data_size & 1))) {
assert(err == MDBX_CORRUPTED); assert(err == MDBX_CORRUPTED);
err = MDBX_CORRUPTED; err = MDBX_CORRUPTED;
break; break;
@ -24621,16 +24628,17 @@ __cold static int walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno,
err = MDBX_CORRUPTED; err = MDBX_CORRUPTED;
} }
for (size_t j = 0; err == MDBX_SUCCESS && j < nsubkeys; for (size_t j = 0; err == MDBX_SUCCESS && j < nsubkeys; ++j) {
subalign_bytes += ((subpayload_size + subalign_bytes) & 1), ++j) {
if (subtype == MDBX_subpage_dupfixed_leaf) { if (subtype == MDBX_subpage_dupfixed_leaf) {
/* LEAF2 pages have no mp_ptrs[] or node headers */ /* LEAF2 pages have no mp_ptrs[] or node headers */
subpayload_size += sp->mp_leaf2_ksize; subpayload_size += sp->mp_leaf2_ksize;
} else { } else {
assert(subtype == MDBX_subpage_leaf); assert(subtype == MDBX_subpage_leaf);
MDBX_node *subnode = page_node(sp, j); const MDBX_node *subnode = page_node(sp, j);
subpayload_size += NODESIZE + node_ks(subnode) + node_ds(subnode); const size_t subnode_size = node_ks(subnode) + node_ds(subnode);
subheader_size += NODESIZE;
subpayload_size += subnode_size;
subalign_bytes += subnode_size & 1;
if (unlikely(node_flags(subnode) != 0)) { if (unlikely(node_flags(subnode) != 0)) {
assert(err == MDBX_CORRUPTED); assert(err == MDBX_CORRUPTED);
err = MDBX_CORRUPTED; err = MDBX_CORRUPTED;
@ -24639,7 +24647,7 @@ __cold static int walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno,
} }
const int rc = const int rc =
ctx->mw_visitor(pgno, 0, ctx->mw_user, deep + 1, sdb, node_ds(node), ctx->mw_visitor(pgno, 0, ctx->mw_user, deep + 1, sdb, node_data_size,
subtype, err, nsubkeys, subpayload_size, subtype, err, nsubkeys, subpayload_size,
subheader_size, subunused_size + subalign_bytes); subheader_size, subunused_size + subalign_bytes);
if (unlikely(rc != MDBX_SUCCESS)) if (unlikely(rc != MDBX_SUCCESS))
@ -24647,7 +24655,7 @@ __cold static int walk_tree(mdbx_walk_ctx_t *ctx, const pgno_t pgno,
header_size += subheader_size; header_size += subheader_size;
unused_size += subunused_size; unused_size += subunused_size;
payload_size += subpayload_size; payload_size += subpayload_size;
align_bytes += subalign_bytes; align_bytes += subalign_bytes + (node_key_size & 1);
} break; } break;
default: default:
@ -27581,19 +27589,12 @@ chk_pgvisitor(const size_t pgno, const unsigned npages, void *const ctx,
pagetype_caption, sizeof(long), header_bytes, pagetype_caption, sizeof(long), header_bytes,
env->me_psize - sizeof(long)); env->me_psize - sizeof(long));
} }
if (payload_bytes < 1) { if (nentries < 1 || (pagetype == MDBX_page_branch && nentries < 2)) {
if (nentries > 1) { chk_object_issue(scope, "page", pgno, nentries ? "half-empty" : "empty",
chk_object_issue(scope, "page", pgno, "zero size-of-entry", "%s-page: payload %" PRIuSIZE " bytes, %" PRIuSIZE
"%s-page: payload %" PRIuSIZE " bytes, %" PRIuSIZE " entries, deep %i",
" entries", pagetype_caption, payload_bytes, nentries, deep);
pagetype_caption, payload_bytes, nentries); sdb->pages.empty += 1;
} else {
chk_object_issue(scope, "page", pgno, "empty",
"%s-page: payload %" PRIuSIZE " bytes, %" PRIuSIZE
" entries, deep %i",
pagetype_caption, payload_bytes, nentries, deep);
sdb->pages.empty += 1;
}
} }
if (npages) { if (npages) {
@ -28402,13 +28403,28 @@ __cold static int env_chk(MDBX_chk_scope_t *const scope) {
chk_line_end( chk_line_end(
chk_puts(chk_line_begin(inner, MDBX_chk_verbose), chk_puts(chk_line_begin(inner, MDBX_chk_verbose),
"performs full check recent-txn-id with meta-pages")); "performs full check recent-txn-id with meta-pages"));
if (prefer_steady_txnid != chk->envinfo.mi_recent_txnid) { eASSERT(env, recent_txnid == chk->envinfo.mi_recent_txnid);
chk_scope_issue( if (prefer_steady_txnid != recent_txnid) {
inner, if ((chk->flags & MDBX_CHK_READWRITE) != 0 &&
"steady meta-%d txn-id mismatch recent-txn-id (%" PRIi64 (env->me_flags & MDBX_RDONLY) == 0 &&
" != %" PRIi64 ")", recent_txnid > prefer_steady_txnid &&
prefer_steady_metanum, prefer_steady_txnid, (chk->envinfo.mi_bootid.current.x |
chk->envinfo.mi_recent_txnid); chk->envinfo.mi_bootid.current.y) != 0 &&
chk->envinfo.mi_bootid.current.x ==
chk->envinfo.mi_bootid.meta[recent_metanum].x &&
chk->envinfo.mi_bootid.current.y ==
chk->envinfo.mi_bootid.meta[recent_metanum].y) {
chk_line_end(
chk_print(chk_line_begin(inner, MDBX_chk_verbose),
"recent meta-%u is weak, but boot-id match current"
" (will synced upon successful check)",
recent_metanum));
} else
chk_scope_issue(
inner,
"steady meta-%d txn-id mismatch recent-txn-id (%" PRIi64
" != %" PRIi64 ")",
prefer_steady_metanum, prefer_steady_txnid, recent_txnid);
} }
} else if (chk->write_locked) { } else if (chk->write_locked) {
chk_line_end( chk_line_end(
@ -28441,7 +28457,6 @@ __cold static int env_chk(MDBX_chk_scope_t *const scope) {
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
eASSERT(env, err == MDBX_SUCCESS);
if (chk->flags & MDBX_CHK_SKIP_BTREE_TRAVERSAL) if (chk->flags & MDBX_CHK_SKIP_BTREE_TRAVERSAL)
chk_line_end(chk_print(chk_line_begin(scope, MDBX_chk_processing), chk_line_end(chk_print(chk_line_begin(scope, MDBX_chk_processing),
"Skipping %s traversal...", "b-tree")); "Skipping %s traversal...", "b-tree"));
@ -28699,7 +28714,8 @@ __cold int mdbx_env_chk(MDBX_env *env, const struct MDBX_chk_callbacks *cb,
rc = chk_scope_begin( rc = chk_scope_begin(
chk, 0, MDBX_chk_lock, nullptr, nullptr, "Taking %slock...", chk, 0, MDBX_chk_lock, nullptr, nullptr, "Taking %slock...",
(env->me_flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) ? "" : "read "); (env->me_flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) ? "" : "read ");
if (likely(!rc) && (env->me_flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == 0) { if (likely(!rc) && (env->me_flags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == 0 &&
(flags & MDBX_CHK_READWRITE)) {
rc = mdbx_txn_lock(env, false); rc = mdbx_txn_lock(env, false);
if (unlikely(rc)) if (unlikely(rc))
chk_error_rc(ctx->scope, rc, "mdbx_txn_lock"); chk_error_rc(ctx->scope, rc, "mdbx_txn_lock");

View File

@ -691,7 +691,8 @@ int main(int argc, char *argv[]) {
bailout: bailout:
if (env) { if (env) {
const bool dont_sync = rc != 0 || chk.result.total_problems; const bool dont_sync = rc != 0 || chk.result.total_problems ||
(chk_flags & MDBX_CHK_READWRITE) == 0;
mdbx_env_close_ex(env, dont_sync); mdbx_env_close_ex(env, dont_sync);
} }
flush(); flush();