HAMMER utilities: Add a verbose (-v) option.
[dragonfly.git] / sbin / hammer / cmd_show.c
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
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
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sbin/hammer/cmd_show.c,v 1.4 2008/01/25 05:53:41 dillon Exp $
35  */
36
37 #include "hammer.h"
38
39 #define FLAG_TOOFARLEFT         0x0001
40 #define FLAG_TOOFARRIGHT        0x0002
41 #define FLAG_BADTYPE            0x0004
42
43 static void print_btree_node(struct cluster_info *cluster,
44                         int32_t node_offset, int depth, int spike,
45                         hammer_base_elm_t left_bound,
46                         hammer_base_elm_t right_bound);
47 static void print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
48                         int flags, const char *label);
49 static int print_elm_flags(hammer_node_ondisk_t node, hammer_btree_elm_t elm,
50                         u_int8_t btype, hammer_base_elm_t left_bound,
51                         hammer_base_elm_t right_bound);
52
53 void
54 hammer_cmd_show(int32_t vol_no, int32_t clu_no, int depth)
55 {
56         struct volume_info *volume;
57         struct cluster_info *cluster;
58         int32_t node_offset;
59
60         if (vol_no == -1) {
61                 if (RootVolNo < 0)
62                         errx(1, "hammer show: root volume number unknown");
63                 vol_no = RootVolNo;
64         }
65         volume = get_volume(vol_no);
66         if (volume == NULL)
67                 errx(1, "hammer show: Unable to locate volume %d", vol_no);
68         if (clu_no == -1)
69                 clu_no = volume->ondisk->vol0_root_clu_no;
70         cluster = get_cluster(volume, clu_no, 0);
71         printf("show %d:%d root@%08x parent@%d:%d:%08x depth %d\n",
72                vol_no, clu_no,
73                cluster->ondisk->clu_btree_root,
74                cluster->ondisk->clu_btree_parent_vol_no,
75                cluster->ondisk->clu_btree_parent_clu_no,
76                cluster->ondisk->clu_btree_parent_offset,
77                depth);
78         if (VerboseOpt) {
79                 printf("\trecords=%d\n",
80                        cluster->ondisk->stat_records);
81         }
82         node_offset = cluster->ondisk->clu_btree_root;
83         print_btree_node(cluster, node_offset, depth, 0,
84                          &cluster->ondisk->clu_btree_beg,
85                          &cluster->ondisk->clu_btree_end);
86         print_btree_node(cluster, node_offset, depth, 1,
87                          &cluster->ondisk->clu_btree_beg,
88                          &cluster->ondisk->clu_btree_end);
89         rel_cluster(cluster);
90         rel_volume(volume);
91 }
92
93 static void
94 print_btree_node(struct cluster_info *cluster, int32_t node_offset, int depth,
95                  int spike,
96                  hammer_base_elm_t left_bound, hammer_base_elm_t right_bound)
97 {
98         struct buffer_info *buffer = NULL;
99         hammer_node_ondisk_t node;
100         hammer_btree_elm_t elm;
101         int i;
102         int flags;
103
104         node = get_node(cluster, node_offset, &buffer);
105
106         if (spike == 0) {
107                 printf("    NODE %d:%d:%08x count=%d parent=%08x "
108                        "type=%c depth=%d {\n",
109                        cluster->volume->vol_no,
110                        cluster->clu_no,
111                         node_offset, node->count, node->parent,
112                         (node->type ? node->type : '?'),
113                         depth);
114
115                 for (i = 0; i < node->count; ++i) {
116                         elm = &node->elms[i];
117                         flags = print_elm_flags(node, elm, elm->base.btype,
118                                                 left_bound, right_bound);
119                         print_btree_elm(elm, i, node->type, flags, "ELM");
120                 }
121                 if (node->type == HAMMER_BTREE_TYPE_INTERNAL) {
122                         elm = &node->elms[i];
123                         flags = print_elm_flags(node, elm, 'I',
124                                                 left_bound, right_bound);
125                         print_btree_elm(elm, i, node->type, flags, "RBN");
126                 }
127                 printf("    }\n");
128         }
129
130         for (i = 0; i < node->count; ++i) {
131                 elm = &node->elms[i];
132
133                 switch(node->type) {
134                 case HAMMER_BTREE_TYPE_INTERNAL:
135                         if (elm->internal.subtree_offset) {
136                                 print_btree_node(cluster,
137                                                  elm->internal.subtree_offset,
138                                                  depth + 1, spike,
139                                                  &elm[0].base, &elm[1].base);
140                         }
141                         break;
142                 case HAMMER_BTREE_TYPE_LEAF:
143                         if (RecurseOpt && spike &&
144                             elm->leaf.base.btype == HAMMER_BTREE_TYPE_SPIKE_END) {
145                                 hammer_cmd_show(elm->leaf.spike_vol_no,
146                                                 elm->leaf.spike_clu_no,
147                                                 depth + 1);
148                         }
149                         break;
150                 }
151         }
152         rel_buffer(buffer);
153 }
154
155 static
156 void
157 print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
158                 int flags, const char *label)
159 {
160         char flagstr[8] = { 0, '-', '-', '-', '-', '-', '-', 0 };
161
162         flagstr[0] = flags ? 'B' : 'G';
163         if (flags & FLAG_TOOFARLEFT)
164                 flagstr[2] = 'L';
165         if (flags & FLAG_TOOFARRIGHT)
166                 flagstr[3] = 'R';
167         if (flags & FLAG_BADTYPE)
168                 flagstr[4] = 'T';
169
170         printf("%s\t%s %2d %c ",
171                flagstr, label, i,
172                (elm->base.btype ? elm->base.btype : '?'));
173         printf("obj=%016llx key=%016llx rt=%02x ot=%02x\n",
174                elm->base.obj_id,
175                elm->base.key,
176                elm->base.rec_type,
177                elm->base.obj_type);
178         printf("\t         tids %016llx:%016llx ",
179                elm->base.create_tid,
180                elm->base.delete_tid);
181
182         switch(type) {
183         case HAMMER_BTREE_TYPE_INTERNAL:
184                 printf("suboff=%08x", elm->internal.subtree_offset);
185                 break;
186         case HAMMER_BTREE_TYPE_LEAF:
187                 switch(elm->base.btype) {
188                 case HAMMER_BTREE_TYPE_RECORD:
189                         printf("recoff=%08x", elm->leaf.rec_offset);
190                         break;
191                 case HAMMER_BTREE_TYPE_SPIKE_BEG:
192                 case HAMMER_BTREE_TYPE_SPIKE_END:
193                         printf("spike %d:%d",
194                                elm->leaf.spike_vol_no,
195                                elm->leaf.spike_clu_no);
196                         break;
197                 }
198                 break;
199         default:
200                 break;
201         }
202         printf("\n");
203 }
204
205 static
206 int
207 print_elm_flags(hammer_node_ondisk_t node, hammer_btree_elm_t elm,
208                 u_int8_t btype,
209                 hammer_base_elm_t left_bound, hammer_base_elm_t right_bound)
210 {
211         int flags = 0;
212
213         switch(node->type) {
214         case HAMMER_BTREE_TYPE_INTERNAL:
215                 switch(btype) {
216                 case HAMMER_BTREE_TYPE_INTERNAL:
217                         if (hammer_btree_cmp(&elm->base, left_bound) < 0)
218                                 flags |= FLAG_TOOFARLEFT;
219                         if (hammer_btree_cmp(&elm->base, right_bound) > 0)
220                                 flags |= FLAG_TOOFARRIGHT;
221                         break;
222                 case HAMMER_BTREE_TYPE_LEAF:
223                         if (hammer_btree_cmp(&elm->base, left_bound) < 0)
224                                 flags |= FLAG_TOOFARLEFT;
225                         if (hammer_btree_cmp(&elm->base, right_bound) >= 0)
226                                 flags |= FLAG_TOOFARRIGHT;
227                         break;
228                 default:
229                         flags |= FLAG_BADTYPE;
230                         break;
231                 }
232                 break;
233         case HAMMER_BTREE_TYPE_LEAF:
234                 switch(btype) {
235                 case HAMMER_BTREE_TYPE_SPIKE_END:
236                         if (hammer_btree_cmp(&elm->base, left_bound) < 0)
237                                 flags |= FLAG_TOOFARLEFT;
238                         if (hammer_btree_cmp(&elm->base, right_bound) > 0)
239                                 flags |= FLAG_TOOFARRIGHT;
240                         break;
241                 case HAMMER_BTREE_TYPE_SPIKE_BEG:
242                 case HAMMER_BTREE_TYPE_RECORD:
243                         if (hammer_btree_cmp(&elm->base, left_bound) < 0)
244                                 flags |= FLAG_TOOFARLEFT;
245                         if (hammer_btree_cmp(&elm->base, right_bound) >= 0)
246                                 flags |= FLAG_TOOFARRIGHT;
247                         break;
248                 default:
249                         flags |= FLAG_BADTYPE;
250                         break;
251                 }
252                 break;
253         default:
254                 flags |= FLAG_BADTYPE;
255                 break;
256         }
257         return(flags);
258 }
259