summaryrefslogtreecommitdiff
path: root/ndb/tools/restore/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/tools/restore/main.cpp')
-rw-r--r--ndb/tools/restore/main.cpp398
1 files changed, 398 insertions, 0 deletions
diff --git a/ndb/tools/restore/main.cpp b/ndb/tools/restore/main.cpp
new file mode 100644
index 00000000000..482212911cb
--- /dev/null
+++ b/ndb/tools/restore/main.cpp
@@ -0,0 +1,398 @@
+/* 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*>;