HAMMER 30/many: blockmap work.
[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.6 2008/02/23 03:01:06 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(hammer_off_t node_offset, int depth, int spike,
44                         hammer_base_elm_t left_bound,
45                         hammer_base_elm_t right_bound);
46 static void print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
47                         int flags, const char *label);
48 static int print_elm_flags(hammer_node_ondisk_t node, hammer_btree_elm_t elm,
49                         u_int8_t btype, hammer_base_elm_t left_bound,
50                         hammer_base_elm_t right_bound);
51 static void print_bigblock_fill(hammer_off_t offset);
52
53 void
54 hammer_cmd_show(hammer_off_t node_offset, int depth,
55                 hammer_base_elm_t left_bound, hammer_base_elm_t right_bound)
56 {
57         struct volume_info *volume;
58
59         if (node_offset == (hammer_off_t)-1) {
60                 volume = get_volume(RootVolNo);
61                 node_offset = volume->ondisk->vol0_btree_root;
62                 if (VerboseOpt) {
63                         printf("\trecords=%lld\n",
64                                volume->ondisk->vol0_stat_records);
65                 }
66                 rel_volume(volume);
67         }
68         printf("show %016llx depth %d\n", node_offset, depth);
69         print_btree_node(node_offset, depth, 0, left_bound, right_bound);
70         print_btree_node(node_offset, depth, 1, left_bound, right_bound);
71 }
72
73 static void
74 print_btree_node(hammer_off_t node_offset, int depth, int spike,
75                  hammer_base_elm_t left_bound, hammer_base_elm_t right_bound)
76 {
77         struct buffer_info *buffer = NULL;
78         hammer_node_ondisk_t node;
79         hammer_btree_elm_t elm;
80         int i;
81         int flags;
82
83         node = get_node(node_offset, &buffer);
84
85         if (spike == 0) {
86                 printf("    NODE %016llx count=%d parent=%016llx "
87                        "type=%c depth=%d fill=",
88                        node_offset, node->count, node->parent,
89                        (node->type ? node->type : '?'), depth);
90                 if (VerboseOpt)
91                         print_bigblock_fill(node_offset);
92                 printf(" {\n");
93
94                 for (i = 0; i < node->count; ++i) {
95                         elm = &node->elms[i];
96                         flags = print_elm_flags(node, elm, elm->base.btype,
97                                                 left_bound, right_bound);
98                         print_btree_elm(elm, i, node->type, flags, "ELM");
99                 }
100                 if (node->type == HAMMER_BTREE_TYPE_INTERNAL) {
101                         elm = &node->elms[i];
102                         flags = print_elm_flags(node, elm, 'I',
103                                                 left_bound, right_bound);
104                         print_btree_elm(elm, i, node->type, flags, "RBN");
105                 }
106                 printf("    }\n");
107         }
108
109         for (i = 0; i < node->count; ++i) {
110                 elm = &node->elms[i];
111
112                 switch(node->type) {
113                 case HAMMER_BTREE_TYPE_INTERNAL:
114                         if (elm->internal.subtree_offset) {
115                                 print_btree_node(elm->internal.subtree_offset,
116                                                  depth + 1, spike,
117                                                  &elm[0].base, &elm[1].base);
118                         }
119                         break;
120                 default:
121                         break;
122                 }
123         }
124         rel_buffer(buffer);
125 }
126
127 static
128 void
129 print_btree_elm(hammer_btree_elm_t elm, int i, u_int8_t type,
130                 int flags, const char *label)
131 {
132         char flagstr[8] = { 0, '-', '-', '-', '-', '-', '-', 0 };
133
134         flagstr[0] = flags ? 'B' : 'G';
135         if (flags & FLAG_TOOFARLEFT)
136                 flagstr[2] = 'L';
137         if (flags & FLAG_TOOFARRIGHT)
138                 flagstr[3] = 'R';
139         if (flags & FLAG_BADTYPE)
140                 flagstr[4] = 'T';
141
142         printf("%s\t%s %2d %c ",
143                flagstr, label, i,
144                (elm->base.btype ? elm->base.btype : '?'));
145         printf("obj=%016llx key=%016llx rt=%02x ot=%02x\n",
146                elm->base.obj_id,
147                elm->base.key,
148                elm->base.rec_type,
149                elm->base.obj_type);
150         printf("\t         tids %016llx:%016llx ",
151                elm->base.create_tid,
152                elm->base.delete_tid);
153
154         switch(type) {
155         case HAMMER_BTREE_TYPE_INTERNAL:
156                 printf("suboff=%016llx", elm->internal.subtree_offset);
157                 break;
158         case HAMMER_BTREE_TYPE_LEAF:
159                 switch(elm->base.btype) {
160                 case HAMMER_BTREE_TYPE_RECORD:
161                         printf("\n\t         ");
162                         printf("recoff=%016llx", elm->leaf.rec_offset);
163                         printf(" dataoff=%016llx/%d",
164                                 elm->leaf.data_offset, elm->leaf.data_len);
165                         if (VerboseOpt) {
166                                 printf("\n\t         fills=");
167                                 print_bigblock_fill(elm->leaf.rec_offset);
168                                 printf(", ");
169                                 print_bigblock_fill(elm->leaf.data_offset);
170                         }
171                         break;
172                 }
173                 break;
174         default:
175                 break;
176         }
177         printf("\n");
178 }
179
180 static
181 int
182 print_elm_flags(hammer_node_ondisk_t node, hammer_btree_elm_t elm,
183                 u_int8_t btype,
184                 hammer_base_elm_t left_bound, hammer_base_elm_t right_bound)
185 {
186         int flags = 0;
187
188         switch(node->type) {
189         case HAMMER_BTREE_TYPE_INTERNAL:
190                 switch(btype) {
191                 case HAMMER_BTREE_TYPE_INTERNAL:
192                         if (left_bound == NULL || right_bound == NULL)
193                                 break;
194                         if (hammer_btree_cmp(&elm->base, left_bound) < 0)
195                                 flags |= FLAG_TOOFARLEFT;
196                         if (hammer_btree_cmp(&elm->base, right_bound) > 0)
197                                 flags |= FLAG_TOOFARRIGHT;
198                         break;
199                 case HAMMER_BTREE_TYPE_LEAF:
200                         if (left_bound == NULL || right_bound == NULL)
201                                 break;
202                         if (hammer_btree_cmp(&elm->base, left_bound) < 0)
203                                 flags |= FLAG_TOOFARLEFT;
204                         if (hammer_btree_cmp(&elm->base, right_bound) >= 0)
205                                 flags |= FLAG_TOOFARRIGHT;
206                         break;
207                 default:
208                         flags |= FLAG_BADTYPE;
209                         break;
210                 }
211                 break;
212         case HAMMER_BTREE_TYPE_LEAF:
213                 switch(btype) {
214                 case HAMMER_BTREE_TYPE_RECORD:
215                         if (left_bound == NULL || right_bound == NULL)
216                                 break;
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                 default:
223                         flags |= FLAG_BADTYPE;
224                         break;
225                 }
226                 break;
227         default:
228                 flags |= FLAG_BADTYPE;
229                 break;
230         }
231         return(flags);
232 }
233
234 static
235 void
236 print_bigblock_fill(hammer_off_t offset)
237 {
238         struct hammer_blockmap_layer1 layer1;
239         struct hammer_blockmap_layer2 layer2;
240         int fill;
241
242         blockmap_lookup(offset, &layer1, &layer2);
243         fill = layer2.bytes_free * 100 / HAMMER_LARGEBLOCK_SIZE;
244         fill = 100 - fill;
245
246         printf("z%d:%lld=%d%%",
247                 HAMMER_ZONE_DECODE(offset),
248                 (offset & ~HAMMER_OFF_ZONE_MASK) / HAMMER_LARGEBLOCK_SIZE,
249                 fill
250         );
251 }
252