2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)db_pr.c 10.29 (Sleepycat) 5/23/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
30 static void __db_proff
__P((void *));
31 static void __db_psize
__P((DB_MPOOLFILE
*));
35 * Force loading of this file.
37 * PUBLIC: void __db_loadme __P((void));
48 * 64K is the maximum page size, so by default we check for offsets
49 * larger than that, and, where possible, we refine the test.
51 #define PSIZE_BOUNDARY (64 * 1024 + 1)
52 static size_t set_psize
= PSIZE_BOUNDARY
;
56 * Initialize tree printing routines.
58 * PUBLIC: FILE *__db_prinit __P((FILE *));
65 set_fp
= fp
== NULL
? stdout
: fp
;
71 * Dump the tree to a file.
73 * PUBLIC: int __db_dump __P((DB *, char *, int));
76 __db_dump(dbp
, name
, all
)
83 COMPQUIET(save_fp
, NULL
);
85 if (set_psize
== PSIZE_BOUNDARY
)
89 if ((fp
= fopen(name
, "w")) == NULL
)
94 fp
= __db_prinit(NULL
);
97 if (dbp
->type
== DB_HASH
)
98 (void)__db_prhash(dbp
);
100 (void)__db_prbtree(dbp
);
101 fprintf(fp
, "%s\n", DB_LINE
);
102 __db_prtree(dbp
->mpf
, all
);
113 * Print out the DB structure information.
115 * PUBLIC: int __db_prdb __P((DB *));
121 static const FN fn
[] = {
122 { DB_AM_DUP
, "duplicates" },
123 { DB_AM_INMEM
, "in-memory" },
124 { DB_AM_LOCKING
, "locking" },
125 { DB_AM_LOGGING
, "logging" },
126 { DB_AM_MLOCAL
, "local mpool" },
127 { DB_AM_PGDEF
, "default page size" },
128 { DB_AM_RDONLY
, "read-only" },
129 { DB_AM_RECOVER
, "recover" },
130 { DB_AM_SWAP
, "needswap" },
131 { DB_AM_THREAD
, "thread" },
132 { DB_BT_RECNUM
, "btree:records" },
133 { DB_HS_DIRTYMETA
, "hash:dirty-meta" },
134 { DB_RE_DELIMITER
, "recno:delimiter" },
135 { DB_RE_FIXEDLEN
, "recno:fixed-length" },
136 { DB_RE_PAD
, "recno:pad" },
137 { DB_RE_RENUMBER
, "recno:renumber" },
138 { DB_RE_SNAPSHOT
, "recno:snapshot" },
144 fp
= __db_prinit(NULL
);
161 fprintf(fp
, "%s ", t
);
162 __db_prflags(dbp
->flags
, fn
, fp
);
170 * Print out the btree internal information.
172 * PUBLIC: int __db_prbtree __P((DB *));
178 static const FN mfn
[] = {
179 { BTM_DUP
, "duplicates" },
180 { BTM_RECNO
, "recno" },
181 { BTM_RECNUM
, "btree:records" },
182 { BTM_FIXEDLEN
, "recno:fixed-length" },
183 { BTM_RENUMBER
, "recno:renumber" },
196 fp
= __db_prinit(NULL
);
198 (void)fprintf(fp
, "%s\nOn-page metadata:\n", DB_LINE
);
201 if ((ret
= __bam_pget(dbp
, (PAGE
**)&mp
, &i
, 0)) != 0)
204 (void)fprintf(fp
, "magic %#lx\n", (u_long
)mp
->magic
);
205 (void)fprintf(fp
, "version %#lx\n", (u_long
)mp
->version
);
206 (void)fprintf(fp
, "pagesize %lu\n", (u_long
)mp
->pagesize
);
207 (void)fprintf(fp
, "maxkey: %lu minkey: %lu\n",
208 (u_long
)mp
->maxkey
, (u_long
)mp
->minkey
);
210 (void)fprintf(fp
, "free %lu", (u_long
)mp
->free
);
211 for (i
= mp
->free
; i
!= PGNO_INVALID
;) {
212 if ((ret
= __bam_pget(dbp
, &h
, &i
, 0)) != 0)
215 (void)memp_fput(dbp
->mpf
, h
, 0);
216 (void)fprintf(fp
, ", %lu", (u_long
)i
);
218 (void)fprintf(fp
, "\n");
220 (void)fprintf(fp
, "flags %#lx", (u_long
)mp
->flags
);
221 __db_prflags(mp
->flags
, mfn
, fp
);
222 (void)fprintf(fp
, "\n");
223 (void)memp_fput(dbp
->mpf
, mp
, 0);
225 (void)fprintf(fp
, "%s\nDB_INFO:\n", DB_LINE
);
226 (void)fprintf(fp
, "bt_maxkey: %lu bt_minkey: %lu\n",
227 (u_long
)t
->bt_maxkey
, (u_long
)t
->bt_minkey
);
228 (void)fprintf(fp
, "bt_compare: %#lx bt_prefix: %#lx\n",
229 (u_long
)t
->bt_compare
, (u_long
)t
->bt_prefix
);
230 if ((rp
= t
->bt_recno
) != NULL
) {
232 "re_delim: %#lx re_pad: %#lx re_len: %lu re_source: %s\n",
233 (u_long
)rp
->re_delim
, (u_long
)rp
->re_pad
,
235 rp
->re_source
== NULL
? "" : rp
->re_source
);
237 "cmap: %#lx smap: %#lx emap: %#lx msize: %lu\n",
238 (u_long
)rp
->re_cmap
, (u_long
)rp
->re_smap
,
239 (u_long
)rp
->re_emap
, (u_long
)rp
->re_msize
);
241 (void)fprintf(fp
, "stack:");
242 for (epg
= t
->bt_stack
; epg
< t
->bt_sp
; ++epg
)
243 (void)fprintf(fp
, " %lu", (u_long
)epg
->page
->pgno
);
244 (void)fprintf(fp
, "\n");
245 (void)fprintf(fp
, "ovflsize: %lu\n", (u_long
)t
->bt_ovflsize
);
252 * Print out the hash internal information.
254 * PUBLIC: int __db_prhash __P((DB *));
262 int i
, put_page
, ret
;
267 fp
= __db_prinit(NULL
);
269 fprintf(fp
, "\thash_accesses %lu\n", (u_long
)t
->hash_accesses
);
270 fprintf(fp
, "\thash_collisions %lu\n", (u_long
)t
->hash_collisions
);
271 fprintf(fp
, "\thash_expansions %lu\n", (u_long
)t
->hash_expansions
);
272 fprintf(fp
, "\thash_overflows %lu\n", (u_long
)t
->hash_overflows
);
273 fprintf(fp
, "\thash_bigpages %lu\n", (u_long
)t
->hash_bigpages
);
276 if (t
->hdr
== NULL
) {
277 pgno
= PGNO_METADATA
;
278 if ((ret
= memp_fget(dbp
->mpf
, &pgno
, 0, &t
->hdr
)) != 0)
284 fprintf(fp
, "\tmagic %#lx\n", (u_long
)t
->hdr
->magic
);
285 fprintf(fp
, "\tversion %lu\n", (u_long
)t
->hdr
->version
);
286 fprintf(fp
, "\tpagesize %lu\n", (u_long
)t
->hdr
->pagesize
);
287 fprintf(fp
, "\tovfl_point %lu\n", (u_long
)t
->hdr
->ovfl_point
);
288 fprintf(fp
, "\tlast_freed %lu\n", (u_long
)t
->hdr
->last_freed
);
289 fprintf(fp
, "\tmax_bucket %lu\n", (u_long
)t
->hdr
->max_bucket
);
290 fprintf(fp
, "\thigh_mask %#lx\n", (u_long
)t
->hdr
->high_mask
);
291 fprintf(fp
, "\tlow_mask %#lx\n", (u_long
)t
->hdr
->low_mask
);
292 fprintf(fp
, "\tffactor %lu\n", (u_long
)t
->hdr
->ffactor
);
293 fprintf(fp
, "\tnelem %lu\n", (u_long
)t
->hdr
->nelem
);
294 fprintf(fp
, "\th_charkey %#lx\n", (u_long
)t
->hdr
->h_charkey
);
296 for (i
= 0; i
< NCACHED
; i
++)
297 fprintf(fp
, "%lu ", (u_long
)t
->hdr
->spares
[i
]);
302 (void)memp_fput(dbp
->mpf
, (PAGE
*)t
->hdr
, 0);
310 * Print out the entire tree.
312 * PUBLIC: int __db_prtree __P((DB_MPOOLFILE *, int));
315 __db_prtree(mpf
, all
)
323 if (set_psize
== PSIZE_BOUNDARY
)
327 for (i
= PGNO_ROOT
;; ++i
) {
328 if ((ret
= memp_fget(mpf
, &i
, 0, &h
)) != 0)
330 if (TYPE(h
) != P_INVALID
)
331 if ((t_ret
= __db_prpage(h
, all
)) != 0 && ret
== 0)
333 (void)memp_fput(mpf
, h
, 0);
335 (void)fflush(__db_prinit(NULL
));
341 * -- Print out a specific page.
343 * PUBLIC: int __db_prnpage __P((DB_MPOOLFILE *, db_pgno_t));
346 __db_prnpage(mpf
, pgno
)
353 if (set_psize
== PSIZE_BOUNDARY
)
356 if ((ret
= memp_fget(mpf
, &pgno
, 0, &h
)) != 0)
359 ret
= __db_prpage(h
, 1);
360 (void)fflush(__db_prinit(NULL
));
362 (void)memp_fput(mpf
, h
, 0);
368 * -- Print out a page.
370 * PUBLIC: int __db_prpage __P((PAGE *, int));
382 db_indx_t dlen
, len
, i
;
386 u_int8_t
*ep
, *hk
, *p
;
389 fp
= __db_prinit(NULL
);
399 s
= "btree internal";
405 s
= "recno internal";
417 fprintf(fp
, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
418 (u_long
)h
->pgno
, (u_long
)TYPE(h
));
421 fprintf(fp
, "page %4lu: (%s)\n", (u_long
)h
->pgno
, s
);
422 fprintf(fp
, " lsn.file: %lu lsn.offset: %lu",
423 (u_long
)LSN(h
).file
, (u_long
)LSN(h
).offset
);
424 if (TYPE(h
) == P_IBTREE
|| TYPE(h
) == P_IRECNO
||
425 (TYPE(h
) == P_LRECNO
&& h
->pgno
== PGNO_ROOT
))
426 fprintf(fp
, " total records: %4lu", (u_long
)RE_NREC(h
));
428 if (TYPE(h
) == P_LBTREE
|| TYPE(h
) == P_LRECNO
||
429 TYPE(h
) == P_DUPLICATE
|| TYPE(h
) == P_OVERFLOW
)
430 fprintf(fp
, " prev: %4lu next: %4lu",
431 (u_long
)PREV_PGNO(h
), (u_long
)NEXT_PGNO(h
));
432 if (TYPE(h
) == P_IBTREE
|| TYPE(h
) == P_LBTREE
)
433 fprintf(fp
, " level: %2lu", (u_long
)h
->level
);
434 if (TYPE(h
) == P_OVERFLOW
) {
435 fprintf(fp
, " ref cnt: %4lu ", (u_long
)OV_REF(h
));
436 __db_pr((u_int8_t
*)h
+ P_OVERHEAD
, OV_LEN(h
));
439 fprintf(fp
, " entries: %4lu", (u_long
)NUM_ENT(h
));
440 fprintf(fp
, " offset: %4lu\n", (u_long
)HOFFSET(h
));
442 if (!all
|| TYPE(h
) == P_INVALID
)
446 for (i
= 0; i
< NUM_ENT(h
); i
++) {
447 if (P_ENTRY(h
, i
) - (u_int8_t
*)h
< P_OVERHEAD
||
448 (size_t)(P_ENTRY(h
, i
) - (u_int8_t
*)h
) >= set_psize
) {
450 "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
451 (u_long
)i
, (u_long
)h
->inp
[i
]);
464 deleted
= i
% 2 == 0 &&
465 B_DISSET(GET_BKEYDATA(h
, i
+ O_INDX
)->type
);
470 deleted
= B_DISSET(GET_BKEYDATA(h
, i
)->type
);
474 "ILLEGAL PAGE ITEM: %lu\n", (u_long
)TYPE(h
));
478 fprintf(fp
, " %s[%03lu] %4lu ",
479 deleted
? "D" : " ", (u_long
)i
, (u_long
)h
->inp
[i
]);
483 switch (HPAGE_PTYPE(hk
)) {
486 HOFFDUP_PGNO(hk
), sizeof(db_pgno_t
));
488 "%4lu [offpage dups]\n", (u_long
)pgno
);
492 * If this is the first item on a page, then
493 * we cannot figure out how long it is, so
494 * we only print the first one in the duplicate
498 len
= LEN_HKEYDATA(h
, 0, i
);
502 fprintf(fp
, "Duplicates:\n");
503 for (p
= HKEYDATA_DATA(hk
),
504 ep
= p
+ len
; p
< ep
;) {
505 memcpy(&dlen
, p
, sizeof(db_indx_t
));
506 p
+= sizeof(db_indx_t
);
509 p
+= sizeof(db_indx_t
) + dlen
;
514 __db_pr(HKEYDATA_DATA(hk
),
515 LEN_HKEYDATA(h
, 0, i
));
517 fprintf(fp
, "%s\n", HKEYDATA_DATA(hk
));
520 memcpy(&a_hkd
, hk
, HOFFPAGE_SIZE
);
522 "overflow: total len: %4lu page: %4lu\n",
523 (u_long
)a_hkd
.tlen
, (u_long
)a_hkd
.pgno
);
529 fprintf(fp
, "count: %4lu pgno: %4lu ",
530 (u_long
)bi
->nrecs
, (u_long
)bi
->pgno
);
531 switch (B_TYPE(bi
->type
)) {
533 __db_pr(bi
->data
, bi
->len
);
537 __db_proff(bi
->data
);
540 fprintf(fp
, "ILLEGAL BINTERNAL TYPE: %lu\n",
541 (u_long
)B_TYPE(bi
->type
));
548 fprintf(fp
, "entries %4lu pgno %4lu\n",
549 (u_long
)ri
->nrecs
, (u_long
)ri
->pgno
);
555 switch (B_TYPE(bk
->type
)) {
557 __db_pr(bk
->data
, bk
->len
);
565 "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
566 (u_long
)B_TYPE(bk
->type
));
579 * -- Decide if a page is corrupted.
581 * PUBLIC: int __db_isbad __P((PAGE *, int));
594 fp
= __db_prinit(NULL
);
607 fprintf(fp
, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
608 (u_long
)h
->pgno
, (u_long
)TYPE(h
));
612 for (i
= 0; i
< NUM_ENT(h
); i
++) {
613 if (P_ENTRY(h
, i
) - (u_int8_t
*)h
< P_OVERHEAD
||
614 (size_t)(P_ENTRY(h
, i
) - (u_int8_t
*)h
) >= set_psize
) {
616 "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
617 (u_long
)i
, (u_long
)h
->inp
[i
]);
622 type
= HPAGE_TYPE(h
, i
);
623 if (type
!= H_OFFDUP
&&
624 type
!= H_DUPLICATE
&&
627 fprintf(fp
, "ILLEGAL HASH TYPE: %lu\n",
633 bi
= GET_BINTERNAL(h
, i
);
634 if (B_TYPE(bi
->type
) != B_KEYDATA
&&
635 B_TYPE(bi
->type
) != B_DUPLICATE
&&
636 B_TYPE(bi
->type
) != B_OVERFLOW
) {
637 fprintf(fp
, "ILLEGAL BINTERNAL TYPE: %lu\n",
638 (u_long
)B_TYPE(bi
->type
));
647 bk
= GET_BKEYDATA(h
, i
);
648 if (B_TYPE(bk
->type
) != B_KEYDATA
&&
649 B_TYPE(bk
->type
) != B_DUPLICATE
&&
650 B_TYPE(bk
->type
) != B_OVERFLOW
) {
652 "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
653 (u_long
)B_TYPE(bk
->type
));
659 "ILLEGAL PAGE ITEM: %lu\n", (u_long
)TYPE(h
));
674 * Print out a data element.
676 * PUBLIC: void __db_pr __P((u_int8_t *, u_int32_t));
687 fp
= __db_prinit(NULL
);
689 fprintf(fp
, "len: %3lu", (u_long
)len
);
692 fprintf(fp
, " data: ");
693 for (i
= len
<= 20 ? len
: 20; i
> 0; --i
, ++p
) {
695 if (isprint(*p
) || *p
== '\n')
696 fprintf(fp
, "%c", *p
);
698 fprintf(fp
, "0x%.2x", (u_int
)*p
);
711 * Print out a DBT data element.
713 * PUBLIC: int __db_prdbt __P((DBT *, int, FILE *));
716 __db_prdbt(dbtp
, checkprint
, fp
)
721 static const char hex
[] = "0123456789abcdef";
727 * This routine is the routine that dumps out items in the format
728 * used by db_dump(1) and db_load(1). This means that the format
732 for (len
= dbtp
->size
, p
= dbtp
->data
; len
--; ++p
)
734 if (*p
== '\\' && fprintf(fp
, "\\") != 1)
736 if (fprintf(fp
, "%c", *p
) != 1)
739 if (fprintf(fp
, "\\%c%c",
740 hex
[(u_int8_t
)(*p
& 0xf0) >> 4],
741 hex
[*p
& 0x0f]) != 3)
744 for (len
= dbtp
->size
, p
= dbtp
->data
; len
--; ++p
)
745 if (fprintf(fp
, "%c%c",
746 hex
[(u_int8_t
)(*p
& 0xf0) >> 4],
747 hex
[*p
& 0x0f]) != 2)
750 return (fprintf(fp
, "\n") == 1 ? 0 : EIO
);
755 * Print out an off-page element.
764 fp
= __db_prinit(NULL
);
767 switch (B_TYPE(bo
->type
)) {
769 fprintf(fp
, "overflow: total len: %4lu page: %4lu\n",
770 (u_long
)bo
->tlen
, (u_long
)bo
->pgno
);
773 fprintf(fp
, "duplicate: page: %4lu\n", (u_long
)bo
->pgno
);
780 * Print out flags values.
782 * PUBLIC: void __db_prflags __P((u_int32_t, const FN *, FILE *));
785 __db_prflags(flags
, fn
, fp
)
795 for (found
= 0, fnp
= fn
; fnp
->mask
!= 0; ++fnp
)
796 if (LF_ISSET(fnp
->mask
)) {
797 fprintf(fp
, "%s%s", sep
, fnp
->name
);
816 set_psize
= PSIZE_BOUNDARY
- 1;
818 pgno
= PGNO_METADATA
;
819 if (memp_fget(mpf
, &pgno
, 0, &mp
) != 0)
825 set_psize
= mp
->pagesize
;
828 (void)memp_fput(mpf
, mp
, 0);