mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / ndb / tools / restore / restore_main.cpp
blob7425f76dc89d9a197f310c470fac5524ae2ba7ca
1 /* Copyright (c) 2003-2007 MySQL AB
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16 #include <ndb_global.h>
17 #include <ndb_opts.h>
18 #include <Vector.hpp>
19 #include <ndb_limits.h>
20 #include <NdbTCP.h>
21 #include <NdbMem.h>
22 #include <NdbOut.hpp>
23 #include <OutputStream.hpp>
24 #include <NDBT_ReturnCodes.h>
26 #include "consumer_restore.hpp"
27 #include "consumer_printer.hpp"
29 extern FilteredNdbOut err;
30 extern FilteredNdbOut info;
31 extern FilteredNdbOut debug;
33 static int ga_nodeId = 0;
34 static int ga_nParallelism = 128;
35 static int ga_backupId = 0;
36 static bool ga_dont_ignore_systab_0 = false;
37 static bool ga_no_upgrade = false;
38 static Vector<class BackupConsumer *> g_consumers;
39 static BackupPrinter* g_printer = NULL;
41 static const char* default_backupPath = "." DIR_SEPARATOR;
42 static const char* ga_backupPath = default_backupPath;
44 static const char *opt_nodegroup_map_str= 0;
45 static unsigned opt_nodegroup_map_len= 0;
46 static NODE_GROUP_MAP opt_nodegroup_map[MAX_NODE_GROUP_MAPS];
47 #define OPT_NDB_NODEGROUP_MAP 'z'
49 const char *opt_ndb_database= NULL;
50 const char *opt_ndb_table= NULL;
51 unsigned int opt_verbose;
52 unsigned int opt_hex_format;
53 Vector<BaseString> g_databases;
54 Vector<BaseString> g_tables;
55 NdbRecordPrintFormat g_ndbrecord_print_format;
57 NDB_STD_OPTS_VARS;
59 /**
60 * print and restore flags
62 static bool ga_restore_epoch = false;
63 static bool ga_restore = false;
64 static bool ga_print = false;
65 static bool ga_skip_table_check = false;
66 static int _print = 0;
67 static int _print_meta = 0;
68 static int _print_data = 0;
69 static int _print_log = 0;
70 static int _restore_data = 0;
71 static int _restore_meta = 0;
72 static int _no_restore_disk = 0;
73 BaseString g_options("ndb_restore");
75 const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 };
77 enum ndb_restore_options {
78 OPT_PRINT= NDB_STD_OPTIONS_LAST,
79 OPT_PRINT_DATA,
80 OPT_PRINT_LOG,
81 OPT_PRINT_META,
82 OPT_BACKUP_PATH,
83 OPT_HEX_FORMAT,
84 OPT_FIELDS_ENCLOSED_BY,
85 OPT_FIELDS_TERMINATED_BY,
86 OPT_FIELDS_OPTIONALLY_ENCLOSED_BY,
87 OPT_LINES_TERMINATED_BY,
88 OPT_APPEND,
89 OPT_VERBOSE
91 static const char *opt_fields_enclosed_by= NULL;
92 static const char *opt_fields_terminated_by= NULL;
93 static const char *opt_fields_optionally_enclosed_by= NULL;
94 static const char *opt_lines_terminated_by= NULL;
96 static const char *tab_path= NULL;
97 static int opt_append;
99 static struct my_option my_long_options[] =
101 NDB_STD_OPTS("ndb_restore"),
102 { "connect", 'c', "same as --connect-string",
103 (uchar**) &opt_connect_str, (uchar**) &opt_connect_str, 0,
104 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
105 { "nodeid", 'n', "Backup files from node with id",
106 (uchar**) &ga_nodeId, (uchar**) &ga_nodeId, 0,
107 GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
108 { "backupid", 'b', "Backup id",
109 (uchar**) &ga_backupId, (uchar**) &ga_backupId, 0,
110 GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
111 { "restore_data", 'r',
112 "Restore table data/logs into NDB Cluster using NDBAPI",
113 (uchar**) &_restore_data, (uchar**) &_restore_data, 0,
114 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
115 { "restore_meta", 'm',
116 "Restore meta data into NDB Cluster using NDBAPI",
117 (uchar**) &_restore_meta, (uchar**) &_restore_meta, 0,
118 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
119 { "no-upgrade", 'u',
120 "Don't upgrade array type for var attributes, which don't resize VAR data and don't change column attributes",
121 (uchar**) &ga_no_upgrade, (uchar**) &ga_no_upgrade, 0,
122 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
123 { "no-restore-disk-objects", 'd',
124 "Dont restore disk objects (tablespace/logfilegroups etc)",
125 (uchar**) &_no_restore_disk, (uchar**) &_no_restore_disk, 0,
126 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
127 { "restore_epoch", 'e',
128 "Restore epoch info into the status table. Convenient on a MySQL Cluster "
129 "replication slave, for starting replication. The row in "
130 NDB_REP_DB "." NDB_APPLY_TABLE " with id 0 will be updated/inserted.",
131 (uchar**) &ga_restore_epoch, (uchar**) &ga_restore_epoch, 0,
132 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
133 { "skip-table-check", 's', "Skip table structure check during restore of data",
134 (uchar**) &ga_skip_table_check, (uchar**) &ga_skip_table_check, 0,
135 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
136 { "parallelism", 'p',
137 "No of parallel transactions during restore of data."
138 "(parallelism can be 1 to 1024)",
139 (uchar**) &ga_nParallelism, (uchar**) &ga_nParallelism, 0,
140 GET_INT, REQUIRED_ARG, 128, 1, 1024, 0, 1, 0 },
141 { "print", OPT_PRINT, "Print metadata, data and log to stdout",
142 (uchar**) &_print, (uchar**) &_print, 0,
143 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
144 { "print_data", OPT_PRINT_DATA, "Print data to stdout",
145 (uchar**) &_print_data, (uchar**) &_print_data, 0,
146 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
147 { "print_meta", OPT_PRINT_META, "Print meta data to stdout",
148 (uchar**) &_print_meta, (uchar**) &_print_meta, 0,
149 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
150 { "print_log", OPT_PRINT_LOG, "Print log to stdout",
151 (uchar**) &_print_log, (uchar**) &_print_log, 0,
152 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
153 { "backup_path", OPT_BACKUP_PATH, "Path to backup files",
154 (uchar**) &ga_backupPath, (uchar**) &ga_backupPath, 0,
155 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
156 { "dont_ignore_systab_0", 'f',
157 "Experimental. Do not ignore system table during restore.",
158 (uchar**) &ga_dont_ignore_systab_0, (uchar**) &ga_dont_ignore_systab_0, 0,
159 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
160 { "ndb-nodegroup-map", OPT_NDB_NODEGROUP_MAP,
161 "Nodegroup map for ndbcluster. Syntax: list of (source_ng, dest_ng)",
162 (uchar**) &opt_nodegroup_map_str,
163 (uchar**) &opt_nodegroup_map_str,
165 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
166 { "fields-enclosed-by", OPT_FIELDS_ENCLOSED_BY,
167 "Fields are enclosed by ...",
168 (uchar**) &opt_fields_enclosed_by, (uchar**) &opt_fields_enclosed_by, 0,
169 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
170 { "fields-terminated-by", OPT_FIELDS_TERMINATED_BY,
171 "Fields are terminated by ...",
172 (uchar**) &opt_fields_terminated_by,
173 (uchar**) &opt_fields_terminated_by, 0,
174 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
175 { "fields-optionally-enclosed-by", OPT_FIELDS_OPTIONALLY_ENCLOSED_BY,
176 "Fields are optionally enclosed by ...",
177 (uchar**) &opt_fields_optionally_enclosed_by,
178 (uchar**) &opt_fields_optionally_enclosed_by, 0,
179 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
180 { "hex", OPT_HEX_FORMAT, "print binary types in hex format",
181 (uchar**) &opt_hex_format, (uchar**) &opt_hex_format, 0,
182 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
183 { "tab", 'T', "Creates tab separated textfile for each table to "
184 "given path. (creates .txt files)",
185 (uchar**) &tab_path, (uchar**) &tab_path, 0,
186 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
187 { "append", OPT_APPEND, "for --tab append data to file",
188 (uchar**) &opt_append, (uchar**) &opt_append, 0,
189 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
190 { "lines-terminated-by", OPT_LINES_TERMINATED_BY, "",
191 (uchar**) &opt_lines_terminated_by, (uchar**) &opt_lines_terminated_by, 0,
192 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
193 { "verbose", OPT_VERBOSE,
194 "verbosity",
195 (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
196 GET_INT, REQUIRED_ARG, 1, 0, 255, 0, 0, 0 },
197 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
201 static char* analyse_one_map(char *map_str, uint16 *source, uint16 *dest)
203 char *end_ptr;
204 int number;
205 DBUG_ENTER("analyse_one_map");
207 Search for pattern ( source_ng , dest_ng )
210 while (isspace(*map_str)) map_str++;
212 if (*map_str != '(')
214 DBUG_RETURN(NULL);
216 map_str++;
218 while (isspace(*map_str)) map_str++;
220 number= strtol(map_str, &end_ptr, 10);
221 if (!end_ptr || number < 0 || number >= MAX_NODE_GROUP_MAPS)
223 DBUG_RETURN(NULL);
225 *source= (uint16)number;
226 map_str= end_ptr;
228 while (isspace(*map_str)) map_str++;
230 if (*map_str != ',')
232 DBUG_RETURN(NULL);
234 map_str++;
236 number= strtol(map_str, &end_ptr, 10);
237 if (!end_ptr || number < 0 || number >= UNDEF_NODEGROUP)
239 DBUG_RETURN(NULL);
241 *dest= (uint16)number;
242 map_str= end_ptr;
244 if (*map_str != ')')
246 DBUG_RETURN(NULL);
248 map_str++;
250 while (isspace(*map_str)) map_str++;
251 DBUG_RETURN(map_str);
254 static bool insert_ng_map(NODE_GROUP_MAP *ng_map,
255 uint16 source_ng, uint16 dest_ng)
257 uint index= source_ng;
258 uint ng_index= ng_map[index].no_maps;
260 opt_nodegroup_map_len++;
261 if (ng_index >= MAX_MAPS_PER_NODE_GROUP)
262 return true;
263 ng_map[index].no_maps++;
264 ng_map[index].map_array[ng_index]= dest_ng;
265 return false;
268 static void init_nodegroup_map()
270 uint i,j;
271 NODE_GROUP_MAP *ng_map = &opt_nodegroup_map[0];
273 for (i = 0; i < MAX_NODE_GROUP_MAPS; i++)
275 ng_map[i].no_maps= 0;
276 for (j= 0; j < MAX_MAPS_PER_NODE_GROUP; j++)
277 ng_map[i].map_array[j]= UNDEF_NODEGROUP;
281 static bool analyse_nodegroup_map(const char *ng_map_str,
282 NODE_GROUP_MAP *ng_map)
284 uint16 source_ng, dest_ng;
285 char *local_str= (char*)ng_map_str;
286 DBUG_ENTER("analyse_nodegroup_map");
290 if (!local_str)
292 DBUG_RETURN(TRUE);
294 local_str= analyse_one_map(local_str, &source_ng, &dest_ng);
295 if (!local_str)
297 DBUG_RETURN(TRUE);
299 if (insert_ng_map(ng_map, source_ng, dest_ng))
301 DBUG_RETURN(TRUE);
303 if (!(*local_str))
304 break;
305 } while (TRUE);
306 DBUG_RETURN(FALSE);
309 static void short_usage_sub(void)
311 printf("Usage: %s [OPTIONS] [<path to backup files>]\n", my_progname);
313 static void usage()
315 short_usage_sub();
316 ndb_std_print_version();
317 print_defaults(MYSQL_CONFIG_NAME,load_default_groups);
318 puts("");
319 my_print_help(my_long_options);
320 my_print_variables(my_long_options);
322 static my_bool
323 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
324 char *argument)
326 #ifndef DBUG_OFF
327 opt_debug= "d:t:O,/tmp/ndb_restore.trace";
328 #endif
329 ndb_std_get_one_option(optid, opt, argument);
330 switch (optid) {
331 case OPT_VERBOSE:
332 info.setThreshold(255-opt_verbose);
333 break;
334 case 'n':
335 if (ga_nodeId == 0)
337 err << "Error in --nodeid,-n setting, see --help";
338 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
340 info.setLevel(254);
341 info << "Nodeid = " << ga_nodeId << endl;
342 break;
343 case 'b':
344 if (ga_backupId == 0)
346 err << "Error in --backupid,-b setting, see --help";
347 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
349 info.setLevel(254);
350 info << "Backup Id = " << ga_backupId << endl;
351 break;
352 case OPT_NDB_NODEGROUP_MAP:
354 This option is used to set a map from nodegroup in original cluster
355 to nodegroup in new cluster.
357 opt_nodegroup_map_len= 0;
359 info.setLevel(254);
360 info << "Analyse node group map" << endl;
361 if (analyse_nodegroup_map(opt_nodegroup_map_str,
362 &opt_nodegroup_map[0]))
364 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
366 break;
368 return 0;
370 bool
371 readArguments(int *pargc, char*** pargv)
373 Uint32 i;
374 debug << "Load defaults" << endl;
375 const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 };
377 init_nodegroup_map();
378 load_defaults("my",load_default_groups,pargc,pargv);
379 debug << "handle_options" << endl;
380 if (handle_options(pargc, pargv, my_long_options, get_one_option))
382 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
384 for (i = 0; i < MAX_NODE_GROUP_MAPS; i++)
385 opt_nodegroup_map[i].curr_index = 0;
387 #if 0
389 Test code written t{
390 o verify nodegroup mapping
392 printf("Handled options successfully\n");
393 Uint16 map_ng[16];
394 Uint32 j;
395 for (j = 0; j < 4; j++)
397 for (i = 0; i < 4 ; i++)
398 map_ng[i] = i;
399 map_nodegroups(&map_ng[0], (Uint32)4);
400 for (i = 0; i < 4 ; i++)
401 printf("NG %u mapped to %u \n", i, map_ng[i]);
403 for (j = 0; j < 4; j++)
405 for (i = 0; i < 8 ; i++)
406 map_ng[i] = i >> 1;
407 map_nodegroups(&map_ng[0], (Uint32)8);
408 for (i = 0; i < 8 ; i++)
409 printf("NG %u mapped to %u \n", i >> 1, map_ng[i]);
411 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
412 #endif
414 g_printer = new BackupPrinter(opt_nodegroup_map,
415 opt_nodegroup_map_len);
416 if (g_printer == NULL)
417 return false;
419 BackupRestore* restore = new BackupRestore(opt_nodegroup_map,
420 opt_nodegroup_map_len,
421 ga_nParallelism);
422 if (restore == NULL)
424 delete g_printer;
425 g_printer = NULL;
426 return false;
429 if (_print)
431 ga_print = true;
432 ga_restore = true;
433 g_printer->m_print = true;
435 if (_print_meta)
437 ga_print = true;
438 g_printer->m_print_meta = true;
440 if (_print_data)
442 ga_print = true;
443 g_printer->m_print_data = true;
445 if (_print_log)
447 ga_print = true;
448 g_printer->m_print_log = true;
451 if (_restore_data)
453 ga_restore = true;
454 restore->m_restore = true;
457 if (_restore_meta)
459 // ga_restore = true;
460 restore->m_restore_meta = true;
463 if (_no_restore_disk)
465 restore->m_no_restore_disk = true;
468 if (ga_no_upgrade)
470 restore->m_no_upgrade = true;
473 if (ga_restore_epoch)
475 restore->m_restore_epoch = true;
479 BackupConsumer * c = g_printer;
480 g_consumers.push_back(c);
483 BackupConsumer * c = restore;
484 g_consumers.push_back(c);
486 for (;;)
488 int i= 0;
489 if (ga_backupPath == default_backupPath)
491 // Set backup file path
492 if ((*pargv)[i] == NULL)
493 break;
494 ga_backupPath = (*pargv)[i++];
496 if ((*pargv)[i] == NULL)
497 break;
498 g_databases.push_back((*pargv)[i++]);
499 while ((*pargv)[i] != NULL)
501 g_tables.push_back((*pargv)[i++]);
503 break;
505 info.setLevel(254);
506 info << "backup path = " << ga_backupPath << endl;
507 if (g_databases.size() > 0)
509 info << "Restoring only from database " << g_databases[0].c_str() << endl;
510 if (g_tables.size() > 0)
511 info << "Restoring only tables:";
512 for (unsigned i= 0; i < g_tables.size(); i++)
514 info << " " << g_tables[i].c_str();
516 if (g_tables.size() > 0)
517 info << endl;
520 the below formatting follows the formatting from mysqldump
521 do not change unless to adopt to changes in mysqldump
523 g_ndbrecord_print_format.fields_enclosed_by=
524 opt_fields_enclosed_by ? opt_fields_enclosed_by : "";
525 g_ndbrecord_print_format.fields_terminated_by=
526 opt_fields_terminated_by ? opt_fields_terminated_by : "\t";
527 g_ndbrecord_print_format.fields_optionally_enclosed_by=
528 opt_fields_optionally_enclosed_by ? opt_fields_optionally_enclosed_by : "";
529 g_ndbrecord_print_format.lines_terminated_by=
530 opt_lines_terminated_by ? opt_lines_terminated_by : "\n";
531 if (g_ndbrecord_print_format.fields_optionally_enclosed_by[0] == '\0')
532 g_ndbrecord_print_format.null_string= "\\N";
533 else
534 g_ndbrecord_print_format.null_string= "";
535 g_ndbrecord_print_format.hex_prefix= "";
536 g_ndbrecord_print_format.hex_format= opt_hex_format;
537 return true;
540 void
541 clearConsumers()
543 for(Uint32 i= 0; i<g_consumers.size(); i++)
544 delete g_consumers[i];
545 g_consumers.clear();
548 static inline bool
549 checkSysTable(const TableS* table)
551 return ga_dont_ignore_systab_0 || ! table->getSysTable();
554 static inline bool
555 checkSysTable(const RestoreMetaData& metaData, uint i)
557 assert(i < metaData.getNoOfTables());
558 return checkSysTable(metaData[i]);
561 static inline bool
562 isBlobTable(const TableS* table)
564 return table->getMainTable() != NULL;
567 static inline bool
568 isIndex(const TableS* table)
570 const NdbTableImpl & tmptab = NdbTableImpl::getImpl(* table->m_dictTable);
571 return (int) tmptab.m_indexType != (int) NdbDictionary::Index::Undefined;
574 static inline bool
575 checkDbAndTableName(const TableS* table)
577 if (g_tables.size() == 0 &&
578 g_databases.size() == 0)
579 return true;
580 if (g_databases.size() == 0)
581 g_databases.push_back("TEST_DB");
583 // Filter on the main table name for indexes and blobs
584 const char *table_name;
585 if (isBlobTable(table))
586 table_name= table->getMainTable()->getTableName();
587 else if (isIndex(table))
588 table_name=
589 NdbTableImpl::getImpl(*table->m_dictTable).m_primaryTable.c_str();
590 else
591 table_name= table->getTableName();
593 unsigned i;
594 for (i= 0; i < g_databases.size(); i++)
596 if (strncmp(table_name, g_databases[i].c_str(),
597 g_databases[i].length()) == 0 &&
598 table_name[g_databases[i].length()] == '/')
600 // we have a match
601 if (g_databases.size() > 1 || g_tables.size() == 0)
602 return true;
603 break;
606 if (i == g_databases.size())
607 return false; // no match found
609 while (*table_name != '/') table_name++;
610 table_name++;
611 while (*table_name != '/') table_name++;
612 table_name++;
614 for (i= 0; i < g_tables.size(); i++)
616 if (strcmp(table_name, g_tables[i].c_str()) == 0)
618 // we have a match
619 return true;
622 return false;
625 static void
626 free_data_callback()
628 for(Uint32 i= 0; i < g_consumers.size(); i++)
629 g_consumers[i]->tuple_free();
632 const char * g_connect_string = 0;
633 static void exitHandler(int code)
635 NDBT_ProgramExit(code);
636 if (opt_core)
637 abort();
638 else
639 exit(code);
643 main(int argc, char** argv)
645 NDB_INIT(argv[0]);
647 debug << "Start readArguments" << endl;
648 if (!readArguments(&argc, &argv))
650 exitHandler(NDBT_FAILED);
653 g_options.appfmt(" -b %d", ga_backupId);
654 g_options.appfmt(" -n %d", ga_nodeId);
655 if (_restore_meta)
656 g_options.appfmt(" -m");
657 if (ga_no_upgrade)
658 g_options.appfmt(" -u");
659 if (ga_skip_table_check)
660 g_options.appfmt(" -s");
661 if (_restore_data)
662 g_options.appfmt(" -r");
663 if (ga_restore_epoch)
664 g_options.appfmt(" -e");
665 if (_no_restore_disk)
666 g_options.appfmt(" -d");
667 g_options.appfmt(" -p %d", ga_nParallelism);
669 g_connect_string = opt_connect_str;
671 * we must always load meta data, even if we will only print it to stdout
673 debug << "Start restoring meta data" << endl;
674 RestoreMetaData metaData(ga_backupPath, ga_nodeId, ga_backupId);
675 if (!metaData.readHeader())
677 err << "Failed to read " << metaData.getFilename() << endl << endl;
678 exitHandler(NDBT_FAILED);
681 const BackupFormat::FileHeader & tmp = metaData.getFileHeader();
682 const Uint32 version = tmp.NdbVersion;
684 char buf[NDB_VERSION_STRING_BUF_SZ];
685 info.setLevel(254);
686 info << "Ndb version in backup files: "
687 << ndbGetVersionString(version, 0, buf, sizeof(buf)) << endl;
690 * check wheater we can restore the backup (right version).
692 // in these versions there was an error in how replica info was
693 // stored on disk
694 if (version >= MAKE_VERSION(5,1,3) && version <= MAKE_VERSION(5,1,9))
696 err << "Restore program incompatible with backup versions between "
697 << ndbGetVersionString(MAKE_VERSION(5,1,3), 0, buf, sizeof(buf))
698 << " and "
699 << ndbGetVersionString(MAKE_VERSION(5,1,9), 0, buf, sizeof(buf))
700 << endl;
701 exitHandler(NDBT_FAILED);
704 if (version > NDB_VERSION)
706 err << "Restore program older than backup version. Not supported. "
707 << "Use new restore program" << endl;
708 exitHandler(NDBT_FAILED);
711 debug << "Load content" << endl;
712 int res = metaData.loadContent();
714 if (res == 0)
716 err << "Restore: Failed to load content" << endl;
717 exitHandler(NDBT_FAILED);
719 debug << "Get no of Tables" << endl;
720 if (metaData.getNoOfTables() == 0)
722 err << "The backup contains no tables" << endl;
723 exitHandler(NDBT_FAILED);
725 debug << "Validate Footer" << endl;
727 if (!metaData.validateFooter())
729 err << "Restore: Failed to validate footer." << endl;
730 exitHandler(NDBT_FAILED);
732 debug << "Init Backup objects" << endl;
733 Uint32 i;
734 for(i= 0; i < g_consumers.size(); i++)
736 if (!g_consumers[i]->init())
738 clearConsumers();
739 err << "Failed to initialize consumers" << endl;
740 exitHandler(NDBT_FAILED);
744 debug << "Restore objects (tablespaces, ..)" << endl;
745 for(i = 0; i<metaData.getNoOfObjects(); i++)
747 for(Uint32 j= 0; j < g_consumers.size(); j++)
748 if (!g_consumers[j]->object(metaData.getObjType(i),
749 metaData.getObjPtr(i)))
751 err << "Restore: Failed to restore table: ";
752 err << metaData[i]->getTableName() << " ... Exiting " << endl;
753 exitHandler(NDBT_FAILED);
757 Vector<OutputStream *> table_output(metaData.getNoOfTables());
758 debug << "Restoring tables" << endl;
759 for(i = 0; i<metaData.getNoOfTables(); i++)
761 const TableS *table= metaData[i];
762 table_output.push_back(NULL);
763 if (!checkDbAndTableName(table))
764 continue;
765 if (checkSysTable(table))
767 if (!tab_path || isBlobTable(table) || isIndex(table))
769 table_output[i]= ndbout.m_out;
771 else
773 FILE* res;
774 char filename[FN_REFLEN], tmp_path[FN_REFLEN];
775 const char *table_name;
776 table_name= table->getTableName();
777 while (*table_name != '/') table_name++;
778 table_name++;
779 while (*table_name != '/') table_name++;
780 table_name++;
781 convert_dirname(tmp_path, tab_path, NullS);
782 res= my_fopen(fn_format(filename, table_name, tmp_path, ".txt", 4),
783 opt_append ?
784 O_WRONLY|O_APPEND|O_CREAT :
785 O_WRONLY|O_TRUNC|O_CREAT,
786 MYF(MY_WME));
787 if (res == 0)
789 exitHandler(NDBT_FAILED);
791 FileOutputStream *f= new FileOutputStream(res);
792 table_output[i]= f;
794 for(Uint32 j= 0; j < g_consumers.size(); j++)
795 if (!g_consumers[j]->table(* table))
797 err << "Restore: Failed to restore table: `";
798 err << table->getTableName() << "` ... Exiting " << endl;
799 exitHandler(NDBT_FAILED);
801 } else {
802 for(Uint32 j= 0; j < g_consumers.size(); j++)
803 if (!g_consumers[j]->createSystable(* table))
805 err << "Restore: Failed to restore system table: ";
806 err << table->getTableName() << " ... Exiting " << endl;
807 exitHandler(NDBT_FAILED);
811 debug << "Close tables" << endl;
812 for(i= 0; i < g_consumers.size(); i++)
813 if (!g_consumers[i]->endOfTables())
815 err << "Restore: Failed while closing tables" << endl;
816 exitHandler(NDBT_FAILED);
818 debug << "Iterate over data" << endl;
819 if (ga_restore || ga_print)
821 if(_restore_data || _print_data)
823 if (!ga_skip_table_check){
824 for(i=0; i < metaData.getNoOfTables(); i++){
825 if (checkSysTable(metaData, i))
827 for(Uint32 j= 0; j < g_consumers.size(); j++)
828 if (!g_consumers[j]->table_equal(* metaData[i]))
830 err << "Restore: Failed to restore data, ";
831 err << metaData[i]->getTableName() << " table structure doesn't match backup ... Exiting " << endl;
832 exitHandler(NDBT_FAILED);
837 RestoreDataIterator dataIter(metaData, &free_data_callback);
839 // Read data file header
840 if (!dataIter.readHeader())
842 err << "Failed to read header of data file. Exiting..." << endl;
843 exitHandler(NDBT_FAILED);
846 Uint32 fragmentId;
847 while (dataIter.readFragmentHeader(res= 0, &fragmentId))
849 const TupleS* tuple;
850 while ((tuple = dataIter.getNextTuple(res= 1)) != 0)
852 const TableS* table = tuple->getTable();
853 OutputStream *output = table_output[table->getLocalId()];
854 if (!output)
855 continue;
856 OutputStream *tmp = ndbout.m_out;
857 ndbout.m_out = output;
858 for(Uint32 j= 0; j < g_consumers.size(); j++)
859 g_consumers[j]->tuple(* tuple, fragmentId);
860 ndbout.m_out = tmp;
861 } // while (tuple != NULL);
863 if (res < 0)
865 err <<" Restore: An error occured while restoring data. Exiting...";
866 err << endl;
867 exitHandler(NDBT_FAILED);
869 if (!dataIter.validateFragmentFooter()) {
870 err << "Restore: Error validating fragment footer. ";
871 err << "Exiting..." << endl;
872 exitHandler(NDBT_FAILED);
874 } // while (dataIter.readFragmentHeader(res))
876 if (res < 0)
878 err << "Restore: An error occured while restoring data. Exiting... "
879 << "res= " << res << endl;
880 exitHandler(NDBT_FAILED);
884 dataIter.validateFooter(); //not implemented
886 for (i= 0; i < g_consumers.size(); i++)
887 g_consumers[i]->endOfTuples();
890 if(_restore_data || _print_log)
892 RestoreLogIterator logIter(metaData);
893 if (!logIter.readHeader())
895 err << "Failed to read header of data file. Exiting..." << endl;
896 exitHandler(NDBT_FAILED);
899 const LogEntry * logEntry = 0;
900 while ((logEntry = logIter.getNextLogEntry(res= 0)) != 0)
902 const TableS* table = logEntry->m_table;
903 OutputStream *output = table_output[table->getLocalId()];
904 if (!output)
905 continue;
906 for(Uint32 j= 0; j < g_consumers.size(); j++)
907 g_consumers[j]->logEntry(* logEntry);
909 if (res < 0)
911 err << "Restore: An restoring the data log. Exiting... res="
912 << res << endl;
913 exitHandler(NDBT_FAILED);
915 logIter.validateFooter(); //not implemented
916 for (i= 0; i < g_consumers.size(); i++)
917 g_consumers[i]->endOfLogEntrys();
920 if(_restore_data)
922 for(i = 0; i<metaData.getNoOfTables(); i++)
924 const TableS* table = metaData[i];
925 OutputStream *output = table_output[table->getLocalId()];
926 if (!output)
927 continue;
928 for(Uint32 j= 0; j < g_consumers.size(); j++)
929 if (!g_consumers[j]->finalize_table(*table))
931 err << "Restore: Failed to finalize restore table: %s. ";
932 err << "Exiting... " << metaData[i]->getTableName() << endl;
933 exitHandler(NDBT_FAILED);
938 if (ga_restore_epoch)
940 for (i= 0; i < g_consumers.size(); i++)
941 if (!g_consumers[i]->update_apply_status(metaData))
943 err << "Restore: Failed to restore epoch" << endl;
944 return -1;
948 for(Uint32 j= 0; j < g_consumers.size(); j++)
950 if (g_consumers[j]->has_temp_error())
952 clearConsumers();
953 ndbout_c("\nRestore successful, but encountered temporary error, "
954 "please look at configuration.");
958 clearConsumers();
960 for(i = 0; i < metaData.getNoOfTables(); i++)
962 if (table_output[i] &&
963 table_output[i] != ndbout.m_out)
965 my_fclose(((FileOutputStream *)table_output[i])->getFile(), MYF(MY_WME));
966 delete table_output[i];
967 table_output[i] = NULL;
971 if (opt_verbose)
972 return NDBT_ProgramExit(NDBT_OK);
973 else
974 return 0;
975 } // main
977 template class Vector<BackupConsumer*>;
978 template class Vector<OutputStream*>;