mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-30 11:29:19 +08:00
mdbx-tools: skip iteration & checking records if corresponding tree is corrupted.
Hope final for https://github.com/erthink/libmdbx/issues/217
This commit is contained in:
parent
c8743cb9c4
commit
fe5f008d39
@ -112,7 +112,7 @@ struct problem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct problem *problems_list;
|
struct problem *problems_list;
|
||||||
uint64_t total_problems;
|
uint64_t total_problems, data_tree_problems, gc_tree_problems;
|
||||||
|
|
||||||
static void MDBX_PRINTF_ARGS(1, 2) print(const char *msg, ...) {
|
static void MDBX_PRINTF_ARGS(1, 2) print(const char *msg, ...) {
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
@ -299,14 +299,20 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
|||||||
const size_t nentries, const size_t payload_bytes,
|
const size_t nentries, const size_t payload_bytes,
|
||||||
const size_t header_bytes, const size_t unused_bytes) {
|
const size_t header_bytes, const size_t unused_bytes) {
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
|
const bool is_gc_tree = dbi_name_or_tag == MDBX_PGWALK_GC;
|
||||||
if (deep > 42) {
|
if (deep > 42) {
|
||||||
problem_add("deep", deep, "too large", nullptr);
|
problem_add("deep", deep, "too large", nullptr);
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
return MDBX_CORRUPTED /* avoid infinite loop/recursion */;
|
return MDBX_CORRUPTED /* avoid infinite loop/recursion */;
|
||||||
}
|
}
|
||||||
|
|
||||||
walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false);
|
walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false);
|
||||||
if (!dbi)
|
if (!dbi) {
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
return MDBX_ENOMEM;
|
return MDBX_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
const size_t page_bytes = payload_bytes + header_bytes + unused_bytes;
|
const size_t page_bytes = payload_bytes + header_bytes + unused_bytes;
|
||||||
walk.pgcount += pgnumber;
|
walk.pgcount += pgnumber;
|
||||||
@ -319,13 +325,19 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
|||||||
(unsigned)pagetype, deep);
|
(unsigned)pagetype, deep);
|
||||||
pagetype_caption = "unknown";
|
pagetype_caption = "unknown";
|
||||||
dbi->pages.other += pgnumber;
|
dbi->pages.other += pgnumber;
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
break;
|
break;
|
||||||
case MDBX_page_broken:
|
case MDBX_page_broken:
|
||||||
pagetype_caption = "broken";
|
pagetype_caption = "broken";
|
||||||
dbi->pages.other += pgnumber;
|
dbi->pages.other += pgnumber;
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
break;
|
break;
|
||||||
case MDBX_subpage_broken:
|
case MDBX_subpage_broken:
|
||||||
pagetype_caption = "broken-subpage";
|
pagetype_caption = "broken-subpage";
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
break;
|
break;
|
||||||
case MDBX_page_meta:
|
case MDBX_page_meta:
|
||||||
pagetype_caption = "meta";
|
pagetype_caption = "meta";
|
||||||
@ -375,17 +387,21 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
|||||||
bool already_used = false;
|
bool already_used = false;
|
||||||
for (unsigned n = 0; n < pgnumber; ++n) {
|
for (unsigned n = 0; n < pgnumber; ++n) {
|
||||||
uint64_t spanpgno = pgno + n;
|
uint64_t spanpgno = pgno + n;
|
||||||
if (spanpgno >= alloc_pages)
|
if (spanpgno >= alloc_pages) {
|
||||||
problem_add("page", spanpgno, "wrong page-no",
|
problem_add("page", spanpgno, "wrong page-no",
|
||||||
"%s-page: %" PRIu64 " > %" PRIu64 ", deep %i",
|
"%s-page: %" PRIu64 " > %" PRIu64 ", deep %i",
|
||||||
pagetype_caption, spanpgno, alloc_pages, deep);
|
pagetype_caption, spanpgno, alloc_pages, deep);
|
||||||
else if (walk.pagemap[spanpgno]) {
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
|
} else if (walk.pagemap[spanpgno]) {
|
||||||
walk_dbi_t *coll_dbi = &walk.dbi[walk.pagemap[spanpgno] - 1];
|
walk_dbi_t *coll_dbi = &walk.dbi[walk.pagemap[spanpgno] - 1];
|
||||||
problem_add("page", spanpgno,
|
problem_add("page", spanpgno,
|
||||||
(branch && coll_dbi == dbi) ? "loop" : "already used",
|
(branch && coll_dbi == dbi) ? "loop" : "already used",
|
||||||
"%s-page: by %s, deep %i", pagetype_caption, coll_dbi->name,
|
"%s-page: by %s, deep %i", pagetype_caption, coll_dbi->name,
|
||||||
deep);
|
deep);
|
||||||
already_used = true;
|
already_used = true;
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
} else {
|
} else {
|
||||||
walk.pagemap[spanpgno] = (short)(dbi - walk.dbi + 1);
|
walk.pagemap[spanpgno] = (short)(dbi - walk.dbi + 1);
|
||||||
dbi->pages.total += 1;
|
dbi->pages.total += 1;
|
||||||
@ -399,18 +415,26 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
|||||||
|
|
||||||
if (MDBX_IS_ERROR(err)) {
|
if (MDBX_IS_ERROR(err)) {
|
||||||
problem_add("page", pgno, "invalid/corrupted", "%s-page", pagetype_caption);
|
problem_add("page", pgno, "invalid/corrupted", "%s-page", pagetype_caption);
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
} else {
|
} else {
|
||||||
if (unused_bytes > page_size)
|
if (unused_bytes > page_size) {
|
||||||
problem_add("page", pgno, "illegal unused-bytes",
|
problem_add("page", pgno, "illegal unused-bytes",
|
||||||
"%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0,
|
"%s-page: %u < %" PRIuPTR " < %u", pagetype_caption, 0,
|
||||||
unused_bytes, envinfo.mi_dxb_pagesize);
|
unused_bytes, envinfo.mi_dxb_pagesize);
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
|
}
|
||||||
|
|
||||||
if (header_bytes < (int)sizeof(long) ||
|
if (header_bytes < (int)sizeof(long) ||
|
||||||
(size_t)header_bytes >= envinfo.mi_dxb_pagesize - sizeof(long))
|
(size_t)header_bytes >= envinfo.mi_dxb_pagesize - sizeof(long)) {
|
||||||
problem_add("page", pgno, "illegal header-length",
|
problem_add("page", pgno, "illegal header-length",
|
||||||
"%s-page: %" PRIuPTR " < %" PRIuPTR " < %" PRIuPTR,
|
"%s-page: %" PRIuPTR " < %" PRIuPTR " < %" PRIuPTR,
|
||||||
pagetype_caption, sizeof(long), header_bytes,
|
pagetype_caption, sizeof(long), header_bytes,
|
||||||
envinfo.mi_dxb_pagesize - sizeof(long));
|
envinfo.mi_dxb_pagesize - sizeof(long));
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
|
}
|
||||||
if (payload_bytes < 1) {
|
if (payload_bytes < 1) {
|
||||||
if (nentries > 1) {
|
if (nentries > 1) {
|
||||||
problem_add("page", pgno, "zero size-of-entry",
|
problem_add("page", pgno, "zero size-of-entry",
|
||||||
@ -420,12 +444,16 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
|||||||
// LY: hush a misuse error
|
// LY: hush a misuse error
|
||||||
page_bytes = page_size;
|
page_bytes = page_size;
|
||||||
} */
|
} */
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
} else {
|
} else {
|
||||||
problem_add("page", pgno, "empty",
|
problem_add("page", pgno, "empty",
|
||||||
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
|
"%s-page: payload %" PRIuPTR " bytes, %" PRIuPTR
|
||||||
" entries, deep %i",
|
" entries, deep %i",
|
||||||
pagetype_caption, payload_bytes, nentries, deep);
|
pagetype_caption, payload_bytes, nentries, deep);
|
||||||
dbi->pages.empty += 1;
|
dbi->pages.empty += 1;
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,6 +466,8 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
|||||||
payload_bytes, unused_bytes, deep);
|
payload_bytes, unused_bytes, deep);
|
||||||
if (page_size > page_bytes)
|
if (page_size > page_bytes)
|
||||||
dbi->lost_bytes += page_size - page_bytes;
|
dbi->lost_bytes += page_size - page_bytes;
|
||||||
|
data_tree_problems += !is_gc_tree;
|
||||||
|
gc_tree_problems += is_gc_tree;
|
||||||
} else {
|
} else {
|
||||||
dbi->payload_bytes += payload_bytes + header_bytes;
|
dbi->payload_bytes += payload_bytes + header_bytes;
|
||||||
walk.total_payload_bytes += payload_bytes + header_bytes;
|
walk.total_payload_bytes += payload_bytes + header_bytes;
|
||||||
@ -1558,8 +1588,19 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
print("Iterating DBIs...\n");
|
print("Iterating DBIs...\n");
|
||||||
problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr, false);
|
if (data_tree_problems) {
|
||||||
problems_freedb = process_db(FREE_DBI, "@GC", handle_freedb, false);
|
print("Skip processing %s since tree is corrupted (%" PRIu64 " problems)\n",
|
||||||
|
"@MAIN", data_tree_problems);
|
||||||
|
problems_maindb = data_tree_problems;
|
||||||
|
} else
|
||||||
|
problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr, false);
|
||||||
|
|
||||||
|
if (gc_tree_problems) {
|
||||||
|
print("Skip processing %s since tree is corrupted (%" PRIu64 " problems)\n",
|
||||||
|
"@GC", gc_tree_problems);
|
||||||
|
problems_freedb = gc_tree_problems;
|
||||||
|
} else
|
||||||
|
problems_freedb = process_db(FREE_DBI, "@GC", handle_freedb, false);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
uint64_t value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize;
|
uint64_t value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize;
|
||||||
|
Loading…
Reference in New Issue
Block a user