xref: /netbsd-src/lib/libc/db/btree/bt_debug.c (revision 04b0597d11fd9ec3a0fd156bca2401b22f1d993e)
1*04b0597dSjoerg /*	$NetBSD: bt_debug.c,v 1.19 2016/10/09 11:48:24 joerg Exp $	*/
2a954b078Scgd 
39f0aa214Scgd /*-
4a6d14e36Scgd  * Copyright (c) 1990, 1993, 1994
59f0aa214Scgd  *	The Regents of the University of California.  All rights reserved.
69f0aa214Scgd  *
79f0aa214Scgd  * This code is derived from software contributed to Berkeley by
89f0aa214Scgd  * Mike Olson.
99f0aa214Scgd  *
109f0aa214Scgd  * Redistribution and use in source and binary forms, with or without
119f0aa214Scgd  * modification, are permitted provided that the following conditions
129f0aa214Scgd  * are met:
139f0aa214Scgd  * 1. Redistributions of source code must retain the above copyright
149f0aa214Scgd  *    notice, this list of conditions and the following disclaimer.
159f0aa214Scgd  * 2. Redistributions in binary form must reproduce the above copyright
169f0aa214Scgd  *    notice, this list of conditions and the following disclaimer in the
179f0aa214Scgd  *    documentation and/or other materials provided with the distribution.
18eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
199f0aa214Scgd  *    may be used to endorse or promote products derived from this software
209f0aa214Scgd  *    without specific prior written permission.
219f0aa214Scgd  *
229f0aa214Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239f0aa214Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249f0aa214Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259f0aa214Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269f0aa214Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279f0aa214Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289f0aa214Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299f0aa214Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309f0aa214Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319f0aa214Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329f0aa214Scgd  * SUCH DAMAGE.
339f0aa214Scgd  */
349f0aa214Scgd 
35b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H
36b2f78261Sjmc #include "nbtool_config.h"
37b2f78261Sjmc #endif
38b2f78261Sjmc 
3900ae392dSchristos #include <sys/cdefs.h>
40*04b0597dSjoerg __RCSID("$NetBSD: bt_debug.c,v 1.19 2016/10/09 11:48:24 joerg Exp $");
419f0aa214Scgd 
42cb9daf8fSchristos #include <assert.h>
439f0aa214Scgd #include <stdio.h>
449f0aa214Scgd #include <stdlib.h>
459f0aa214Scgd #include <string.h>
469f0aa214Scgd 
479f0aa214Scgd #include <db.h>
489f0aa214Scgd #include "btree.h"
499f0aa214Scgd 
5086147b1cSchristos #if defined(DEBUG) || defined(STATISTICS)
5186147b1cSchristos 
5286147b1cSchristos static FILE *tracefp;
5386147b1cSchristos 
5486147b1cSchristos /*
5586147b1cSchristos  * __bt_dinit --
5686147b1cSchristos  *     initialize debugging.
5786147b1cSchristos  */
5886147b1cSchristos static void
__bt_dinit(void)5986147b1cSchristos __bt_dinit(void)
6086147b1cSchristos {
6186147b1cSchristos 	if (tracefp != NULL)
6286147b1cSchristos 		return;
6386147b1cSchristos 
6486147b1cSchristos #ifndef TRACE_TO_STDERR
6586147b1cSchristos 	if ((tracefp = fopen("/tmp/__bt_debug", "w")) != NULL)
6686147b1cSchristos 		return;
6786147b1cSchristos #endif
6886147b1cSchristos 	tracefp = stderr;
6986147b1cSchristos }
7086147b1cSchristos #endif
7186147b1cSchristos 
7286147b1cSchristos 
739f0aa214Scgd #ifdef DEBUG
749f0aa214Scgd /*
759f0aa214Scgd  * BT_DUMP -- Dump the tree
769f0aa214Scgd  *
779f0aa214Scgd  * Parameters:
789f0aa214Scgd  *	dbp:	pointer to the DB
799f0aa214Scgd  */
809f0aa214Scgd void
__bt_dump(DB * dbp)81cb9daf8fSchristos __bt_dump(DB *dbp)
829f0aa214Scgd {
839f0aa214Scgd 	BTREE *t;
849f0aa214Scgd 	PAGE *h;
859f0aa214Scgd 	pgno_t i;
86ec567cd3Schristos 	const char *sep;
879f0aa214Scgd 
8886147b1cSchristos 	__bt_dinit();
8986147b1cSchristos 
909f0aa214Scgd 	t = dbp->internal;
9186147b1cSchristos 	(void)fprintf(tracefp, "%s: pgsz %d",
9224420c01Scgd 	    F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
9324420c01Scgd 	if (F_ISSET(t, R_RECNO))
9486147b1cSchristos 		(void)fprintf(tracefp, " keys %lu", (unsigned long) t->bt_nrecs);
959f0aa214Scgd #undef X
969f0aa214Scgd #define	X(flag, name) \
9724420c01Scgd 	if (F_ISSET(t, flag)) { \
9886147b1cSchristos 		(void)fprintf(tracefp, "%s%s", sep, name); \
999f0aa214Scgd 		sep = ", "; \
1009f0aa214Scgd 	}
10124420c01Scgd 	if (t->flags != 0) {
1029f0aa214Scgd 		sep = " flags (";
1039f0aa214Scgd 		X(R_FIXLEN,	"FIXLEN");
1049f0aa214Scgd 		X(B_INMEM,	"INMEM");
1059f0aa214Scgd 		X(B_NODUPS,	"NODUPS");
1069f0aa214Scgd 		X(B_RDONLY,	"RDONLY");
1079f0aa214Scgd 		X(R_RECNO,	"RECNO");
1089f0aa214Scgd 		X(B_METADIRTY,"METADIRTY");
10986147b1cSchristos 		(void)fprintf(tracefp, ")\n");
1109f0aa214Scgd 	}
1119f0aa214Scgd #undef X
1129f0aa214Scgd 
11386147b1cSchristos 	for (i = P_ROOT; i < t->bt_mp->npages &&
114aae80e6bSchristos 	    (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
1159f0aa214Scgd 		__bt_dpage(h);
11686147b1cSchristos 
11786147b1cSchristos 	(void)fflush(tracefp);
1189f0aa214Scgd }
1199f0aa214Scgd 
1209f0aa214Scgd /*
1219f0aa214Scgd  * BT_DMPAGE -- Dump the meta page
1229f0aa214Scgd  *
1239f0aa214Scgd  * Parameters:
1249f0aa214Scgd  *	h:	pointer to the PAGE
1259f0aa214Scgd  */
1269f0aa214Scgd void
__bt_dmpage(PAGE * h)127cb9daf8fSchristos __bt_dmpage(PAGE *h)
1289f0aa214Scgd {
1299f0aa214Scgd 	BTMETA *m;
130ec567cd3Schristos 	const char *sep;
1319f0aa214Scgd 
132ec567cd3Schristos 	m = (BTMETA *)(void *)h;
13386147b1cSchristos 	(void)fprintf(tracefp, "magic %lx\n", (unsigned long) m->magic);
13486147b1cSchristos 	(void)fprintf(tracefp, "version %lu\n", (unsigned long) m->version);
13586147b1cSchristos 	(void)fprintf(tracefp, "psize %lu\n", (unsigned long) m->psize);
13686147b1cSchristos 	(void)fprintf(tracefp, "free %lu\n", (unsigned long) m->free);
13786147b1cSchristos 	(void)fprintf(tracefp, "nrecs %lu\n", (unsigned long) m->nrecs);
13886147b1cSchristos 	(void)fprintf(tracefp, "flags %lu", (unsigned long) m->flags);
1399f0aa214Scgd #undef X
1409f0aa214Scgd #define	X(flag, name) \
14124420c01Scgd 	if (m->flags & flag) { \
14286147b1cSchristos 		(void)fprintf(tracefp, "%s%s", sep, name); \
1439f0aa214Scgd 		sep = ", "; \
1449f0aa214Scgd 	}
14524420c01Scgd 	if (m->flags) {
1469f0aa214Scgd 		sep = " (";
1479f0aa214Scgd 		X(B_NODUPS,	"NODUPS");
1489f0aa214Scgd 		X(R_RECNO,	"RECNO");
14986147b1cSchristos 		(void)fprintf(tracefp, ")");
1509f0aa214Scgd 	}
15186147b1cSchristos 	(void)fprintf(tracefp, "\n");
15286147b1cSchristos 	(void)fflush(tracefp);
1539f0aa214Scgd }
1549f0aa214Scgd 
155ab0103deSchristos static pgno_t
__bt_pgno_t(const void * m)156ab0103deSchristos __bt_pgno_t(const void *m)
157ab0103deSchristos {
158ab0103deSchristos 	pgno_t r;
159ab0103deSchristos 	memcpy(&r, m, sizeof(r));
160ab0103deSchristos 	return r;
161ab0103deSchristos }
162ab0103deSchristos 
163ab0103deSchristos static uint32_t
__bt_uint32_t(const void * m)164ab0103deSchristos __bt_uint32_t(const void *m)
165ab0103deSchristos {
166ab0103deSchristos 	uint32_t r;
167ab0103deSchristos 	memcpy(&r, m, sizeof(r));
168ab0103deSchristos 	return r;
169ab0103deSchristos }
170ab0103deSchristos 
1719f0aa214Scgd /*
1729f0aa214Scgd  * BT_DNPAGE -- Dump the page
1739f0aa214Scgd  *
1749f0aa214Scgd  * Parameters:
1759f0aa214Scgd  *	n:	page number to dump.
1769f0aa214Scgd  */
1779f0aa214Scgd void
__bt_dnpage(DB * dbp,pgno_t pgno)178cb9daf8fSchristos __bt_dnpage(DB *dbp, pgno_t pgno)
1799f0aa214Scgd {
1809f0aa214Scgd 	BTREE *t;
1819f0aa214Scgd 	PAGE *h;
1829f0aa214Scgd 
18386147b1cSchristos 	__bt_dinit();
18486147b1cSchristos 
1859f0aa214Scgd 	t = dbp->internal;
186aae80e6bSchristos 	if ((h = mpool_get(t->bt_mp, pgno, MPOOL_IGNOREPIN)) != NULL) {
1879f0aa214Scgd 		__bt_dpage(h);
1889f0aa214Scgd 		(void)mpool_put(t->bt_mp, h, 0);
1899f0aa214Scgd 	}
19086147b1cSchristos 	(void)fflush(tracefp);
1919f0aa214Scgd }
1929f0aa214Scgd 
1939f0aa214Scgd /*
1949f0aa214Scgd  * BT_DPAGE -- Dump the page
1959f0aa214Scgd  *
1969f0aa214Scgd  * Parameters:
1979f0aa214Scgd  *	h:	pointer to the PAGE
1989f0aa214Scgd  */
1999f0aa214Scgd void
__bt_dpage(PAGE * h)200cb9daf8fSchristos __bt_dpage(PAGE *h)
2019f0aa214Scgd {
2029f0aa214Scgd 	BINTERNAL *bi;
2039f0aa214Scgd 	BLEAF *bl;
2049f0aa214Scgd 	RINTERNAL *ri;
2059f0aa214Scgd 	RLEAF *rl;
2069f0aa214Scgd 	indx_t cur, top;
207ec567cd3Schristos 	const char *sep;
2089f0aa214Scgd 
20986147b1cSchristos 	__bt_dinit();
21086147b1cSchristos 
21186147b1cSchristos 	(void)fprintf(tracefp, "    page %d: (", h->pgno);
2129f0aa214Scgd #undef X
2139f0aa214Scgd #define	X(flag, name) \
2149f0aa214Scgd 	if (h->flags & flag) { \
21586147b1cSchristos 		(void)fprintf(tracefp, "%s%s", sep, name); \
2169f0aa214Scgd 		sep = ", "; \
2179f0aa214Scgd 	}
2189f0aa214Scgd 	sep = "";
2199f0aa214Scgd 	X(P_BINTERNAL,	"BINTERNAL")		/* types */
2209f0aa214Scgd 	X(P_BLEAF,	"BLEAF")
2219f0aa214Scgd 	X(P_RINTERNAL,	"RINTERNAL")		/* types */
2229f0aa214Scgd 	X(P_RLEAF,	"RLEAF")
2239f0aa214Scgd 	X(P_OVERFLOW,	"OVERFLOW")
2249f0aa214Scgd 	X(P_PRESERVE,	"PRESERVE");
22586147b1cSchristos 	(void)fprintf(tracefp, ")\n");
2269f0aa214Scgd #undef X
2279f0aa214Scgd 
22886147b1cSchristos 	(void)fprintf(tracefp, "\tprev %2d next %2d", h->prevpg, h->nextpg);
2299f0aa214Scgd 	if (h->flags & P_OVERFLOW)
2309f0aa214Scgd 		return;
2319f0aa214Scgd 
2329f0aa214Scgd 	top = NEXTINDEX(h);
23386147b1cSchristos 	(void)fprintf(tracefp, " lower %3d upper %3d nextind %d\n",
2349f0aa214Scgd 	    h->lower, h->upper, top);
2359f0aa214Scgd 	for (cur = 0; cur < top; cur++) {
23686147b1cSchristos 		(void)fprintf(tracefp, "\t[%03d] %4d ", cur, h->linp[cur]);
2379f0aa214Scgd 		switch (h->flags & P_TYPE) {
2389f0aa214Scgd 		case P_BINTERNAL:
2399f0aa214Scgd 			bi = GETBINTERNAL(h, cur);
24086147b1cSchristos 			(void)fprintf(tracefp,
2419f0aa214Scgd 			    "size %03d pgno %03d", bi->ksize, bi->pgno);
2429f0aa214Scgd 			if (bi->flags & P_BIGKEY)
24386147b1cSchristos 				(void)fprintf(tracefp, " (indirect)");
2449f0aa214Scgd 			else if (bi->ksize)
24586147b1cSchristos 				(void)fprintf(tracefp,
2469f0aa214Scgd 				    " {%.*s}", (int)bi->ksize, bi->bytes);
2479f0aa214Scgd 			break;
2489f0aa214Scgd 		case P_RINTERNAL:
2499f0aa214Scgd 			ri = GETRINTERNAL(h, cur);
25086147b1cSchristos 			(void)fprintf(tracefp, "entries %03d pgno %03d",
2519f0aa214Scgd 				ri->nrecs, ri->pgno);
2529f0aa214Scgd 			break;
2539f0aa214Scgd 		case P_BLEAF:
2549f0aa214Scgd 			bl = GETBLEAF(h, cur);
2559f0aa214Scgd 			if (bl->flags & P_BIGKEY)
25686147b1cSchristos 				(void)fprintf(tracefp,
2579f0aa214Scgd 				    "big key page %lu size %u/",
258ab0103deSchristos 				    (unsigned long) __bt_pgno_t(bl->bytes),
259ab0103deSchristos 				    __bt_uint32_t(bl->bytes + sizeof(pgno_t)));
2609f0aa214Scgd 			else if (bl->ksize)
26186147b1cSchristos 				(void)fprintf(tracefp, "%s/", bl->bytes);
2629f0aa214Scgd 			if (bl->flags & P_BIGDATA)
26386147b1cSchristos 				(void)fprintf(tracefp,
2649f0aa214Scgd 				    "big data page %lu size %u",
265ab0103deSchristos 				    (unsigned long)
266ab0103deSchristos 				    __bt_pgno_t(bl->bytes + bl->ksize),
267ab0103deSchristos 				    __bt_uint32_t(bl->bytes + bl->ksize +
2689f0aa214Scgd 				    sizeof(pgno_t)));
2699f0aa214Scgd 			else if (bl->dsize)
27086147b1cSchristos 				(void)fprintf(tracefp, "%.*s",
2719f0aa214Scgd 				    (int)bl->dsize, bl->bytes + bl->ksize);
2729f0aa214Scgd 			break;
2739f0aa214Scgd 		case P_RLEAF:
2749f0aa214Scgd 			rl = GETRLEAF(h, cur);
2759f0aa214Scgd 			if (rl->flags & P_BIGDATA)
27686147b1cSchristos 				(void)fprintf(tracefp,
2779f0aa214Scgd 				    "big data page %lu size %u",
278ab0103deSchristos 				    (unsigned long) __bt_pgno_t(rl->bytes),
279ab0103deSchristos 				    __bt_uint32_t(rl->bytes + sizeof(pgno_t)));
2809f0aa214Scgd 			else if (rl->dsize)
28186147b1cSchristos 				(void)fprintf(tracefp,
2829f0aa214Scgd 				    "%.*s", (int)rl->dsize, rl->bytes);
2839f0aa214Scgd 			break;
2849f0aa214Scgd 		}
28586147b1cSchristos 		(void)fprintf(tracefp, "\n");
2869f0aa214Scgd 	}
28786147b1cSchristos 	(void)fflush(tracefp);
2889f0aa214Scgd }
2899f0aa214Scgd #endif
2909f0aa214Scgd 
2919f0aa214Scgd #ifdef STATISTICS
2929f0aa214Scgd /*
2939f0aa214Scgd  * BT_STAT -- Gather/print the tree statistics
2949f0aa214Scgd  *
2959f0aa214Scgd  * Parameters:
2969f0aa214Scgd  *	dbp:	pointer to the DB
2979f0aa214Scgd  */
2989f0aa214Scgd void
__bt_stat(DB * dbp)299cb9daf8fSchristos __bt_stat(DB *dbp)
3009f0aa214Scgd {
30140b37a3bSjoerg 	extern unsigned long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
30240b37a3bSjoerg 	extern unsigned long bt_sortsplit, bt_split;
3039f0aa214Scgd 	BTREE *t;
3049f0aa214Scgd 	PAGE *h;
3059f0aa214Scgd 	pgno_t i, pcont, pinternal, pleaf;
30640b37a3bSjoerg 	unsigned long ifree, lfree, nkeys;
3079f0aa214Scgd 	int levels;
3089f0aa214Scgd 
30986147b1cSchristos 	__bt_dinit();
31086147b1cSchristos 
3119f0aa214Scgd 	t = dbp->internal;
3129f0aa214Scgd 	pcont = pinternal = pleaf = 0;
3139f0aa214Scgd 	nkeys = ifree = lfree = 0;
31486147b1cSchristos 	for (i = P_ROOT; i < t->bt_mp->npages &&
315*04b0597dSjoerg 	    (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i) {
3169f0aa214Scgd 		switch (h->flags & P_TYPE) {
3179f0aa214Scgd 		case P_BINTERNAL:
3189f0aa214Scgd 		case P_RINTERNAL:
3199f0aa214Scgd 			++pinternal;
3209f0aa214Scgd 			ifree += h->upper - h->lower;
3219f0aa214Scgd 			break;
3229f0aa214Scgd 		case P_BLEAF:
3239f0aa214Scgd 		case P_RLEAF:
3249f0aa214Scgd 			++pleaf;
3259f0aa214Scgd 			lfree += h->upper - h->lower;
3269f0aa214Scgd 			nkeys += NEXTINDEX(h);
3279f0aa214Scgd 			break;
3289f0aa214Scgd 		case P_OVERFLOW:
3299f0aa214Scgd 			++pcont;
3309f0aa214Scgd 			break;
3319f0aa214Scgd 		}
3329f0aa214Scgd 		(void)mpool_put(t->bt_mp, h, 0);
3339f0aa214Scgd 	}
3349f0aa214Scgd 
3359f0aa214Scgd 	/* Count the levels of the tree. */
3369f0aa214Scgd 	for (i = P_ROOT, levels = 0 ;; ++levels) {
337aae80e6bSchristos 		h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN);
3389f0aa214Scgd 		if (h->flags & (P_BLEAF|P_RLEAF)) {
3399f0aa214Scgd 			if (levels == 0)
3409f0aa214Scgd 				levels = 1;
3419f0aa214Scgd 			(void)mpool_put(t->bt_mp, h, 0);
3429f0aa214Scgd 			break;
3439f0aa214Scgd 		}
34424420c01Scgd 		i = F_ISSET(t, R_RECNO) ?
3459f0aa214Scgd 		    GETRINTERNAL(h, 0)->pgno :
3469f0aa214Scgd 		    GETBINTERNAL(h, 0)->pgno;
3479f0aa214Scgd 		(void)mpool_put(t->bt_mp, h, 0);
3489f0aa214Scgd 	}
3499f0aa214Scgd 
35086147b1cSchristos 	(void)fprintf(tracefp, "%d level%s with %ld keys",
3519f0aa214Scgd 	    levels, levels == 1 ? "" : "s", nkeys);
35224420c01Scgd 	if (F_ISSET(t, R_RECNO))
35386147b1cSchristos 		(void)fprintf(tracefp, " (%ld header count)", (long)t->bt_nrecs);
35486147b1cSchristos 	(void)fprintf(tracefp,
3559f0aa214Scgd 	    "\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n",
356cb9daf8fSchristos 	    (long)pinternal + pleaf + pcont, (long)pleaf, (long)pinternal,
357cb9daf8fSchristos 	    (long)pcont);
35886147b1cSchristos 	(void)fprintf(tracefp, "%ld cache hits, %ld cache misses\n",
3599f0aa214Scgd 	    bt_cache_hit, bt_cache_miss);
36086147b1cSchristos 	(void)fprintf(tracefp, "%ld splits (%ld root splits, %ld sort splits)\n",
3619f0aa214Scgd 	    bt_split, bt_rootsplit, bt_sortsplit);
3629f0aa214Scgd 	pleaf *= t->bt_psize - BTDATAOFF;
3639f0aa214Scgd 	if (pleaf)
36486147b1cSchristos 		(void)fprintf(tracefp,
3659f0aa214Scgd 		    "%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n",
3669f0aa214Scgd 		    ((double)(pleaf - lfree) / pleaf) * 100,
3679f0aa214Scgd 		    pleaf - lfree, lfree);
3689f0aa214Scgd 	pinternal *= t->bt_psize - BTDATAOFF;
3699f0aa214Scgd 	if (pinternal)
37086147b1cSchristos 		(void)fprintf(tracefp,
3719f0aa214Scgd 		    "%.0f%% internal fill (%ld bytes used, %ld bytes free\n",
3729f0aa214Scgd 		    ((double)(pinternal - ifree) / pinternal) * 100,
3739f0aa214Scgd 		    pinternal - ifree, ifree);
3749f0aa214Scgd 	if (bt_pfxsaved)
37586147b1cSchristos 		(void)fprintf(tracefp, "prefix checking removed %lu bytes.\n",
3769f0aa214Scgd 		    bt_pfxsaved);
37786147b1cSchristos 	(void)fflush(tracefp);
3789f0aa214Scgd }
3799f0aa214Scgd #endif
380