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/*======
5This file is part of PerconaFT.
6
7
8Copyright (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
61using namespace std;
62
63static int do_dump_data = 1;
64static int do_interactive = 0;
65static int do_json = 0;
66static int do_header = 0;
67static int do_fragmentation = 0;
68static int do_garbage = 0;
69static int do_translation_table = 0;
70static int do_summary = 0;
71static int do_rootnode = 0;
72static int do_node = 0;
73static BLOCKNUM do_node_num;
74static int do_tsv = 0;
75static const char *arg0;
76static const char *fname;
77
78//it holdes the messges count for each FT's node
79typedef struct nodeMessage{
80 int id;
81 int clean;//0=clean >=1 dirty
82 int *count;//holds the messages
83 nodeMessage *nextNode;
84}NMC;
85enum { maxline = 128};
86
87static int printNodeMessagesToSTDout(NMC* ptr);
88
89static int printLevelSTDout(int *);
90
91static void treeToSTDout(NMC *msgs[], int height);
92
93static 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
100static 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
114static 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
121static 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
152static 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
158static 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
172static 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
199static int64_t getRootNode(FT ft) {
200 return ft->h->root_blocknum.b;
201}
202
203static 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
211static 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
222static 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
232static 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
242static 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
257static 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 */
269static 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 */
298static 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
322static 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 */
341static 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
353static 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
397static 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?");
487ok:
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
515static void dump_block_translation(FT ft, uint64_t offset) {
516 ft->blocktable.blocknum_dump_translation(make_blocknum(offset));
517}
518
519static 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
536typedef struct {
537 int fd;
538 FT ft;
539 uint64_t blocksizes;
540 uint64_t leafsizes;
541 uint64_t leafblocks;
542} frag_help_extra;
543
544static 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
563static 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
577typedef 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
596static 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
656static 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
666static 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
716static 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
729typedef struct __dump_node_extra {
730 int fd;
731 FT ft;
732} dump_node_extra;
733
734static 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
740static uint32_t get_unaligned_uint32(unsigned char *p) {
741 uint32_t n;
742 memcpy(&n, p, sizeof n);
743 return n;
744}
745
746struct dump_sub_block {
747 uint32_t compressed_size;
748 uint32_t uncompressed_size;
749 uint32_t xsum;
750};
751
752static 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
758static 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
801static 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
814static 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
828static void set_file(int fd, uint64_t offset, unsigned char newc) {
829 toku_os_pwrite(fd, &newc, sizeof newc, offset);
830}
831
832static 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
842static 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
855static 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
864static 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
879static 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
895static 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
916static 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
968static 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
989static 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
1020static 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
1121static 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
1141int 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