restore_main.cpp 11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* 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 */

17 18
#include <ndb_global.h>
#include <ndb_opts.h>
19 20
#include <Vector.hpp>
#include <ndb_limits.h>
21
#include <NdbTCP.h>
22
#include <NdbOut.hpp>
23
#include <NDBT_ReturnCodes.h>
24

25 26
#include "consumer_restore.hpp"
#include "consumer_printer.hpp"
27 28 29 30 31 32

extern FilteredNdbOut err;
extern FilteredNdbOut info;
extern FilteredNdbOut debug;

static int ga_nodeId = 0;
33
static int ga_nParallelism = 128;
34 35
static int ga_backupId = 0;
static bool ga_dont_ignore_systab_0 = false;
unknown's avatar
unknown committed
36
static Vector<class BackupConsumer *> g_consumers;
37

38
static const char* ga_backupPath = "." DIR_SEPARATOR;
39

40
NDB_STD_OPTS_VARS;
41 42 43 44 45 46

/**
 * print and restore flags
 */
static bool ga_restore = false;
static bool ga_print = false;
47 48 49 50 51 52
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;
unknown's avatar
ndb:  
unknown committed
53 54
BaseString g_options("ndb_restore");

55 56
const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 };

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
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,
unknown's avatar
unknown committed
81
    GET_INT, REQUIRED_ARG, 128, 1, 1024, 0, 1, 0 },
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
  { "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}
};
100

101 102 103 104 105 106 107
static void short_usage_sub(void)
{
  printf("Usage: %s [OPTIONS] [<path to backup files>]\n", my_progname);
}
static void usage()
{
  short_usage_sub();
108
  ndb_std_print_version();
109 110
  print_defaults(MYSQL_CONFIG_NAME,load_default_groups);
  puts("");
111 112 113 114 115 116 117
  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)
{
118 119 120 121
#ifndef DBUG_OFF
  opt_debug= "d:t:O,/tmp/ndb_restore.trace";
#endif
  ndb_std_get_one_option(optid, opt, argument);
122
  switch (optid) {
unknown's avatar
unknown committed
123 124 125
  case 'n':
    if (ga_nodeId == 0)
    {
126
      printf("Error in --nodeid,-n setting, see --help\n");
127
      exit(NDBT_ProgramExit(NDBT_WRONGARGS));
unknown's avatar
unknown committed
128
    }
129
    break;
unknown's avatar
unknown committed
130 131 132
  case 'b':
    if (ga_backupId == 0)
    {
133
      printf("Error in --backupid,-b setting, see --help\n");
134
      exit(NDBT_ProgramExit(NDBT_WRONGARGS));
unknown's avatar
unknown committed
135
    }
136
    break;
137 138 139 140 141 142 143
  }
  return 0;
}
bool
readArguments(int *pargc, char*** pargv) 
{
  load_defaults("my",load_default_groups,pargc,pargv);
unknown's avatar
unknown committed
144 145
  if (handle_options(pargc, pargv, my_long_options, get_one_option))
  {
146
    exit(NDBT_ProgramExit(NDBT_WRONGARGS));
147 148 149 150 151 152 153 154 155
  }

  BackupPrinter* printer = new BackupPrinter();
  if (printer == NULL)
    return false;

  BackupRestore* restore = new BackupRestore(ga_nParallelism);
  if (restore == NULL) 
  {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    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;
  }

  {
unknown's avatar
unknown committed
195
    BackupConsumer * c = printer;
196 197 198
    g_consumers.push_back(c);
  }
  {
unknown's avatar
unknown committed
199
    BackupConsumer * c = restore;
200 201 202
    g_consumers.push_back(c);
  }
  // Set backup file path
203
  if (*pargv[0] != NULL) 
204
  {
205
    ga_backupPath = *pargv[0];
206 207 208 209 210 211 212 213
  }

  return true;
}

void
clearConsumers()
{
unknown's avatar
unknown committed
214
  for(Uint32 i= 0; i<g_consumers.size(); i++)
215 216 217 218
    delete g_consumers[i];
  g_consumers.clear();
}

219
static bool
220 221 222 223 224 225 226 227 228
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);
}

229 230 231
static void
free_data_callback()
{
unknown's avatar
unknown committed
232
  for(Uint32 i= 0; i < g_consumers.size(); i++) 
233 234 235
    g_consumers[i]->tuple_free();
}

236
const char * g_connect_string = 0;
237 238 239 240 241 242 243 244
static void exitHandler(int code)
{
  NDBT_ProgramExit(code);
  if (opt_core)
    abort();
  else
    exit(code);
}
245

