mdbx-chk: fix false-positive 'wrong idl entry' error(s).

Исторически mdbx_env_info() получает информацию вне контекста
транзакции. Поэтому транзакция чтения, внутри которой проверяются записи
GC, может быть не последней. При этом в более новых транзакциях
последние страницы могут быть возвращены в пул нераспределенных с
уменьшением номера последней выделенной страницы. Тогда в проверяемом
снимке в записях GC могут быть номера страниц больше, чем возвращает
mdbx_env_info() в поле mi_last_pgno, что трактовалось в mdbx_chk как
ошибка.

Change-Id: I51ae102603e1eda77d6b6d511e2094410ab8c2c2
This commit is contained in:
Leonid Yuriev 2019-08-11 16:33:03 +03:00
parent 8917fb30bf
commit 036144eed4

View File

@ -91,7 +91,7 @@ MDBX_txn *txn;
MDBX_envinfo envinfo; MDBX_envinfo envinfo;
MDBX_stat envstat; MDBX_stat envstat;
size_t maxkeysize, userdb_count, skipped_subdb; size_t maxkeysize, userdb_count, skipped_subdb;
uint64_t reclaimable_pages, gc_pages, lastpgno, unused_pages; uint64_t reclaimable_pages, gc_pages, alloc_pages, unused_pages, backed_pages;
unsigned verbose; unsigned verbose;
char ignore_wrong_order, quiet; char ignore_wrong_order, quiet;
const char *only_subdb; const char *only_subdb;
@ -329,10 +329,10 @@ 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 >= lastpgno) 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, lastpgno, deep); pagetype_caption, spanpgno, alloc_pages, deep);
else if (walk.pagemap[spanpgno]) { 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,
@ -450,9 +450,17 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
pgno_t span = 1; pgno_t span = 1;
for (unsigned i = 0; i < number; ++i) { for (unsigned i = 0; i < number; ++i) {
const pgno_t pgno = iptr[i]; const pgno_t pgno = iptr[i];
if (pgno < NUM_METAS || pgno > envinfo.mi_last_pgno) if (pgno < NUM_METAS)
problem_add("entry", txnid, "wrong idl entry", problem_add("entry", txnid, "wrong idl entry",
"%u < %" PRIaPGNO " < %" PRIu64, NUM_METAS, pgno, "pgno %" PRIaPGNO " < meta-pages %u", pgno, NUM_METAS);
else if (pgno >= backed_pages)
problem_add("entry", txnid, "wrong idl entry",
"pgno %" PRIaPGNO " >= backed-pages %" PRIu64, pgno,
backed_pages);
else if (pgno > envinfo.mi_last_pgno &&
envinfo.mi_recent_txnid == txn->mt_txnid)
problem_add("entry", txnid, "wrong idl entry",
"pgno %" PRIaPGNO " > alloc-pages %" PRIu64, pgno,
envinfo.mi_last_pgno); envinfo.mi_last_pgno);
else { else {
if (MDBX_PNL_DISORDERED(prev, pgno)) { if (MDBX_PNL_DISORDERED(prev, pgno)) {
@ -1062,7 +1070,8 @@ int main(int argc, char *argv[]) {
goto bailout; goto bailout;
} }
lastpgno = envinfo.mi_last_pgno + 1; alloc_pages = envinfo.mi_last_pgno + 1;
backed_pages = envinfo.mi_geo.current / envinfo.mi_dxb_pagesize;
errno = 0; errno = 0;
if (verbose) { if (verbose) {
@ -1131,7 +1140,7 @@ int main(int argc, char *argv[]) {
print("Traversal b-tree by txn#%" PRIaTXN "...\n", txn->mt_txnid); print("Traversal b-tree by txn#%" PRIaTXN "...\n", txn->mt_txnid);
fflush(NULL); fflush(NULL);
walk.pagemap = mdbx_calloc((size_t)lastpgno, sizeof(*walk.pagemap)); walk.pagemap = mdbx_calloc((size_t)alloc_pages, sizeof(*walk.pagemap));
if (!walk.pagemap) { if (!walk.pagemap) {
rc = errno ? errno : MDBX_ENOMEM; rc = errno ? errno : MDBX_ENOMEM;
error("calloc failed, error %d %s\n", rc, mdbx_strerror(rc)); error("calloc failed, error %d %s\n", rc, mdbx_strerror(rc));
@ -1152,7 +1161,7 @@ int main(int argc, char *argv[]) {
goto bailout; goto bailout;
} }
for (uint64_t n = 0; n < lastpgno; ++n) for (uint64_t n = 0; n < alloc_pages; ++n)
if (!walk.pagemap[n]) if (!walk.pagemap[n])
unused_pages += 1; unused_pages += 1;
@ -1242,15 +1251,16 @@ int main(int argc, char *argv[]) {
uint64_t value = envinfo.mi_mapsize / envstat.ms_psize; uint64_t value = envinfo.mi_mapsize / envstat.ms_psize;
double percent = value / 100.0; double percent = value / 100.0;
print(" - space: %" PRIu64 " total pages", value); print(" - space: %" PRIu64 " total pages", value);
value = envinfo.mi_geo.current / envinfo.mi_dxb_pagesize; print(", backed %" PRIu64 " (%.1f%%)", backed_pages,
print(", backed %" PRIu64 " (%.1f%%)", value, value / percent); backed_pages / percent);
print(", allocated %" PRIu64 " (%.1f%%)", lastpgno, lastpgno / percent); print(", allocated %" PRIu64 " (%.1f%%)", alloc_pages,
alloc_pages / percent);
if (verbose > 1) { if (verbose > 1) {
value = envinfo.mi_mapsize / envstat.ms_psize - lastpgno; value = envinfo.mi_mapsize / envstat.ms_psize - alloc_pages;
print(", remained %" PRIu64 " (%.1f%%)", value, value / percent); print(", remained %" PRIu64 " (%.1f%%)", value, value / percent);
value = lastpgno - gc_pages; value = alloc_pages - gc_pages;
print(", used %" PRIu64 " (%.1f%%)", value, value / percent); print(", used %" PRIu64 " (%.1f%%)", value, value / percent);
print(", gc %" PRIu64 " (%.1f%%)", gc_pages, gc_pages / percent); print(", gc %" PRIu64 " (%.1f%%)", gc_pages, gc_pages / percent);
@ -1263,16 +1273,16 @@ int main(int argc, char *argv[]) {
} }
value = value =
envinfo.mi_mapsize / envstat.ms_psize - lastpgno + reclaimable_pages; envinfo.mi_mapsize / envstat.ms_psize - alloc_pages + reclaimable_pages;
print(", available %" PRIu64 " (%.1f%%)\n", value, value / percent); print(", available %" PRIu64 " (%.1f%%)\n", value, value / percent);
} }
if (problems_maindb == 0 && problems_freedb == 0) { if (problems_maindb == 0 && problems_freedb == 0) {
if (!dont_traversal && if (!dont_traversal &&
(envflags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) != MDBX_RDONLY) { (envflags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) != MDBX_RDONLY) {
if (walk.pgcount != lastpgno - gc_pages) { if (walk.pgcount != alloc_pages - gc_pages) {
error("used pages mismatch (%" PRIu64 " != %" PRIu64 ")\n", error("used pages mismatch (%" PRIu64 " != %" PRIu64 ")\n",
walk.pgcount, lastpgno - gc_pages); walk.pgcount, alloc_pages - gc_pages);
} }
if (unused_pages != gc_pages) { if (unused_pages != gc_pages) {
error("gc pages mismatch (%" PRIu64 " != %" PRIu64 ")\n", unused_pages, error("gc pages mismatch (%" PRIu64 " != %" PRIu64 ")\n", unused_pages,