mirror of
https://github.com/isar/libmdbx.git
synced 2025-03-01 04:08:13 +08:00
mdbx: доработка chk-функционала с устранением ошибок и недочетов.
This commit is contained in:
parent
fb5dbbdf20
commit
164d112507
100
src/core.c
100
src/core.c
@ -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");
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user