mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-06 19:24:13 +08:00
lmdb: '-d' option to mdb_chk for disabling b-tree traversal.
Change-Id: Ifd3bb0d93a4fa6d93f46b547fd73ee92dc331418
This commit is contained in:
parent
db7e7ae4df
commit
69beb1525f
113
mdb_chk.c
113
mdb_chk.c
@ -48,19 +48,24 @@ flagbit dbflags[] = {
|
|||||||
|
|
||||||
static volatile sig_atomic_t gotsignal;
|
static volatile sig_atomic_t gotsignal;
|
||||||
|
|
||||||
static void signal_hanlder( int sig )
|
static void signal_hanlder( int sig ) {
|
||||||
{
|
|
||||||
gotsignal = 1;
|
gotsignal = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_DBI 32768
|
#define MAX_DBI 32768
|
||||||
|
|
||||||
const char* dbi_names[MAX_DBI] = { "@gc" };
|
struct {
|
||||||
|
const char* dbi_names[MAX_DBI];
|
||||||
size_t dbi_pages[MAX_DBI];
|
size_t dbi_pages[MAX_DBI];
|
||||||
size_t dbi_payload_bytes[MAX_DBI];
|
size_t dbi_payload_bytes[MAX_DBI];
|
||||||
short *pagemap;
|
short *pagemap;
|
||||||
|
size_t total_payload_bytes;
|
||||||
size_t pgcount;
|
size_t pgcount;
|
||||||
size_t total_payload_bytes, total_unused_bytes;
|
} walk = {
|
||||||
|
.dbi_names = { "@gc" }
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t total_unused_bytes;
|
||||||
int exclusive = 2;
|
int exclusive = 2;
|
||||||
|
|
||||||
MDB_env *env;
|
MDB_env *env;
|
||||||
@ -109,17 +114,17 @@ error(const char* msg, ...) {
|
|||||||
static int pagemap_lookup_dbi(const char* dbi) {
|
static int pagemap_lookup_dbi(const char* dbi) {
|
||||||
static int last;
|
static int last;
|
||||||
|
|
||||||
if (last > 0 && strcmp(dbi_names[last], dbi) == 0)
|
if (last > 0 && strcmp(walk.dbi_names[last], dbi) == 0)
|
||||||
return last;
|
return last;
|
||||||
|
|
||||||
for(last = 1; dbi_names[last] && last < MAX_DBI; ++last)
|
for(last = 1; walk.dbi_names[last] && last < MAX_DBI; ++last)
|
||||||
if (strcmp(dbi_names[last], dbi) == 0)
|
if (strcmp(walk.dbi_names[last], dbi) == 0)
|
||||||
return last;
|
return last;
|
||||||
|
|
||||||
if (last == MAX_DBI)
|
if (last == MAX_DBI)
|
||||||
return last = -1;
|
return last = -1;
|
||||||
|
|
||||||
dbi_names[last] = strdup(dbi);
|
walk.dbi_names[last] = strdup(dbi);
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,12 +190,12 @@ static int pgvisitor(size_t pgno, unsigned pgnumber, void* ctx, const char* dbi,
|
|||||||
char type, int payload_bytes, int header_bytes)
|
char type, int payload_bytes, int header_bytes)
|
||||||
{
|
{
|
||||||
if (pgnumber) {
|
if (pgnumber) {
|
||||||
pgcount += pgnumber;
|
|
||||||
|
|
||||||
int index = pagemap_lookup_dbi(dbi);
|
int index = pagemap_lookup_dbi(dbi);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
|
walk.pgcount += pgnumber;
|
||||||
|
|
||||||
if (header_bytes < sizeof(long) || header_bytes >= stat.ms_psize - sizeof(long))
|
if (header_bytes < sizeof(long) || header_bytes >= stat.ms_psize - sizeof(long))
|
||||||
problem_add(pgno, "wrong header-length", "(%zu < %i < %zu)",
|
problem_add(pgno, "wrong header-length", "(%zu < %i < %zu)",
|
||||||
sizeof(long), header_bytes, header_bytes >= stat.ms_psize - sizeof(long));
|
sizeof(long), header_bytes, header_bytes >= stat.ms_psize - sizeof(long));
|
||||||
@ -200,18 +205,18 @@ static int pgvisitor(size_t pgno, unsigned pgnumber, void* ctx, const char* dbi,
|
|||||||
problem_add(pgno, "overflowed page", "(%zu + %zu > %zu)",
|
problem_add(pgno, "overflowed page", "(%zu + %zu > %zu)",
|
||||||
payload_bytes, header_bytes, pgnumber * stat.ms_psize);
|
payload_bytes, header_bytes, pgnumber * stat.ms_psize);
|
||||||
else {
|
else {
|
||||||
dbi_payload_bytes[index] += payload_bytes + header_bytes;
|
walk.dbi_payload_bytes[index] += payload_bytes + header_bytes;
|
||||||
total_payload_bytes += payload_bytes + header_bytes;
|
walk.total_payload_bytes += payload_bytes + header_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (pgno >= lastpgno)
|
if (pgno >= lastpgno)
|
||||||
problem_add(pgno, "wrong page-no", "(> %zi)", lastpgno);
|
problem_add(pgno, "wrong page-no", "(> %zi)", lastpgno);
|
||||||
else if (pagemap[pgno])
|
else if (walk.pagemap[pgno])
|
||||||
problem_add(pgno, "page already used", "(in %s)", dbi_names[pagemap[pgno]]);
|
problem_add(pgno, "page already used", "(in %s)", walk.dbi_names[walk.pagemap[pgno]]);
|
||||||
else {
|
else {
|
||||||
pagemap[pgno] = index;
|
walk.pagemap[pgno] = index;
|
||||||
dbi_pages[index] += 1;
|
walk.dbi_pages[index] += 1;
|
||||||
}
|
}
|
||||||
++pgno;
|
++pgno;
|
||||||
} while(--pgnumber);
|
} while(--pgnumber);
|
||||||
@ -468,7 +473,8 @@ static void usage(char *prog)
|
|||||||
" -v\tmore verbose, could be used multiple times\n"
|
" -v\tmore verbose, could be used multiple times\n"
|
||||||
" -n\tNOSUBDIR mode for open\n"
|
" -n\tNOSUBDIR mode for open\n"
|
||||||
" -q\tbe quiet\n"
|
" -q\tbe quiet\n"
|
||||||
" -w\tstart write-txn to lock db\n"
|
" -w\tlock DB for writing while checking\n"
|
||||||
|
" -d\tdisable page-by-page traversal of b-tree\n"
|
||||||
" -c\tforce cooperative mode (don't try exclusive)\n", prog);
|
" -c\tforce cooperative mode (don't try exclusive)\n", prog);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -495,13 +501,14 @@ int main(int argc, char *argv[])
|
|||||||
char *envname;
|
char *envname;
|
||||||
int envflags = MDB_RDONLY;
|
int envflags = MDB_RDONLY;
|
||||||
int problems_maindb = 0, problems_freedb = 0, problems_meta = 0;
|
int problems_maindb = 0, problems_freedb = 0, problems_meta = 0;
|
||||||
|
int dont_traversal = 0;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
usage(prog);
|
usage(prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((i = getopt(argc, argv, "Vvqnwc")) != EOF) {
|
while ((i = getopt(argc, argv, "Vvqnwcd")) != EOF) {
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("%s\n", MDB_VERSION_STRING);
|
printf("%s\n", MDB_VERSION_STRING);
|
||||||
@ -522,6 +529,9 @@ int main(int argc, char *argv[])
|
|||||||
case 'c':
|
case 'c':
|
||||||
exclusive = 0;
|
exclusive = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
dont_traversal = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(prog);
|
usage(prog);
|
||||||
}
|
}
|
||||||
@ -594,12 +604,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
lastpgno = info.me_last_pgno + 1;
|
lastpgno = info.me_last_pgno + 1;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
pagemap = calloc(lastpgno, sizeof(*pagemap));
|
|
||||||
if (! pagemap) {
|
|
||||||
rc = errno ? errno : ENOMEM;
|
|
||||||
error("calloc failed, error %d %s\n", rc, mdb_strerror(rc));
|
|
||||||
goto bailout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
double k = 1024.0;
|
double k = 1024.0;
|
||||||
@ -666,41 +670,52 @@ int main(int argc, char *argv[])
|
|||||||
print(" - skip check last-txn-id with meta-pages (monopolistic or write-lock mode only)\n");
|
print(" - skip check last-txn-id with meta-pages (monopolistic or write-lock mode only)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Walking b-tree...\n");
|
if (!dont_traversal) {
|
||||||
|
print("Traversal b-tree...\n");
|
||||||
|
walk.pagemap = calloc(lastpgno, sizeof(*walk.pagemap));
|
||||||
|
if (! walk.pagemap) {
|
||||||
|
rc = errno ? errno : ENOMEM;
|
||||||
|
error("calloc failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
|
||||||
rc = mdb_env_pgwalk(txn, pgvisitor, NULL);
|
rc = mdb_env_pgwalk(txn, pgvisitor, NULL);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
error("mdb_env_pgwalk failed, error %d %s\n", rc, mdb_strerror(rc));
|
error("mdb_env_pgwalk failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
for( n = 0; n < lastpgno; ++n)
|
for( n = 0; n < lastpgno; ++n)
|
||||||
if (! pagemap[n])
|
if (! walk.pagemap[n])
|
||||||
dbi_pages[0] += 1;
|
walk.dbi_pages[0] += 1;
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
size_t total_page_bytes = pgcount * stat.ms_psize;
|
size_t total_page_bytes = walk.pgcount * stat.ms_psize;
|
||||||
print(" - dbi pages: %zu total", pgcount);
|
print(" - dbi pages: %zu total", walk.pgcount);
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
for (i = 1; i < MAX_DBI && dbi_names[i]; ++i)
|
for (i = 1; i < MAX_DBI && walk.dbi_names[i]; ++i)
|
||||||
print(", %s %zu", dbi_names[i], dbi_pages[i]);
|
print(", %s %zu", walk.dbi_names[i], walk.dbi_pages[i]);
|
||||||
print(", %s %zu\n", dbi_names[0], dbi_pages[0]);
|
print(", %s %zu\n", walk.dbi_names[0], walk.dbi_pages[0]);
|
||||||
if (verbose > 1) {
|
if (verbose > 1) {
|
||||||
print(" - space info: total %zu bytes, payload %.2f%% (%zu), unused %.2f%% (%zu)\n",
|
print(" - space info: total %zu bytes, payload %.2f%% (%zu), unused %.2f%% (%zu)\n",
|
||||||
total_page_bytes,
|
total_page_bytes,
|
||||||
total_payload_bytes * 100.0 / total_page_bytes, total_payload_bytes,
|
walk.total_payload_bytes * 100.0 / total_page_bytes, walk.total_payload_bytes,
|
||||||
(total_page_bytes - total_payload_bytes) * 100.0 / total_page_bytes,
|
(total_page_bytes - walk.total_payload_bytes) * 100.0 / total_page_bytes,
|
||||||
total_page_bytes - total_payload_bytes);
|
total_page_bytes - walk.total_payload_bytes);
|
||||||
for (i = 1; i < MAX_DBI && dbi_names[i]; ++i) {
|
for (i = 1; i < MAX_DBI && walk.dbi_names[i]; ++i) {
|
||||||
size_t dbi_bytes = dbi_pages[i] * stat.ms_psize;
|
size_t dbi_bytes = walk.dbi_pages[i] * stat.ms_psize;
|
||||||
print(" %s: subtotal %.2f%% (%zu), payload %.2f%% (%zu), unused %.2f%% (%zu)\n",
|
print(" %s: subtotal %.2f%% (%zu), payload %.2f%% (%zu), unused %.2f%% (%zu)\n",
|
||||||
dbi_names[i],
|
walk.dbi_names[i],
|
||||||
dbi_bytes * 100.0 / total_page_bytes, dbi_bytes,
|
dbi_bytes * 100.0 / total_page_bytes, dbi_bytes,
|
||||||
dbi_payload_bytes[i] * 100.0 / dbi_bytes, dbi_payload_bytes[i],
|
walk.dbi_payload_bytes[i] * 100.0 / dbi_bytes, walk.dbi_payload_bytes[i],
|
||||||
(dbi_bytes - dbi_payload_bytes[i]) * 100.0 / dbi_bytes,
|
(dbi_bytes - walk.dbi_payload_bytes[i]) * 100.0 / dbi_bytes,
|
||||||
dbi_bytes - dbi_payload_bytes[i]);
|
dbi_bytes - walk.dbi_payload_bytes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print(" - summary: average fill %.2f%%, %zu problems\n",
|
print(" - summary: average fill %.2f%%, %zu problems\n",
|
||||||
total_payload_bytes * 100.0 / total_page_bytes, total_problems);
|
walk.total_payload_bytes * 100.0 / total_page_bytes, total_problems);
|
||||||
|
}
|
||||||
|
} else if (verbose) {
|
||||||
|
print("Skipping b-tree walk...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! verbose)
|
if (! verbose)
|
||||||
@ -734,15 +749,15 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (problems_maindb == 0 && problems_freedb == 0) {
|
if (problems_maindb == 0 && problems_freedb == 0) {
|
||||||
if (exclusive || locktxn) {
|
if (!dont_traversal && (exclusive || locktxn)) {
|
||||||
if (pgcount != lastpgno - freedb_pages) {
|
if (walk.pgcount != lastpgno - freedb_pages) {
|
||||||
error("used pages mismatch (%zu != %zu)\n", pgcount, lastpgno - freedb_pages);
|
error("used pages mismatch (%zu != %zu)\n", walk.pgcount, lastpgno - freedb_pages);
|
||||||
}
|
}
|
||||||
if (dbi_pages[0] != freedb_pages) {
|
if (walk.dbi_pages[0] != freedb_pages) {
|
||||||
error("gc pages mismatch (%zu != %zu)\n", dbi_pages[0], freedb_pages);
|
error("gc pages mismatch (%zu != %zu)\n", walk.dbi_pages[0], freedb_pages);
|
||||||
}
|
}
|
||||||
} else if (verbose) {
|
} else if (verbose) {
|
||||||
print(" - skip check used and gc pages (monopolistic or write-lock mode only)\n");
|
print(" - skip check used and gc pages (btree-traversal with monopolistic or write-lock mode only)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! process_db(-1, NULL, handle_maindb, 1)) {
|
if (! process_db(-1, NULL, handle_maindb, 1)) {
|
||||||
@ -758,7 +773,7 @@ bailout:
|
|||||||
mdb_txn_abort(locktxn);
|
mdb_txn_abort(locktxn);
|
||||||
if (env)
|
if (env)
|
||||||
mdb_env_close(env);
|
mdb_env_close(env);
|
||||||
free(pagemap);
|
free(walk.pagemap);
|
||||||
if (rc)
|
if (rc)
|
||||||
return EXIT_FAILURE + 2;
|
return EXIT_FAILURE + 2;
|
||||||
total_problems += problems_meta;
|
total_problems += problems_meta;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user