1 | /*- |
2 | * Copyright (c) 1990, 1993, 1994 |
3 | * The Regents of the University of California. All rights reserved. |
4 | * |
5 | * This code is derived from software contributed to Berkeley by |
6 | * Mike Olson. |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions |
10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. All advertising materials mentioning features or use of this software |
17 | * must display the following acknowledgement: |
18 | * This product includes software developed by the University of |
19 | * California, Berkeley and its contributors. |
20 | * 4. Neither the name of the University nor the names of its contributors |
21 | * may be used to endorse or promote products derived from this software |
22 | * without specific prior written permission. |
23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. |
35 | */ |
36 | |
37 | #if defined(LIBC_SCCS) && !defined(lint) |
38 | static char sccsid[] = "@(#)bt_debug.c 8.5 (Berkeley) 8/17/94" ; |
39 | #endif /* LIBC_SCCS and not lint */ |
40 | |
41 | #include <sys/param.h> |
42 | |
43 | #include <stdio.h> |
44 | #include <stdlib.h> |
45 | #include <string.h> |
46 | |
47 | #include <db.h> |
48 | #include "btree.h" |
49 | |
50 | #ifdef DEBUG |
51 | /* |
52 | * BT_DUMP -- Dump the tree |
53 | * |
54 | * Parameters: |
55 | * dbp: pointer to the DB |
56 | */ |
57 | void |
58 | __bt_dump(dbp) |
59 | DB *dbp; |
60 | { |
61 | BTREE *t; |
62 | PAGE *h; |
63 | pgno_t i; |
64 | char *sep; |
65 | |
66 | t = dbp->internal; |
67 | (void)fprintf(stderr, "%s: pgsz %d" , |
68 | F_ISSET(t, B_INMEM) ? "memory" : "disk" , t->bt_psize); |
69 | if (F_ISSET(t, R_RECNO)) |
70 | (void)fprintf(stderr, " keys %lu" , t->bt_nrecs); |
71 | #undef X |
72 | #define X(flag, name) \ |
73 | if (F_ISSET(t, flag)) { \ |
74 | (void)fprintf(stderr, "%s%s", sep, name); \ |
75 | sep = ", "; \ |
76 | } |
77 | if (t->flags != 0) { |
78 | sep = " flags (" ; |
79 | X(R_FIXLEN, "FIXLEN" ); |
80 | X(B_INMEM, "INMEM" ); |
81 | X(B_NODUPS, "NODUPS" ); |
82 | X(B_RDONLY, "RDONLY" ); |
83 | X(R_RECNO, "RECNO" ); |
84 | X(B_METADIRTY,"METADIRTY" ); |
85 | (void)fprintf(stderr, ")\n" ); |
86 | } |
87 | #undef X |
88 | |
89 | for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) { |
90 | __bt_dpage(h); |
91 | (void)mpool_put(t->bt_mp, h, 0); |
92 | } |
93 | } |
94 | |
95 | /* |
96 | * BT_DMPAGE -- Dump the meta page |
97 | * |
98 | * Parameters: |
99 | * h: pointer to the PAGE |
100 | */ |
101 | void |
102 | __bt_dmpage(h) |
103 | PAGE *h; |
104 | { |
105 | BTMETA *m; |
106 | char *sep; |
107 | |
108 | m = (BTMETA *)h; |
109 | (void)fprintf(stderr, "magic %lx\n" , m->magic); |
110 | (void)fprintf(stderr, "version %lu\n" , m->version); |
111 | (void)fprintf(stderr, "psize %lu\n" , m->psize); |
112 | (void)fprintf(stderr, "free %lu\n" , m->free); |
113 | (void)fprintf(stderr, "nrecs %lu\n" , m->nrecs); |
114 | (void)fprintf(stderr, "flags %lu" , m->flags); |
115 | #undef X |
116 | #define X(flag, name) \ |
117 | if (m->flags & flag) { \ |
118 | (void)fprintf(stderr, "%s%s", sep, name); \ |
119 | sep = ", "; \ |
120 | } |
121 | if (m->flags) { |
122 | sep = " (" ; |
123 | X(B_NODUPS, "NODUPS" ); |
124 | X(R_RECNO, "RECNO" ); |
125 | (void)fprintf(stderr, ")" ); |
126 | } |
127 | } |
128 | |
129 | /* |
130 | * BT_DNPAGE -- Dump the page |
131 | * |
132 | * Parameters: |
133 | * n: page number to dump. |
134 | */ |
135 | void |
136 | __bt_dnpage(dbp, pgno) |
137 | DB *dbp; |
138 | pgno_t pgno; |
139 | { |
140 | BTREE *t; |
141 | PAGE *h; |
142 | |
143 | t = dbp->internal; |
144 | if ((h = mpool_get(t->bt_mp, pgno, 0)) != NULL) { |
145 | __bt_dpage(h); |
146 | (void)mpool_put(t->bt_mp, h, 0); |
147 | } |
148 | } |
149 | |
150 | /* |
151 | * BT_DPAGE -- Dump the page |
152 | * |
153 | * Parameters: |
154 | * h: pointer to the PAGE |
155 | */ |
156 | void |
157 | __bt_dpage(h) |
158 | PAGE *h; |
159 | { |
160 | BINTERNAL *bi; |
161 | BLEAF *bl; |
162 | RINTERNAL *ri; |
163 | RLEAF *rl; |
164 | indx_t cur, top; |
165 | char *sep; |
166 | |
167 | (void)fprintf(stderr, " page %d: (" , h->pgno); |
168 | #undef X |
169 | #define X(flag, name) \ |
170 | if (h->flags & flag) { \ |
171 | (void)fprintf(stderr, "%s%s", sep, name); \ |
172 | sep = ", "; \ |
173 | } |
174 | sep = "" ; |
175 | X(P_BINTERNAL, "BINTERNAL" ) /* types */ |
176 | X(P_BLEAF, "BLEAF" ) |
177 | X(P_RINTERNAL, "RINTERNAL" ) /* types */ |
178 | X(P_RLEAF, "RLEAF" ) |
179 | X(P_OVERFLOW, "OVERFLOW" ) |
180 | X(P_PRESERVE, "PRESERVE" ); |
181 | (void)fprintf(stderr, ")\n" ); |
182 | #undef X |
183 | |
184 | (void)fprintf(stderr, "\tprev %2d next %2d" , h->prevpg, h->nextpg); |
185 | if (h->flags & P_OVERFLOW) |
186 | return; |
187 | |
188 | top = NEXTINDEX(h); |
189 | (void)fprintf(stderr, " lower %3d upper %3d nextind %d\n" , |
190 | h->lower, h->upper, top); |
191 | for (cur = 0; cur < top; cur++) { |
192 | (void)fprintf(stderr, "\t[%03d] %4d " , cur, h->linp[cur]); |
193 | switch (h->flags & P_TYPE) { |
194 | case P_BINTERNAL: |
195 | bi = GETBINTERNAL(h, cur); |
196 | (void)fprintf(stderr, |
197 | "size %03d pgno %03d" , bi->ksize, bi->pgno); |
198 | if (bi->flags & P_BIGKEY) |
199 | (void)fprintf(stderr, " (indirect)" ); |
200 | else if (bi->ksize) |
201 | (void)fprintf(stderr, |
202 | " {%.*s}" , (int)bi->ksize, bi->bytes); |
203 | break; |
204 | case P_RINTERNAL: |
205 | ri = GETRINTERNAL(h, cur); |
206 | (void)fprintf(stderr, "entries %03d pgno %03d" , |
207 | ri->nrecs, ri->pgno); |
208 | break; |
209 | case P_BLEAF: |
210 | bl = GETBLEAF(h, cur); |
211 | if (bl->flags & P_BIGKEY) |
212 | (void)fprintf(stderr, |
213 | "big key page %lu size %u/" , |
214 | *(pgno_t *)bl->bytes, |
215 | *(u_int32_t *)(bl->bytes + sizeof(pgno_t))); |
216 | else if (bl->ksize) |
217 | (void)fprintf(stderr, "%s/" , bl->bytes); |
218 | if (bl->flags & P_BIGDATA) |
219 | (void)fprintf(stderr, |
220 | "big data page %lu size %u" , |
221 | *(pgno_t *)(bl->bytes + bl->ksize), |
222 | *(u_int32_t *)(bl->bytes + bl->ksize + |
223 | sizeof(pgno_t))); |
224 | else if (bl->dsize) |
225 | (void)fprintf(stderr, "%.*s" , |
226 | (int)bl->dsize, bl->bytes + bl->ksize); |
227 | break; |
228 | case P_RLEAF: |
229 | rl = GETRLEAF(h, cur); |
230 | if (rl->flags & P_BIGDATA) |
231 | (void)fprintf(stderr, |
232 | "big data page %lu size %u" , |
233 | *(pgno_t *)rl->bytes, |
234 | *(u_int32_t *)(rl->bytes + sizeof(pgno_t))); |
235 | else if (rl->dsize) |
236 | (void)fprintf(stderr, |
237 | "%.*s" , (int)rl->dsize, rl->bytes); |
238 | break; |
239 | } |
240 | (void)fprintf(stderr, "\n" ); |
241 | } |
242 | } |
243 | #endif |
244 | |
245 | #ifdef STATISTICS |
246 | /* |
247 | * BT_STAT -- Gather/print the tree statistics |
248 | * |
249 | * Parameters: |
250 | * dbp: pointer to the DB |
251 | */ |
252 | void |
253 | __bt_stat(dbp) |
254 | DB *dbp; |
255 | { |
256 | extern u_long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit; |
257 | extern u_long bt_sortsplit, bt_split; |
258 | BTREE *t; |
259 | PAGE *h; |
260 | pgno_t i, pcont, pinternal, pleaf; |
261 | u_long ifree, lfree, nkeys; |
262 | int levels; |
263 | |
264 | t = dbp->internal; |
265 | pcont = pinternal = pleaf = 0; |
266 | nkeys = ifree = lfree = 0; |
267 | for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) { |
268 | switch (h->flags & P_TYPE) { |
269 | case P_BINTERNAL: |
270 | case P_RINTERNAL: |
271 | ++pinternal; |
272 | ifree += h->upper - h->lower; |
273 | break; |
274 | case P_BLEAF: |
275 | case P_RLEAF: |
276 | ++pleaf; |
277 | lfree += h->upper - h->lower; |
278 | nkeys += NEXTINDEX(h); |
279 | break; |
280 | case P_OVERFLOW: |
281 | ++pcont; |
282 | break; |
283 | } |
284 | (void)mpool_put(t->bt_mp, h, 0); |
285 | } |
286 | |
287 | /* Count the levels of the tree. */ |
288 | for (i = P_ROOT, levels = 0 ;; ++levels) { |
289 | h = mpool_get(t->bt_mp, i, 0); |
290 | if (h->flags & (P_BLEAF|P_RLEAF)) { |
291 | if (levels == 0) |
292 | levels = 1; |
293 | (void)mpool_put(t->bt_mp, h, 0); |
294 | break; |
295 | } |
296 | i = F_ISSET(t, R_RECNO) ? |
297 | GETRINTERNAL(h, 0)->pgno : |
298 | GETBINTERNAL(h, 0)->pgno; |
299 | (void)mpool_put(t->bt_mp, h, 0); |
300 | } |
301 | |
302 | (void)fprintf(stderr, "%d level%s with %ld keys" , |
303 | levels, levels == 1 ? "" : "s" , nkeys); |
304 | if (F_ISSET(t, R_RECNO)) |
305 | (void)fprintf(stderr, " (%ld header count)" , t->bt_nrecs); |
306 | (void)fprintf(stderr, |
307 | "\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n" , |
308 | pinternal + pleaf + pcont, pleaf, pinternal, pcont); |
309 | (void)fprintf(stderr, "%ld cache hits, %ld cache misses\n" , |
310 | bt_cache_hit, bt_cache_miss); |
311 | (void)fprintf(stderr, "%ld splits (%ld root splits, %ld sort splits)\n" , |
312 | bt_split, bt_rootsplit, bt_sortsplit); |
313 | pleaf *= t->bt_psize - BTDATAOFF; |
314 | if (pleaf) |
315 | (void)fprintf(stderr, |
316 | "%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n" , |
317 | ((double)(pleaf - lfree) / pleaf) * 100, |
318 | pleaf - lfree, lfree); |
319 | pinternal *= t->bt_psize - BTDATAOFF; |
320 | if (pinternal) |
321 | (void)fprintf(stderr, |
322 | "%.0f%% internal fill (%ld bytes used, %ld bytes free\n" , |
323 | ((double)(pinternal - ifree) / pinternal) * 100, |
324 | pinternal - ifree, ifree); |
325 | if (bt_pfxsaved) |
326 | (void)fprintf(stderr, "prefix checking removed %lu bytes.\n" , |
327 | bt_pfxsaved); |
328 | } |
329 | #endif |
330 | |