mariadb/ndb/tools/restore/main.cpp
tomas@poseidon.ndb.mysql.com 0d55af3f0e moved ndb_restore together with rest of the ndb tools
kernel includes needed by ndb_restore
    changed link order
    moved LocalConfig to mgmapi
    Moved NdbConfig to Portlib
    mgmapi to use LocalConfig for connectstring parsing instead of it's own
    enable usage of "NULL" connectstring for default
    new ndbmgmclient lib that can be used by e.g. mysqladmin later
    LocalConfig no longer needed here, now in mgmapi
    Send connectstring to mgmapi instead
    added valid connectstring to be with only host without port i.e.
    valid connectstring =host1,host2,host3
    default port will be added
2004-11-14 11:02:06 +00:00

398 lines
9.8 KiB
C++

/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <ndb_global.h>
#include <ndb_opts.h>
#include <Vector.hpp>
#include <ndb_limits.h>
#include <NdbTCP.h>
#include <NdbOut.hpp>
#include "consumer_restore.hpp"
#include "consumer_printer.hpp"
extern FilteredNdbOut err;
extern FilteredNdbOut info;
extern FilteredNdbOut debug;
static int ga_nodeId = 0;
static int ga_nParallelism = 128;
static int ga_backupId = 0;
static bool ga_dont_ignore_systab_0 = false;
static Vector<class BackupConsumer *> g_consumers;
static const char* ga_backupPath = "." DIR_SEPARATOR;
static const char* opt_connect_str= NULL;
/**
* print and restore flags
*/
static bool ga_restore = false;
static bool ga_print = false;
static int _print = 0;
static int _print_meta = 0;
static int _print_data = 0;
static int _print_log = 0;
static int _restore_data = 0;
static int _restore_meta = 0;
static struct my_option my_long_options[] =
{
NDB_STD_OPTS("ndb_restore"),
{ "connect", 'c', "same as --connect-string",
(gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "nodeid", 'n', "Backup files from node with id",
(gptr*) &ga_nodeId, (gptr*) &ga_nodeId, 0,
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "backupid", 'b', "Backup id",
(gptr*) &ga_backupId, (gptr*) &ga_backupId, 0,
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "restore_data", 'r',
"Restore table data/logs into NDB Cluster using NDBAPI",
(gptr*) &_restore_data, (gptr*) &_restore_data, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "restore_meta", 'm',
"Restore meta data into NDB Cluster using NDBAPI",
(gptr*) &_restore_meta, (gptr*) &_restore_meta, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "parallelism", 'p',
"No of parallel transactions during restore of data."
"(parallelism can be 1 to 1024)",
(gptr*) &ga_nParallelism, (gptr*) &ga_nParallelism, 0,
GET_INT, REQUIRED_ARG, 128, 0, 0, 0, 0, 0 },
{ "print", 256, "Print data and log to stdout",
(gptr*) &_print, (gptr*) &_print, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "print_data", 257, "Print data to stdout",
(gptr*) &_print_data, (gptr*) &_print_data, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "print_meta", 258, "Print meta data to stdout",
(gptr*) &_print_meta, (gptr*) &_print_meta, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "print_log", 259, "Print log to stdout",
(gptr*) &_print_log, (gptr*) &_print_log, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "dont_ignore_systab_0", 'f',
"Experimental. Do not ignore system table during restore.",
(gptr*) &ga_dont_ignore_systab_0, (gptr*) &ga_dont_ignore_systab_0, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
static void short_usage_sub(void)
{
printf("Usage: %s [OPTIONS] [<path to backup files>]\n", my_progname);
}
static void print_version()
{
printf("MySQL distrib %s, for %s (%s)\n",MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
}
static void usage()
{
short_usage_sub();
print_version();
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument)
{
switch (optid) {
case '#':
DBUG_PUSH(argument ? argument : "d:t:O,/tmp/ndb_restore.trace");
break;
case 'V':
print_version();
exit(0);
case '?':
usage();
exit(0);
}
return 0;
}
bool
readArguments(int *pargc, char*** pargv)
{
const char *load_default_groups[]= { "ndb_tools","ndb_restore",0 };
load_defaults("my",load_default_groups,pargc,pargv);
if (handle_options(pargc, pargv, my_long_options, get_one_option) ||
ga_nodeId == 0 ||
ga_backupId == 0 ||
ga_nParallelism < 1 ||
ga_nParallelism >1024) {
exit(1);
}
BackupPrinter* printer = new BackupPrinter();
if (printer == NULL)
return false;
BackupRestore* restore = new BackupRestore(ga_nParallelism);
if (restore == NULL)
{
delete printer;
return false;
}
if (_print)
{
ga_print = true;
ga_restore = true;
printer->m_print = true;
}
if (_print_meta)
{
ga_print = true;
printer->m_print_meta = true;
}
if (_print_data)
{
ga_print = true;
printer->m_print_data = true;
}
if (_print_log)
{
ga_print = true;
printer->m_print_log = true;
}
if (_restore_data)
{
ga_restore = true;
restore->m_restore = true;
}
if (_restore_meta)
{
// ga_restore = true;
restore->m_restore_meta = true;
}
{
BackupConsumer * c = printer;
g_consumers.push_back(c);
}
{
BackupConsumer * c = restore;
g_consumers.push_back(c);
}
// Set backup file path
if (*pargv[0] != NULL)
{
ga_backupPath = *pargv[0];
}
return true;
}
void
clearConsumers()
{
for(Uint32 i= 0; i<g_consumers.size(); i++)
delete g_consumers[i];
g_consumers.clear();
}
static bool
checkSysTable(const char *tableName)
{
return ga_dont_ignore_systab_0 ||
(strcmp(tableName, "SYSTAB_0") != 0 &&
strcmp(tableName, "NDB$EVENTS_0") != 0 &&
strcmp(tableName, "sys/def/SYSTAB_0") != 0 &&
strcmp(tableName, "sys/def/NDB$EVENTS_0") != 0);
}
static void
free_data_callback()
{
for(Uint32 i= 0; i < g_consumers.size(); i++)
g_consumers[i]->tuple_free();
}
int
main(int argc, char** argv)
{
NDB_INIT(argv[0]);
if (!readArguments(&argc, &argv))
{
return -1;
}
Ndb::setConnectString(opt_connect_str);
/**
* we must always load meta data, even if we will only print it to stdout
*/
RestoreMetaData metaData(ga_backupPath, ga_nodeId, ga_backupId);
if (!metaData.readHeader())
{
ndbout << "Failed to read " << metaData.getFilename() << endl << endl;
return -1;
}
/**
* check wheater we can restore the backup (right version).
*/
int res = metaData.loadContent();
if (res == 0)
{
ndbout_c("Restore: Failed to load content");
return -1;
}
if (metaData.getNoOfTables() == 0)
{
ndbout_c("Restore: The backup contains no tables ");
return -1;
}
if (!metaData.validateFooter())
{
ndbout_c("Restore: Failed to validate footer.");
return -1;
}
Uint32 i;
for(i= 0; i < g_consumers.size(); i++)
{
if (!g_consumers[i]->init())
{
clearConsumers();
return -11;
}
}
for(i = 0; i<metaData.getNoOfTables(); i++)
{
if (checkSysTable(metaData[i]->getTableName()))
{
for(Uint32 j= 0; j < g_consumers.size(); j++)
if (!g_consumers[j]->table(* metaData[i]))
{
ndbout_c("Restore: Failed to restore table: %s. "
"Exiting...",
metaData[i]->getTableName());
return -11;
}
}
}
for(i= 0; i < g_consumers.size(); i++)
if (!g_consumers[i]->endOfTables())
{
ndbout_c("Restore: Failed while closing tables");
return -11;
}
if (ga_restore || ga_print)
{
if (ga_restore)
{
RestoreDataIterator dataIter(metaData, &free_data_callback);
// Read data file header
if (!dataIter.readHeader())
{
ndbout << "Failed to read header of data file. Exiting..." ;
return -11;
}
while (dataIter.readFragmentHeader(res= 0))
{
const TupleS* tuple;
while ((tuple = dataIter.getNextTuple(res= 1)) != 0)
{
if (checkSysTable(tuple->getTable()->getTableName()))
for(Uint32 i= 0; i < g_consumers.size(); i++)
g_consumers[i]->tuple(* tuple);
} // while (tuple != NULL);
if (res < 0)
{
ndbout_c("Restore: An error occured while restoring data. "
"Exiting...");
return -1;
}
if (!dataIter.validateFragmentFooter()) {
ndbout_c("Restore: Error validating fragment footer. "
"Exiting...");
return -1;
}
} // while (dataIter.readFragmentHeader(res))
if (res < 0)
{
err << "Restore: An error occured while restoring data. Exiting... res=" << res << endl;
return -1;
}
dataIter.validateFooter(); //not implemented
for (i= 0; i < g_consumers.size(); i++)
g_consumers[i]->endOfTuples();
RestoreLogIterator logIter(metaData);
if (!logIter.readHeader())
{
err << "Failed to read header of data file. Exiting..." << endl;
return -1;
}
const LogEntry * logEntry = 0;
while ((logEntry = logIter.getNextLogEntry(res= 0)) != 0)
{
if (checkSysTable(logEntry->m_table->getTableName()))
for(Uint32 i= 0; i < g_consumers.size(); i++)
g_consumers[i]->logEntry(* logEntry);
}
if (res < 0)
{
err << "Restore: An restoring the data log. Exiting... res=" << res << endl;
return -1;
}
logIter.validateFooter(); //not implemented
for (i= 0; i < g_consumers.size(); i++)
g_consumers[i]->endOfLogEntrys();
for(i = 0; i<metaData.getNoOfTables(); i++)
{
if (checkSysTable(metaData[i]->getTableName()))
{
for(Uint32 j= 0; j < g_consumers.size(); j++)
if (!g_consumers[j]->finalize_table(* metaData[i]))
{
ndbout_c("Restore: Failed to finalize restore table: %s. "
"Exiting...",
metaData[i]->getTableName());
return -11;
}
}
}
}
}
clearConsumers();
return 0;
} // main
template class Vector<BackupConsumer*>;