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>
19 #include <ndb_limits.h>
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
;
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
,
84 OPT_FIELDS_ENCLOSED_BY
,
85 OPT_FIELDS_TERMINATED_BY
,
86 OPT_FIELDS_OPTIONALLY_ENCLOSED_BY
,
87 OPT_LINES_TERMINATED_BY
,
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 },
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
,
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
)
205 DBUG_ENTER("analyse_one_map");
207 Search for pattern ( source_ng , dest_ng )
210 while (isspace(*map_str
)) 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
)
225 *source
= (uint16
)number
;
228 while (isspace(*map_str
)) map_str
++;
236 number
= strtol(map_str
, &end_ptr
, 10);
237 if (!end_ptr
|| number
< 0 || number
>= UNDEF_NODEGROUP
)
241 *dest
= (uint16
)number
;
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
)
263 ng_map
[index
].no_maps
++;
264 ng_map
[index
].map_array
[ng_index
]= dest_ng
;
268 static void init_nodegroup_map()
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");
294 local_str
= analyse_one_map(local_str
, &source_ng
, &dest_ng
);
299 if (insert_ng_map(ng_map
, source_ng
, dest_ng
))
309 static void short_usage_sub(void)
311 printf("Usage: %s [OPTIONS] [<path to backup files>]\n", my_progname
);
316 ndb_std_print_version();
317 print_defaults(MYSQL_CONFIG_NAME
,load_default_groups
);
319 my_print_help(my_long_options
);
320 my_print_variables(my_long_options
);
323 get_one_option(int optid
, const struct my_option
*opt
__attribute__((unused
)),
327 opt_debug
= "d:t:O,/tmp/ndb_restore.trace";
329 ndb_std_get_one_option(optid
, opt
, argument
);
332 info
.setThreshold(255-opt_verbose
);
337 err
<< "Error in --nodeid,-n setting, see --help";
338 exit(NDBT_ProgramExit(NDBT_WRONGARGS
));
341 info
<< "Nodeid = " << ga_nodeId
<< endl
;
344 if (ga_backupId
== 0)
346 err
<< "Error in --backupid,-b setting, see --help";
347 exit(NDBT_ProgramExit(NDBT_WRONGARGS
));
350 info
<< "Backup Id = " << ga_backupId
<< endl
;
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;
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
));
371 readArguments(int *pargc
, char*** pargv
)
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;
390 o verify nodegroup mapping
392 printf("Handled options successfully\n");
395 for (j
= 0; j
< 4; j
++)
397 for (i
= 0; i
< 4 ; 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
++)
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
));
414 g_printer
= new BackupPrinter(opt_nodegroup_map
,
415 opt_nodegroup_map_len
);
416 if (g_printer
== NULL
)
419 BackupRestore
* restore
= new BackupRestore(opt_nodegroup_map
,
420 opt_nodegroup_map_len
,
433 g_printer
->m_print
= true;
438 g_printer
->m_print_meta
= true;
443 g_printer
->m_print_data
= true;
448 g_printer
->m_print_log
= true;
454 restore
->m_restore
= true;
459 // ga_restore = true;
460 restore
->m_restore_meta
= true;
463 if (_no_restore_disk
)
465 restore
->m_no_restore_disk
= true;
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
);
489 if (ga_backupPath
== default_backupPath
)
491 // Set backup file path
492 if ((*pargv
)[i
] == NULL
)
494 ga_backupPath
= (*pargv
)[i
++];
496 if ((*pargv
)[i
] == NULL
)
498 g_databases
.push_back((*pargv
)[i
++]);
499 while ((*pargv
)[i
] != NULL
)
501 g_tables
.push_back((*pargv
)[i
++]);
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)
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";
534 g_ndbrecord_print_format
.null_string
= "";
535 g_ndbrecord_print_format
.hex_prefix
= "";
536 g_ndbrecord_print_format
.hex_format
= opt_hex_format
;
543 for(Uint32 i
= 0; i
<g_consumers
.size(); i
++)
544 delete g_consumers
[i
];
549 checkSysTable(const TableS
* table
)
551 return ga_dont_ignore_systab_0
|| ! table
->getSysTable();
555 checkSysTable(const RestoreMetaData
& metaData
, uint i
)
557 assert(i
< metaData
.getNoOfTables());
558 return checkSysTable(metaData
[i
]);
562 isBlobTable(const TableS
* table
)
564 return table
->getMainTable() != NULL
;
568 isIndex(const TableS
* table
)
570 const NdbTableImpl
& tmptab
= NdbTableImpl::getImpl(* table
->m_dictTable
);
571 return (int) tmptab
.m_indexType
!= (int) NdbDictionary::Index::Undefined
;
575 checkDbAndTableName(const TableS
* table
)
577 if (g_tables
.size() == 0 &&
578 g_databases
.size() == 0)
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
))
589 NdbTableImpl::getImpl(*table
->m_dictTable
).m_primaryTable
.c_str();
591 table_name
= table
->getTableName();
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()] == '/')
601 if (g_databases
.size() > 1 || g_tables
.size() == 0)
606 if (i
== g_databases
.size())
607 return false; // no match found
609 while (*table_name
!= '/') table_name
++;
611 while (*table_name
!= '/') table_name
++;
614 for (i
= 0; i
< g_tables
.size(); i
++)
616 if (strcmp(table_name
, g_tables
[i
].c_str()) == 0)
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
);
643 main(int argc
, char** argv
)
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
);
656 g_options
.appfmt(" -m");
658 g_options
.appfmt(" -u");
659 if (ga_skip_table_check
)
660 g_options
.appfmt(" -s");
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
];
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
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
))
699 << ndbGetVersionString(MAKE_VERSION(5,1,9), 0, buf
, sizeof(buf
))
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();
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
;
734 for(i
= 0; i
< g_consumers
.size(); i
++)
736 if (!g_consumers
[i
]->init())
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
))
765 if (checkSysTable(table
))
767 if (!tab_path
|| isBlobTable(table
) || isIndex(table
))
769 table_output
[i
]= ndbout
.m_out
;
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
++;
779 while (*table_name
!= '/') table_name
++;
781 convert_dirname(tmp_path
, tab_path
, NullS
);
782 res
= my_fopen(fn_format(filename
, table_name
, tmp_path
, ".txt", 4),
784 O_WRONLY
|O_APPEND
|O_CREAT
:
785 O_WRONLY
|O_TRUNC
|O_CREAT
,
789 exitHandler(NDBT_FAILED
);
791 FileOutputStream
*f
= new FileOutputStream(res
);
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
);
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
);
847 while (dataIter
.readFragmentHeader(res
= 0, &fragmentId
))
850 while ((tuple
= dataIter
.getNextTuple(res
= 1)) != 0)
852 const TableS
* table
= tuple
->getTable();
853 OutputStream
*output
= table_output
[table
->getLocalId()];
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
);
861 } // while (tuple != NULL);
865 err
<<" Restore: An error occured while restoring data. Exiting...";
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))
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()];
906 for(Uint32 j
= 0; j
< g_consumers
.size(); j
++)
907 g_consumers
[j
]->logEntry(* logEntry
);
911 err
<< "Restore: An restoring the data log. Exiting... res="
913 exitHandler(NDBT_FAILED
);
915 logIter
.validateFooter(); //not implemented
916 for (i
= 0; i
< g_consumers
.size(); i
++)
917 g_consumers
[i
]->endOfLogEntrys();
922 for(i
= 0; i
<metaData
.getNoOfTables(); i
++)
924 const TableS
* table
= metaData
[i
];
925 OutputStream
*output
= table_output
[table
->getLocalId()];
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
;
948 for(Uint32 j
= 0; j
< g_consumers
.size(); j
++)
950 if (g_consumers
[j
]->has_temp_error())
953 ndbout_c("\nRestore successful, but encountered temporary error, "
954 "please look at configuration.");
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
;
972 return NDBT_ProgramExit(NDBT_OK
);
977 template class Vector
<BackupConsumer
*>;
978 template class Vector
<OutputStream
*>;