1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 // Dump a fractal tree file
40 
41 #include <ctype.h>
42 #include <stdint.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <inttypes.h>
46 #include <limits.h>
47 #include <string>
48 #include <iostream>
49 #include <fstream>
50 #include <map>
51 #include <string>
52 #include <string.h>
53 #include "ft/serialize/block_table.h"
54 #include "ft/cachetable/cachetable.h"
55 #include "ft/ft.h"
56 #include "ft/ft-internal.h"
57 #include "ft/serialize/ft-serialize.h"
58 #include "ft/serialize/ft_node-serialize.h"
59 #include "ft/node.h"
60 
61 using namespace std;
62 
63 static int do_dump_data = 1;
64 static int do_interactive = 0;
65 static int do_json = 0;
66 static int do_header = 0;
67 static int do_fragmentation = 0;
68 static int do_garbage = 0;
69 static int do_translation_table = 0;
70 static int do_summary = 0;
71 static int do_rootnode = 0;
72 static int do_node = 0;
73 static BLOCKNUM do_node_num;
74 static int do_tsv = 0;
75 static const char *arg0;
76 static const char *fname;
77 
78 //it holdes the messges count for each FT's node
79 typedef struct nodeMessage{
80     int id;
81     int clean;//0=clean >=1 dirty
82     int *count;//holds the messages
83     nodeMessage *nextNode;
84 }NMC;
85 enum { maxline = 128};
86 
87 static int printNodeMessagesToSTDout(NMC* ptr);
88 
89 static int printLevelSTDout(int  *);
90 
91 static void treeToSTDout(NMC *msgs[], int height);
92 
format_time(const uint64_t time_int,char * buf)93 static void format_time(const uint64_t time_int, char *buf) {
94     time_t timer = (time_t) time_int;
95     ctime_r(&timer, buf);
96     assert(buf[24] == '\n');
97     buf[24] = 0;
98 }
99 
print_item(const void * val,uint32_t len)100 static void print_item(const void *val, uint32_t len) {
101     printf("\"");
102     uint32_t i;
103     for (i=0; i<len; i++) {
104         unsigned char ch = ((unsigned char*)val)[i];
105         if (isprint(ch) && ch!='\\' && ch!='"') {
106             printf("%c", ch);
107         } else {
108             printf("\\%03o", ch);
109         }
110     }
111     printf("\"");
112 }
113 
simple_hex_dump(unsigned char * vp,uint64_t size)114 static void simple_hex_dump(unsigned char *vp, uint64_t size) {
115     for (uint64_t i = 0; i < size; i++) {
116         unsigned char c = vp[i];
117         printf("%2.2X", c);
118     }
119 }
120 
hex_dump(unsigned char * vp,uint64_t offset,uint64_t size)121 static void hex_dump(unsigned char *vp, uint64_t offset, uint64_t size) {
122     uint64_t n = size / 32;
123     for (uint64_t i = 0; i < n; i++) {
124         printf("%" PRIu64 ": ", offset);
125         for (uint64_t j = 0; j < 32; j++) {
126             unsigned char c = vp[j];
127             printf("%2.2X", c);
128             if (((j+1) % 4) == 0)
129                 printf(" ");
130         }
131         for (uint64_t j = 0; j < 32; j++) {
132             unsigned char c = vp[j];
133             printf("%c", isprint(c) ? c : ' ');
134         }
135         printf("\n");
136         vp += 32;
137         offset += 32;
138     }
139     size = size % 32;
140     for (uint64_t i=0; i<size; i++) {
141         if ((i % 32) == 0)
142             printf("%" PRIu64 ": ", offset+i);
143         printf("%2.2X", vp[i]);
144         if (((i+1) % 4) == 0)
145             printf(" ");
146         if (((i+1) % 32) == 0)
147             printf("\n");
148     }
149     printf("\n");
150 }
151 
dump_descriptor(DESCRIPTOR d)152 static void dump_descriptor(DESCRIPTOR d) {
153     printf(" descriptor size %u ", d->dbt.size);
154     simple_hex_dump((unsigned char*) d->dbt.data, d->dbt.size);
155     printf("\n");
156 }
157 
open_header(int fd,FT * header,CACHEFILE cf)158 static void open_header(int fd, FT *header, CACHEFILE cf) {
159     FT ft = NULL;
160     int r;
161     const char *fn = toku_cachefile_fname_in_env(cf);
162     r = toku_deserialize_ft_from (fd, fn, MAX_LSN, &ft);
163     if (r != 0) {
164         fprintf(stderr, "%s: can not deserialize from %s error %d\n", arg0, fname, r);
165         exit(1);
166     }
167     assert_zero(r);
168     ft->cf = cf;
169     *header = ft;
170 }
171 
dump_header(FT ft)172 static void dump_header(FT ft) {
173     char timestr[26];
174     printf("ft:\n");
175     printf(" layout_version=%d\n", ft->h->layout_version);
176     printf(" layout_version_original=%d\n", ft->h->layout_version_original);
177     printf(" layout_version_read_from_disk=%d\n", ft->layout_version_read_from_disk);
178     printf(" build_id=%d\n", ft->h->build_id);
179     printf(" build_id_original=%d\n", ft->h->build_id_original);
180     format_time(ft->h->time_of_creation, timestr);
181     printf(" time_of_creation=         %" PRIu64 "    %s\n", ft->h->time_of_creation, timestr);
182     format_time(ft->h->time_of_last_modification, timestr);
183     printf(" time_of_last_modification=%" PRIu64 "    %s\n", ft->h->time_of_last_modification, timestr);
184     printf(" dirty=%d\n", ft->h->dirty());
185     printf(" checkpoint_count=%" PRId64 "\n", ft->h->checkpoint_count);
186     printf(" checkpoint_lsn=%" PRId64 "\n", ft->h->checkpoint_lsn.lsn);
187     printf(" nodesize=%u\n", ft->h->nodesize);
188     printf(" fanout=%u\n", ft->h->fanout);
189     printf(" basementnodesize=%u\n", ft->h->basementnodesize);
190     printf(" compression_method=%u\n", (unsigned) ft->h->compression_method);
191     printf(" unnamed_root=%" PRId64 "\n", ft->h->root_blocknum.b);
192     printf(" flags=%u\n", ft->h->flags);
193     dump_descriptor(&ft->descriptor);
194     printf(" estimated numrows=%" PRId64 "\n", ft->in_memory_stats.numrows);
195     printf(" estimated numbytes=%" PRId64 "\n", ft->in_memory_stats.numbytes);
196     printf(" logical row count=%" PRId64 "\n", ft->in_memory_logical_rows);
197 }
198 
getRootNode(FT ft)199 static int64_t getRootNode(FT ft) {
200     return ft->h->root_blocknum.b;
201 }
202 
print_le(const void * key,const uint32_t keylen,const LEAFENTRY & le,const uint32_t idx UU (),void * const ai UU ())203 static int print_le(const void* key, const uint32_t keylen, const LEAFENTRY &le, const uint32_t idx UU(), void *const ai UU()) {
204     unsigned int *le_index = (unsigned int *) ai;
205     printf("%u: ", *le_index); *le_index += 1;
206     print_klpair(stdout, key, keylen, le);
207     printf("\n");
208     return 0;
209 }
210 
getHeight(int fd,BLOCKNUM blocknum,FT ft)211 static int getHeight(int fd, BLOCKNUM blocknum, FT ft){
212     FTNODE n;
213     FTNODE_DISK_DATA ndd = nullptr;
214     ftnode_fetch_extra bfe;
215     bfe.create_for_full_read(ft);
216     int r = toku_deserialize_ftnode_from (fd, blocknum, 0 /*pass zero for hash, it doesn't matter*/, &n, &ndd, &bfe);
217     assert_zero(r);
218     assert(n!=0);
219     return n->height;
220 }
221 
getNode(int fd,BLOCKNUM blocknum,FT ft)222 static FTNODE  getNode(int fd, BLOCKNUM blocknum, FT ft) {
223     FTNODE n;
224     FTNODE_DISK_DATA ndd = nullptr;
225     ftnode_fetch_extra bfe;
226     bfe.create_for_full_read(ft);
227     int r = toku_deserialize_ftnode_from (fd, blocknum, 0 /*pass zero for hash, it doesn't matter*/, &n, &ndd, &bfe);
228     assert_zero(r);;
229     return n;
230 }
231 
countNodes(NMC * level)232 static int countNodes(NMC *level){
233     int count=0;
234     NMC *ptr=level;
235     while(ptr!=NULL){
236         count++;
237         ptr=ptr->nextNode;
238     }
239     return count;
240 }
241 
countMessages(NMC * level)242 static int * countMessages(NMC *level){
243     int *counts=new int[16];
244     for(int i=0;i<16;i++){
245         counts[i]=0;
246     }
247     NMC *ptr=level;
248     while(ptr!=NULL){
249         for(int i=0;i<16;i++){
250             counts[i]+=ptr->count[i];
251         }
252         ptr=ptr->nextNode;
253     }
254     return counts;
255 }
256 
getLast(NMC * level)257 static NMC * getLast(NMC *level){
258     if (level==NULL) return NULL;
259     NMC *ptr=level;
260     while(ptr->nextNode!=NULL){
261         ptr=ptr->nextNode;
262     }
263     return ptr;
264 }
265 
266 /*
267  * Prints the total messages at each to STDout
268  */
printLevelSTDout(int * count)269 static int  printLevelSTDout(int *count){
270     int isEmpty=0;
271     for(int j=0;j<16;j++){
272         if(count[j]>0){
273             cout <<count[j]<<" ";
274             isEmpty++;
275             switch (j)   {
276                 case FT_INSERT: cout <<"INSERT(s) ";  break;
277                 case FT_INSERT_NO_OVERWRITE: cout <<"INSERT_NO_OVERWRITE(s) ";  break;
278                 case FT_DELETE_ANY: cout <<"DELETE_ANY(s) ";  break;
279                 case FT_ABORT_ANY: cout <<"ABORT_ANY(s) ";  break;
280                 case FT_COMMIT_ANY: cout <<"COMMIT_ANY(s) ";  break;
281                 case FT_COMMIT_BROADCAST_ALL: cout <<"COMMIT_BROADCAST_ALL(s) ";  break;
282                 case FT_COMMIT_BROADCAST_TXN: cout <<"COMMIT_BROADCAST_TXN(s) ";  break;
283                 case FT_ABORT_BROADCAST_TXN: cout <<"ABORT_BROADCAST_TXN(s) ";  break;
284                 case FT_OPTIMIZE: cout <<"OPTIMIZE(s) ";  break;
285                 case FT_OPTIMIZE_FOR_UPGRADE: cout <<"OPTIMIZE_FOR_UPGRADE(s) ";  break;
286                 case FT_UPDATE:   cout <<"UPDATE(s) ";  break;
287                 case FT_UPDATE_BROADCAST_ALL: cout <<"UPDATE_BROADCAST_ALL(s) ";  break;
288             }
289 
290         }
291     }
292     return isEmpty;
293 }
294 
295 /*
296  * Prints the total # of messages in a node  to STD output
297  */
printNodeMessagesToSTDout(NMC * ptr)298 static int  printNodeMessagesToSTDout(NMC *ptr){
299     cout <<"\nNode :"<<ptr->id<<" has :";
300         for(int j=0;j<16;j++){
301         if(ptr->count[j]>0){
302             cout <<ptr->count[j]<<" ";
303             switch (j)   {
304                 case FT_INSERT: cout <<"INSERT(s) ";  break;
305                 case FT_INSERT_NO_OVERWRITE: cout <<"INSERT_NO_OVERWRITE(s) ";  break;
306                 case FT_DELETE_ANY: cout <<"DELETE_ANY(s) ";  break;
307                 case FT_ABORT_ANY: cout <<"ABORT_ANY(s) ";  break;
308                 case FT_COMMIT_ANY: cout <<"COMMIT_ANY(s) ";  break;
309                 case FT_COMMIT_BROADCAST_ALL: cout <<"COMMIT_BROADCAST_ALL(s) ";  break;
310                 case FT_COMMIT_BROADCAST_TXN: cout <<"COMMIT_BROADCAST_TXN(s) ";  break;
311                 case FT_ABORT_BROADCAST_TXN: cout <<"ABORT_BROADCAST_TXN(s) ";  break;
312                 case FT_OPTIMIZE: cout <<"OPTIMIZE(s) ";  break;
313                 case FT_OPTIMIZE_FOR_UPGRADE: cout <<"OPTIMIZE_FOR_UPGRADE(s) ";  break;
314                 case FT_UPDATE:   cout <<"UPDATE(s) ";  break;
315                 case FT_UPDATE_BROADCAST_ALL: cout <<"UPDATE_BROADCAST_ALL(s) ";  break;
316             }
317         }
318     }
319     return 1;
320 }
321 
levelToSTDout(NMC * list,int level)322 static void levelToSTDout(NMC *list, int level){
323     NMC *ptr=list;
324     cout <<endl<<"Height : "<<level<<endl;
325     while(ptr!=NULL){
326         if(ptr->clean!=0){
327             printNodeMessagesToSTDout(ptr);
328         }
329         else{
330             cout << "\nNode : "<<ptr->id<<" has no messages";
331         }
332         ptr=ptr->nextNode;
333     }
334     cout <<endl;
335 }
336 
337 /*
338  * prints the tree total # of nodes and total # of  messages at each height in :
339  * STDout in human readable format
340  */
treeToSTDout(NMC * msgs[],int height)341 static void treeToSTDout(NMC *msgs[], int height){
342     for(int i=height; i>=0 ; i--){
343         cout <<"At height "<<i;
344         int *counts=countMessages(msgs[i]);
345         cout <<"\n     Node Count: "<< countNodes(msgs[i])<<endl;
346         cout <<"           Messages: ";
347         if(printLevelSTDout(counts)==0) cout <<"0\n";
348         else cout <<endl;
349     }
350 }
351 
352 //traverse through the FT and report back the count of messages in every node
countMessagesInFT(int fd,BLOCKNUM blocknum,FT ft,NMC * msgs[])353 static void  countMessagesInFT(int fd, BLOCKNUM blocknum, FT ft,NMC *msgs[]){
354     FTNODE n=getNode(fd,blocknum,ft);
355 
356     NMC *last=NULL;
357     if(msgs[n->height]==NULL){
358         last = msgs[n->height]=new NMC;
359     }else {
360         last=getLast(msgs[n->height]);
361         last->nextNode=new NMC;
362         last=last->nextNode;
363     }
364     last->id=blocknum.b;
365     last->count=new int[16];
366     for(int i=0;i<16;i++){
367         last->count[i]=0;
368     }
369     last->clean=0;
370     last->nextNode=NULL;
371 
372     if (n->height==0){
373         toku_ftnode_free(&n);
374         return;
375     }
376     for(int i=0;i<n->n_children;i++){
377         NONLEAF_CHILDINFO bnc = BNC(n, i);
378         if (n->height==1 && n->bp[i].ptr.tag==BCT_NULL){
379             cout <<n->bp[i].ptr.tag;
380         }
381         auto dump_fn=[&](const ft_msg &msg, bool UU(is_fresh)) {
382             enum ft_msg_type type = (enum ft_msg_type) msg.type();
383             last->count[type]++;
384             last->clean=1;
385             return 0;
386         };
387 
388         bnc->msg_buffer.iterate(dump_fn);
389 
390         blocknum=make_blocknum(BP_BLOCKNUM(n, i).b);
391         countMessagesInFT(fd,blocknum,ft, msgs);
392     }
393 
394     toku_ftnode_free(&n);
395 }
396 
dump_node(int fd,BLOCKNUM blocknum,FT ft)397 static void dump_node(int fd, BLOCKNUM blocknum, FT ft) {
398     FTNODE n;
399     FTNODE_DISK_DATA ndd = nullptr;
400     ftnode_fetch_extra bfe;
401     bfe.create_for_full_read(ft);
402     int r = toku_deserialize_ftnode_from (fd, blocknum, 0 /*pass zero for hash, it doesn't matter*/, &n, &ndd, &bfe);
403     assert_zero(r);
404     assert(n!=0);
405     printf("ftnode\n");
406     DISKOFF disksize, diskoffset;
407     ft->blocktable.translate_blocknum_to_offset_size(blocknum, &diskoffset, &disksize);
408     printf(" diskoffset  =%" PRId64 "\n", diskoffset);
409     printf(" disksize    =%" PRId64 "\n", disksize);
410     printf(" serialize_size =%u\n", toku_serialize_ftnode_size(n));
411     printf(" flags       =%u\n", n->flags);
412     printf(" blocknum=%" PRId64 "\n", n->blocknum.b);
413     //printf(" log_lsn     =%lld\n", n->log_lsn.lsn); // The log_lsn is a memory-only value.
414     printf(" height      =%d\n",   n->height);
415     printf(" layout_version=%d\n", n->layout_version);
416     printf(" layout_version_original=%d\n", n->layout_version_original);
417     printf(" layout_version_read_from_disk=%d\n", n->layout_version_read_from_disk);
418     printf(" build_id=%d\n", n->build_id);
419     printf(" max_msn_applied_to_node_on_disk=%" PRId64 " (0x%" PRIx64 ")\n", n->max_msn_applied_to_node_on_disk.msn, n->max_msn_applied_to_node_on_disk.msn);
420     printf(" io time %lf decompress time %lf deserialize time %lf\n",
421            tokutime_to_seconds(bfe.io_time),
422            tokutime_to_seconds(bfe.decompress_time),
423            tokutime_to_seconds(bfe.deserialize_time));
424 
425     printf(" n_children=%d\n", n->n_children);
426     printf(" pivotkeys.total_size()=%u\n", (unsigned) n->pivotkeys.total_size());
427 
428     if (n->height > 0) {
429 	printf(" pivots:\n");
430     } else {
431 	printf("LEAF keys:\n");
432     }
433 
434     for (int i=0; i<n->n_children-1; i++) {
435         const DBT piv = n->pivotkeys.get_pivot(i);
436         printf("  pivot %2d:", i);
437         if (n->flags)
438             printf(" flags=%x ", n->flags);
439         print_item(piv.data, piv.size);
440         printf("\n");
441     }
442 
443     if (n->height > 0) {
444 	printf(" children:\n");
445     } else {
446 	printf("LEAF data:\n");
447     }
448 
449     for (int i=0; i<n->n_children; i++) {
450             printf("  child %d: ", i);
451         if (n->height > 0) {
452             printf("%" PRId64 "\n", BP_BLOCKNUM(n, i).b);
453             NONLEAF_CHILDINFO bnc = BNC(n, i);
454             unsigned int n_bytes = toku_bnc_nbytesinbuf(bnc);
455             int n_entries = toku_bnc_n_entries(bnc);
456             if (n_bytes > 0 || n_entries > 0) {
457                 printf("   buffer contains %u bytes (%d items)\n", n_bytes, n_entries);
458             }
459             if (do_dump_data) {
460                 struct dump_data_fn {
461                     int operator()(const ft_msg &msg, bool UU(is_fresh)) {
462                         enum ft_msg_type type = (enum ft_msg_type) msg.type();
463                         MSN msn = msg.msn();
464                         XIDS xids = msg.xids();
465                         const void *key = msg.kdbt()->data;
466                         const void *data = msg.vdbt()->data;
467                         uint32_t keylen = msg.kdbt()->size;
468                         uint32_t datalen = msg.vdbt()->size;
469                         printf("    msn=%" PRIu64 " (0x%" PRIx64 ") ", msn.msn, msn.msn);
470                         printf("    TYPE=");
471                         switch (type) {
472                             case FT_NONE: printf("NONE"); goto ok;
473                             case FT_INSERT: printf("INSERT"); goto ok;
474                             case FT_INSERT_NO_OVERWRITE: printf("INSERT_NO_OVERWRITE"); goto ok;
475                             case FT_DELETE_ANY: printf("DELETE_ANY"); goto ok;
476                             case FT_ABORT_ANY: printf("ABORT_ANY"); goto ok;
477                             case FT_COMMIT_ANY: printf("COMMIT_ANY"); goto ok;
478                             case FT_COMMIT_BROADCAST_ALL: printf("COMMIT_BROADCAST_ALL"); goto ok;
479                             case FT_COMMIT_BROADCAST_TXN: printf("COMMIT_BROADCAST_TXN"); goto ok;
480                             case FT_ABORT_BROADCAST_TXN: printf("ABORT_BROADCAST_TXN"); goto ok;
481                             case FT_OPTIMIZE: printf("OPTIMIZE"); goto ok;
482                             case FT_OPTIMIZE_FOR_UPGRADE: printf("OPTIMIZE_FOR_UPGRADE"); goto ok;
483                             case FT_UPDATE:   printf("UPDATE"); goto ok;
484                             case FT_UPDATE_BROADCAST_ALL: printf("UPDATE_BROADCAST_ALL"); goto ok;
485                         }
486                         printf("HUH?");
487 ok:
488                         printf(" xid=");
489                         toku_xids_fprintf(stdout, xids);
490                         printf(" ");
491                         print_item(key, keylen);
492                         if (datalen>0) {
493                             printf(" ");
494                             print_item(data, datalen);
495                         }
496                         printf("\n");
497                         return 0;
498                     }
499                 } dump_fn;
500                 bnc->msg_buffer.iterate(dump_fn);
501             }
502         } else {
503             printf(" n_bytes_in_buffer= %" PRIu64 "", BLB_DATA(n, i)->get_disk_size());
504             printf(" items_in_buffer=%u\n", BLB_DATA(n, i)->num_klpairs());
505             if (do_dump_data) {
506                 unsigned int le_index = 0;
507                 BLB_DATA(n, i)->iterate<void, print_le>(&le_index);
508             }
509         }
510     }
511     toku_ftnode_free(&n);
512     toku_free(ndd);
513 }
514 
dump_block_translation(FT ft,uint64_t offset)515 static void dump_block_translation(FT ft, uint64_t offset) {
516     ft->blocktable.blocknum_dump_translation(make_blocknum(offset));
517 }
518 
dump_fragmentation(int UU (f),FT ft,int tsv)519 static void dump_fragmentation(int UU(f), FT ft, int tsv) {
520     int64_t used_space;
521     int64_t total_space;
522     ft->blocktable.internal_fragmentation(&total_space, &used_space);
523     int64_t fragsizes = total_space - used_space;
524 
525     if (tsv) {
526         printf("%" PRId64 "\t%" PRId64 "\t%" PRId64 "\t%.1f\n", used_space, total_space, fragsizes,
527                100. * ((double)fragsizes / (double)(total_space)));
528     } else {
529         printf("used_size\t%" PRId64 "\n",  used_space);
530         printf("total_size\t%" PRId64 "\n", total_space);
531         printf("fragsizes\t%" PRId64 "\n", fragsizes);
532         printf("fragmentation\t%.1f\n", 100. * ((double)fragsizes / (double)(total_space)));
533     }
534 }
535 
536 typedef struct {
537     int fd;
538     FT ft;
539     uint64_t blocksizes;
540     uint64_t leafsizes;
541     uint64_t leafblocks;
542 } frag_help_extra;
543 
nodesizes_helper(BLOCKNUM b,int64_t size,int64_t UU (address),void * extra)544 static int nodesizes_helper(BLOCKNUM b, int64_t size, int64_t UU(address), void *extra) {
545     frag_help_extra *CAST_FROM_VOIDP(info, extra);
546     FTNODE n;
547     FTNODE_DISK_DATA ndd = NULL;
548     ftnode_fetch_extra bfe;
549     bfe.create_for_full_read(info->ft);
550     int r = toku_deserialize_ftnode_from(info->fd, b, 0 /*pass zero for hash, it doesn't matter*/, &n, &ndd, &bfe);
551     if (r==0) {
552         info->blocksizes += size;
553         if (n->height == 0) {
554             info->leafsizes += size;
555             info->leafblocks++;
556         }
557         toku_ftnode_free(&n);
558         toku_free(ndd);
559     }
560     return 0;
561 }
562 
dump_nodesizes(int fd,FT ft)563 static void dump_nodesizes(int fd, FT ft) {
564     frag_help_extra info;
565     memset(&info, 0, sizeof(info));
566     info.fd = fd;
567     info.ft = ft;
568     ft->blocktable.iterate(block_table::TRANSLATION_CHECKPOINTED,
569                            nodesizes_helper, &info, true, true);
570     printf("leafblocks\t%" PRIu64 "\n", info.leafblocks);
571     printf("blocksizes\t%" PRIu64 "\n", info.blocksizes);
572     printf("leafsizes\t%" PRIu64 "\n", info.leafsizes);
573 }
574 
575 /* ===== struct and function to get a summary of atree ===== */
576 
577 typedef struct {
578     int fd;
579     FT ft;
580     uint64_t blocksizes;
581     uint64_t leafsizes;
582     uint64_t serialsize; // sizes of serialized data (assume uncomressed)
583     uint64_t leafblocks; // count of leaf nodes
584     uint64_t nonleafnode_cnt; // count of non-leaf nodes
585     uint64_t maxheight; // height of the tree
586     uint64_t msg_cnt; // message count in non-leafs
587     uint64_t msg_size; // size (in bytes of all messages in non-leafs
588     uint64_t pairs_cnt; // count of pairs in leaf nodes
589     std::map<int, int> height_cnt; // count of nodes per height
590     std::map<int, int> hmsg_cnt; // count of message per height
591     std::map<int, uint64_t> hmsg_size; // size of message per height
592     std::map<int, uint64_t> hdisk_size; // disk size per height
593     std::map<int, uint64_t> hserial_size; // serial size  per height
594 } summary_help_extra;
595 
summary_helper(BLOCKNUM b,int64_t size,int64_t UU (address),void * extra)596 static int summary_helper(BLOCKNUM b, int64_t size, int64_t UU(address), void *extra) {
597     summary_help_extra *CAST_FROM_VOIDP(info, extra);
598     FTNODE n;
599     FTNODE_DISK_DATA ndd = NULL;
600     ftnode_fetch_extra bfe;
601 
602     bfe.create_for_full_read(info->ft);
603     int r = toku_deserialize_ftnode_from(info->fd, b, 0 /*pass zero for hash, it doesn't matter*/, &n, &ndd, &bfe);
604     if (r==0) {
605         info->blocksizes += size;
606 
607 	(info->height_cnt)[n->height]++;
608 
609         if (n->height == 0) {
610             info->leafsizes += size;
611             info->leafblocks++;
612         } else {
613 	    info->nonleafnode_cnt++;
614 	}
615 
616 	info->hdisk_size[n->height] += size;
617 	auto serialsize = toku_serialize_ftnode_size(n);
618 	info->serialsize += serialsize;
619 	info->hserial_size[n->height] += serialsize;
620 
621 
622 	if ((uint64_t)n->height > info->maxheight) {
623 	    info->maxheight = n->height;
624 	}
625 
626 
627 
628 	for (int i=0; i<n->n_children; i++) {
629 	    //printf("  child %d: ", i);
630 	    if (n->height > 0) {
631 		NONLEAF_CHILDINFO bnc = BNC(n, i);
632 		unsigned int n_bytes = toku_bnc_nbytesinbuf(bnc);
633 		int n_entries = toku_bnc_n_entries(bnc);
634 		//if (n_bytes > 0 || n_entries > 0) {
635 		//    printf("   buffer contains %u bytes (%d items)\n", n_bytes, n_entries);
636 		//}
637 		info->msg_cnt += n_entries;
638 		info->msg_size += n_bytes;
639 		info->hmsg_cnt[n->height] += n_entries;
640 		info->hmsg_size[n->height] += n_bytes;
641 	    } else {
642 		info->pairs_cnt += BLB_DATA(n, i)->num_klpairs();
643 	    }
644 	}
645 	if (n->height ==0) {
646 	    info->hmsg_cnt[0] += n->n_children; // this way we count partitions per leaf node
647 	}
648 
649 
650         toku_ftnode_free(&n);
651         toku_free(ndd);
652     }
653     return 0;
654 }
655 
humanNumber(uint64_t value)656 static std::string  humanNumber(uint64_t value) {
657     std::string numWithCommas = to_string(value);
658     int insertPosition = numWithCommas.length() - 3;
659     while (insertPosition > 0) {
660 	numWithCommas.insert(insertPosition, ",");
661 	insertPosition-=3;
662     }
663     return numWithCommas;
664 }
665 
dump_summary(int fd,FT ft)666 static void dump_summary(int fd, FT ft) {
667     summary_help_extra info;
668     //memset(&info, 0, sizeof(info));
669     info.fd = fd;
670     info.ft = ft;
671     info.blocksizes = 0;
672     info.leafsizes = 0;
673     info.serialsize = 0;
674     info.leafblocks = 0;
675     info.nonleafnode_cnt = 0;
676     info.maxheight = 0;
677     info.msg_cnt  = 0;
678     info.msg_size = 0;
679     info.pairs_cnt = 0;
680 
681     ft->blocktable.iterate(block_table::TRANSLATION_CHECKPOINTED,
682                            summary_helper, &info, true, true);
683     printf("leaf nodes:\t%" PRIu64 "\n", info.leafblocks);
684     printf("non-leaf nodes:\t%" PRIu64 "\n", info.nonleafnode_cnt);
685     printf("Leaf size:\t%s\n", humanNumber(info.leafsizes).c_str());
686     printf("Total size:\t%s\n", humanNumber(info.blocksizes).c_str());
687     printf("Total uncompressed size:\t%s\n", humanNumber(info.serialsize).c_str());
688     printf("Messages count:\t%" PRIu64 "\n", info.msg_cnt);
689     printf("Messages size:\t%s\n", humanNumber(info.msg_size).c_str());
690     printf("Records count:\t%" PRIu64 "\n", info.pairs_cnt);
691     printf("Tree height:\t%" PRIu64 "\n", info.maxheight);
692     for(auto elem : info.height_cnt) {
693 	std::string hdr;
694 	double children_per_node;
695 	if (elem.first == 0) {
696 	    hdr = "basement nodes";
697 	    children_per_node = (double)info.hmsg_cnt[0]/elem.second;
698 	} else {
699 	    hdr = "msg cnt";
700 	    children_per_node = (double)info.height_cnt[elem.first-1]/elem.second;
701 	}
702 
703 	printf("height: %d, nodes count: %d; avg children/node: %f\n\t %s: %d; msg size: %s; disksize: %s; uncompressed size: %s; ratio: %f\n",
704 		elem.first, elem.second, children_per_node,
705 		    hdr.c_str(),
706 		    info.hmsg_cnt[elem.first],
707 		    humanNumber(info.hmsg_size[elem.first]).c_str(),
708 		    humanNumber(info.hdisk_size[elem.first]).c_str(),
709 		    humanNumber(info.hserial_size[elem.first]).c_str(),
710 		    (double)info.hserial_size[elem.first]/info.hdisk_size[elem.first] );
711     }
712 }
713 
714 /* ===== end of summary ===== */
715 
dump_garbage_stats(int fd,FT ft)716 static void dump_garbage_stats(int fd, FT ft) {
717     assert(fd == toku_cachefile_get_fd(ft->cf));
718     uint64_t total_space = 0;
719     uint64_t used_space = 0;
720     toku_ft_get_garbage(ft, &total_space, &used_space);
721     printf("garbage total size :%20" PRIu64 "\n", total_space);
722     printf("garbage used size  :%20" PRIu64 "\n", used_space);
723     float a=used_space,b=total_space;
724 
725     float percentage=((1-a/b)*100);
726     printf("Total garbage : %2.3f%%\n", percentage);
727 }
728 
729 typedef struct __dump_node_extra {
730     int fd;
731     FT ft;
732 } dump_node_extra;
733 
dump_node_wrapper(BLOCKNUM b,int64_t UU (size),int64_t UU (address),void * extra)734 static int dump_node_wrapper(BLOCKNUM b, int64_t UU(size), int64_t UU(address), void *extra) {
735     dump_node_extra *CAST_FROM_VOIDP(info, extra);
736     dump_node(info->fd, b, info->ft);
737     return 0;
738 }
739 
get_unaligned_uint32(unsigned char * p)740 static uint32_t get_unaligned_uint32(unsigned char *p) {
741     uint32_t n;
742     memcpy(&n, p, sizeof n);
743     return n;
744 }
745 
746 struct dump_sub_block {
747     uint32_t compressed_size;
748     uint32_t uncompressed_size;
749     uint32_t xsum;
750 };
751 
sub_block_deserialize(struct dump_sub_block * sb,unsigned char * sub_block_header)752 static void sub_block_deserialize(struct dump_sub_block *sb, unsigned char *sub_block_header) {
753     sb->compressed_size = toku_dtoh32(get_unaligned_uint32(sub_block_header+0));
754     sb->uncompressed_size = toku_dtoh32(get_unaligned_uint32(sub_block_header+4));
755     sb->xsum = toku_dtoh32(get_unaligned_uint32(sub_block_header+8));
756 }
757 
verify_block(unsigned char * cp,uint64_t file_offset,uint64_t size)758 static void verify_block(unsigned char *cp, uint64_t file_offset, uint64_t size) {
759     // verify the header checksum
760     const size_t node_header = 8 + sizeof (uint32_t) + sizeof (uint32_t) + sizeof (uint32_t);
761 
762     printf("%.8s layout_version=%u %u build=%d\n", cp, get_unaligned_uint32(cp+8), get_unaligned_uint32(cp+12), get_unaligned_uint32(cp+16));
763 
764     unsigned char *sub_block_header = &cp[node_header];
765     uint32_t n_sub_blocks = toku_dtoh32(get_unaligned_uint32(&sub_block_header[0]));
766     uint32_t header_length = node_header + n_sub_blocks * sizeof (struct dump_sub_block);
767     header_length += sizeof (uint32_t); // CRC
768     if (header_length > size) {
769         printf("header length too big: %u\n", header_length);
770         return;
771     }
772     uint32_t header_xsum = toku_x1764_memory(cp, header_length);
773     uint32_t expected_xsum = toku_dtoh32(get_unaligned_uint32(&cp[header_length]));
774     if (header_xsum != expected_xsum) {
775         printf("header checksum failed: %u %u\n", header_xsum, expected_xsum);
776         return;
777     }
778 
779     // deserialize the sub block header
780     struct dump_sub_block sub_block[n_sub_blocks];
781     sub_block_header += sizeof (uint32_t);
782     for (uint32_t i = 0 ; i < n_sub_blocks; i++) {
783         sub_block_deserialize(&sub_block[i], sub_block_header);
784         sub_block_header += sizeof (struct dump_sub_block);
785     }
786 
787     // verify the sub block header
788     uint32_t offset = header_length + 4;
789     for (uint32_t i = 0 ; i < n_sub_blocks; i++) {
790         uint32_t xsum = toku_x1764_memory(cp + offset, sub_block[i].compressed_size);
791         printf("%u: %u %u %u", i, sub_block[i].compressed_size, sub_block[i].uncompressed_size, sub_block[i].xsum);
792         if (xsum != sub_block[i].xsum)
793             printf(" fail %u offset %" PRIu64, xsum, file_offset + offset);
794         printf("\n");
795         offset += sub_block[i].compressed_size;
796     }
797     if (offset != size)
798         printf("offset %u expected %" PRIu64 "\n", offset, size);
799 }
800 
dump_block(int fd,BLOCKNUM blocknum,FT ft)801 static void dump_block(int fd, BLOCKNUM blocknum, FT ft) {
802     DISKOFF offset, size;
803     ft->blocktable.translate_blocknum_to_offset_size(blocknum, &offset, &size);
804     printf("%" PRId64 " at %" PRId64 " size %" PRId64 "\n", blocknum.b, offset, size);
805 
806     unsigned char *CAST_FROM_VOIDP(vp, toku_malloc(size));
807     uint64_t r = pread(fd, vp, size, offset);
808     if (r == (uint64_t)size) {
809         verify_block(vp, offset, size);
810     }
811     toku_free(vp);
812 }
813 
dump_file(int fd,uint64_t offset,uint64_t size,FILE * outfp)814 static void dump_file(int fd, uint64_t offset, uint64_t size, FILE *outfp) {
815     unsigned char *XMALLOC_N(size, vp);
816     uint64_t r = pread(fd, vp, size, offset);
817     if (r == size) {
818         if (outfp == stdout) {
819             hex_dump(vp, offset, size);
820         } else {
821             size_t wrote = fwrite(vp, size, 1, outfp);
822             assert(wrote == 1);
823         }
824     }
825     toku_free(vp);
826 }
827 
set_file(int fd,uint64_t offset,unsigned char newc)828 static void set_file(int fd, uint64_t offset, unsigned char newc) {
829     toku_os_pwrite(fd, &newc, sizeof newc, offset);
830 }
831 
readline(char * line,int maxline)832 static int readline(char *line, int maxline) {
833     int i = 0;
834     int c;
835     while ((c = getchar()) != EOF && c != '\n' && i < maxline) {
836         line[i++] = (char)c;
837     }
838     line[i++] = 0;
839     return c == EOF ? EOF : i;
840 }
841 
split_fields(char * line,char * fields[],int maxfields)842 static int split_fields(char *line, char *fields[], int maxfields) {
843     int i;
844     for (i=0; i<maxfields; i++)
845         fields[i] = NULL;
846     for (i=0; i<maxfields; i++, line=NULL) {
847         fields[i] = strtok(line, " ");
848         if (fields[i] == NULL) {
849             break;
850         }
851     }
852     return i;
853 }
854 
getuint64(const char * f)855 static uint64_t getuint64(const char *f) {
856     if (strncmp(f, "0x", 2) == 0 || strncmp(f, "0X", 2) == 0)
857         return strtoull(f, 0, 16);
858     else if (strncmp(f, "0", 1) == 0)
859         return strtoull(f, 0, 8);
860     else
861         return strtoull(f, 0, 10);
862 }
863 
interactive_help(void)864 static void interactive_help(void) {
865     fprintf(stderr, "help\n");
866     fprintf(stderr, "header\n");
867     cout <<"mr/MessagesReport [NUMBER] \n      Reports messages for the level of the tree you want get more details about\n";
868     cout <<"rf/readFile ft-file-name \n      Switch to a different FT\n";
869     fprintf(stderr, "node NUMBER \n");
870     fprintf(stderr, "bx OFFSET | block_translation OFFSET\n");
871     fprintf(stderr, "dumpdata 0|1\n");
872     fprintf(stderr, "fragmentation\n");
873     fprintf(stderr, "nodesizes\n");
874     fprintf(stderr, "garbage\n");
875     fprintf(stderr, "file OFFSET SIZE [outfilename]\n");
876     fprintf(stderr, "quit\n");
877 }
878 
freeNMC(NMC * msgs[],int height)879 static void freeNMC(NMC *msgs[], int height){
880     for(int i=0;i<height;i++){
881         if(msgs[i]!=NULL){
882             delete(msgs[i]->count);
883 
884             while(msgs[i]->nextNode!=NULL){
885                 NMC* ptr=msgs[i]->nextNode;
886                 msgs[i]=msgs[i]->nextNode;
887                 delete ptr;
888 
889             }
890             msgs[i]=NULL;
891         }
892     }
893 }
894 
writeTree(NMC * msgs[],int height,char * name UU ())895 static void writeTree(NMC *msgs[],int height,char *name UU()){
896     ofstream mytree ("/tmp/tree.txt",fstream::out);
897     if (mytree.is_open()){
898         for(int i=height;i>=0;i--){
899             NMC * ptr=msgs[i];
900             mytree <<i<<endl;
901             while(ptr!=NULL){
902                 mytree << ptr->id<<"\t";
903                 if(ptr->clean!=0)mytree << "1"<<"\t";
904                 else mytree << "0"<<"\t";
905                 for(int j=0;j<15;j++)mytree << ptr->count[j]<<" ";
906                 mytree << ptr->count[i]<<endl;
907                 ptr=ptr->nextNode;
908             }
909              mytree <<endl;
910         }
911     }
912     else cout << "Unable to open file";
913     mytree.close();
914 }
915 
writeJson(NMC * msgs[],int height,const char * name)916 static void writeJson(NMC *msgs[],int height,const char *name){
917     ofstream mytree (name,fstream::out);
918     if (mytree.is_open()){
919         mytree <<"{\n \"FT\":[";
920         for(int i=height;i>=0;i--){
921             NMC * ptr=msgs[i];
922             mytree <<"{\n\"Level\": {\"Height\":\""<<i<<"\",\n \"Nodes\":[";
923             while(ptr!=NULL){
924                 mytree <<"{\"ID\":\""<< ptr->id<<"\",";
925                 if(ptr->clean!=0){
926                     mytree <<"\"Messages\":[";
927                     for(int j=0;j<16;j++)
928                         {
929                         mytree <<"{";
930                         switch (j)   {
931                             case FT_INSERT: mytree <<"\"INSERT\":\""<<ptr->count[j]<<"\""; break;
932                             case FT_INSERT_NO_OVERWRITE: mytree <<"\"INSERT_NOVERWTE\":\""<<ptr->count[j]<<"\""; break;
933                             case FT_DELETE_ANY: mytree <<"\"DELETE\":\""<<ptr->count[j]<<"\""; break;
934                             case FT_ABORT_ANY: mytree <<"\"ABORT\":\""<<ptr->count[j]<<"\""; break;
935                             case FT_COMMIT_ANY: mytree <<"\"COMMITY\":\""<<ptr->count[j]<<"\""; break;
936                             case FT_COMMIT_BROADCAST_ALL: mytree <<"\"COMMIT_BROADCAST_ALL\":\""<<ptr->count[j]<<"\"" ;    break;
937                             case FT_COMMIT_BROADCAST_TXN: mytree <<"\"COMMIT_BROADCAST_TXN\":\""<<ptr->count[j]<<"\""; break;
938                             case FT_ABORT_BROADCAST_TXN: mytree <<"\"ABORT_BROADCAST_TXN\":\""<<ptr->count[j]<<"\"";break;
939                             case FT_OPTIMIZE: mytree <<"\"OPTIMIZE\":\""<<ptr->count[j]<<"\""; break;
940                             case FT_OPTIMIZE_FOR_UPGRADE: mytree <<"\"OPTIMIZE_FOR_UPGRADE\":\""<<ptr->count[j]<<"\"";break;
941                             case FT_UPDATE:   mytree <<"\"UPDATE\":\""<<ptr->count[j]<<"\""; break;
942                             case FT_UPDATE_BROADCAST_ALL: mytree <<"\"UPDATE_BROADCAST_ALL\":\""<<ptr->count[j]<<"\""; break;
943                         }
944                         mytree <<"}";
945                         if(j<15)mytree<<",";
946                     }
947 
948                     mytree <<"]}";
949 
950                 }
951                 else {
952                     mytree <<"\"Messages\":\""<< "0"<<"\"}";
953                 }
954                 if(ptr->nextNode!=NULL)mytree <<",\n";
955                 else mytree <<"]}\n";
956                 ptr=ptr->nextNode;
957             }
958             mytree <<"\n}\n";
959             if(i!=0)mytree <<",\n";
960         }
961         mytree <<"\n]}\n";
962 
963     }
964     else cout << "Unable to open file";
965     mytree.close();
966 }
967 
writeTree(NMC * msgs[],int height)968 static void writeTree(NMC *msgs[],int height){
969     ofstream mytree ("/tmp/tree1.txt",fstream::out);
970     if (mytree.is_open()){
971         for(int i=height;i>=0;i--){
972             NMC * ptr=msgs[i];
973             mytree <<i<<endl;
974             while(ptr!=NULL){
975                 mytree << ptr->id<<",";
976                 if(ptr->clean!=0)mytree << "1"<<",";
977                 else mytree << "0"<<",";
978                 for(int j=0;j<15;j++)mytree << ptr->count[j]<<",";
979                 mytree << ptr->count[i]<<endl;
980                 ptr=ptr->nextNode;
981             }
982              mytree <<".\"";
983         }
984     }
985     else cout << "Unable to open file";
986     mytree.close();
987 }
988 
FT_to_JSON(int fd,FT ft,CACHEFILE cf,const char * JsonFile)989 static void FT_to_JSON(int fd, FT ft, CACHEFILE cf, const char * JsonFile){
990     toku_ft_free(ft);
991     open_header(fd, &ft, cf);
992     int root=getRootNode(ft);
993     BLOCKNUM off = make_blocknum(root);
994     int height=getHeight(fd,off, ft);
995     NMC *msgs[height];
996     for(int i=0;i<=height;i++){
997         msgs[i]=NULL;
998     }
999     open_header(fd, &ft, cf);
1000     root=getRootNode(ft);
1001     off = make_blocknum(root);
1002     countMessagesInFT(fd,off, ft,msgs);
1003     cout <<"to STD output: \n";
1004     treeToSTDout(msgs,height);
1005     writeTree(msgs,height);
1006     cout<<"FT's json file was generated here:";
1007     if(JsonFile!=NULL)  {
1008         cout <<JsonFile;
1009         writeJson(msgs,height,JsonFile);
1010     }
1011     else {
1012         cout <<"./FT.json";
1013         writeJson(msgs,height,"./FT.json");
1014     }
1015     cout<<endl;
1016     freeNMC(msgs,height);
1017     exit(0);
1018 }
1019 
run_iteractive_loop(int fd,FT ft,CACHEFILE cf)1020 static void run_iteractive_loop(int fd, FT ft, CACHEFILE cf) {
1021     toku_ft_free(ft);
1022     open_header(fd, &ft, cf);
1023     int root=getRootNode(ft);
1024     BLOCKNUM off = make_blocknum(root);
1025     int height=getHeight(fd,off, ft);
1026     NMC *msgs[height];
1027     for(int i=0;i<=height;i++){
1028         msgs[i]=NULL;
1029     }
1030     while (1) {
1031         printf("ftdump>");
1032         fflush(stdout);
1033         char line[maxline+1];
1034         int r = readline(line, maxline);
1035         if (r == EOF)
1036             break;
1037         const int maxfields = 4;
1038         char *fields[maxfields];
1039         int nfields = split_fields(line, fields, maxfields);
1040         if (nfields == 0)
1041             continue;
1042         if (strcmp(fields[0], "help") == 0) {
1043             interactive_help();
1044         } else if (strcmp(fields[0], "header") == 0) {
1045             toku_ft_free(ft);
1046             open_header(fd, &ft, cf);
1047             dump_header(ft);
1048         } else if (strcmp(fields[0], "rn") == 0||strcmp(fields[0], "rootNode")==0||strcmp(fields[0], "rootnode") == 0) {
1049             printf("Root node :%d\n",root);
1050         } else if (strcmp(fields[0], "block") == 0 && nfields == 2) {
1051             BLOCKNUM blocknum = make_blocknum(getuint64(fields[1]));
1052             dump_block(fd, blocknum, ft);
1053         }else if ((strcmp(fields[0], "readFile") == 0 ||strcmp(fields[0], "readfile") == 0 ||strcmp(fields[0], "rf") == 0 )&& nfields == 2) {
1054             fname=fields[1];
1055             fd = open(fname, O_RDWR + O_BINARY);
1056             toku_ft_free(ft);
1057             open_header(fd, &ft, cf);
1058             root=getRootNode(ft);
1059             off = make_blocknum(root);
1060             height=getHeight(fd,off, ft);
1061             if (fd < 0) {
1062                 fprintf(stderr, "%s: can not open the FT dump %s errno %d\n", arg0, fname, errno);
1063                 continue;
1064             }
1065         } else if (strcmp(fields[0], "node") == 0 && nfields == 2) {
1066             off = make_blocknum(getuint64(fields[1]));
1067             dump_node(fd, off, ft);
1068         }else if ((strcmp(fields[0], "mr") == 0||(strcmp(fields[0], "nc")) == 0 ||strcmp(fields[0], "messagesReport") == 0 )) {
1069             freeNMC(msgs,height);
1070             toku_ft_free(ft);
1071             open_header(fd, &ft, cf);
1072             root=getRootNode(ft);
1073             off = make_blocknum(root);
1074             countMessagesInFT(fd,off, ft,msgs);
1075             int level=-1;
1076             if(nfields == 2)level=getuint64(fields[1]);
1077             if(level>=0){
1078                 levelToSTDout(msgs[level], level);
1079             }
1080             else{
1081                 cout <<"to STD output: \n";
1082                 treeToSTDout(msgs,height);
1083             }
1084             writeTree(msgs,height);
1085             writeTree(msgs,height, NULL);
1086 
1087         }else if (strcmp(fields[0], "dumpdata") == 0 && nfields == 2) {
1088 
1089             do_dump_data = strtol(fields[1], NULL, 10);
1090         }
1091         else if (strcmp(fields[0], "block_translation") == 0 || strcmp(fields[0], "bx") == 0) {
1092             uint64_t offset = 0;
1093             if (nfields == 2)
1094                 offset = getuint64(fields[1]);
1095             dump_block_translation(ft, offset);
1096         } else if (strcmp(fields[0], "fragmentation") == 0) {
1097             dump_fragmentation(fd, ft, do_tsv);
1098         } else if (strcmp(fields[0], "nodesizes") == 0) {
1099             dump_nodesizes(fd, ft);
1100         } else if (strcmp(fields[0], "garbage") == 0||strcmp(fields[0], "g") == 0) {
1101             dump_garbage_stats(fd, ft);
1102         } else if (strcmp(fields[0], "file") == 0 && nfields >= 3) {
1103             uint64_t offset = getuint64(fields[1]);
1104             uint64_t size = getuint64(fields[2]);
1105             FILE *outfp = stdout;
1106             if (nfields >= 4)
1107                 outfp = fopen(fields[3], "w");
1108             dump_file(fd, offset, size, outfp);
1109         } else if (strcmp(fields[0], "setfile") == 0 && nfields == 3) {
1110             uint64_t offset = getuint64(fields[1]);
1111             unsigned char newc = getuint64(fields[2]);
1112             set_file(fd, offset, newc);
1113         } else if (strcmp(fields[0], "quit") == 0 || strcmp(fields[0], "q") == 0) {
1114             toku_ft_free(ft);
1115             exit(0);
1116         }
1117     }
1118     freeNMC(msgs,height);
1119 }
1120 
usage(void)1121 static int usage(void) {
1122     fprintf(stderr, "Usage: %s ", arg0);
1123     fprintf(stderr, "--interactive ");
1124     fprintf(stderr, "--support /path/to/fractal-tree/file \n\t an interactive way to see what messages and/or switch between FTs");
1125     fprintf(stderr, "--json /path/to/fractal-tree/file [output json file]\n\t if left empty an FT.json will be created automatically");
1126     fprintf(stderr, "--nodata ");
1127     fprintf(stderr, "--dumpdata 0|1 ");
1128     fprintf(stderr, "--header ");
1129     fprintf(stderr, "--rootnode ");
1130     fprintf(stderr, "--node N ");
1131     fprintf(stderr, "--fragmentation ");
1132     fprintf(stderr, "--garbage ");
1133     fprintf(stderr, "--tsv ");
1134     fprintf(stderr, "--translation-table ");
1135     fprintf(stderr, "--tsv ");
1136     fprintf(stderr, "--summary ");
1137     fprintf(stderr, "filename \n");
1138     return 1;
1139 }
1140 
main(int argc,const char * const argv[])1141 int main (int argc, const char *const argv[]) {
1142     arg0 = argv[0];
1143     argc--; argv++;
1144     while (argc>0) {
1145         if (strcmp(argv[0], "--interactive") == 0 || strcmp(argv[0], "--i") == 0) {
1146             do_interactive = 1;
1147         }
1148         else if ((strcmp(argv[0], "--json") == 0 || strcmp(argv[0], "--s")== 0)&& argc >= 2) {
1149             do_json = 1;
1150             fname=argv[1];
1151             argc--; argv++;
1152             break;
1153         } else if (strcmp(argv[0], "--nodata") == 0) {
1154             do_dump_data = 0;
1155         } else if (strcmp(argv[0], "--dumpdata") == 0 && argc > 1) {
1156             do_dump_data = atoi(argv[0]);
1157         } else if (strcmp(argv[0], "--header") == 0) {
1158             do_header = 1;
1159         } else if (strcmp(argv[0], "--rootnode") == 0) {
1160             do_rootnode = 1;
1161         } else if (strcmp(argv[0], "--node") == 0 && argc > 1) {
1162             argc--; argv++;
1163             do_node = 1;
1164             do_node_num = make_blocknum(getuint64(argv[0]));
1165         } else if (strcmp(argv[0], "--fragmentation") == 0) {
1166             do_fragmentation = 1;
1167         } else if (strcmp(argv[0], "--garbage") == 0) {
1168             do_garbage = 1;
1169         } else if (strcmp(argv[0], "--tsv") == 0) {
1170             do_tsv = 1;
1171         } else if (strcmp(argv[0], "--translation-table") == 0) {
1172             do_translation_table = 1;
1173         } else if (strcmp(argv[0], "--summary") == 0) {
1174             do_summary = 1;
1175         } else if (strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-?") == 0 || strcmp(argv[0], "-h") == 0) {
1176             return usage();
1177         } else {
1178             break;
1179         }
1180         argc--; argv++;
1181     }
1182     if (argc != 1 && do_json==0)
1183     return usage();
1184 
1185     int r = toku_ft_layer_init();
1186     assert_zero(r);
1187     if(fname==NULL)fname = argv[0];
1188     int fd = open(fname, O_RDWR + O_BINARY);
1189     if (fd < 0) {
1190         fprintf(stderr, "%s: can not open %s errno %d\n", arg0, fname, errno);
1191         return 1;
1192     }
1193     // create a cachefile for the header
1194     CACHETABLE ct = NULL;
1195     toku_cachetable_create(&ct, 1<<25, (LSN){0}, 0);
1196     CACHEFILE cf = NULL;
1197     r = toku_cachetable_openfd (&cf, ct, fd, fname);
1198     assert_zero(r);
1199     FT ft = NULL;
1200     open_header(fd, &ft, cf);
1201     if (do_json ) {
1202         const char *arg=argv[1];
1203         FT_to_JSON(fd, ft, cf,arg);
1204     }
1205     if (do_interactive) {
1206         run_iteractive_loop(fd, ft, cf);
1207     }
1208     else {
1209         if (do_header) {
1210             dump_header(ft);
1211         }
1212         if (do_rootnode) {
1213             dump_node(fd, ft->h->root_blocknum, ft);
1214         }
1215         if (do_node) {
1216             dump_node(fd, do_node_num, ft);
1217         }
1218         if (do_fragmentation) {
1219             dump_fragmentation(fd, ft, do_tsv);
1220         }
1221         if (do_translation_table) {
1222             ft->blocktable.dump_translation_table_pretty(stdout);
1223         }
1224         if (do_summary) {
1225 	    dump_summary(fd, ft);
1226         }
1227         if (do_garbage) {
1228             dump_garbage_stats(fd, ft);
1229         }
1230         if (!do_header && !do_rootnode && !do_fragmentation && !do_translation_table && !do_garbage && !do_summary) {
1231             printf("Block translation:");
1232             ft->blocktable.dump_translation_table(stdout);
1233             dump_header(ft);
1234             struct __dump_node_extra info;
1235             info.fd = fd;
1236             info.ft = ft;
1237             ft->blocktable.iterate(block_table::TRANSLATION_CHECKPOINTED,
1238             dump_node_wrapper, &info, true, true);
1239         }
1240     }
1241     toku_cachefile_close(&cf, false, ZERO_LSN);
1242     toku_cachetable_close(&ct);
1243     toku_ft_free(ft);
1244     toku_ft_layer_destroy();
1245     return 0;
1246 }
1247