| 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 | |