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