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 = 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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
158 | static void (int fd, FT *, 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 | |
172 | static void (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 | |
199 | static int64_t getRootNode(FT ft) { |
200 | return ft->h->root_blocknum.b; |
201 | } |
202 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | */ |
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 | */ |
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 | |
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 | */ |
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 |
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 | |
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 | |
515 | static void dump_block_translation(FT ft, uint64_t offset) { |
516 | ft->blocktable.blocknum_dump_translation(make_blocknum(offset)); |
517 | } |
518 | |
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 | } ; |
543 | |
544 | static int nodesizes_helper(BLOCKNUM b, int64_t size, int64_t UU(address), void *) { |
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 | |
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 | } ; |
595 | |
596 | static int summary_helper(BLOCKNUM b, int64_t size, int64_t UU(address), void *) { |
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 | |
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 | |
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 | |
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 { |
730 | int ; |
731 | FT ; |
732 | } ; |
733 | |
734 | static int dump_node_wrapper(BLOCKNUM b, int64_t UU(size), int64_t UU(address), void *) { |
735 | dump_node_extra *CAST_FROM_VOIDP(info, extra); |
736 | dump_node(info->fd, b, info->ft); |
737 | return 0; |
738 | } |
739 | |
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 | |
752 | static void sub_block_deserialize(struct dump_sub_block *sb, unsigned char *) { |
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 | |
758 | static void verify_block(unsigned char *cp, uint64_t file_offset, uint64_t size) { |
759 | // verify the header checksum |
760 | const size_t = 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 * = &cp[node_header]; |
765 | uint32_t n_sub_blocks = toku_dtoh32(get_unaligned_uint32(&sub_block_header[0])); |
766 | uint32_t = 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 = 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 | |
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 | |
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 | |
828 | static void set_file(int fd, uint64_t offset, unsigned char newc) { |
829 | toku_os_pwrite(fd, &newc, sizeof newc, offset); |
830 | } |
831 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |