18 #include <ndb_global.h>
21 #include <Properties.hpp>
22 #include <ndb_limits.h>
26 #include <OutputStream.hpp>
27 #include <NDBT_ReturnCodes.h>
29 #include "consumer_restore.hpp"
30 #include "consumer_printer.hpp"
31 #include "../src/ndbapi/NdbDictionaryImpl.hpp"
33 extern FilteredNdbOut err;
34 extern FilteredNdbOut info;
35 extern FilteredNdbOut debug;
37 static Uint32 g_tableCompabilityMask = 0;
38 static int ga_nodeId = 0;
39 static int ga_nParallelism = 128;
40 static int ga_backupId = 0;
41 bool ga_dont_ignore_systab_0 =
false;
42 static bool ga_no_upgrade =
false;
43 static bool ga_promote_attributes =
false;
44 static bool ga_demote_attributes =
false;
48 static const char* default_backupPath =
"." DIR_SEPARATOR;
49 static const char* ga_backupPath = default_backupPath;
51 static const char *opt_nodegroup_map_str= 0;
52 static unsigned opt_nodegroup_map_len= 0;
54 #define OPT_NDB_NODEGROUP_MAP 'z'
56 const char *opt_ndb_database= NULL;
57 const char *opt_ndb_table= NULL;
58 unsigned int opt_verbose;
59 unsigned int opt_hex_format;
60 unsigned int opt_progress_frequency;
61 NDB_TICKS g_report_next;
68 unsigned int opt_no_binlog;
79 static void save_include_exclude(
int optid,
char * argument);
81 static inline void parse_rewrite_database(
char * argument);
86 static bool ga_restore_epoch =
false;
87 static bool ga_restore =
false;
88 static bool ga_print =
false;
89 static bool ga_skip_table_check =
false;
90 static bool ga_exclude_missing_columns =
false;
91 static int _print = 0;
92 static int _print_meta = 0;
93 static int _print_data = 0;
94 static int _print_log = 0;
95 static int _restore_data = 0;
96 static int _restore_meta = 0;
97 static int _no_restore_disk = 0;
98 static bool _preserve_trailing_spaces =
false;
99 static bool ga_disable_indexes =
false;
100 static bool ga_rebuild_indexes =
false;
101 bool ga_skip_unknown_objects =
false;
102 bool ga_skip_broken_objects =
false;
105 const char *load_default_groups[]= {
"mysql_cluster",
"ndb_restore",0 };
107 enum ndb_restore_options {
108 OPT_VERBOSE = NDB_STD_OPTIONS_LAST,
111 OPT_INCLUDE_DATABASES,
112 OPT_EXCLUDE_DATABASES,
115 static const char *opt_fields_enclosed_by= NULL;
116 static const char *opt_fields_terminated_by= NULL;
117 static const char *opt_fields_optionally_enclosed_by= NULL;
118 static const char *opt_lines_terminated_by= NULL;
120 static const char *tab_path= NULL;
121 static int opt_append;
122 static const char *opt_exclude_tables= NULL;
123 static const char *opt_include_tables= NULL;
124 static const char *opt_exclude_databases= NULL;
125 static const char *opt_include_databases= NULL;
126 static const char *opt_rewrite_database= NULL;
127 static bool opt_restore_privilege_tables =
false;
129 static struct my_option my_long_options[] =
131 NDB_STD_OPTS(
"ndb_restore"),
132 {
"connect",
'c',
"same as --connect-string",
133 (uchar**) &opt_ndb_connectstring, (uchar**) &opt_ndb_connectstring, 0,
134 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
135 {
"nodeid",
'n',
"Backup files from node with id",
136 (uchar**) &ga_nodeId, (uchar**) &ga_nodeId, 0,
137 GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
138 {
"backupid",
'b',
"Backup id",
139 (uchar**) &ga_backupId, (uchar**) &ga_backupId, 0,
140 GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
141 {
"restore_data",
'r',
142 "Restore table data/logs into NDB Cluster using NDBAPI",
143 (uchar**) &_restore_data, (uchar**) &_restore_data, 0,
144 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
145 {
"restore_meta",
'm',
146 "Restore meta data into NDB Cluster using NDBAPI",
147 (uchar**) &_restore_meta, (uchar**) &_restore_meta, 0,
148 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
150 "Don't upgrade array type for var attributes, which don't resize VAR data and don't change column attributes",
151 (uchar**) &ga_no_upgrade, (uchar**) &ga_no_upgrade, 0,
152 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
153 {
"promote-attributes",
'A',
154 "Allow attributes to be promoted when restoring data from backup",
155 (uchar**) &ga_promote_attributes, (uchar**) &ga_promote_attributes, 0,
156 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
157 {
"lossy-conversions",
'L',
158 "Allow lossy conversions for attributes (type demotions or integral"
159 " signed/unsigned type changes) when restoring data from backup",
160 (uchar**) &ga_demote_attributes, (uchar**) &ga_demote_attributes, 0,
161 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
162 {
"preserve-trailing-spaces",
'P',
163 "Allow to preserve the tailing spaces (including paddings) When char->varchar or binary->varbinary is promoted",
164 (uchar**) &_preserve_trailing_spaces, (uchar**)_preserve_trailing_spaces , 0,
165 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
166 {
"no-restore-disk-objects",
'd',
167 "Dont restore disk objects (tablespace/logfilegroups etc)",
168 (uchar**) &_no_restore_disk, (uchar**) &_no_restore_disk, 0,
169 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
170 {
"restore_epoch",
'e',
171 "Restore epoch info into the status table. Convenient on a MySQL Cluster "
172 "replication slave, for starting replication. The row in "
173 NDB_REP_DB
"." NDB_APPLY_TABLE
" with id 0 will be updated/inserted.",
174 (uchar**) &ga_restore_epoch, (uchar**) &ga_restore_epoch, 0,
175 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
176 {
"skip-table-check",
's',
"Skip table structure check during restore of data",
177 (uchar**) &ga_skip_table_check, (uchar**) &ga_skip_table_check, 0,
178 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
179 {
"parallelism",
'p',
180 "No of parallel transactions during restore of data."
181 "(parallelism can be 1 to 1024)",
182 (uchar**) &ga_nParallelism, (uchar**) &ga_nParallelism, 0,
183 GET_INT, REQUIRED_ARG, 128, 1, 1024, 0, 1, 0 },
184 {
"print", NDB_OPT_NOSHORT,
"Print metadata, data and log to stdout",
185 (uchar**) &_print, (uchar**) &_print, 0,
186 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
187 {
"print_data", NDB_OPT_NOSHORT,
"Print data to stdout",
188 (uchar**) &_print_data, (uchar**) &_print_data, 0,
189 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
190 {
"print_meta", NDB_OPT_NOSHORT,
"Print meta data to stdout",
191 (uchar**) &_print_meta, (uchar**) &_print_meta, 0,
192 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
193 {
"print_log", NDB_OPT_NOSHORT,
"Print log to stdout",
194 (uchar**) &_print_log, (uchar**) &_print_log, 0,
195 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
196 {
"backup_path", NDB_OPT_NOSHORT,
"Path to backup files",
197 (uchar**) &ga_backupPath, (uchar**) &ga_backupPath, 0,
198 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
199 {
"dont_ignore_systab_0",
'f',
200 "Do not ignore system table during --print-data.",
201 (uchar**) &ga_dont_ignore_systab_0, (uchar**) &ga_dont_ignore_systab_0, 0,
202 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
203 {
"ndb-nodegroup-map", OPT_NDB_NODEGROUP_MAP,
204 "Nodegroup map for ndbcluster. Syntax: list of (source_ng, dest_ng)",
205 (uchar**) &opt_nodegroup_map_str,
206 (uchar**) &opt_nodegroup_map_str,
208 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
209 {
"fields-enclosed-by", NDB_OPT_NOSHORT,
210 "Fields are enclosed by ...",
211 (uchar**) &opt_fields_enclosed_by, (uchar**) &opt_fields_enclosed_by, 0,
212 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
213 {
"fields-terminated-by", NDB_OPT_NOSHORT,
214 "Fields are terminated by ...",
215 (uchar**) &opt_fields_terminated_by,
216 (uchar**) &opt_fields_terminated_by, 0,
217 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
218 {
"fields-optionally-enclosed-by", NDB_OPT_NOSHORT,
219 "Fields are optionally enclosed by ...",
220 (uchar**) &opt_fields_optionally_enclosed_by,
221 (uchar**) &opt_fields_optionally_enclosed_by, 0,
222 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
223 {
"hex", NDB_OPT_NOSHORT,
"print binary types in hex format",
224 (uchar**) &opt_hex_format, (uchar**) &opt_hex_format, 0,
225 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
226 {
"tab",
'T',
"Creates tab separated textfile for each table to "
227 "given path. (creates .txt files)",
228 (uchar**) &tab_path, (uchar**) &tab_path, 0,
229 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
230 {
"append", NDB_OPT_NOSHORT,
"for --tab append data to file",
231 (uchar**) &opt_append, (uchar**) &opt_append, 0,
232 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
233 {
"lines-terminated-by", NDB_OPT_NOSHORT,
"",
234 (uchar**) &opt_lines_terminated_by, (uchar**) &opt_lines_terminated_by, 0,
235 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
236 {
"progress-frequency", NDB_OPT_NOSHORT,
237 "Print status uf restore periodically in given seconds",
238 (uchar**) &opt_progress_frequency, (uchar**) &opt_progress_frequency, 0,
239 GET_INT, REQUIRED_ARG, 0, 0, 65535, 0, 0, 0 },
240 {
"no-binlog", NDB_OPT_NOSHORT,
241 "If a mysqld is connected and has binary log, do not log the restored data",
242 (uchar**) &opt_no_binlog, (uchar**) &opt_no_binlog, 0,
243 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
244 {
"verbose", OPT_VERBOSE,
246 (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
247 GET_INT, REQUIRED_ARG, 1, 0, 255, 0, 0, 0 },
248 {
"include-databases", OPT_INCLUDE_DATABASES,
249 "Comma separated list of databases to restore. Example: db1,db3",
250 (uchar**) &opt_include_databases, (uchar**) &opt_include_databases, 0,
251 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
252 {
"exclude-databases", OPT_EXCLUDE_DATABASES,
253 "Comma separated list of databases to not restore. Example: db1,db3",
254 (uchar**) &opt_exclude_databases, (uchar**) &opt_exclude_databases, 0,
255 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
256 {
"rewrite-database", OPT_REWRITE_DATABASE,
257 "A pair 'source,dest' of database names from/into which to restore. "
258 "Example: --rewrite-database=oldDb,newDb",
259 (uchar**) &opt_rewrite_database, (uchar**) &opt_rewrite_database, 0,
260 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
261 {
"include-tables", OPT_INCLUDE_TABLES,
"Comma separated list of tables to "
262 "restore. Table name should include database name. Example: db1.t1,db3.t1",
263 (uchar**) &opt_include_tables, (uchar**) &opt_include_tables, 0,
264 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
265 {
"exclude-tables", OPT_EXCLUDE_TABLES,
"Comma separated list of tables to "
266 "not restore. Table name should include database name. "
267 "Example: db1.t1,db3.t1",
268 (uchar**) &opt_exclude_tables, (uchar**) &opt_exclude_tables, 0,
269 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
270 {
"restore-privilege-tables", NDB_OPT_NOSHORT,
271 "Restore privilege tables (after they have been moved to ndb)",
272 (uchar**) &opt_restore_privilege_tables,
273 (uchar**) &opt_restore_privilege_tables, 0,
274 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
275 {
"exclude-missing-columns", NDB_OPT_NOSHORT,
276 "Ignore columns present in backup but not in database",
277 (uchar**) &ga_exclude_missing_columns,
278 (uchar**) &ga_exclude_missing_columns, 0,
279 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
280 {
"disable-indexes", NDB_OPT_NOSHORT,
282 (uchar**) &ga_disable_indexes,
283 (uchar**) &ga_disable_indexes, 0,
284 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
285 {
"rebuild-indexes", NDB_OPT_NOSHORT,
287 (uchar**) &ga_rebuild_indexes,
288 (uchar**) &ga_rebuild_indexes, 0,
289 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
290 {
"skip-unknown-objects", 256,
"Skip unknown object when parsing backup",
291 (uchar**) &ga_skip_unknown_objects, (uchar**) &ga_skip_unknown_objects, 0,
292 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
293 {
"skip-broken-objects", 256,
"Skip broken object when parsing backup",
294 (uchar**) &ga_skip_broken_objects, (uchar**) &ga_skip_broken_objects, 0,
295 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
296 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
300 static char* analyse_one_map(
char *map_str, uint16 *source, uint16 *dest)
304 DBUG_ENTER(
"analyse_one_map");
309 while (isspace(*map_str)) map_str++;
317 while (isspace(*map_str)) map_str++;
319 number= strtol(map_str, &end_ptr, 10);
320 if (!end_ptr || number < 0 || number >= MAX_NODE_GROUP_MAPS)
324 *source= (uint16)number;
327 while (isspace(*map_str)) map_str++;
335 number= strtol(map_str, &end_ptr, 10);
336 if (!end_ptr || number < 0 || number >= NDB_UNDEF_NODEGROUP)
340 *dest= (uint16)number;
349 while (isspace(*map_str)) map_str++;
350 DBUG_RETURN(map_str);
354 uint16 source_ng, uint16 dest_ng)
356 uint
index= source_ng;
357 uint ng_index= ng_map[
index].no_maps;
359 opt_nodegroup_map_len++;
360 if (ng_index >= MAX_MAPS_PER_NODE_GROUP)
362 ng_map[
index].no_maps++;
363 ng_map[
index].map_array[ng_index]= dest_ng;
367 static void init_nodegroup_map()
372 for (i = 0; i < MAX_NODE_GROUP_MAPS; i++)
374 ng_map[
i].no_maps= 0;
375 for (j= 0; j < MAX_MAPS_PER_NODE_GROUP; j++)
376 ng_map[i].map_array[j]= NDB_UNDEF_NODEGROUP;
380 static bool analyse_nodegroup_map(
const char *ng_map_str,
383 uint16 source_ng, dest_ng;
384 char *local_str= (
char*)ng_map_str;
385 DBUG_ENTER(
"analyse_nodegroup_map");
393 local_str= analyse_one_map(local_str, &source_ng, &dest_ng);
398 if (insert_ng_map(ng_map, source_ng, dest_ng))
408 static void short_usage_sub(
void)
410 ndb_short_usage_sub(
"[<path to backup files>]");
414 ndb_usage(short_usage_sub, load_default_groups, my_long_options);
418 get_one_option(
int optid,
const struct my_option *opt __attribute__((unused)),
422 opt_debug=
"d:t:O,/tmp/ndb_restore.trace";
424 ndb_std_get_one_option(optid, opt, argument);
427 info.setThreshold(255-opt_verbose);
432 err <<
"Error in --nodeid,-n setting, see --help";
433 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
436 info <<
"Nodeid = " << ga_nodeId << endl;
439 if (ga_backupId == 0)
441 err <<
"Error in --backupid,-b setting, see --help";
442 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
445 info <<
"Backup Id = " << ga_backupId << endl;
447 case OPT_NDB_NODEGROUP_MAP:
452 opt_nodegroup_map_len= 0;
455 info <<
"Analyse node group map" << endl;
456 if (analyse_nodegroup_map(opt_nodegroup_map_str,
457 &opt_nodegroup_map[0]))
459 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
462 case OPT_INCLUDE_DATABASES:
463 case OPT_EXCLUDE_DATABASES:
464 case OPT_INCLUDE_TABLES:
465 case OPT_EXCLUDE_TABLES:
466 save_include_exclude(optid, argument);
468 case OPT_REWRITE_DATABASE:
469 parse_rewrite_database(argument);
475 static const char* SCHEMA_NAME=
"/def/";
476 static const int SCHEMA_NAME_SIZE= 5;
479 makeInternalTableName(
const BaseString &externalName,
486 if (externalName.
indexOf(
'.') == -1)
488 externalName.
split(parts,
".");
490 if (parts.size() != 2)
492 internalName.
clear();
493 internalName.
append(parts[0]);
494 internalName.
append(SCHEMA_NAME);
495 internalName.
append(parts[1]);
508 for (i=0; i < tmp.size(); i++)
511 if (makeInternalTableName(tmp[i], internalName))
513 info <<
"`" << tmp[
i] <<
"` is not a valid tablename!" << endl;
514 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
516 lst.push_back(internalName);
521 makeExternalTableName(
const BaseString &internalName)
526 ssize_t idx = internalName.
indexOf(
'/');
527 externalName = internalName.
substr(0,idx);
529 externalName.
append(internalName.
substr(idx + SCHEMA_NAME_SIZE,
534 #include "../../../../sql/ndb_dist_priv_util.h"
538 exclude_privilege_tables()
542 while((table_name= dist_priv.iter_next_table()))
546 g_exclude_tables.push_back(priv_tab);
547 save_include_exclude(OPT_EXCLUDE_TABLES, (
char *)priv_tab.
c_str());
553 readArguments(
int *pargc,
char*** pargv)
557 debug <<
"Load defaults" << endl;
558 const char *load_default_groups[]= {
"mysql_cluster",
"ndb_restore",0 };
560 init_nodegroup_map();
561 load_defaults(
"my",load_default_groups,pargc,pargv);
562 debug <<
"handle_options" << endl;
564 ndb_opt_set_usage_funcs(short_usage_sub, usage);
566 if (handle_options(pargc, pargv, my_long_options, get_one_option))
568 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
570 for (i = 0; i < MAX_NODE_GROUP_MAPS; i++)
571 opt_nodegroup_map[i].curr_index = 0;
578 printf(
"Handled options successfully\n");
581 for (j = 0; j < 4; j++)
583 for (i = 0; i < 4 ; i++)
585 map_nodegroups(&map_ng[0], (Uint32)4);
586 for (i = 0; i < 4 ; i++)
587 printf(
"NG %u mapped to %u \n", i, map_ng[i]);
589 for (j = 0; j < 4; j++)
591 for (i = 0; i < 8 ; i++)
593 map_nodegroups(&map_ng[0], (Uint32)8);
594 for (i = 0; i < 8 ; i++)
595 printf(
"NG %u mapped to %u \n", i >> 1, map_ng[i]);
597 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
601 opt_nodegroup_map_len);
602 if (g_printer == NULL)
608 opt_nodegroup_map_len,
621 g_printer->m_print =
true;
626 g_printer->m_print_meta =
true;
631 g_printer->m_print_data =
true;
636 g_printer->m_print_log =
true;
642 restore->m_restore =
true;
648 restore->m_restore_meta =
true;
651 if (_no_restore_disk)
653 restore->m_no_restore_disk =
true;
658 restore->m_no_upgrade =
true;
661 if (_preserve_trailing_spaces)
663 restore->m_preserve_trailing_spaces =
true;
666 if (ga_restore_epoch)
668 restore->m_restore_epoch =
true;
671 if (ga_disable_indexes)
673 restore->m_disable_indexes =
true;
676 if (ga_rebuild_indexes)
678 restore->m_rebuild_indexes =
true;
683 g_consumers.push_back(c);
687 g_consumers.push_back(c);
692 if (ga_backupPath == default_backupPath)
695 if ((*pargv)[i] == NULL)
697 ga_backupPath = (*pargv)[i++];
699 if ((*pargv)[i] == NULL)
701 g_databases.push_back((*pargv)[i++]);
702 while ((*pargv)[i] != NULL)
704 g_tables.push_back((*pargv)[i++]);
709 info <<
"backup path = " << ga_backupPath << endl;
710 if (g_databases.size() > 0)
712 info <<
"WARNING! Using deprecated syntax for selective object restoration." << endl;
713 info <<
"Please use --include-*/--exclude-* options in future." << endl;
714 info <<
"Restoring only from database " << g_databases[0].c_str() << endl;
715 if (g_tables.size() > 0)
717 info <<
"Restoring tables:";
719 for (
unsigned i= 0; i < g_tables.size(); i++)
721 info <<
" " << g_tables[
i].c_str();
723 if (g_tables.size() > 0)
730 if (!opt_restore_privilege_tables)
731 exclude_privilege_tables();
734 if (g_databases.size() > 0)
737 tab_prefix.
append(g_databases[0].c_str());
739 if (g_tables.size() == 0)
741 g_include_databases.push_back(g_databases[0]);
742 save_include_exclude(OPT_INCLUDE_DATABASES,
743 (
char *)g_databases[0].c_str());
745 for (
unsigned i= 0; i < g_tables.size(); i++)
749 g_include_tables.push_back(tab);
750 save_include_exclude(OPT_INCLUDE_TABLES, (
char *)tab.
c_str());
755 if (opt_include_databases)
758 tmp.
split(g_include_databases,
",");
759 info <<
"Including Databases: ";
760 for (i= 0; i < g_include_databases.size(); i++)
762 info << g_include_databases[
i] <<
" ";
767 if (opt_exclude_databases)
770 tmp.
split(g_exclude_databases,
",");
771 info <<
"Excluding databases: ";
772 for (i= 0; i < g_exclude_databases.size(); i++)
774 info << g_exclude_databases[
i] <<
" ";
779 if (opt_rewrite_database)
781 info <<
"Rewriting databases:";
784 for (src = it.first(); src != NULL; src = it.next()) {
785 const char * dst = NULL;
786 bool r = g_rewrite_databases.get(src, &dst);
787 assert(r && (dst != NULL));
788 info <<
" (" << src <<
"->" << dst <<
")";
793 if (opt_include_tables)
795 processTableList(opt_include_tables, g_include_tables);
796 info <<
"Including tables: ";
797 for (i= 0; i < g_include_tables.size(); i++)
799 info << makeExternalTableName(g_include_tables[i]).
c_str() <<
" ";
804 if (opt_exclude_tables)
806 processTableList(opt_exclude_tables, g_exclude_tables);
807 info <<
"Excluding tables: ";
808 for (i= 0; i < g_exclude_tables.size(); i++)
810 info << makeExternalTableName(g_exclude_tables[i]).
c_str() <<
" ";
819 g_ndbrecord_print_format.fields_enclosed_by=
820 opt_fields_enclosed_by ? opt_fields_enclosed_by :
"";
821 g_ndbrecord_print_format.fields_terminated_by=
822 opt_fields_terminated_by ? opt_fields_terminated_by :
"\t";
823 g_ndbrecord_print_format.fields_optionally_enclosed_by=
824 opt_fields_optionally_enclosed_by ? opt_fields_optionally_enclosed_by :
"";
825 g_ndbrecord_print_format.lines_terminated_by=
826 opt_lines_terminated_by ? opt_lines_terminated_by :
"\n";
827 if (g_ndbrecord_print_format.fields_optionally_enclosed_by[0] ==
'\0')
828 g_ndbrecord_print_format.null_string=
"\\N";
830 g_ndbrecord_print_format.null_string=
"";
831 g_ndbrecord_print_format.hex_prefix=
"";
832 g_ndbrecord_print_format.hex_format= opt_hex_format;
834 if (ga_skip_table_check)
836 g_tableCompabilityMask = ~(Uint32)0;
837 ga_skip_unknown_objects =
true;
840 if (ga_promote_attributes)
842 g_tableCompabilityMask |= TCM_ATTRIBUTE_PROMOTION;
845 if (ga_demote_attributes)
847 g_tableCompabilityMask |= TCM_ATTRIBUTE_DEMOTION;
850 if (ga_exclude_missing_columns)
852 g_tableCompabilityMask |= TCM_EXCLUDE_MISSING_COLUMNS;
860 for(Uint32 i= 0; i<g_consumers.size(); i++)
861 delete g_consumers[i];
868 return ! table->getSysTable();
874 assert(i < metaData.getNoOfTables());
875 return checkSysTable(metaData[i]);
879 isBlobTable(
const TableS* table)
881 return table->getMainTable() != NULL;
885 isIndex(
const TableS* table)
887 const NdbTableImpl & tmptab = NdbTableImpl::getImpl(* table->m_dictTable);
892 isSYSTAB_0(
const TableS* table)
894 return table->isSYSTAB_0();
900 for (i= 0; i < lst.size(); i++)
902 if (strcmp(needle.
c_str(), lst[
i].c_str()) == 0)
909 getTableName(
const TableS* table)
912 if (isBlobTable(table))
913 table_name= table->getMainTable()->getTableName();
914 else if (isIndex(table))
918 table_name= table->getTableName();
923 static void parse_rewrite_database(
char * argument)
927 unsigned int n = arg.split(args,
",");
929 && (args[0].length() > 0)
930 && (args[1].length() > 0)) {
934 bool r = g_rewrite_databases.
put(src.
c_str(), dst.
c_str(), replace);
939 info <<
"argument `" << arg.c_str()
940 <<
"` is not a pair 'a,b' of non-empty names." << endl;
941 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
944 static void save_include_exclude(
int optid,
char * argument)
948 arg.
split(args,
",");
949 for (uint i = 0; i < args.size(); i++)
954 option->optid = optid;
956 case OPT_INCLUDE_TABLES:
957 case OPT_EXCLUDE_TABLES:
958 if (makeInternalTableName(args[i], arg))
960 info <<
"`" << args[
i] <<
"` is not a valid tablename!" << endl;
961 exit(NDBT_ProgramExit(NDBT_WRONGARGS));
968 option->argument = arg;
969 g_include_exclude.push_back(option);
974 const char * db = database.
c_str();
975 const char * tbl = table.
c_str();
976 bool do_include =
true;
978 if (g_include_databases.size() != 0 ||
979 g_include_tables.size() != 0)
989 (g_exclude_databases.size() != 0 ||
990 g_exclude_tables.size() != 0))
1002 if (g_include_exclude.size() != 0)
1009 for(uint i = g_include_exclude.size(); i > 0; i--)
1012 switch (option->optid) {
1013 case OPT_INCLUDE_TABLES:
1014 if (strcmp(tbl, option->argument.
c_str()) == 0)
1017 case OPT_EXCLUDE_TABLES:
1018 if (strcmp(tbl, option->argument.
c_str()) == 0)
1021 case OPT_INCLUDE_DATABASES:
1022 if (strcmp(db, option->argument.
c_str()) == 0)
1025 case OPT_EXCLUDE_DATABASES:
1026 if (strcmp(db, option->argument.
c_str()) == 0)
1039 checkDoRestore(
const TableS* table)
1044 tbl.
assign(getTableName(table));
1045 ssize_t idx = tbl.
indexOf(
'/');
1057 ret = check_include_exclude(db, tbl);
1062 checkDbAndTableName(
const TableS* table)
1064 if (table->isBroken())
1068 if (opt_include_tables || g_exclude_tables.size() > 0 ||
1069 opt_include_databases || opt_exclude_databases ) {
1070 return (checkDoRestore(table));
1073 if (g_tables.size() == 0 && g_databases.size() == 0)
1076 if (g_databases.size() == 0)
1077 g_databases.push_back(
"TEST_DB");
1080 const char *table_name= getTableName(table);
1083 for (i= 0; i < g_databases.size(); i++)
1085 if (strncmp(table_name, g_databases[i].c_str(),
1086 g_databases[i].length()) == 0 &&
1087 table_name[g_databases[
i].length()] ==
'/')
1090 if (g_databases.size() > 1 || g_tables.size() == 0)
1095 if (i == g_databases.size())
1098 while (*table_name !=
'/') table_name++;
1100 while (*table_name !=
'/') table_name++;
1104 for (i= 0; i < g_tables.size(); i++)
1106 if (strcmp(table_name, g_tables[i].c_str()) == 0)
1113 free_data_callback()
1115 for(Uint32 i= 0; i < g_consumers.size(); i++)
1116 g_consumers[i]->tuple_free();
1119 static void exitHandler(
int code)
1121 NDBT_ProgramExit(code);
1128 static void init_progress()
1130 Uint64 now = NdbTick_CurrentMillisecond() / 1000;
1131 g_report_next = now + opt_progress_frequency;
1134 static int check_progress()
1136 if (!opt_progress_frequency)
1139 NDB_TICKS now = NdbTick_CurrentMillisecond() / 1000;
1141 if (now >= g_report_next)
1143 g_report_next = now + opt_progress_frequency;
1149 static void report_progress(
const char *prefix,
const BackupFile &f)
1152 if (f.get_file_size())
1153 info << prefix << (f.get_file_pos() * 100 + f.get_file_size()-1) / f.get_file_size()
1154 <<
"%(" << f.get_file_pos() <<
" bytes)\n";
1156 info << prefix << f.get_file_pos() <<
" bytes\n";
1163 check_data_truncations(
const TableS * table)
1166 const char * tname = table->getTableName();
1167 const int n = table->getNoOfAttributes();
1168 for (
int i = 0; i <
n; i++) {
1170 if (desc->truncation_detected) {
1171 const char * cname = desc->m_column->
getName();
1173 info <<
"Data truncation(s) detected for attribute: "
1174 << tname <<
"." << cname << endl;
1175 desc->truncation_detected =
false;
1181 main(
int argc,
char** argv)
1185 debug <<
"Start readArguments" << endl;
1186 if (!readArguments(&argc, &argv))
1188 exitHandler(NDBT_FAILED);
1191 g_options.
appfmt(
" -b %u", ga_backupId);
1192 g_options.
appfmt(
" -n %d", ga_nodeId);
1197 if (ga_promote_attributes)
1199 if (ga_demote_attributes)
1201 if (_preserve_trailing_spaces)
1203 if (ga_skip_table_check)
1207 if (ga_restore_epoch)
1209 if (_no_restore_disk)
1211 if (ga_exclude_missing_columns)
1212 g_options.
append(
" --exclude-missing-columns");
1213 if (ga_disable_indexes)
1214 g_options.
append(
" --disable-indexes");
1215 if (ga_rebuild_indexes)
1216 g_options.
append(
" --rebuild-indexes");
1217 g_options.
appfmt(
" -p %d", ga_nParallelism);
1218 if (ga_skip_unknown_objects)
1219 g_options.
append(
" --skip-unknown-objects");
1220 if (ga_skip_broken_objects)
1221 g_options.
append(
" --skip-broken-objects");
1228 debug <<
"Start restoring meta data" << endl;
1230 if (!metaData.readHeader())
1232 err <<
"Failed to read " << metaData.getFilename() << endl << endl;
1233 exitHandler(NDBT_FAILED);
1237 const Uint32 version = tmp.BackupVersion;
1239 char buf[NDB_VERSION_STRING_BUF_SZ];
1241 info <<
"Backup version in files: "
1242 << ndbGetVersionString(version, 0,
1243 isDrop6(version) ?
"-drop6" : 0,
1245 if (version >= NDBD_RAW_LCP)
1247 info <<
" ndb version: "
1248 << ndbGetVersionString(tmp.NdbVersion, tmp.MySQLVersion, 0,
1259 if (version >= MAKE_VERSION(5,1,3) && version <= MAKE_VERSION(5,1,9))
1261 err <<
"Restore program incompatible with backup versions between "
1262 << ndbGetVersionString(MAKE_VERSION(5,1,3), 0, 0, buf,
sizeof(buf))
1264 << ndbGetVersionString(MAKE_VERSION(5,1,9), 0, 0, buf,
sizeof(buf))
1266 exitHandler(NDBT_FAILED);
1269 if (version > NDB_VERSION)
1271 err <<
"Restore program older than backup version. Not supported. "
1272 <<
"Use new restore program" << endl;
1273 exitHandler(NDBT_FAILED);
1276 debug <<
"Load content" << endl;
1277 int res = metaData.loadContent();
1279 info <<
"Stop GCP of Backup: " << metaData.getStopGCP() << endl;
1283 err <<
"Restore: Failed to load content" << endl;
1284 exitHandler(NDBT_FAILED);
1286 debug <<
"Get no of Tables" << endl;
1287 if (metaData.getNoOfTables() == 0)
1289 err <<
"The backup contains no tables" << endl;
1290 exitHandler(NDBT_FAILED);
1292 debug <<
"Validate Footer" << endl;
1294 if (!metaData.validateFooter())
1296 err <<
"Restore: Failed to validate footer." << endl;
1297 exitHandler(NDBT_FAILED);
1299 debug <<
"Init Backup objects" << endl;
1301 for(i= 0; i < g_consumers.size(); i++)
1303 if (!g_consumers[i]->init(g_tableCompabilityMask))
1306 err <<
"Failed to initialize consumers" << endl;
1307 exitHandler(NDBT_FAILED);
1313 for (i = 0; i < g_consumers.size(); i++)
1314 g_consumers[i]->report_started(ga_backupId, ga_nodeId);
1316 debug <<
"Restore objects (tablespaces, ..)" << endl;
1317 for(i = 0; i<metaData.getNoOfObjects(); i++)
1319 for(Uint32 j= 0; j < g_consumers.size(); j++)
1320 if (!g_consumers[j]->
object(metaData.getObjType(i),
1321 metaData.getObjPtr(i)))
1323 err <<
"Restore: Failed to restore table: ";
1324 err << metaData[
i]->getTableName() <<
" ... Exiting " << endl;
1325 exitHandler(NDBT_FAILED);
1327 if (check_progress())
1330 info <<
"Object create progress: "
1331 << i+1 <<
" objects out of "
1332 << metaData.getNoOfObjects() << endl;
1337 debug <<
"Restoring tables" << endl;
1338 for(i = 0; i<metaData.getNoOfTables(); i++)
1340 const TableS *table= metaData[
i];
1341 table_output.push_back(NULL);
1342 if (!checkDbAndTableName(table))
1344 if (isSYSTAB_0(table))
1346 table_output[
i]= ndbout.m_out;
1348 if (checkSysTable(table))
1350 if (!tab_path || isBlobTable(table) || isIndex(table))
1352 table_output[
i]= ndbout.m_out;
1357 char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1359 table_name= table->getTableName();
1360 while (*table_name !=
'/') table_name++;
1362 while (*table_name !=
'/') table_name++;
1364 convert_dirname(tmp_path, tab_path, NullS);
1365 res= my_fopen(fn_format(filename, table_name, tmp_path,
".txt", 4),
1367 O_WRONLY|O_APPEND|O_CREAT :
1368 O_WRONLY|O_TRUNC|O_CREAT,
1372 exitHandler(NDBT_FAILED);
1377 for(Uint32 j= 0; j < g_consumers.size(); j++)
1378 if (!g_consumers[j]->
table(* table))
1380 err <<
"Restore: Failed to restore table: `";
1381 err << table->getTableName() <<
"` ... Exiting " << endl;
1382 exitHandler(NDBT_FAILED);
1385 for(Uint32 j= 0; j < g_consumers.size(); j++)
1386 if (!g_consumers[j]->createSystable(* table))
1388 err <<
"Restore: Failed to restore system table: ";
1389 err << table->getTableName() <<
" ... Exiting " << endl;
1390 exitHandler(NDBT_FAILED);
1393 if (check_progress())
1396 info <<
"Table create progress: "
1397 << i+1 <<
" tables out of "
1398 << metaData.getNoOfTables() << endl;
1401 debug <<
"Close tables" << endl;
1402 for(i= 0; i < g_consumers.size(); i++)
1403 if (!g_consumers[i]->endOfTables())
1405 err <<
"Restore: Failed while closing tables" << endl;
1406 exitHandler(NDBT_FAILED);
1409 for(i= 0; i < g_consumers.size(); i++)
1411 g_consumers[
i]->report_meta_data(ga_backupId, ga_nodeId);
1413 debug <<
"Iterate over data" << endl;
1414 if (ga_restore || ga_print)
1416 if(_restore_data || _print_data)
1419 for (i=0; i < metaData.getNoOfTables(); i++){
1420 if (checkSysTable(metaData, i) &&
1421 checkDbAndTableName(metaData[i]))
1423 for(Uint32 j= 0; j < g_consumers.size(); j++)
1425 if (!g_consumers[j]->table_compatible_check(*metaData[i]))
1427 err <<
"Restore: Failed to restore data, ";
1428 err << metaData[
i]->getTableName() <<
" table structure incompatible with backup's ... Exiting " << endl;
1429 exitHandler(NDBT_FAILED);
1437 if (!dataIter.readHeader())
1439 err <<
"Failed to read header of data file. Exiting..." << endl;
1440 exitHandler(NDBT_FAILED);
1444 while (dataIter.readFragmentHeader(res= 0, &fragmentId))
1447 while ((tuple = dataIter.getNextTuple(res= 1)) != 0)
1449 const TableS* table = tuple->getTable();
1450 OutputStream *output = table_output[table->getLocalId()];
1454 ndbout.m_out = output;
1455 for(Uint32 j= 0; j < g_consumers.size(); j++)
1456 g_consumers[j]->
tuple(* tuple, fragmentId);
1458 if (check_progress())
1459 report_progress(
"Data file progress: ", dataIter);
1464 err <<
" Restore: An error occured while restoring data. Exiting...";
1466 exitHandler(NDBT_FAILED);
1468 if (!dataIter.validateFragmentFooter()) {
1469 err <<
"Restore: Error validating fragment footer. ";
1470 err <<
"Exiting..." << endl;
1471 exitHandler(NDBT_FAILED);
1477 err <<
"Restore: An error occured while restoring data. Exiting... "
1478 <<
"res= " << res << endl;
1479 exitHandler(NDBT_FAILED);
1483 dataIter.validateFooter();
1485 for (i= 0; i < g_consumers.size(); i++)
1486 g_consumers[i]->endOfTuples();
1489 for(i= 0; i < g_consumers.size(); i++)
1491 g_consumers[
i]->report_data(ga_backupId, ga_nodeId);
1495 if(_restore_data || _print_log)
1498 if (!logIter.readHeader())
1500 err <<
"Failed to read header of data file. Exiting..." << endl;
1501 exitHandler(NDBT_FAILED);
1505 while ((logEntry = logIter.getNextLogEntry(res= 0)) != 0)
1507 const TableS* table = logEntry->m_table;
1508 OutputStream *output = table_output[table->getLocalId()];
1511 for(Uint32 j= 0; j < g_consumers.size(); j++)
1512 g_consumers[j]->logEntry(* logEntry);
1514 if (check_progress())
1515 report_progress(
"Log file progress: ", logIter);
1519 err <<
"Restore: An restoring the data log. Exiting... res="
1521 exitHandler(NDBT_FAILED);
1523 logIter.validateFooter();
1524 for (i= 0; i < g_consumers.size(); i++)
1525 g_consumers[i]->endOfLogEntrys();
1528 for(i= 0; i < g_consumers.size(); i++)
1530 g_consumers[
i]->report_log(ga_backupId, ga_nodeId);
1536 for(i = 0; i < metaData.getNoOfTables(); i++)
1538 const TableS* table = metaData[
i];
1539 check_data_truncations(table);
1540 OutputStream *output = table_output[table->getLocalId()];
1543 for(Uint32 j= 0; j < g_consumers.size(); j++)
1544 if (!g_consumers[j]->finalize_table(*table))
1546 err <<
"Restore: Failed to finalize restore table: %s. ";
1547 err <<
"Exiting... " << metaData[
i]->getTableName() << endl;
1548 exitHandler(NDBT_FAILED);
1553 if (ga_restore_epoch)
1555 for (i= 0; i < g_consumers.size(); i++)
1556 if (!g_consumers[i]->update_apply_status(metaData))
1558 err <<
"Restore: Failed to restore epoch" << endl;
1564 for(j= 0; j < g_consumers.size(); j++)
1566 if (g_consumers[j]->has_temp_error())
1569 ndbout_c(
"\nRestore successful, but encountered temporary error, "
1570 "please look at configuration.");
1574 if (ga_rebuild_indexes)
1576 debug <<
"Rebuilding indexes" << endl;
1577 for(i = 0; i<metaData.getNoOfTables(); i++)
1579 const TableS *table= metaData[
i];
1580 if (! (checkSysTable(table) && checkDbAndTableName(table)))
1582 if (isBlobTable(table) || isIndex(table))
1584 for(Uint32 j= 0; j < g_consumers.size(); j++)
1586 if (!g_consumers[j]->rebuild_indexes(* table))
1593 for (i = 0; i < g_consumers.size(); i++)
1594 g_consumers[i]->report_completed(ga_backupId, ga_nodeId);
1598 for(i = 0; i < metaData.getNoOfTables(); i++)
1600 if (table_output[i] &&
1601 table_output[i] != ndbout.m_out)
1604 delete table_output[
i];
1605 table_output[
i] = NULL;
1610 return NDBT_ProgramExit(NDBT_OK);