1 /*
2 Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <ndb_global.h>
26
27 #include <NdbTCP.h>
28 #include <NdbOut.hpp>
29 #include "BackupFormat.hpp"
30 #include <AttributeHeader.hpp>
31 #include <SimpleProperties.hpp>
32 #include <util/version.h>
33 #include <ndb_version.h>
34 #include <util/ndbzio.h>
35
36 #define JAM_FILE_ID 476
37 static const Uint32 MaxReadWords = 32768;
38
39 bool readHeader(ndbzio_stream*, BackupFormat::FileHeader *);
40 bool readFragHeader(ndbzio_stream*, BackupFormat::DataFile::FragmentHeader *);
41 bool readFragFooter(ndbzio_stream*, BackupFormat::DataFile::FragmentFooter *);
42 Int32 readRecord(ndbzio_stream*, Uint32 **, Uint32*, bool print);
43
44 NdbOut & operator<<(NdbOut&, const BackupFormat::FileHeader &);
45 NdbOut & operator<<(NdbOut&, const BackupFormat::DataFile::FragmentHeader &);
46 NdbOut & operator<<(NdbOut&, const BackupFormat::DataFile::FragmentFooter &);
47
48 bool readLCPCtlFile(ndbzio_stream* f, BackupFormat::LCPCtlFile *ret);
49 bool readTableList(ndbzio_stream*, BackupFormat::CtlFile::TableList **);
50 bool readTableDesc(ndbzio_stream*, BackupFormat::CtlFile::TableDescription **);
51 bool readGCPEntry(ndbzio_stream*, BackupFormat::CtlFile::GCPEntry **);
52
53 NdbOut & operator<<(NdbOut&, const BackupFormat::LCPCtlFile &);
54 NdbOut & operator<<(NdbOut&, const BackupFormat::CtlFile::TableList &);
55 NdbOut & operator<<(NdbOut&, const BackupFormat::CtlFile::TableDescription &);
56 NdbOut & operator<<(NdbOut&, const BackupFormat::CtlFile::GCPEntry &);
57
58 Int32 readLogEntry(ndbzio_stream*, Uint32**, Uint32 file_type, Uint32 version);
59
60 struct RowEntry
61 {
62 Uint32 page_id;
63 Uint32 page_idx;
64 RowEntry *prev_ptr;
65 RowEntry *next_ptr;
66 };
67
68 static Uint32 recNo;
69 static Uint32 recInsert;
70 static Uint32 recWrite;
71 static Uint32 recDeleteByRowId;
72 static Uint32 recDeleteByPageId;
73 static Uint32 logEntryNo;
74 static bool print_restored_rows = false;
75 static int print_restored_rows_table = -1;
76 static int print_restored_rows_fid = -1;
77 static int print_restored_rows_ctl_dir = 0;
78 static int parts_array[BackupFormat::NDB_MAX_LCP_PARTS];
79 static Uint32 max_pages = 0;
80 static int verbose_level = 0;
81 static int already_inserted_count = 0;
82 static int ignored_rows = 0;
83 static int show_ignored_rows = 0;
84 static int print_rows_per_page = 0;
85 static int print_rows_flag = 1;
86 static int num_data_words = 0;
87 static Uint32 all_rows_count = 0;
88 static RowEntry **row_entries = NULL;
89 static RowEntry **row_all_entries = NULL;
90
91 #define IGNORE_PART 1
92 #define ALL_PART 2
93 #define CHANGE_PART 3
94
ndb_end_and_exit(int exitcode)95 [[noreturn]] inline void ndb_end_and_exit(int exitcode)
96 {
97 ndb_end(0);
98 exit(exitcode);
99 }
100
101 Uint32
get_part_id(Uint32 page_id)102 get_part_id(Uint32 page_id)
103 {
104 static Uint32 reverse_3bits_array[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
105 const Uint32 lowest_3bits_page_id = page_id & 7;
106 const Uint32 low_3bits_page_id = (page_id >> 3) & 7;
107 const Uint32 high_3bits_page_id = (page_id >> 6) & 7;
108 const Uint32 highest_3bits_page_id = (page_id >> 9) & 3;
109 Uint32 part_id =
110 reverse_3bits_array[highest_3bits_page_id] +
111 (reverse_3bits_array[high_3bits_page_id] << 3) +
112 (reverse_3bits_array[low_3bits_page_id] << 6) +
113 (reverse_3bits_array[lowest_3bits_page_id] << 9);
114 part_id >>= 1;
115 return part_id;
116 }
117
118 const char*
get_part_type_string(Uint32 part_type)119 get_part_type_string(Uint32 part_type)
120 {
121 if (part_type == IGNORE_PART)
122 return "IGNORE_PART";
123 if (part_type == ALL_PART)
124 return "ALL_PART";
125 if (part_type == CHANGE_PART)
126 return "CHANGE_PART";
127 assert(false);
128 return "UNKNOWN";
129 }
130
131 const char*
get_header_string(Uint32 header_type)132 get_header_string(Uint32 header_type)
133 {
134 if (header_type == BackupFormat::INSERT_TYPE)
135 return "INSERT";
136 if (header_type == BackupFormat::WRITE_TYPE)
137 return "WRITE";
138 if (header_type == BackupFormat::DELETE_BY_ROWID_TYPE)
139 return "DELETE_BY_ROWID";
140 if (header_type == BackupFormat::DELETE_BY_PAGEID_TYPE)
141 return "DELETE_BY_PAGEID";
142 assert(false);
143 return "UNKNOWN";
144 }
145
move_file_back(Uint32 file,Uint32 num_back)146 Uint32 move_file_back(Uint32 file, Uint32 num_back)
147 {
148 if (file >= num_back)
149 return (file - num_back);
150 return (file + BackupFormat::NDB_MAX_LCP_FILES - num_back);
151 }
152
move_file_forward(Uint32 file,Uint32 num_forward)153 Uint32 move_file_forward(Uint32 file, Uint32 num_forward)
154 {
155 if ((file + num_forward) >= BackupFormat::NDB_MAX_LCP_FILES)
156 return (file + num_forward - BackupFormat::NDB_MAX_LCP_FILES);
157 return (file + num_forward);
158 }
159
move_part_forward(Uint32 file,Uint32 num_forward)160 Uint32 move_part_forward(Uint32 file, Uint32 num_forward)
161 {
162 if ((file + num_forward) >= BackupFormat::NDB_MAX_LCP_PARTS)
163 return (file + num_forward - BackupFormat::NDB_MAX_LCP_PARTS);
164 return (file + num_forward);
165 }
166
find_row(Uint32 page_id,Uint32 page_idx,bool is_all)167 RowEntry* find_row(Uint32 page_id,
168 Uint32 page_idx,
169 bool is_all)
170 {
171 RowEntry **loc_entries;
172 if (is_all)
173 loc_entries = row_all_entries;
174 else
175 loc_entries = row_entries;
176
177 if (page_id >= max_pages)
178 return NULL;
179 if (loc_entries[page_id] == NULL)
180 return NULL;
181 RowEntry *current = loc_entries[page_id];
182 do
183 {
184 if (current->page_id != page_id)
185 {
186 ndbout_c("Inconsistent hash table");
187 ndb_end_and_exit(1);
188 }
189 if (current->page_idx == page_idx)
190 return current;
191 current = current->next_ptr;
192 } while (current != NULL);
193 return NULL;
194 }
195
insert_row(Uint32 page_id,Uint32 page_idx,bool is_insert,bool is_all)196 void insert_row(Uint32 page_id,
197 Uint32 page_idx,
198 bool is_insert,
199 bool is_all)
200 {
201 if (page_id >= max_pages)
202 {
203 ndbout_c("Trying to insert row(%u,%u) beyond max_pages: %u",
204 page_id,
205 page_idx,
206 max_pages);
207 return;
208 }
209 RowEntry *found_row_entry = find_row(page_id, page_idx, is_all);
210 if (found_row_entry != NULL)
211 {
212 if (is_insert && !is_all)
213 {
214 /* Entry already existed */
215 ndbout_c("row(%u,%u) already existed", page_id, page_idx);
216 already_inserted_count++;
217 }
218 return;
219 }
220 RowEntry *new_row_entry = (RowEntry*)malloc(sizeof(struct RowEntry));
221 if (new_row_entry == NULL)
222 {
223 ndbout_c("Malloc failure in insert_row");
224 ndb_end_and_exit(1);
225 }
226 new_row_entry->page_id = page_id;
227 new_row_entry->page_idx = page_idx;
228 new_row_entry->prev_ptr = NULL;
229
230 RowEntry **loc_entries;
231 if (is_all)
232 loc_entries = row_all_entries;
233 else
234 loc_entries = row_entries;
235
236 new_row_entry->next_ptr = loc_entries[page_id];
237 if (loc_entries[page_id] != NULL)
238 {
239 loc_entries[page_id]->prev_ptr = new_row_entry;
240 }
241 loc_entries[page_id] = new_row_entry;
242 if (is_all)
243 {
244 all_rows_count++;
245 }
246 }
247
delete_row(Uint32 page_id,Uint32 page_idx)248 void delete_row(Uint32 page_id, Uint32 page_idx)
249 {
250 if (page_id >= max_pages)
251 {
252 ndbout_c("Trying to delete row(%u,%u) beyond max_pages: %u",
253 page_id,
254 page_idx,
255 max_pages);
256 return;
257 }
258 RowEntry *found_row_entry = find_row(page_id, page_idx, false);
259 if (found_row_entry == NULL)
260 {
261 ndbout_c("Trying to delete row(%u,%u) NOT FOUND",
262 page_id,
263 page_idx);
264 return;
265 }
266 if (found_row_entry->prev_ptr == NULL)
267 {
268 /* First entry in linked list */
269 row_entries[page_id] = found_row_entry->next_ptr;
270 }
271 else
272 {
273 found_row_entry->prev_ptr->next_ptr =
274 found_row_entry->next_ptr;
275 }
276 if (found_row_entry->next_ptr != NULL)
277 {
278 found_row_entry->next_ptr->prev_ptr =
279 found_row_entry->prev_ptr;
280 }
281 free(found_row_entry);
282 }
283
delete_page(Uint32 page_id)284 void delete_page(Uint32 page_id)
285 {
286 if (page_id >= max_pages)
287 {
288 ndbout_c("Trying to delete page(%u) beyond max_pages: %u",
289 page_id,
290 max_pages);
291 return;
292 }
293 if (row_entries[page_id] == NULL)
294 return;
295 RowEntry *current = row_entries[page_id];
296 row_entries[page_id] = NULL;
297 do
298 {
299 RowEntry *free_row = current;
300 current = current->next_ptr;
301 free(free_row);
302 } while (current != NULL);
303 }
304
check_data(const char * file_input)305 void check_data(const char *file_input)
306 {
307 FILE *file = fopen(file_input, "r");
308 if (file != NULL)
309 {
310 char line [100];
311 while (fgets(line,sizeof(line),file)!= NULL) /* read a line from a file */
312 {
313 Uint32 page_id, page_idx;
314 int ret = sscanf(line, "%d %d", &page_id, &page_idx);
315 if (ret != 2)
316 {
317 ndbout_c("-n file expects a file with two numbers page_id space page_idx");
318 ndb_end_and_exit(1);
319 }
320 RowEntry *found_entry = find_row(page_id, page_idx, false);
321 if (found_entry != NULL)
322 {
323 ndbout_c("Found deleted row in hash: row_id(%u,%u)",
324 found_entry->page_id,
325 found_entry->page_idx);
326 }
327 }
328 fclose(file);
329 }
330 }
331
print_rows()332 void print_rows()
333 {
334 Uint32 row_count = 0;
335 for (Uint32 page_id = 0; page_id < max_pages; page_id++)
336 {
337 Uint32 rows_page = 0;
338 if (row_entries[page_id] != NULL)
339 {
340 RowEntry *current = row_entries[page_id];
341 do
342 {
343 if (print_rows_flag)
344 ndbout_c("Found row(%u,%u)", page_id, current->page_idx);
345 current = current->next_ptr;
346 row_count++;
347 rows_page++;
348 } while (current != NULL);
349 if (print_rows_per_page && rows_page != 3)
350 {
351 ndbout_c("Rows on page: %u is %u", page_id, rows_page);
352 }
353 }
354 }
355 ndbout_c("Found a total of %u rows after restore", row_count);
356 if (already_inserted_count != 0)
357 {
358 ndbout_c("Found a total of %u rows already existing",
359 already_inserted_count);
360 }
361 }
362
print_ignored_rows()363 void print_ignored_rows()
364 {
365 ndbout_c("Printing ignored rows");
366 for (Uint32 page_id = 0; page_id < max_pages; page_id++)
367 {
368 if (row_all_entries[page_id] != NULL)
369 {
370 RowEntry *current = row_all_entries[page_id];
371 do
372 {
373 if (!find_row(current->page_id,
374 current->page_idx,
375 false))
376 {
377 ndbout_c("Found ignored rowid(%u,%u)",
378 current->page_id,
379 current->page_idx);
380 }
381 current = current->next_ptr;
382 } while (current != NULL);
383 }
384 }
385 }
delete_all()386 void delete_all()
387 {
388 for (Uint32 page_id = 0; page_id < max_pages; page_id++)
389 {
390 delete_page(page_id);
391 }
392 }
393
handle_print_restored_rows(const char * file_input)394 void handle_print_restored_rows(const char *file_input)
395 {
396 ndbout_c("Print restored rows for T%uF%u",
397 print_restored_rows_table,
398 print_restored_rows_fid);
399
400 char buf[255];
401 ndbzio_stream fo;
402 bzero(&fo, sizeof(fo));
403 BaseString::snprintf(buf, sizeof(buf),
404 "%u/T%uF%u.ctl",
405 print_restored_rows_ctl_dir,
406 print_restored_rows_table,
407 print_restored_rows_fid);
408 int r = ndbzopen(&fo,buf,O_RDONLY);
409 if(r != 1)
410 {
411 ndbout_c("Failed to open file '%s', error: %d",
412 buf, r);
413 ndb_end_and_exit(1);
414 }
415 ndbzio_stream* f = &fo;
416 BackupFormat::FileHeader fileHeader;
417 if (!readHeader(f, &fileHeader))
418 {
419 ndbout << "Invalid ctl file!" << endl;
420 ndb_end_and_exit(1);
421 }
422 if (fileHeader.FileType != BackupFormat::LCP_CTL_FILE)
423 {
424 ndbout << "Invalid ctl file header!" << endl;
425 ndb_end_and_exit(1);
426 }
427 union
428 {
429 BackupFormat::LCPCtlFile lcpCtlFilePtr;
430 char extra_space[4 * BackupFormat::NDB_MAX_LCP_PARTS];
431 };
432 (void)extra_space;
433 if (!readLCPCtlFile(f, &lcpCtlFilePtr))
434 {
435 ndbout << "Invalid LCP Control file!" << endl;
436 ndb_end_and_exit(1);
437 }
438 ndbzclose(f);
439
440 /**
441 * Allocate the array of linked list first pointers.
442 */
443 max_pages = lcpCtlFilePtr.MaxPageCount;
444 row_entries = (RowEntry**)malloc(sizeof(RowEntry*) * max_pages);
445 if (row_entries == NULL)
446 {
447 ndbout << "Malloc failure" << endl;
448 ndb_end_and_exit(1);
449 }
450 memset(row_entries, 0, sizeof(RowEntry*) * max_pages);
451
452 row_all_entries = (RowEntry**)malloc(sizeof(RowEntry*) * max_pages);
453 if (row_all_entries == NULL)
454 {
455 ndbout << "Malloc failure" << endl;
456 ndb_end_and_exit(1);
457 }
458 memset(row_all_entries, 0, sizeof(RowEntry*) * max_pages);
459
460 Uint32 last_file = lcpCtlFilePtr.LastDataFileNumber;
461 Uint32 num_parts = lcpCtlFilePtr.NumPartPairs;
462 Uint32 current_file = move_file_back(last_file, (num_parts - 1));
463 Uint32 inx = 0;
464 Uint32 first_change = lcpCtlFilePtr.partPairs[inx].startPart;
465 for (Uint32 i = current_file; i <= last_file; i = move_file_forward(i,1))
466 {
467 Uint32 first_all = lcpCtlFilePtr.partPairs[inx].startPart;
468 Uint32 first_ignore =
469 move_part_forward(first_all, lcpCtlFilePtr.partPairs[inx].numParts);
470 inx++;
471 memset(&parts_array[0], 0, sizeof(parts_array));
472 for (Uint32 j = first_change; j != first_all; j = move_part_forward(j,1))
473 {
474 parts_array[j] = CHANGE_PART;
475 assert(j < BackupFormat::NDB_MAX_LCP_PARTS);
476 }
477 for (Uint32 j = first_all; j != first_ignore; j = move_part_forward(j,1))
478 {
479 parts_array[j] = ALL_PART;
480 assert(j < BackupFormat::NDB_MAX_LCP_PARTS);
481 }
482 for (Uint32 j = first_ignore; j != first_change; j = move_part_forward(j,1))
483 {
484 parts_array[j] = IGNORE_PART;
485 assert(j < BackupFormat::NDB_MAX_LCP_PARTS);
486 }
487 for (Uint32 j = 0; j < BackupFormat::NDB_MAX_LCP_PARTS; j++)
488 {
489 assert(parts_array[0] != 0);
490 }
491 ndbout_c("Processing %u/T%uF%u.Data",
492 i,
493 print_restored_rows_table,
494 print_restored_rows_fid);
495 bzero(&fo, sizeof(fo));
496 BaseString::snprintf(buf, sizeof(buf),
497 "%u/T%uF%u.Data",
498 i,
499 print_restored_rows_table,
500 print_restored_rows_fid);
501 r = ndbzopen(&fo,buf,O_RDONLY);
502 if(r != 1)
503 {
504 ndbout_c("Failed to open file '%s', error: %d",
505 buf, r);
506 //ndb_end_and_exit(1);
507 continue;
508 }
509 if (!readHeader(f, &fileHeader))
510 {
511 ndbout << "Invalid file!" << endl;
512 ndb_end_and_exit(1);
513 }
514 BackupFormat::CtlFile::TableList * tabList;
515 if (!readTableList(f, &tabList))
516 {
517 ndbout << "Invalid file! No table list" << endl;
518 break;
519 }
520 BackupFormat::DataFile::FragmentHeader fragHeader;
521 if (!readFragHeader(f, &fragHeader))
522 {
523 ndbout << "Invalid file! No table list" << endl;
524 break;
525 }
526 Uint32 len, * data, header_type;
527 while((len = readRecord(f, &data, &header_type, (verbose_level > 0))) > 0)
528 {
529 Uint32 page_id = data[0];
530 Uint32 page_idx = data[1];
531 Uint32 part_id = get_part_id(page_id);
532 const char *header_string = get_header_string(header_type);
533 const char *part_string = get_part_type_string(parts_array[part_id]);
534 if (parts_array[part_id] == IGNORE_PART)
535 {
536 if (header_type == BackupFormat::INSERT_TYPE ||
537 header_type == BackupFormat::WRITE_TYPE)
538 {
539 insert_row(page_id, page_idx, true, true);
540 ndbout_c("IGNORE: rowid(%u,%u)", page_id, page_idx);
541 ignored_rows++;
542 }
543 continue;
544 }
545 else if (parts_array[part_id] == ALL_PART)
546 {
547 if (header_type != BackupFormat::INSERT_TYPE)
548 {
549 ndbout_c("NOT INSERT_TYPE when expected");
550 ndb_end_and_exit(1);
551 }
552 if (verbose_level > 0)
553 ndbout_c("%s: page(%u,%u), len: %u, part_id: %u, part_type: %s",
554 header_string,
555 page_id,
556 page_idx,
557 len,
558 part_id,
559 part_string);
560 insert_row(page_id, page_idx, true, true);
561 insert_row(page_id, page_idx, true, false);
562 }
563 else if (parts_array[part_id] != CHANGE_PART)
564 {
565 ndbout_c("NOT CHANGE_PART when expected");
566 ndb_end_and_exit(1);
567 }
568 else
569 {
570 if (header_type == BackupFormat::INSERT_TYPE)
571 {
572 ndbout_c("INSERT_TYPE in CHANGE_PART");
573 ndb_end_and_exit(1);
574 }
575 if (header_type == BackupFormat::DELETE_BY_PAGEID_TYPE)
576 {
577 if (verbose_level > 0)
578 ndbout_c("%s: page(%u), len: %u, part_id: %u, part_type: %s",
579 header_string,
580 page_id,
581 len,
582 part_id,
583 part_string);
584 delete_page(page_id);
585 }
586 else if (header_type == BackupFormat::WRITE_TYPE)
587 {
588 if (verbose_level > 0)
589 ndbout_c("%s: page(%u,%u), len: %u, part_id: %u, part_type: %s",
590 header_string,
591 page_id,
592 page_idx,
593 len,
594 part_id,
595 part_string);
596 insert_row(page_id, page_idx, false, false);
597 insert_row(page_id, page_idx, true, true);
598 }
599 else if (header_type == BackupFormat::DELETE_BY_ROWID_TYPE)
600 {
601 if (verbose_level > 0)
602 ndbout_c("%s: page(%u,%u), len: %u, part_id: %u, part_type: %s",
603 header_string,
604 page_id,
605 page_idx,
606 len,
607 part_id,
608 part_string);
609 delete_row(page_id, page_idx);
610 }
611 else
612 {
613 ndbout_c("Wrong header_type: %u in CHANGE_PART", header_type);
614 ndb_end_and_exit(1);
615 }
616 }
617 }
618 ndbzclose(f);
619 ndbout_c("Number of all rows currently are: %u", all_rows_count);
620 }
621 print_rows();
622 if (show_ignored_rows)
623 print_ignored_rows();
624 if (file_input)
625 {
626 check_data(file_input);
627 }
628 delete_all();
629 exit(0);
630 }
631
632 int
main(int argc,const char * argv[])633 main(int argc, const char * argv[])
634 {
635 const char *file = argv[1];
636 const char *file_input = NULL;
637 ndb_init();
638 if (argc > 2)
639 {
640 for (int i = 1; i < argc; i++)
641 {
642 if (print_restored_rows)
643 {
644 if (!strncmp(argv[i], "-v", 2))
645 {
646 verbose_level++;
647 }
648 else if (!strncmp(argv[i], "-i", 2))
649 {
650 show_ignored_rows = 1;
651 }
652 else if (!strncmp(argv[i], "-p", 2))
653 {
654 print_rows_per_page = 1;
655 }
656 else if (!strncmp(argv[i], "-u", 2))
657 {
658 print_rows_flag = 0;
659 }
660 else if (!strncmp(argv[i], "-h", 2))
661 {
662 if (i + 1 < argc)
663 {
664 int ret = sscanf(argv[i+1], "%d", &num_data_words);
665 if (ret != 1)
666 {
667 printf("Usage: %s <filename>\n", argv[0]);
668 ndb_end_and_exit(1);
669 }
670 i++;
671 }
672 else
673 {
674 printf("Usage: %s <filename>\n", argv[0]);
675 ndb_end_and_exit(1);
676 }
677 }
678 else if (!strncmp(argv[i], "-c", 2))
679 {
680 if (i + 1 < argc)
681 {
682 int ret = sscanf(argv[i+1], "%d", &print_restored_rows_ctl_dir);
683 if (ret != 1 ||
684 (print_restored_rows_ctl_dir != 0 &&
685 print_restored_rows_ctl_dir != 1))
686 {
687 printf("Usage: %s <filename>\n", argv[0]);
688 ndb_end_and_exit(1);
689 }
690 i++;
691 }
692 else
693 {
694 printf("Usage: %s <filename>\n", argv[0]);
695 ndb_end_and_exit(1);
696 }
697 }
698 else if (!strncmp(argv[i], "-f", 2))
699 {
700 if (i + 1 < argc)
701 {
702 int ret = sscanf(argv[i+1], "%d", &print_restored_rows_fid);
703 if (ret != 1)
704 {
705 printf("Usage: %s <filename>\n", argv[0]);
706 ndb_end_and_exit(1);
707 }
708 i++;
709 }
710 else if (verbose_level == 0)
711 {
712 printf("Usage: %s <filename>\n", argv[0]);
713 ndb_end_and_exit(1);
714 }
715 }
716 else if (!strncmp(argv[i], "-t", 2))
717 {
718 if (i + 1 < argc)
719 {
720 int ret = sscanf(argv[i+1], "%d", &print_restored_rows_table);
721 if (ret != 1)
722 {
723 printf("Usage: %s <filename>\n", argv[0]);
724 ndb_end_and_exit(1);
725 }
726 i++;
727 }
728 else
729 {
730 printf("Usage: %s <filename>\n", argv[0]);
731 ndb_end_and_exit(1);
732 }
733 }
734 else if (!strncmp(argv[i], "-n", 2))
735 {
736 if (i + 1 < argc)
737 {
738 file_input = argv[i+1];
739 i++;
740 }
741 else
742 {
743 printf("Usage: %s <filename>\n", argv[0]);
744 ndb_end_and_exit(1);
745 }
746 }
747 }
748 else
749 {
750 if (!strncmp(argv[i], "--print-restored-rows", 22))
751 {
752 print_restored_rows = true;
753 }
754 else if (!strncmp(argv[i], "-v", 2))
755 {
756 verbose_level++;
757 }
758 else if (verbose_level == 0)
759 {
760 printf("Usage: %s <filename>\n", argv[0]);
761 ndb_end_and_exit(1);
762 }
763 else if (i + 1 == argc)
764 {
765 file = argv[i];
766 }
767 }
768 }
769 }
770 else if (argc == 2)
771 {
772 ;
773 }
774 else if (argc <= 1)
775 {
776 printf("Usage: %s <filename>\n", argv[0]);
777 ndb_end_and_exit(1);
778 }
779 if (print_restored_rows)
780 {
781 if (print_restored_rows_table == -1 ||
782 print_restored_rows_fid == -1)
783 {
784 printf("Usage: %s <filename>\n", argv[0]);
785 ndb_end_and_exit(1);
786 }
787 handle_print_restored_rows(file_input);
788 }
789
790 ndbzio_stream fo;
791 bzero(&fo, sizeof(fo));
792 int r= ndbzopen(&fo,file, O_RDONLY);
793
794 if(r != 1)
795 {
796 ndbout_c("Failed to open file '%s', error: %d",
797 argv[1], r);
798 ndb_end_and_exit(1);
799 }
800
801 ndbzio_stream* f = &fo;
802
803 BackupFormat::FileHeader fileHeader;
804 if(!readHeader(f, &fileHeader)){
805 ndbout << "Invalid file!" << endl;
806 ndb_end_and_exit(1);
807 }
808 ndbout << fileHeader << endl;
809
810 switch(fileHeader.FileType){
811 case BackupFormat::DATA_FILE:
812 while(f->z_eof){
813 BackupFormat::DataFile::FragmentHeader fragHeader;
814 if(!readFragHeader(f, &fragHeader))
815 break;
816 ndbout << fragHeader << endl;
817
818 Uint32 len, * data, header_type;
819 while((len = readRecord(f, &data, &header_type, true)) > 0)
820 {
821 if (verbose_level > 0)
822 {
823 ndbout << "-> " << hex;
824 for(Uint32 i = 0; i < len; i++)
825 {
826 ndbout << data[i] << " ";
827 }
828 ndbout << endl;
829 }
830 }
831
832 BackupFormat::DataFile::FragmentFooter fragFooter;
833 if(!readFragFooter(f, &fragFooter))
834 break;
835 ndbout << fragFooter << endl;
836 }
837 break;
838 case BackupFormat::CTL_FILE:{
839 BackupFormat::CtlFile::TableList * tabList;
840 if(!readTableList(f, &tabList)){
841 ndbout << "Invalid file! No table list" << endl;
842 break;
843 }
844 ndbout << (* tabList) << endl;
845
846 const Uint32 noOfTables = tabList->SectionLength - 2;
847 for(Uint32 i = 0; i<noOfTables; i++){
848 BackupFormat::CtlFile::TableDescription * tabDesc;
849 if(!readTableDesc(f, &tabDesc)){
850 ndbout << "Invalid file missing table description" << endl;
851 break;
852 }
853 ndbout << (* tabDesc) << endl;
854 }
855
856 BackupFormat::CtlFile::GCPEntry * gcpE;
857 if(!readGCPEntry(f, &gcpE)){
858 ndbout << "Invalid file! GCP ENtry" << endl;
859 break;
860 }
861 ndbout << (* gcpE) << endl;
862
863 break;
864 }
865 case BackupFormat::LOG_FILE:
866 case BackupFormat::UNDO_FILE:
867 {
868 logEntryNo = 0;
869
870 const Uint32 log_entry_version =
871 (likely(ndbd_backup_file_fragid(fileHeader.BackupVersion)) ? 2 : 1);
872
873 typedef BackupFormat::LogFile::LogEntry LogEntry;
874
875 Int32 dataLen;
876 Uint32 * data;
877 while ((dataLen = readLogEntry(f, &data, fileHeader.FileType, log_entry_version)) > 0)
878 {
879 LogEntry * logEntry = (LogEntry *) data;
880 /**
881 * Log Entry
882 */
883 Uint32 event = ntohl(logEntry->TriggerEvent);
884 bool gcp = (event & 0x10000) != 0;
885 event &= 0xFFFF;
886 if(gcp)
887 dataLen--;
888
889 ndbout << "LogEntry Table: " << (Uint32)ntohl(logEntry->TableId)
890 << " Event: " << event
891 << " Length: " << dataLen;
892
893 if(gcp)
894 ndbout << " GCP: " << (Uint32)ntohl(logEntry->Data[dataLen]);
895 ndbout << endl;
896 if (verbose_level > 0)
897 {
898 Int32 pos = 0;
899 while (pos < dataLen)
900 {
901 AttributeHeader * ah = (AttributeHeader*)&logEntry->Data[pos];
902 ndbout_c(" Attribut: %d Size: %d",
903 ah->getAttributeId(),
904 ah->getDataSize());
905 pos += ah->getDataSize() + 1;
906 }
907 require(pos == dataLen);
908 }
909 }
910 require(dataLen == 0);
911 break;
912 }
913 case BackupFormat::LCP_FILE:
914 {
915 BackupFormat::CtlFile::TableList * tabList;
916 if(!readTableList(f, &tabList)){
917 ndbout << "Invalid file! No table list" << endl;
918 break;
919 }
920 ndbout << (* tabList) << endl;
921
922 if (fileHeader.BackupVersion < NDB_MAKE_VERSION(7,6,4))
923 {
924 const Uint32 noOfTables = tabList->SectionLength - 2;
925 for(Uint32 i = 0; i<noOfTables; i++){
926 BackupFormat::CtlFile::TableDescription * tabDesc;
927 if(!readTableDesc(f, &tabDesc)){
928 ndbout << "Invalid file missing table description" << endl;
929 break;
930 }
931 ndbout << (* tabDesc) << endl;
932 }
933 }
934 {
935 BackupFormat::DataFile::FragmentHeader fragHeader;
936 if(!readFragHeader(f, &fragHeader))
937 break;
938 ndbout << fragHeader << endl;
939
940 Uint32 len, * data, header_type;
941 while((len = readRecord(f, &data, &header_type, true)) > 0)
942 {
943 if (verbose_level > 0)
944 {
945 ndbout << "-> " << hex;
946 for(Uint32 i = 0; i < len; i++)
947 {
948 ndbout << data[i] << " ";
949 }
950 ndbout << endl;
951 }
952 }
953
954 BackupFormat::DataFile::FragmentFooter fragFooter;
955 if(!readFragFooter(f, &fragFooter))
956 break;
957 ndbout << fragFooter << endl;
958 }
959 break;
960 }
961 case BackupFormat::LCP_CTL_FILE:
962 {
963 union
964 {
965 BackupFormat::LCPCtlFile lcpCtlFilePtr;
966 char extra_space[4 * BackupFormat::NDB_MAX_LCP_PARTS];
967 };
968 (void)extra_space;
969 if (!readLCPCtlFile(f, &lcpCtlFilePtr))
970 {
971 ndbout << "Invalid LCP Control file!" << endl;
972 break;
973 }
974 ndbout << lcpCtlFilePtr << endl;
975 break;
976 }
977 default:
978 ndbout << "Unsupported file type for printer: "
979 << fileHeader.FileType << endl;
980 break;
981 }
982 ndbzclose(f);
983 ndb_end_and_exit(0);
984 }
985
986 #define RETURN_FALSE() { ndbout_c("false: %d", __LINE__); abort(); return false; }
987
988 static bool endian = false;
989
990 static
991 inline
992 size_t
aread(void * buf,size_t sz,size_t n,ndbzio_stream * f)993 aread(void * buf, size_t sz, size_t n, ndbzio_stream* f)
994 {
995 int error = 0;
996 unsigned r = ndbzread(f, buf, (unsigned)(sz * n), &error);
997 if (error || r != (sz * n))
998 {
999 printf("\nFailed to read!!, r = %u, error = %d\n", r, error);
1000 abort();
1001 exit(1);
1002 }
1003 return r / sz;
1004 }
1005
1006 bool
readHeader(ndbzio_stream * f,BackupFormat::FileHeader * dst)1007 readHeader(ndbzio_stream* f, BackupFormat::FileHeader * dst){
1008 if(aread(dst, 4, 3, f) != 3)
1009 RETURN_FALSE();
1010
1011 if(memcmp(dst->Magic, BACKUP_MAGIC, sizeof(BACKUP_MAGIC)) != 0)
1012 {
1013 ndbout_c("Incorrect file-header!");
1014 printf("Found: ");
1015 for (unsigned i = 0; i<sizeof(BACKUP_MAGIC); i++)
1016 printf("0x%.2x ", (Uint32)(Uint8)dst->Magic[i]);
1017 printf("\n");
1018 printf("Expect: ");
1019 for (unsigned i = 0; i<sizeof(BACKUP_MAGIC); i++)
1020 printf("0x%.2x ", (Uint32)(Uint8)BACKUP_MAGIC[i]);
1021 printf("\n");
1022
1023 RETURN_FALSE();
1024 }
1025
1026 dst->BackupVersion = ntohl(dst->BackupVersion);
1027 if(dst->BackupVersion > NDB_VERSION)
1028 {
1029 printf("incorrect versions, file: 0x%x expect: 0x%x\n", dst->BackupVersion, NDB_VERSION);
1030 RETURN_FALSE();
1031 }
1032
1033 if(aread(&dst->SectionType, 4, 2, f) != 2)
1034 RETURN_FALSE();
1035 dst->SectionType = ntohl(dst->SectionType);
1036 dst->SectionLength = ntohl(dst->SectionLength);
1037
1038 if(dst->SectionType != BackupFormat::FILE_HEADER)
1039 RETURN_FALSE();
1040
1041 const Uint32 file_header_section_length =
1042 ((dst->BackupVersion < NDBD_RAW_LCP)
1043 ? sizeof(BackupFormat::FileHeader_pre_backup_version)
1044 : sizeof(BackupFormat::FileHeader))/4 - 3;
1045
1046 if(dst->SectionLength != file_header_section_length)
1047 RETURN_FALSE();
1048
1049 if(aread(&dst->FileType, 4, dst->SectionLength - 2, f) !=
1050 (dst->SectionLength - 2))
1051 RETURN_FALSE();
1052
1053 dst->FileType = ntohl(dst->FileType);
1054 dst->BackupId = ntohl(dst->BackupId);
1055 dst->BackupKey_0 = ntohl(dst->BackupKey_0);
1056 dst->BackupKey_1 = ntohl(dst->BackupKey_1);
1057
1058 if (dst->BackupVersion < NDBD_RAW_LCP)
1059 {
1060 dst->NdbVersion = dst->BackupVersion;
1061 dst->MySQLVersion = 0;
1062 }
1063
1064 if(dst->ByteOrder != 0x12345678)
1065 endian = true;
1066
1067 return true;
1068 }
1069
1070 bool
readFragHeader(ndbzio_stream * f,BackupFormat::DataFile::FragmentHeader * dst)1071 readFragHeader(ndbzio_stream* f, BackupFormat::DataFile::FragmentHeader * dst){
1072 if(aread(dst, 1, sizeof(* dst), f) != sizeof(* dst))
1073 return false;
1074
1075 dst->SectionType = ntohl(dst->SectionType);
1076 dst->SectionLength = ntohl(dst->SectionLength);
1077 dst->TableId = ntohl(dst->TableId);
1078 dst->FragmentNo = ntohl(dst->FragmentNo);
1079 dst->ChecksumType = ntohl(dst->ChecksumType);
1080
1081 if(dst->SectionLength != (sizeof(* dst) >> 2))
1082 RETURN_FALSE();
1083
1084 if(dst->SectionType != BackupFormat::FRAGMENT_HEADER)
1085 RETURN_FALSE();
1086
1087 recNo = 0;
1088 recInsert = 0;
1089 recWrite = 0;
1090 recDeleteByRowId = 0;
1091 recDeleteByPageId = 0;
1092
1093 return true;
1094 }
1095
1096 bool
readFragFooter(ndbzio_stream * f,BackupFormat::DataFile::FragmentFooter * dst)1097 readFragFooter(ndbzio_stream* f, BackupFormat::DataFile::FragmentFooter * dst){
1098 if(aread(dst, 1, sizeof(* dst), f) != sizeof(* dst))
1099 RETURN_FALSE();
1100
1101 dst->SectionType = ntohl(dst->SectionType);
1102 dst->SectionLength = ntohl(dst->SectionLength);
1103 dst->TableId = ntohl(dst->TableId);
1104 dst->FragmentNo = ntohl(dst->FragmentNo);
1105 dst->NoOfRecords = ntohl(dst->NoOfRecords);
1106 dst->Checksum = ntohl(dst->Checksum);
1107
1108 if(dst->SectionLength != (sizeof(* dst) >> 2))
1109 RETURN_FALSE();
1110
1111 if(dst->SectionType != BackupFormat::FRAGMENT_FOOTER)
1112 RETURN_FALSE();
1113 return true;
1114 }
1115
1116
1117 static union {
1118 Uint32 buf[MaxReadWords];
1119 BackupFormat::CtlFile::TableList TableList;
1120 BackupFormat::CtlFile::GCPEntry GcpEntry;
1121 BackupFormat::CtlFile::TableDescription TableDescription;
1122 BackupFormat::LogFile::LogEntry LogEntry;
1123 BackupFormat::LCPCtlFile LCPCtlFile;
1124 char extra_space[4 * BackupFormat::NDB_MAX_LCP_PARTS];
1125 } theData;
1126
1127 Int32
readRecord(ndbzio_stream * f,Uint32 ** dst,Uint32 * ext_header_type,bool print)1128 readRecord(ndbzio_stream* f, Uint32 **dst, Uint32 *ext_header_type, bool print)
1129 {
1130 Uint32 len;
1131 if(aread(&len, 1, 4, f) != 4)
1132 RETURN_FALSE();
1133
1134 Uint32 header = ntohl(len);
1135 len = header & 0xFFFF;
1136
1137 if(aread(theData.buf, 4, len, f) != len)
1138 {
1139 return -1;
1140 }
1141
1142 if(len > 0)
1143 {
1144 Uint32 header_type = header >> 16;
1145 *ext_header_type = header_type;
1146 if (header_type == BackupFormat::INSERT_TYPE)
1147 {
1148 if (print)
1149 {
1150 ndbout_c("INSERT: RecNo: %u: Len: %x, page(%u,%u)",
1151 recNo, len, theData.buf[0], theData.buf[1]);
1152 if (num_data_words)
1153 {
1154 ndbout_c("Header_words[Header:%x,GCI:%u,Checksum: %x, X: %x]",
1155 theData.buf[2],
1156 theData.buf[3],
1157 theData.buf[4],
1158 theData.buf[5]);
1159 }
1160 }
1161 recNo++;
1162 recInsert++;
1163 }
1164 else if (header_type == BackupFormat::WRITE_TYPE)
1165 {
1166 if (print)
1167 {
1168 ndbout_c("WRITE: RecNo: %u: Len: %x, page(%u,%u)",
1169 recNo, len, theData.buf[0], theData.buf[1]);
1170 if (num_data_words)
1171 {
1172 ndbout_c("Header_words[Header:%x,GCI:%u,Checksum: %x, X: %x]",
1173 theData.buf[2],
1174 theData.buf[3],
1175 theData.buf[4],
1176 theData.buf[5]);
1177 }
1178 }
1179 recNo++;
1180 recWrite++;
1181 }
1182 else if (header_type == BackupFormat::DELETE_BY_ROWID_TYPE)
1183 {
1184 if (print)
1185 ndbout_c("DELETE_BY_ROWID: RecNo: %u: Len: %x, page(%u,%u)",
1186 recNo, len, theData.buf[0], theData.buf[1]);
1187 recNo++;
1188 recDeleteByRowId++;
1189 }
1190 else if (header_type == BackupFormat::DELETE_BY_PAGEID_TYPE)
1191 {
1192 if (print)
1193 ndbout_c("DELETE_BY_PAGEID: RecNo: %u: Len: %x, page(%u)",
1194 recNo, len, theData.buf[0]);
1195 recNo++;
1196 recDeleteByPageId++;
1197 }
1198 else
1199 {
1200 ndbout_c("Wrong header type %u", header_type);
1201 }
1202 }
1203 else
1204 {
1205 ndbout_c("Found %d INSERT records", recInsert);
1206 ndbout_c("Found %d WRITE records", recWrite);
1207 ndbout_c("Found %d DELETE BY ROWID records", recDeleteByRowId);
1208 ndbout_c("Found %d DELETE BY PAGEID records", recDeleteByPageId);
1209 ndbout_c("Found %d IGNOREd records", ignored_rows);
1210 ndbout_c("Found %d records", recNo);
1211 ignored_rows = 0;
1212 }
1213
1214 * dst = &theData.buf[0];
1215
1216
1217 return len;
1218 }
1219
1220 Int32
readLogEntry(ndbzio_stream * f,Uint32 ** dst,Uint32 file_type,Uint32 version)1221 readLogEntry(ndbzio_stream* f, Uint32 **dst, Uint32 file_type, Uint32 version)
1222 {
1223 static_assert(MaxReadWords >= BackupFormat::LogFile::LogEntry::MAX_SIZE, "");
1224 constexpr Uint32 word_size = sizeof(Uint32);
1225
1226 Uint32 len;
1227 if(aread(&len, word_size, 1, f) != 1)
1228 RETURN_FALSE();
1229
1230 len = ntohl(len);
1231
1232 if (len == 0)
1233 return 0;
1234
1235 Uint32 data_len;
1236 if (likely(version == 2))
1237 {
1238 constexpr Uint32 header_len =
1239 BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS;
1240 if (len < header_len)
1241 {
1242 return -1;
1243 }
1244 if (1 + len > MaxReadWords)
1245 {
1246 return -1;
1247 }
1248 data_len = len - header_len;
1249 if (aread(&theData.buf[1], word_size, len, f) != len)
1250 {
1251 return -1;
1252 }
1253 }
1254 else
1255 {
1256 assert(version == 1);
1257 constexpr Uint32 header_len =
1258 BackupFormat::LogFile::LogEntry_no_fragid::HEADER_LENGTH_WORDS;
1259 if (len < header_len)
1260 {
1261 return -1;
1262 }
1263 static_assert(header_len <=
1264 BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS,
1265 "");
1266 constexpr Uint32 header_len_diff =
1267 BackupFormat::LogFile::LogEntry::HEADER_LENGTH_WORDS - header_len;
1268 if (1 + len + header_len_diff > MaxReadWords)
1269 {
1270 return -1;
1271 }
1272 data_len = len - header_len;
1273 if (aread(&theData.buf[1], word_size, header_len, f) != header_len)
1274 {
1275 return -1;
1276 }
1277 // No fragment id in log event, set it to zero.
1278 theData.buf[BackupFormat::LogFile::LogEntry::FRAGID_OFFSET] = 0;
1279 if (aread(&theData.buf[BackupFormat::LogFile::LogEntry::DATA_OFFSET],
1280 word_size,
1281 data_len,
1282 f) != data_len)
1283 {
1284 return -1;
1285 }
1286 }
1287
1288 theData.buf[0] = len;
1289
1290 if(len > 0)
1291 logEntryNo++;
1292
1293 * dst = &theData.buf[0];
1294
1295 if (file_type == BackupFormat::UNDO_FILE)
1296 {
1297 Uint32 tail_length;
1298 if (aread(&tail_length, word_size, 1, f) != 1)
1299 {
1300 return -1;
1301 }
1302 tail_length = ntohl(tail_length);
1303
1304 if (len != tail_length)
1305 {
1306 return -1;
1307 }
1308 }
1309
1310 return data_len;
1311 }
1312
1313 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::FileHeader & hf)1314 operator<<(NdbOut& ndbout, const BackupFormat::FileHeader & hf){
1315
1316 char buf[9];
1317 memcpy(buf, hf.Magic, sizeof(hf.Magic));
1318 buf[8] = 0;
1319
1320 ndbout << "-- FileHeader:" << endl;
1321 ndbout << "Magic: " << buf << endl;
1322 ndbout << "BackupVersion: " << hex << hf.BackupVersion << endl;
1323 ndbout << "SectionType: " << hf.SectionType << endl;
1324 ndbout << "SectionLength: " << hf.SectionLength << endl;
1325 ndbout << "FileType: " << hf.FileType << endl;
1326 ndbout << "BackupId: " << hf.BackupId << endl;
1327 ndbout << "BackupKey: [ " << hex << hf.BackupKey_0
1328 << " "<< hf.BackupKey_1 << " ]" << endl;
1329 ndbout << "ByteOrder: " << hex << hf.ByteOrder << endl;
1330 return ndbout;
1331 }
1332
operator <<(NdbOut & ndbout,const BackupFormat::DataFile::FragmentHeader & hf)1333 NdbOut & operator<<(NdbOut& ndbout,
1334 const BackupFormat::DataFile::FragmentHeader & hf){
1335
1336 ndbout << "-- Fragment header:" << endl;
1337 ndbout << "SectionType: " << hf.SectionType << endl;
1338 ndbout << "SectionLength: " << hf.SectionLength << endl;
1339 ndbout << "TableId: " << hf.TableId << endl;
1340 ndbout << "FragmentNo: " << hf.FragmentNo << endl;
1341 ndbout << "ChecksumType: " << hf.ChecksumType << endl;
1342
1343 return ndbout;
1344 }
1345
operator <<(NdbOut & ndbout,const BackupFormat::DataFile::FragmentFooter & hf)1346 NdbOut & operator<<(NdbOut& ndbout,
1347 const BackupFormat::DataFile::FragmentFooter & hf){
1348
1349 ndbout << "-- Fragment footer:" << endl;
1350 ndbout << "SectionType: " << hf.SectionType << endl;
1351 ndbout << "SectionLength: " << hf.SectionLength << endl;
1352 ndbout << "TableId: " << hf.TableId << endl;
1353 ndbout << "FragmentNo: " << hf.FragmentNo << endl;
1354 ndbout << "NoOfRecords: " << hf.NoOfRecords << endl;
1355 ndbout << "Checksum: " << hf.Checksum << endl;
1356
1357 return ndbout;
1358 }
1359
operator <<(NdbOut & ndbout,const BackupFormat::LCPCtlFile & lcf)1360 NdbOut & operator<<(NdbOut& ndbout,
1361 const BackupFormat::LCPCtlFile & lcf)
1362 {
1363 ndbout << "-- LCP Control file part:" << endl;
1364 ndbout << "Checksum: " << hex << lcf.Checksum << endl;
1365 ndbout << "ValidFlag: " << lcf.ValidFlag << endl;
1366 ndbout << "TableId: " << lcf.TableId << endl;
1367 ndbout << "FragmentId: " << lcf.FragmentId << endl;
1368 ndbout << "CreateTableVersion: " << lcf.CreateTableVersion << endl;
1369 ndbout << "CreateGci: " << lcf.CreateGci << endl;
1370 ndbout << "MaxGciCompleted: " << lcf.MaxGciCompleted << endl;
1371 ndbout << "MaxGciWritten: " << lcf.MaxGciWritten << endl;
1372 ndbout << "LcpId: " << lcf.LcpId << endl;
1373 ndbout << "LocalLcpId: " << lcf.LocalLcpId << endl;
1374 ndbout << "MaxPageCount: " << lcf.MaxPageCount << endl;
1375 ndbout << "MaxNumberDataFiles: " << lcf.MaxNumberDataFiles << endl;
1376 ndbout << "LastDataFileNumber: " << lcf.LastDataFileNumber << endl;
1377 ndbout << "RowCount: " <<
1378 Uint64(Uint64(lcf.RowCountLow) +
1379 (Uint64(lcf.RowCountHigh) << 32)) << endl;
1380 ndbout << "MaxPartPairs: " << lcf.MaxPartPairs << endl;
1381 ndbout << "NumPartPairs: " << lcf.NumPartPairs << endl;
1382 if (lcf.NumPartPairs > BackupFormat::NDB_MAX_LCP_PARTS)
1383 {
1384 ndbout_c("Too many parts");
1385 abort();
1386 }
1387 for (Uint32 i = 0; i < lcf.NumPartPairs; i++)
1388 {
1389 ndbout << "Pair[" << i << "]: StartPart: "
1390 << lcf.partPairs[i].startPart << " NumParts: "
1391 << lcf.partPairs[i].numParts << endl;
1392 }
1393 return ndbout;
1394 }
1395
decompress_part_pairs(struct BackupFormat::LCPCtlFile * lcpCtlFilePtr,Uint32 num_parts)1396 Uint32 decompress_part_pairs(
1397 struct BackupFormat::LCPCtlFile *lcpCtlFilePtr,
1398 Uint32 num_parts)
1399 {
1400 static unsigned char c_part_array[BackupFormat::NDB_MAX_LCP_PARTS * 4];
1401 Uint32 total_parts = 0;
1402 unsigned char *part_array = (unsigned char*)&lcpCtlFilePtr->partPairs[0].startPart;
1403 memcpy(c_part_array, part_array, 3 * num_parts);
1404 Uint32 j = 0;
1405 for (Uint32 part = 0; part < num_parts; part++)
1406 {
1407 Uint32 part_0 = c_part_array[j+0];
1408 Uint32 part_1 = c_part_array[j+1];
1409 Uint32 part_2 = c_part_array[j+2];
1410 Uint32 startPart = ((part_1 & 0xF) + (part_0 << 4));
1411 Uint32 numParts = (((part_1 >> 4) & 0xF)) + (part_2 << 4);
1412 lcpCtlFilePtr->partPairs[part].startPart = startPart;
1413 lcpCtlFilePtr->partPairs[part].numParts = numParts;
1414 total_parts += numParts;
1415 j += 3;
1416 }
1417 return total_parts;
1418 }
1419
1420 bool
readLCPCtlFile(ndbzio_stream * f,BackupFormat::LCPCtlFile * ret)1421 readLCPCtlFile(ndbzio_stream* f, BackupFormat::LCPCtlFile *ret)
1422 {
1423 char * struct_dst = (char*)&theData.LCPCtlFile.Checksum;
1424 size_t struct_sz = sizeof(BackupFormat::LCPCtlFile) -
1425 sizeof(BackupFormat::FileHeader);
1426
1427 if(aread(struct_dst, (struct_sz - 4), 1, f) != 1)
1428 RETURN_FALSE();
1429
1430 theData.LCPCtlFile.Checksum = ntohl(theData.LCPCtlFile.Checksum);
1431 theData.LCPCtlFile.ValidFlag = ntohl(theData.LCPCtlFile.ValidFlag);
1432 theData.LCPCtlFile.TableId = ntohl(theData.LCPCtlFile.TableId);
1433 theData.LCPCtlFile.FragmentId = ntohl(theData.LCPCtlFile.FragmentId);
1434 theData.LCPCtlFile.CreateTableVersion =
1435 ntohl(theData.LCPCtlFile.CreateTableVersion);
1436 theData.LCPCtlFile.CreateGci = ntohl(theData.LCPCtlFile.CreateGci);
1437 theData.LCPCtlFile.MaxGciCompleted =
1438 ntohl(theData.LCPCtlFile.MaxGciCompleted);
1439 theData.LCPCtlFile.MaxGciWritten =
1440 ntohl(theData.LCPCtlFile.MaxGciWritten);
1441 theData.LCPCtlFile.LcpId = ntohl(theData.LCPCtlFile.LcpId);
1442 theData.LCPCtlFile.LocalLcpId = ntohl(theData.LCPCtlFile.LocalLcpId);
1443 theData.LCPCtlFile.MaxPageCount = ntohl(theData.LCPCtlFile.MaxPageCount);
1444 theData.LCPCtlFile.MaxNumberDataFiles =
1445 ntohl(theData.LCPCtlFile.MaxNumberDataFiles);
1446 theData.LCPCtlFile.LastDataFileNumber =
1447 ntohl(theData.LCPCtlFile.LastDataFileNumber);
1448 theData.LCPCtlFile.RowCountLow = ntohl(theData.LCPCtlFile.RowCountLow);
1449 theData.LCPCtlFile.RowCountHigh = ntohl(theData.LCPCtlFile.RowCountHigh);
1450 theData.LCPCtlFile.MaxPartPairs = ntohl(theData.LCPCtlFile.MaxPartPairs);
1451 theData.LCPCtlFile.NumPartPairs = ntohl(theData.LCPCtlFile.NumPartPairs);
1452
1453 size_t parts = theData.LCPCtlFile.NumPartPairs;
1454 char * part_dst = (char*)&theData.LCPCtlFile.partPairs[0];
1455 if(aread(part_dst, 3 * parts, 1, f) != 1)
1456 RETURN_FALSE();
1457
1458 decompress_part_pairs(&theData.LCPCtlFile, theData.LCPCtlFile.NumPartPairs);
1459 size_t file_header_sz = sizeof(BackupFormat::FileHeader);
1460 size_t copy_sz = struct_sz + (4 * parts) + file_header_sz;
1461 memcpy((char*)ret, &theData.LCPCtlFile, copy_sz);
1462 return true;
1463 }
1464
1465 bool
readTableList(ndbzio_stream * f,BackupFormat::CtlFile::TableList ** ret)1466 readTableList(ndbzio_stream* f, BackupFormat::CtlFile::TableList **ret){
1467 BackupFormat::CtlFile::TableList * dst = &theData.TableList;
1468
1469 if(aread(dst, 4, 2, f) != 2)
1470 RETURN_FALSE();
1471
1472 dst->SectionType = ntohl(dst->SectionType);
1473 dst->SectionLength = ntohl(dst->SectionLength);
1474
1475 if(dst->SectionType != BackupFormat::TABLE_LIST)
1476 RETURN_FALSE();
1477
1478 const Uint32 len = dst->SectionLength - 2;
1479 if(aread(&dst->TableIds[0], 4, len, f) != len)
1480 RETURN_FALSE();
1481
1482 for(Uint32 i = 0; i<len; i++){
1483 dst->TableIds[i] = ntohl(dst->TableIds[i]);
1484 }
1485
1486 * ret = dst;
1487
1488 return true;
1489 }
1490
1491 bool
readTableDesc(ndbzio_stream * f,BackupFormat::CtlFile::TableDescription ** ret)1492 readTableDesc(ndbzio_stream* f, BackupFormat::CtlFile::TableDescription **ret){
1493 BackupFormat::CtlFile::TableDescription * dst = &theData.TableDescription;
1494
1495 if(aread(dst, 4, 3, f) != 3)
1496 RETURN_FALSE();
1497
1498 dst->SectionType = ntohl(dst->SectionType);
1499 dst->SectionLength = ntohl(dst->SectionLength);
1500 dst->TableType = ntohl(dst->TableType);
1501
1502 if(dst->SectionType != BackupFormat::TABLE_DESCRIPTION)
1503 RETURN_FALSE();
1504
1505 const Uint32 len = dst->SectionLength - 3;
1506 if(aread(&dst->DictTabInfo[0], 4, len, f) != len)
1507 RETURN_FALSE();
1508
1509 * ret = dst;
1510
1511 return true;
1512 }
1513
1514 bool
readGCPEntry(ndbzio_stream * f,BackupFormat::CtlFile::GCPEntry ** ret)1515 readGCPEntry(ndbzio_stream* f, BackupFormat::CtlFile::GCPEntry **ret){
1516 BackupFormat::CtlFile::GCPEntry * dst = &theData.GcpEntry;
1517
1518 if(aread(dst, 4, 4, f) != 4)
1519 RETURN_FALSE();
1520
1521 dst->SectionType = ntohl(dst->SectionType);
1522 dst->SectionLength = ntohl(dst->SectionLength);
1523
1524 if(dst->SectionType != BackupFormat::GCP_ENTRY)
1525 RETURN_FALSE();
1526
1527 dst->StartGCP = ntohl(dst->StartGCP);
1528 dst->StopGCP = ntohl(dst->StopGCP);
1529
1530 * ret = dst;
1531
1532 return true;
1533 }
1534
1535
1536 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::CtlFile::TableList & hf)1537 operator<<(NdbOut& ndbout, const BackupFormat::CtlFile::TableList & hf) {
1538 ndbout << "-- Table List:" << endl;
1539 ndbout << "SectionType: " << hf.SectionType << endl;
1540 ndbout << "SectionLength: " << hf.SectionLength << endl;
1541 ndbout << "Tables: ";
1542 for(Uint32 i = 0; i < hf.SectionLength - 2; i++){
1543 ndbout << hf.TableIds[i] << " ";
1544 if((i + 1) % 16 == 0)
1545 ndbout << endl;
1546 }
1547 ndbout << endl;
1548 return ndbout;
1549 }
1550
1551 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::CtlFile::TableDescription & hf)1552 operator<<(NdbOut& ndbout, const BackupFormat::CtlFile::TableDescription & hf){
1553 ndbout << "-- Table Description:" << endl;
1554 ndbout << "SectionType: " << hf.SectionType << endl;
1555 ndbout << "SectionLength: " << hf.SectionLength << endl;
1556 ndbout << "TableType: " << hf.TableType << endl;
1557
1558 SimplePropertiesLinearReader it(&hf.DictTabInfo[0], hf.SectionLength - 3);
1559 char buf[1024];
1560 for(it.first(); it.valid(); it.next()){
1561 switch(it.getValueType()){
1562 case SimpleProperties::Uint32Value:
1563 ndbout << "Key: " << it.getKey()
1564 << " value(" << it.getValueLen() << ") : "
1565 << it.getUint32() << endl;
1566 break;
1567 case SimpleProperties::StringValue:
1568 if(it.getValueLen() < sizeof(buf)){
1569 it.getString(buf);
1570 ndbout << "Key: " << it.getKey()
1571 << " value(" << it.getValueLen() << ") : "
1572 << "\"" << buf << "\"" << endl;
1573 } else {
1574 ndbout << "Key: " << it.getKey()
1575 << " value(" << it.getValueLen() << ") : "
1576 << "\"" << "<TOO LONG>" << "\"" << endl;
1577
1578 }
1579 break;
1580 case SimpleProperties::BinaryValue:
1581 if(it.getValueLen() < sizeof(buf))
1582 {
1583 ndbout << "Key: " << it.getKey()
1584 << " binary value len = " << it.getValueLen() << endl;
1585
1586 }
1587 else
1588 {
1589 ndbout << "Key: " << it.getKey()
1590 << " value(" << it.getValueLen() << ") : "
1591 << "\"" << "<TOO LONG>" << "\"" << endl;
1592 }
1593 break;
1594 default:
1595 ndbout << "Unknown type for key: " << it.getKey()
1596 << " type: " << it.getValueType() << endl;
1597 }
1598 }
1599
1600 return ndbout;
1601 }
1602
1603 NdbOut &
operator <<(NdbOut & ndbout,const BackupFormat::CtlFile::GCPEntry & hf)1604 operator<<(NdbOut& ndbout, const BackupFormat::CtlFile::GCPEntry & hf) {
1605 ndbout << "-- GCP Entry:" << endl;
1606 ndbout << "SectionType: " << hf.SectionType << endl;
1607 ndbout << "SectionLength: " << hf.SectionLength << endl;
1608 ndbout << "Start GCP: " << hf.StartGCP << endl;
1609 ndbout << "Stop GCP: " << hf.StopGCP << endl;
1610
1611 return ndbout;
1612 }
1613
1614