246
int
247
main(int argc, char** argv)
248
{
249 250 251
  NDB_INIT(argv[0]);

  if (!readArguments(&argc, &argv))
252
  {
253
    exitHandler(NDBT_FAILED);
254 255
  }

unknown's avatar
ndb:  
unknown committed
256 257 258 259 260 261 262 263
  g_options.appfmt(" -b %d", ga_backupId);
  g_options.appfmt(" -n %d", ga_nodeId);
  if (_restore_meta)
    g_options.appfmt(" -m");
  if (_restore_data)
    g_options.appfmt(" -r");
  g_options.appfmt(" -p %d", ga_nParallelism);

264
  g_connect_string = opt_connect_str;
265

266 267 268 269 270 271 272
  /**
   * 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;
273
    exitHandler(NDBT_FAILED);
274
  }
275 276 277 278

  const BackupFormat::FileHeader & tmp = metaData.getFileHeader();
  const Uint32 version = tmp.NdbVersion;
  
279
  char buf[NDB_VERSION_STRING_BUF_SZ];
280
  ndbout << "Ndb version in backup files: " 
281
	 <<  getVersionString(version, 0, buf, sizeof(buf)) << endl;
282
  
283
  /**
284
   * check wheater we can restore the backup (right version).
285
   */
286
  int res  = metaData.loadContent();
287
  
288
  if (res == 0)
289 290
  {
    ndbout_c("Restore: Failed to load content");
291
    exitHandler(NDBT_FAILED);
292 293
  }
  
294
  if (metaData.getNoOfTables() == 0) 
295
  {
296
    ndbout_c("Restore: The backup contains no tables ");
297
    exitHandler(NDBT_FAILED);
298 299 300 301 302 303
  }


  if (!metaData.validateFooter()) 
  {
    ndbout_c("Restore: Failed to validate footer.");
304
    exitHandler(NDBT_FAILED);
305 306
  }

unknown's avatar
unknown committed
307 308
  Uint32 i;
  for(i= 0; i < g_consumers.size(); i++)
309 310 311 312
  {
    if (!g_consumers[i]->init())
    {
      clearConsumers();
313
      exitHandler(NDBT_FAILED);
314 315 316 317
    }

  }

unknown's avatar
unknown committed
318
  for(i = 0; i<metaData.getNoOfTables(); i++)
319 320 321
  {
    if (checkSysTable(metaData[i]->getTableName()))
    {
unknown's avatar
unknown committed
322
      for(Uint32 j= 0; j < g_consumers.size(); j++)
unknown's avatar
unknown committed
323 324 325 326 327
	if (!g_consumers[j]->table(* metaData[i]))
	{
	  ndbout_c("Restore: Failed to restore table: %s. "
		   "Exiting...", 
		   metaData[i]->getTableName());
328
	  exitHandler(NDBT_FAILED);
unknown's avatar
unknown committed
329
	} 
330 331 332
    }
  }
  
333 334 335 336
  for(i= 0; i < g_consumers.size(); i++)
    if (!g_consumers[i]->endOfTables())
    {
      ndbout_c("Restore: Failed while closing tables");
337
      exitHandler(NDBT_FAILED);
338 339
    } 
  
340 341
  if (ga_restore || ga_print) 
  {
unknown's avatar
unknown committed
342
    if(_restore_data || _print_data)
343 344 345 346 347
    {
      RestoreDataIterator dataIter(metaData, &free_data_callback);
      
      // Read data file header
      if (!dataIter.readHeader())
348
      {
349
	ndbout << "Failed to read header of data file. Exiting..." ;
350
	exitHandler(NDBT_FAILED);
351 352 353 354 355 356 357
      }
      
      
      while (dataIter.readFragmentHeader(res= 0))
      {
	const TupleS* tuple;
	while ((tuple = dataIter.getNextTuple(res= 1)) != 0)
358
	{
359 360 361 362
	  if (checkSysTable(tuple->getTable()->getTableName()))
	    for(Uint32 i= 0; i < g_consumers.size(); i++) 
	      g_consumers[i]->tuple(* tuple);
	} // while (tuple != NULL);
363 364 365
	
	if (res < 0)
	{
366 367
	  ndbout_c("Restore: An error occured while restoring data. "
		   "Exiting...");
368
	  exitHandler(NDBT_FAILED);
369
	}
370 371 372
	if (!dataIter.validateFragmentFooter()) {
	  ndbout_c("Restore: Error validating fragment footer. "
		   "Exiting...");
373
	  exitHandler(NDBT_FAILED);
374
	}
375 376 377 378
      } // while (dataIter.readFragmentHeader(res))
      
      if (res < 0)
      {
unknown's avatar
unknown committed
379 380
	err << "Restore: An error occured while restoring data. Exiting... "
	    << "res=" << res << endl;
381
	exitHandler(NDBT_FAILED);
382 383 384 385 386 387 388
      }
      
      
      dataIter.validateFooter(); //not implemented
      
      for (i= 0; i < g_consumers.size(); i++)
	g_consumers[i]->endOfTuples();
unknown's avatar
unknown committed
389
    }
unknown's avatar
unknown committed
390

unknown's avatar
unknown committed
391 392
    if(_restore_data || _print_log)
    {
393 394 395 396
      RestoreLogIterator logIter(metaData);
      if (!logIter.readHeader())
      {
	err << "Failed to read header of data file. Exiting..." << endl;
397
	exitHandler(NDBT_FAILED);
398 399 400 401 402 403 404 405 406 407 408
      }
      
      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)
      {
unknown's avatar
unknown committed
409 410
	err << "Restore: An restoring the data log. Exiting... res=" 
	    << res << endl;
411
	exitHandler(NDBT_FAILED);
412
      }
413 414 415
      logIter.validateFooter(); //not implemented
      for (i= 0; i < g_consumers.size(); i++)
	g_consumers[i]->endOfLogEntrys();
unknown's avatar
unknown committed
416 417 418 419
    }
    
    if(_restore_data)
    {
unknown's avatar
unknown committed
420 421 422 423 424 425 426 427 428 429
      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());
430
	      exitHandler(NDBT_FAILED);
unknown's avatar
unknown committed
431 432 433
	    } 
	}
      }
434
    }
435 436
  }
  clearConsumers();
437
  return NDBT_ProgramExit(NDBT_OK);
438 439
} // main

unknown's avatar
unknown committed
440
template class Vector<BackupConsumer*>;