Drizzled Public API Documentation

xtrabackup.cc
00001 /******************************************************
00002 XtraBackup: The another hot backup tool for InnoDB
00003 (c) 2009 Percona Inc.
00004 (C) 2011 Stewart Smith
00005 Created 3/3/2009 Yasufumi Kinoshita
00006 
00007 This program is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; version 2 of the License.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00019 
00020 *******************************************************/
00021 
00022 #ifndef XTRABACKUP_VERSION
00023 #define XTRABACKUP_VERSION "undefined"
00024 #endif
00025 #ifndef XTRABACKUP_REVISION
00026 #define XTRABACKUP_REVISION "undefined"
00027 #endif
00028 
00029 #include <config.h>
00030 #include <string>
00031 #include <drizzled/internal/my_sys.h>
00032 #include <drizzled/charset.h>
00033 #include <drizzled/gettext.h>
00034 #include <drizzled/constrained_value.h>
00035 #include <drizzled/configmake.h>
00036 #include <drizzled/error/priority_t.h>
00037 
00038 #include "ha_prototypes.h"
00039  //#define XTRABACKUP_TARGET_IS_PLUGIN
00040 #include <boost/program_options.hpp>
00041 #include <boost/scoped_array.hpp>
00042 #include <boost/scoped_ptr.hpp>
00043 
00044 typedef drizzled::charset_info_st CHARSET_INFO;
00045 
00046 #define my_progname "xtrabackup"
00047 
00048 #define MYSQL_VERSION_ID 50507 /* Drizzle is much greater */
00049 
00050 #include <univ.i>
00051 #include <os0file.h>
00052 #include <os0thread.h>
00053 #include <srv0start.h>
00054 #include <srv0srv.h>
00055 #include <trx0roll.h>
00056 #include <trx0trx.h>
00057 #include <trx0sys.h>
00058 #include <mtr0mtr.h>
00059 #include <row0ins.h>
00060 #include <row0mysql.h>
00061 #include <row0sel.h>
00062 #include <row0upd.h>
00063 #include <log0log.h>
00064 #include <log0recv.h>
00065 #include <lock0lock.h>
00066 #include <dict0crea.h>
00067 #include <btr0cur.h>
00068 #include <btr0btr.h>
00069 #include <btr0sea.h>
00070 #include <fsp0fsp.h>
00071 #include <sync0sync.h>
00072 #include <fil0fil.h>
00073 #include <trx0xa.h>
00074 
00075 #ifdef INNODB_VERSION_SHORT
00076 #include <ibuf0ibuf.h>
00077 #else
00078 #error ENOCOOL
00079 #endif
00080 
00081 #define IB_INT64 ib_int64_t
00082 #define LSN64 ib_uint64_t
00083 #define MACH_READ_64 mach_read_from_8
00084 #define MACH_WRITE_64 mach_write_to_8
00085 #define OS_MUTEX_CREATE() os_mutex_create()
00086 #define ut_dulint_zero 0
00087 #define ut_dulint_cmp(A, B) (A > B ? 1 : (A == B ? 0 : -1))
00088 #define ut_dulint_add(A, B) (A + B)
00089 #define ut_dulint_minus(A, B) (A - B)
00090 #define ut_dulint_align_down(A, B) (A & ~((ib_int64_t)B - 1))
00091 #define ut_dulint_align_up(A, B) ((A + B - 1) & ~((ib_int64_t)B - 1))
00092 
00093 #ifdef __WIN__
00094 #define SRV_PATH_SEPARATOR  '\\'
00095 #define SRV_PATH_SEPARATOR_STR  "\\"  
00096 #else
00097 #define SRV_PATH_SEPARATOR  '/'
00098 #define SRV_PATH_SEPARATOR_STR  "/"
00099 #endif
00100 
00101 #ifndef UNIV_PAGE_SIZE_MAX
00102 #define UNIV_PAGE_SIZE_MAX UNIV_PAGE_SIZE
00103 #endif
00104 #ifndef UNIV_PAGE_SIZE_SHIFT_MAX
00105 #define UNIV_PAGE_SIZE_SHIFT_MAX UNIV_PAGE_SIZE_SHIFT
00106 #endif
00107 
00108 using namespace drizzled;
00109 namespace po=boost::program_options;
00110 
00111 namespace drizzled {
00112   bool errmsg_printf (error::priority_t, char const *format, ...);
00113 
00114   bool errmsg_printf (error::priority_t, char const *format, ...)
00115   {
00116     bool rv;
00117     va_list args;
00118     va_start(args, format);
00119     rv= vfprintf(stderr, format, args);
00120     va_end(args);
00121     fprintf(stderr, "\n");
00122     return rv;
00123   }
00124 
00125 }
00126 
00127 #include "xtrabackup_api.h"
00128 
00129  /* prototypes for static functions in original */
00130 
00131  ulint
00132  recv_find_max_checkpoint(
00133  /*=====================*/
00134                                          /* out: error code or DB_SUCCESS */
00135          log_group_t**  max_group,  /* out: max group */
00136          ulint*   max_field); /* out: LOG_CHECKPOINT_1 or
00137                                          LOG_CHECKPOINT_2 */
00138 
00139 
00140  void
00141  os_file_set_nocache(
00142  /*================*/
00143          int    fd,   /* in: file descriptor to alter */
00144          const char*  file_name,  /* in: used in the diagnostic message */
00145          const char*  operation_name);  /* in: used in the diagnostic message,
00146                                          we call os_file_set_nocache()
00147                                          immediately after opening or creating
00148                                          a file, so this is either "open" or
00149                                          "create" */
00150 
00151  #include <fcntl.h>
00152  #include <regex.h>
00153 
00154  #ifdef POSIX_FADV_NORMAL
00155  #define USE_POSIX_FADVISE
00156  #endif
00157 
00158  /* ==start === definition at fil0fil.c === */
00159  // ##################################################################
00160  // NOTE: We should check the following definitions fit to the source.
00161  // ##################################################################
00162 
00163  //Plugin ?
00165  struct fil_node_struct {
00166          fil_space_t* space;  
00168          char*    name; 
00169          ibool    open; 
00170          os_file_t  handle; 
00171          ibool    is_raw_disk;
00173          ulint    size; 
00176          ulint    n_pending;
00180          ulint    n_pending_flushes;
00184          ib_int64_t modification_counter;
00186          ib_int64_t flush_counter;
00189          UT_LIST_NODE_T(fil_node_t) chain;
00191          UT_LIST_NODE_T(fil_node_t) LRU;
00193          ulint    magic_n;
00194  };
00195 
00196  struct fil_space_struct {
00197          char*    name; 
00199          ulint    id; 
00200          ib_int64_t tablespace_version;
00206          ibool    mark; 
00210          ibool    stop_ios;
00214          ibool    stop_ibuf_merges;
00217          ibool    is_being_deleted;
00224          ulint    purpose;
00226          UT_LIST_BASE_NODE_T(fil_node_t) chain;
00228          ulint    size; 
00232          ulint    flags;  
00233          ulint    n_reserved_extents;
00236          ulint    n_pending_flushes; 
00239          ulint    n_pending_ibuf_merges;
00245          hash_node_t  hash; 
00246          hash_node_t  name_hash;
00247  #ifndef UNIV_HOTBACKUP
00248          rw_lock_t  latch;  
00250  #endif /* !UNIV_HOTBACKUP */
00251          UT_LIST_NODE_T(fil_space_t) unflushed_spaces;
00254          ibool    is_in_unflushed_spaces; 
00256  #ifdef XTRADB_BASED
00257          ibool    is_corrupt;
00258  #endif
00259          UT_LIST_NODE_T(fil_space_t) space_list;
00261          ulint    magic_n;
00262  };
00263 
00264  typedef  struct fil_system_struct  fil_system_t;
00265 
00266  struct fil_system_struct {
00267  #ifndef UNIV_HOTBACKUP
00268          mutex_t    mutex;    
00269  #ifdef XTRADB55
00270          mutex_t    file_extend_mutex;
00271  #endif
00272  #endif /* !UNIV_HOTBACKUP */
00273          hash_table_t*  spaces;   
00276          hash_table_t*  name_hash;  
00278          UT_LIST_BASE_NODE_T(fil_node_t) LRU;
00289          UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces;
00295          ulint    n_open;   
00296          ulint    max_n_open; 
00298          ib_int64_t modification_counter;
00300          ulint    max_assigned_id;
00306          ib_int64_t tablespace_version;
00314          UT_LIST_BASE_NODE_T(fil_space_t) space_list;
00316  };
00317 
00318  typedef struct {
00319          ulint  page_size;
00320  } xb_delta_info_t;
00321 
00322  extern fil_system_t*   fil_system;
00323 
00324  /* ==end=== definition  at fil0fil.c === */
00325 
00326 
00327  bool innodb_inited= 0;
00328 
00329  /* === xtrabackup specific options === */
00330  char xtrabackup_real_target_dir[FN_REFLEN] = "./xtrabackup_backupfiles/";
00331  const char *xtrabackup_target_dir= xtrabackup_real_target_dir;
00332  bool xtrabackup_backup = false;
00333  bool xtrabackup_stats = false;
00334  bool xtrabackup_prepare = false;
00335  bool xtrabackup_print_param = false;
00336 
00337  bool xtrabackup_export = false;
00338  bool xtrabackup_apply_log_only = false;
00339 
00340  bool xtrabackup_suspend_at_end = false;
00341  uint64_t xtrabackup_use_memory = 100*1024*1024L;
00342  bool xtrabackup_create_ib_logfile = false;
00343 
00344  long xtrabackup_throttle = 0; /* 0:unlimited */
00345  lint io_ticket;
00346  os_event_t wait_throttle = NULL;
00347 
00348  bool xtrabackup_stream = false;
00349 const char *xtrabackup_incremental = NULL;
00350  LSN64 incremental_lsn;
00351  LSN64 incremental_to_lsn;
00352  LSN64 incremental_last_lsn;
00353  byte* incremental_buffer = NULL;
00354  byte* incremental_buffer_base = NULL;
00355 
00356 const char *xtrabackup_incremental_basedir = NULL; /* for --backup */
00357 const char *xtrabackup_extra_lsndir = NULL; /* for --backup with --extra-lsndir */
00358 char *xtrabackup_incremental_dir = NULL; /* for --prepare */
00359 
00360  char *xtrabackup_tables = NULL;
00361  int tables_regex_num;
00362  regex_t *tables_regex;
00363  regmatch_t tables_regmatch[1];
00364 
00365 const char *xtrabackup_tables_file = NULL;
00366  hash_table_t* tables_hash;
00367 
00368  struct xtrabackup_tables_struct{
00369          char*    name;
00370          hash_node_t  name_hash;
00371  };
00372  typedef struct xtrabackup_tables_struct  xtrabackup_tables_t;
00373 
00374  #ifdef XTRADB_BASED
00375  static ulint   thread_nr[SRV_MAX_N_IO_THREADS + 6 + 64];
00376  static os_thread_id_t  thread_ids[SRV_MAX_N_IO_THREADS + 6 + 64];
00377  #else
00378  static ulint   thread_nr[SRV_MAX_N_IO_THREADS + 6];
00379  static os_thread_id_t  thread_ids[SRV_MAX_N_IO_THREADS + 6];
00380  #endif
00381 
00382  LSN64 checkpoint_lsn_start;
00383  LSN64 checkpoint_no_start;
00384  LSN64 log_copy_scanned_lsn;
00385  IB_INT64 log_copy_offset = 0;
00386  ibool log_copying = TRUE;
00387  ibool log_copying_running = FALSE;
00388  ibool log_copying_succeed = FALSE;
00389 
00390  ibool xtrabackup_logfile_is_renamed = FALSE;
00391 
00392  uint parallel;
00393 
00394  /* === metadata of backup === */
00395  #define XTRABACKUP_METADATA_FILENAME "xtrabackup_checkpoints"
00396  char metadata_type[30] = ""; /*[full-backuped|full-prepared|incremental]*/
00397 
00398  ib_uint64_t metadata_from_lsn = 0;
00399  ib_uint64_t metadata_to_lsn = 0;
00400  ib_uint64_t metadata_last_lsn = 0;
00401 
00402  #define XB_DELTA_INFO_SUFFIX ".meta"
00403 
00404  /* === sharing with thread === */
00405  os_file_t       dst_log = -1;
00406  char            dst_log_path[FN_REFLEN];
00407 
00408  /* === some variables from mysqld === */
00409  char mysql_real_data_home[FN_REFLEN] = "./";
00410  char *mysql_data_home= mysql_real_data_home;
00411 std::string mysql_data_home_arg;
00412  static char mysql_data_home_buff[2];
00413 
00414 const char *opt_mysql_tmpdir = NULL;
00415 
00416 /* === static parameters in ha_innodb.cc */
00417 
00418 #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
00419 #define HA_INNOBASE_RANGE_COUNT   100
00420 
00421 ulong   innobase_large_page_size = 0;
00422 
00423 /* The default values for the following, type long or longlong, start-up
00424 parameters are declared in mysqld.cc: */
00425 
00426 long innobase_additional_mem_pool_size = 1*1024*1024L;
00427 long innobase_buffer_pool_awe_mem_mb = 0;
00428 long innobase_file_io_threads = 4;
00429 long innobase_read_io_threads = 4;
00430 long innobase_write_io_threads = 4;
00431 long innobase_force_recovery = 0;
00432 long innobase_lock_wait_timeout = 50;
00433 long innobase_log_buffer_size = 1024*1024L;
00434 long innobase_log_files_in_group = 2;
00435 long innobase_log_files_in_group_backup;
00436 long innobase_mirrored_log_groups = 1;
00437 long innobase_open_files = 300L;
00438 
00439 long innobase_page_size = (1 << 14); /* 16KB */
00440 static ulong innobase_log_block_size = 512;
00441 bool innobase_fast_checksum = false;
00442 bool  innobase_extra_undoslots = false;
00443 char* innobase_doublewrite_file = NULL;
00444 
00445 uint64_t innobase_buffer_pool_size = 8*1024*1024L;
00446 
00447 typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
00448 static log_file_constraint innobase_log_file_size;
00449 
00450 uint64_t innobase_log_file_size_backup;
00451 
00452 /* The default values for the following char* start-up parameters
00453 are determined in innobase_init below: */
00454 
00455 char* innobase_data_home_dir      = NULL;
00456 const char* innobase_data_file_path     = NULL;
00457 char*   innobase_log_group_home_dir   = NULL;
00458 char* innobase_log_group_home_dir_backup  = NULL;
00459 char* innobase_log_arch_dir     = NULL;/* unused */
00460 /* The following has a misleading name: starting from 4.0.5, this also
00461 affects Windows: */
00462 char* innobase_unix_file_flush_method   = NULL;
00463 
00464 /* Below we have boolean-valued start-up parameters, and their default
00465 values */
00466 
00467 ulong innobase_fast_shutdown      = 1;
00468 bool innobase_log_archive     = FALSE;/* unused */
00469 bool innobase_use_doublewrite    = TRUE;
00470 bool innobase_use_checksums      = TRUE;
00471 bool innobase_use_large_pages    = FALSE;
00472 bool  innobase_file_per_table     = FALSE;
00473 bool innobase_locks_unsafe_for_binlog        = FALSE;
00474 bool innobase_rollback_on_timeout   = FALSE;
00475 bool innobase_create_status_file    = FALSE;
00476 bool innobase_adaptive_hash_index   = TRUE;
00477 
00478 static char *internal_innobase_data_file_path = NULL;
00479 
00480 /* The following counter is used to convey information to InnoDB
00481 about server activity: in selects it is not sensible to call
00482 srv_active_wake_master_thread after each fetch or search, we only do
00483 it every INNOBASE_WAKE_INTERVAL'th step. */
00484 
00485 #define INNOBASE_WAKE_INTERVAL  32
00486 ulong innobase_active_counter = 0;
00487 
00488 UNIV_INTERN
00489 bool
00490 innobase_isspace(
00491   const void *cs,
00492   char char_to_test)
00493 {
00494   return static_cast<const CHARSET_INFO*>(cs)->isspace(char_to_test);
00495 }
00496 
00497 UNIV_INTERN
00498 void
00499 innobase_rec_to_mysql(
00500   Table*      ,
00501   const rec_t*    ,
00502   const dict_index_t* ,
00503   const ulint*    );
00504 
00505 UNIV_INTERN
00506 void
00507 innobase_rec_to_mysql(
00508 /*==================*/
00509   Table*      ,   
00510   const rec_t*    ,   
00511   const dict_index_t* ,   
00512   const ulint*    ) 
00514 {
00515   fprintf(stderr, "ERROR: innobase_rec_to_mysql called\n");
00516   return;
00517 }
00518 
00519 UNIV_INTERN
00520 void
00521 innobase_rec_reset(Table*);
00522 
00523 UNIV_INTERN
00524 void
00525 innobase_rec_reset(
00526 /*===============*/
00527   Table*      )   
00528 {
00529   fprintf(stderr, "ERROR: innobase_rec_reset called\n");
00530   return;
00531 }
00532 
00533 UNIV_INTERN
00534 void
00535 thd_set_lock_wait_time(
00536 /*===================*/
00537   drizzled::Session*  , 
00538   ulint );  
00540 UNIV_INTERN
00541 void
00542 thd_set_lock_wait_time(
00543 /*===================*/
00544   drizzled::Session*  , 
00545   ulint ) 
00546 {
00547   return;
00548 }
00549 
00550 
00551 
00552 /* ======== Datafiles iterator ======== */
00553 typedef struct {
00554   fil_system_t *system;
00555   fil_space_t  *space;
00556   fil_node_t   *node;
00557   ibool        started;
00558   os_mutex_t   mutex;
00559 } datafiles_iter_t;
00560 
00561 static
00562 datafiles_iter_t *
00563 datafiles_iter_new(fil_system_t *f_system)
00564 {
00565   datafiles_iter_t *it;
00566 
00567   it = (datafiles_iter_t*) ut_malloc(sizeof(datafiles_iter_t));
00568   it->mutex = OS_MUTEX_CREATE();
00569 
00570   it->system = f_system;
00571   it->space = NULL;
00572   it->node = NULL;
00573   it->started = FALSE;
00574 
00575   return it;
00576 }
00577 
00578 static
00579 fil_node_t *
00580 datafiles_iter_next(datafiles_iter_t *it, ibool *space_changed)
00581 {
00582   os_mutex_enter(it->mutex);
00583 
00584   *space_changed = FALSE;
00585 
00586   if (it->node == NULL) {
00587     if (it->started)
00588       goto end;
00589     it->started = TRUE;
00590   } else {
00591     it->node = UT_LIST_GET_NEXT(chain, it->node);
00592     if (it->node != NULL)
00593       goto end;
00594   }
00595 
00596   it->space = (it->space == NULL) ?
00597     UT_LIST_GET_FIRST(it->system->space_list) :
00598     UT_LIST_GET_NEXT(space_list, it->space);
00599 
00600   while (it->space != NULL &&
00601          (it->space->purpose != FIL_TABLESPACE ||
00602     UT_LIST_GET_LEN(it->space->chain) == 0))
00603     it->space = UT_LIST_GET_NEXT(space_list, it->space);
00604   if (it->space == NULL)
00605     goto end;
00606   *space_changed = TRUE;
00607 
00608   it->node = UT_LIST_GET_FIRST(it->space->chain);
00609 
00610 end:
00611   os_mutex_exit(it->mutex);
00612 
00613   return it->node;
00614 }
00615 
00616 static
00617 void
00618 datafiles_iter_free(datafiles_iter_t *it)
00619 {
00620   os_mutex_free(it->mutex);
00621   ut_free(it);
00622 }
00623 
00624 /* ======== Date copying thread context ======== */
00625 
00626 typedef struct {
00627   datafiles_iter_t  *it;
00628   uint      num;
00629   uint      *count;
00630   os_mutex_t    count_mutex;
00631   os_thread_id_t    id;
00632 } data_thread_ctxt_t;
00633 
00634 static void print_version(void)
00635 {
00636   printf("%s  Ver %s Rev %s for %s %s (%s)\n" ,my_progname,
00637     XTRABACKUP_VERSION, XTRABACKUP_REVISION, "Drizzle7",
00638          TARGET_OS, TARGET_CPU);
00639 }
00640 
00641 static void usage(void)
00642 {
00643   puts("Open source backup tool for InnoDB and XtraDB\n\
00644 \n\
00645 Copyright (C) 2009 Percona Inc.\n\
00646 \n\
00647 This program is free software; you can redistribute it and/or\n\
00648 modify it under the terms of the GNU General Public License\n\
00649 as published by the Free Software Foundation version 2\n\
00650 of the License.\n\
00651 \n\
00652 This program is distributed in the hope that it will be useful,\n\
00653 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
00654 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
00655 GNU General Public License for more details.\n\
00656 \n\
00657 You can download full text of the license on http://www.gnu.org/licenses/gpl-2.0.txt\n");
00658 
00659   printf("Usage: [%s [--defaults-file=#] --backup | %s [--defaults-file=#] --prepare] [OPTIONS]\n",my_progname,my_progname);
00660   // FIXME: print what variables we have
00661 }
00662 
00663 /* ================ Dummys =================== */
00664 
00665 UNIV_INTERN
00666 ibool
00667 thd_is_replication_slave_thread(
00668 /*============================*/
00669   drizzled::Session* ) 
00670 {
00671   fprintf(stderr, "xtrabackup: thd_is_replication_slave_thread() is called\n");
00672   return(FALSE);
00673 }
00674 
00675 UNIV_INTERN
00676 ibool
00677 thd_has_edited_nontrans_tables(
00678 /*===========================*/
00679   drizzled::Session *)  
00680 {
00681   fprintf(stderr, "xtrabackup: thd_has_edited_nontrans_tables() is called\n");
00682   return(FALSE);
00683 }
00684 
00685 UNIV_INTERN
00686 ibool
00687 thd_is_select(
00688 /*==========*/
00689   const drizzled::Session *)  
00690 {
00691   fprintf(stderr, "xtrabackup: thd_is_select() is called\n");
00692         return(false);
00693 }
00694 
00695 UNIV_INTERN
00696 void
00697 innobase_mysql_print_thd(
00698   FILE*,
00699   drizzled::Session*,
00700   uint)
00701 {
00702   fprintf(stderr, "xtrabackup: innobase_mysql_print_thd() is called\n");
00703 }
00704 
00705 void
00706 innobase_get_cset_width(
00707   ulint cset,
00708   ulint*  mbminlen,
00709   ulint*  mbmaxlen)
00710 {
00711   CHARSET_INFO* cs;
00712   ut_ad(cset < 256);
00713   ut_ad(mbminlen);
00714   ut_ad(mbmaxlen);
00715 
00716   cs = all_charsets[cset];
00717   if (cs) {
00718     *mbminlen = cs->mbminlen;
00719     *mbmaxlen = cs->mbmaxlen;
00720   } else {
00721     ut_a(cset == 0);
00722     *mbminlen = *mbmaxlen = 0;
00723   }
00724 }
00725 
00726 UNIV_INTERN
00727 void
00728 innobase_convert_from_table_id(
00729 /*===========================*/
00730   const void*,      
00731   char*     , 
00732   const char* , 
00733   ulint     )  
00734 {
00735   fprintf(stderr, "xtrabackup: innobase_convert_from_table_id() is called\n");
00736 }
00737 
00738 UNIV_INTERN
00739 void
00740 innobase_convert_from_id(
00741 /*=====================*/
00742   const void*,      
00743   char*     , 
00744   const char*   , 
00745   ulint     )  
00746 {
00747   fprintf(stderr, "xtrabackup: innobase_convert_from_id() is called\n");
00748 }
00749 
00750 int
00751 innobase_strcasecmp(
00752   const char* a,
00753   const char* b)
00754 {
00755   return my_charset_utf8_general_ci.strcasecmp(a, b);
00756 }
00757 
00758 void
00759 innobase_casedn_str(
00760   char* a)
00761 {
00762   my_charset_utf8_general_ci.casedn_str(a);
00763 }
00764 
00765 UNIV_INTERN
00766 const char*
00767 innobase_get_stmt(
00768 /*==============*/
00769        drizzled::Session *,      
00770        size_t* )         
00771 {
00772   fprintf(stderr, "xtrabackup: innobase_get_stmt() is called\n");
00773   return("nothing");
00774 }
00775 
00776 int
00777 innobase_mysql_tmpfile(void)
00778 {
00779   char  filename[FN_REFLEN];
00780   int fd2 = -1;
00781   int fd = internal::create_temp_file(filename, opt_mysql_tmpdir,
00782                                                 "ib",
00783 #ifdef __WIN__
00784         O_BINARY | O_TRUNC | O_SEQUENTIAL |
00785         O_TEMPORARY | O_SHORT_LIVED |
00786 #endif /* __WIN__ */
00787         O_CREAT | O_EXCL | O_RDWR);
00788   if (fd >= 0) {
00789 #ifndef __WIN__
00790     /* On Windows, open files cannot be removed, but files can be
00791     created with the O_TEMPORARY flag to the same effect
00792     ("delete on close"). */
00793     unlink(filename);
00794 #endif /* !__WIN__ */
00795     /* Copy the file descriptor, so that the additional resources
00796     allocated by create_temp_file() can be freed by invoking
00797     my_close().
00798 
00799     Because the file descriptor returned by this function
00800     will be passed to fdopen(), it will be closed by invoking
00801     fclose(), which in turn will invoke close() instead of
00802     my_close(). */
00803     fd2 = dup(fd);
00804     if (fd2 < 0) {
00805       fprintf(stderr, "xtrabackup: Got error %d on dup\n",fd2);
00806                 }
00807     close(fd);
00808   }
00809   return(fd2);
00810 }
00811 
00812 void
00813 innobase_invalidate_query_cache(
00814   trx_t*  ,
00815   const char* ,
00816   ulint )
00817 {
00818   /* do nothing */
00819 }
00820 
00821 /*****************************************************************/
00825 static
00826 char*
00827 innobase_convert_identifier(
00828 /*========================*/
00829   char*   buf,  
00830   ulint   buflen, 
00831   const char* id, 
00832   ulint   idlen,  
00833   void*   , 
00834   ibool   )
00836 {
00837   const char* s = id;
00838   int   q;
00839 
00840   /* See if the identifier needs to be quoted. */
00841   q = '"';
00842 
00843   if (q == EOF) {
00844     if (UNIV_UNLIKELY(idlen > buflen)) {
00845       idlen = buflen;
00846     }
00847     memcpy(buf, s, idlen);
00848     return(buf + idlen);
00849   }
00850 
00851   /* Quote the identifier. */
00852   if (buflen < 2) {
00853     return(buf);
00854   }
00855 
00856   *buf++ = q;
00857   buflen--;
00858 
00859   for (; idlen; idlen--) {
00860     int c = *s++;
00861     if (UNIV_UNLIKELY(c == q)) {
00862       if (UNIV_UNLIKELY(buflen < 3)) {
00863         break;
00864       }
00865 
00866       *buf++ = c;
00867       *buf++ = c;
00868       buflen -= 2;
00869     } else {
00870       if (UNIV_UNLIKELY(buflen < 2)) {
00871         break;
00872       }
00873 
00874       *buf++ = c;
00875       buflen--;
00876     }
00877   }
00878 
00879   *buf++ = q;
00880   return(buf);
00881 }
00882 
00883 /*****************************************************************/
00887 UNIV_INTERN
00888 char*
00889 innobase_convert_name(
00890 /*==================*/
00891   char*   buf,  
00892   ulint   buflen, 
00893   const char* id, 
00894   ulint   idlen,  
00895   drizzled::Session *session,
00896   ibool   table_id)
00898 {
00899   char*   s = buf;
00900   const char* bufend  = buf + buflen;
00901 
00902   if (table_id) {
00903     const char* slash = (const char*) memchr(id, '/', idlen);
00904     if (!slash) {
00905 
00906       goto no_db_name;
00907     }
00908 
00909     /* Print the database name and table name separately. */
00910     s = innobase_convert_identifier(s, bufend - s, id, slash - id,
00911             session, TRUE);
00912     if (UNIV_LIKELY(s < bufend)) {
00913       *s++ = '.';
00914       s = innobase_convert_identifier(s, bufend - s,
00915               slash + 1, idlen
00916               - (slash - id) - 1,
00917               session, TRUE);
00918     }
00919   } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
00920     /* Temporary index name (smart ALTER TABLE) */
00921     const char temp_index_suffix[]= "--temporary--";
00922 
00923     s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
00924             session, FALSE);
00925     if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
00926       memcpy(s, temp_index_suffix,
00927              sizeof temp_index_suffix - 1);
00928       s += sizeof temp_index_suffix - 1;
00929     }
00930   } else {
00931 no_db_name:
00932     s = innobase_convert_identifier(buf, buflen, id, idlen,
00933             session, table_id);
00934   }
00935 
00936   return(s);
00937 
00938 }
00939 
00940 ibool
00941 trx_is_interrupted(
00942   trx_t*  )
00943 {
00944   /* There are no mysql_thd */
00945   return(FALSE);
00946 }
00947 
00948 UNIV_INTERN int
00949 innobase_mysql_cmp(
00950 /*===============*/
00951   int   mysql_type, 
00952   uint    charset_number, 
00953   const unsigned char* a,   
00954   unsigned int  a_length, 
00956   const unsigned char* b,   /* in: data field */
00957   unsigned int  b_length);  /* in: data field length,
00958           not UNIV_SQL_NULL */
00959 
00960 int
00961 innobase_mysql_cmp(
00962 /*===============*/
00963           /* out: 1, 0, -1, if a is greater, equal, less than b, respectively */
00964   int   mysql_type, /* in: MySQL type */
00965   uint    charset_number, /* in: number of the charset */
00966   const unsigned char* a,   /* in: data field */
00967   unsigned int  a_length, /* in: data field length, not UNIV_SQL_NULL */
00968   const unsigned char* b,   /* in: data field */
00969   unsigned int  b_length) /* in: data field length, not UNIV_SQL_NULL */
00970 {
00971   const CHARSET_INFO* charset;
00972   enum_field_types  mysql_tp;
00973   int     ret;
00974 
00975   assert(a_length != UNIV_SQL_NULL);
00976   assert(b_length != UNIV_SQL_NULL);
00977 
00978   mysql_tp = (enum_field_types) mysql_type;
00979 
00980   switch (mysql_tp) {
00981 
00982   case DRIZZLE_TYPE_BLOB:
00983   case DRIZZLE_TYPE_VARCHAR:
00984     /* Use the charset number to pick the right charset struct for
00985       the comparison. Since the MySQL function get_charset may be
00986       slow before Bar removes the mutex operation there, we first
00987       look at 2 common charsets directly. */
00988 
00989     if (charset_number == default_charset_info->number) {
00990       charset = default_charset_info;
00991     } else {
00992       charset = get_charset(charset_number);
00993 
00994       if (charset == NULL) {
00995         fprintf(stderr, "xtrabackup needs charset %lu for doing "
00996                 "a comparison, but MySQL cannot "
00997                 "find that charset.",
00998                 (ulong) charset_number);
00999         ut_a(0);
01000       }
01001     }
01002 
01003     /* Starting from 4.1.3, we use strnncollsp() in comparisons of
01004       non-latin1_swedish_ci strings. NOTE that the collation order
01005       changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
01006       having indexes on such data need to rebuild their tables! */
01007 
01008     ret = charset->coll->strnncollsp(charset,
01009                                      a, a_length,
01010                                      b, b_length, 0);
01011     if (ret < 0) {
01012       return(-1);
01013     } else if (ret > 0) {
01014       return(1);
01015     } else {
01016       return(0);
01017     }
01018   default:
01019     ut_error;
01020   }
01021 
01022   return(0);
01023 }
01024 
01025 ulint
01026 innobase_get_at_most_n_mbchars(
01027   ulint charset_id,
01028   ulint prefix_len,
01029   ulint data_len,
01030   const char* str)
01031 {
01032   ulint char_length;  /* character length in bytes */
01033   ulint n_chars;    /* number of characters in prefix */
01034   const CHARSET_INFO* charset;  /* charset used in the field */
01035 
01036   charset = get_charset((uint) charset_id);
01037 
01038   ut_ad(charset);
01039   ut_ad(charset->mbmaxlen);
01040 
01041   /* Calculate how many characters at most the prefix index contains */
01042 
01043   n_chars = prefix_len / charset->mbmaxlen;
01044 
01045   /* If the charset is multi-byte, then we must find the length of the
01046   first at most n chars in the string. If the string contains less
01047   characters than n, then we return the length to the end of the last
01048   character. */
01049 
01050   if (charset->mbmaxlen > 1) {
01051     /* my_charpos() returns the byte length of the first n_chars
01052     characters, or a value bigger than the length of str, if
01053     there were not enough full characters in str.
01054 
01055     Why does the code below work:
01056     Suppose that we are looking for n UTF-8 characters.
01057 
01058     1) If the string is long enough, then the prefix contains at
01059     least n complete UTF-8 characters + maybe some extra
01060     characters + an incomplete UTF-8 character. No problem in
01061     this case. The function returns the pointer to the
01062     end of the nth character.
01063 
01064     2) If the string is not long enough, then the string contains
01065     the complete value of a column, that is, only complete UTF-8
01066     characters, and we can store in the column prefix index the
01067     whole string. */
01068 
01069     char_length = my_charpos(charset, str,
01070             str + data_len, (int) n_chars);
01071     if (char_length > data_len) {
01072       char_length = data_len;
01073     }
01074   } else {
01075     if (data_len < prefix_len) {
01076       char_length = data_len;
01077     } else {
01078       char_length = prefix_len;
01079     }
01080   }
01081 
01082   return(char_length);
01083 }
01084 
01085 UNIV_INTERN
01086 ulint
01087 innobase_raw_format(
01088 /*================*/
01089   const char* ,   
01090   ulint   , 
01092   ulint   ,   
01093   char*   ,    
01094   ulint   ) 
01096 {
01097   fprintf(stderr, "xtrabackup: innobase_raw_format() is called\n");
01098   return(0);
01099 }
01100 
01101 UNIV_INTERN
01102 ulong
01103 thd_lock_wait_timeout(
01104 /*==================*/
01105   drizzled::Session*)  
01107 {
01108   return(innobase_lock_wait_timeout);
01109 }
01110 
01111 UNIV_INTERN
01112 ibool
01113 thd_supports_xa(
01114 /*============*/
01115   drizzled::Session* )  
01117 {
01118   return(FALSE);
01119 }
01120 
01121 ibool
01122 trx_is_strict(
01123 /*==========*/
01124   trx_t*) 
01125 {
01126   return(FALSE);
01127 }
01128 
01129 #ifdef XTRADB_BASED
01130 trx_t*
01131 innobase_get_trx()
01132 {
01133   return(NULL);
01134 }
01135 
01136 ibool
01137 innobase_get_slow_log()
01138 {
01139   return(FALSE);
01140 }
01141 #endif
01142 
01143 /***********************************************************************
01144 Computes bit shift for a given value. If the argument is not a power
01145 of 2, returns 0.*/
01146 UNIV_INLINE
01147 ulint
01148 get_bit_shift(ulint value)
01149 {
01150   ulint shift;
01151 
01152   if (value == 0)
01153     return 0;
01154 
01155   for (shift = 0; !(value & 1UL); shift++) {
01156     value >>= 1;
01157   }
01158   return (value >> 1) ? 0 : shift;
01159 }
01160 
01161 static bool
01162 innodb_init_param(void)
01163 {
01164   /* innobase_init */
01165   static char current_dir[3];   /* Set if using current lib */
01166   bool    ret;
01167   char    *default_path;
01168 
01169   /* dummy for initialize all_charsets[] */
01170   get_charset_name(0);
01171 
01172 #ifdef XTRADB_BASED
01173   srv_page_size = 0;
01174   srv_page_size_shift = 0;
01175 
01176   if (innobase_page_size != (1 << 14)) {
01177     int n_shift = get_bit_shift(innobase_page_size);
01178 
01179     if (n_shift >= 12 && n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX) {
01180       fprintf(stderr,
01181         "InnoDB: Warning: innodb_page_size has been "
01182         "changed from default value 16384.\n");
01183       srv_page_size_shift = n_shift;
01184       srv_page_size = 1 << n_shift;
01185       fprintf(stderr,
01186         "InnoDB: The universal page size of the "
01187         "database is set to %lu.\n", srv_page_size);
01188     } else {
01189       fprintf(stderr, "InnoDB: Error: invalid value of "
01190              "innobase_page_size: %lu", innobase_page_size);
01191       exit(EXIT_FAILURE);
01192     }
01193   } else {
01194     srv_page_size_shift = 14;
01195     srv_page_size = (1 << srv_page_size_shift);
01196   }
01197 
01198   srv_log_block_size = 0;
01199   if (innobase_log_block_size != 512) {
01200     uint  n_shift = get_bit_shift(innobase_log_block_size);;
01201 
01202     fprintf(stderr,
01203       "InnoDB: Warning: innodb_log_block_size has "
01204       "been changed from its default value. "
01205       "(###EXPERIMENTAL### operation)\n");
01206     if (n_shift > 0) {
01207       srv_log_block_size = (1 << n_shift);
01208       fprintf(stderr,
01209         "InnoDB: The log block size is set to %lu.\n",
01210         srv_log_block_size);
01211     }
01212   } else {
01213     srv_log_block_size = 512;
01214   }
01215 
01216   if (!srv_log_block_size) {
01217     fprintf(stderr,
01218       "InnoDB: Error: %lu is not valid value for "
01219       "innodb_log_block_size.\n", innobase_log_block_size);
01220     goto error;
01221   }
01222 
01223   srv_fast_checksum = (ibool) innobase_fast_checksum;
01224 #endif
01225 
01226   /* Check that values don't overflow on 32-bit systems. */
01227   if (sizeof(ulint) == 4) {
01228     if (xtrabackup_use_memory > UINT32_MAX) {
01229       fprintf(stderr,
01230         "xtrabackup: use-memory can't be over 4GB"
01231         " on 32-bit systems\n");
01232     }
01233 
01234     if (innobase_buffer_pool_size > UINT32_MAX) {
01235       fprintf(stderr,
01236         "xtrabackup: innobase_buffer_pool_size can't be over 4GB"
01237         " on 32-bit systems\n");
01238 
01239       goto error;
01240     }
01241 
01242     if (innobase_log_file_size > UINT32_MAX) {
01243       fprintf(stderr,
01244         "xtrabackup: innobase_log_file_size can't be over 4GB"
01245         " on 32-bit systemsi\n");
01246 
01247       goto error;
01248     }
01249   }
01250 
01251     os_innodb_umask = (ulint)0664;
01252 
01253   /* First calculate the default path for innodb_data_home_dir etc.,
01254   in case the user has not given any value.
01255 
01256   Note that when using the embedded server, the datadirectory is not
01257   necessarily the current directory of this program. */
01258 
01259       /* It's better to use current lib, to keep paths short */
01260       current_dir[0] = FN_CURLIB;
01261       current_dir[1] = FN_LIBCHAR;
01262       current_dir[2] = 0;
01263       default_path = current_dir;
01264 
01265   ut_a(default_path);
01266 
01267   /* Set InnoDB initialization parameters according to the values
01268   read from MySQL .cnf file */
01269 
01270   if (xtrabackup_backup || xtrabackup_stats) {
01271     fprintf(stderr, "xtrabackup: Target instance is assumed as followings.\n");
01272   } else {
01273     fprintf(stderr, "xtrabackup: Temporary instance for recovery is set as followings.\n");
01274   }
01275 
01276   /*--------------- Data files -------------------------*/
01277 
01278   /* The default dir for data files is the datadir of MySQL */
01279 
01280   srv_data_home = ((xtrabackup_backup || xtrabackup_stats) && innobase_data_home_dir
01281        ? innobase_data_home_dir : default_path);
01282   fprintf(stderr, "xtrabackup:   innodb_data_home_dir = %s\n", srv_data_home);
01283 
01284   /* Set default InnoDB data file size to 10 MB and let it be
01285     auto-extending. Thus users can use InnoDB in >= 4.0 without having
01286   to specify any startup options. */
01287 
01288   if (!innobase_data_file_path) {
01289       innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
01290   }
01291   fprintf(stderr, "xtrabackup:   innodb_data_file_path = %s\n",
01292     innobase_data_file_path);
01293 
01294   /* Since InnoDB edits the argument in the next call, we make another
01295   copy of it: */
01296 
01297   internal_innobase_data_file_path = strdup(innobase_data_file_path);
01298 
01299   ret = (bool) srv_parse_data_file_paths_and_sizes(
01300       internal_innobase_data_file_path);
01301   if (ret == FALSE) {
01302       fprintf(stderr,
01303       "xtrabackup: syntax error in innodb_data_file_path\n");
01304 mem_free_and_error:
01305       free(internal_innobase_data_file_path);
01306                 goto error;
01307   }
01308 
01309   if (xtrabackup_prepare) {
01310     /* "--prepare" needs filenames only */
01311     ulint i;
01312 
01313     for (i=0; i < srv_n_data_files; i++) {
01314       char *p;
01315 
01316       p = srv_data_file_names[i];
01317       while ((p = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
01318       {
01319         p++;
01320         srv_data_file_names[i] = p;
01321       }
01322     }
01323   }
01324 
01325 #ifdef XTRADB_BASED
01326   srv_doublewrite_file = innobase_doublewrite_file;
01327 #ifndef XTRADB55
01328   srv_extra_undoslots = (ibool) innobase_extra_undoslots;
01329 #endif
01330 #endif
01331 
01332   /* -------------- Log files ---------------------------*/
01333 
01334   /* The default dir for log files is the datadir of MySQL */
01335 
01336   if (!((xtrabackup_backup || xtrabackup_stats) && innobase_log_group_home_dir)) {
01337       innobase_log_group_home_dir = default_path;
01338   }
01339   if (xtrabackup_prepare && xtrabackup_incremental_dir) {
01340     innobase_log_group_home_dir = xtrabackup_incremental_dir;
01341   }
01342   fprintf(stderr, "xtrabackup:   innodb_log_group_home_dir = %s\n",
01343     innobase_log_group_home_dir);
01344 
01345 #ifdef UNIV_LOG_ARCHIVE
01346   /* Since innodb_log_arch_dir has no relevance under MySQL,
01347   starting from 4.0.6 we always set it the same as
01348   innodb_log_group_home_dir: */
01349 
01350   innobase_log_arch_dir = innobase_log_group_home_dir;
01351 
01352   srv_arch_dir = innobase_log_arch_dir;
01353 #endif /* UNIG_LOG_ARCHIVE */
01354 
01355   ret = (bool)
01356     srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
01357 
01358   if (ret == FALSE || innobase_mirrored_log_groups != 1) {
01359     fprintf(stderr, "xtrabackup: syntax error in innodb_log_group_home_dir, or a "
01360         "wrong number of mirrored log groups\n");
01361 
01362                 goto mem_free_and_error;
01363   }
01364 
01365   srv_adaptive_flushing = FALSE;
01366   srv_use_sys_malloc = TRUE;
01367   srv_file_format = 1; /* Barracuda */
01368   srv_max_file_format_at_startup = DICT_TF_FORMAT_51; /* on */
01369 
01370   /* --------------------------------------------------*/
01371 
01372   srv_file_flush_method_str = innobase_unix_file_flush_method;
01373 
01374   srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
01375   srv_n_log_files = (ulint) innobase_log_files_in_group;
01376   srv_log_file_size = (ulint) innobase_log_file_size;
01377   fprintf(stderr, "xtrabackup:   innodb_log_files_in_group = %ld\n",
01378     srv_n_log_files);
01379   fprintf(stderr, "xtrabackup:   innodb_log_file_size = %ld\n",
01380     srv_log_file_size);
01381 
01382 #ifdef UNIV_LOG_ARCHIVE
01383   srv_log_archive_on = (ulint) innobase_log_archive;
01384 #endif /* UNIV_LOG_ARCHIVE */
01385   srv_log_buffer_size = (ulint) innobase_log_buffer_size;
01386 
01387         /* We set srv_pool_size here in units of 1 kB. InnoDB internally
01388         changes the value so that it becomes the number of database pages. */
01389 
01390   //srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
01391   srv_buf_pool_size = (ulint) xtrabackup_use_memory;
01392 
01393   srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
01394 
01395   srv_n_file_io_threads = (ulint) innobase_file_io_threads;
01396 
01397   srv_n_read_io_threads = (ulint) innobase_read_io_threads;
01398   srv_n_write_io_threads = (ulint) innobase_write_io_threads;
01399 
01400   srv_force_recovery = (ulint) innobase_force_recovery;
01401 
01402   srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
01403   srv_use_checksums = (ibool) innobase_use_checksums;
01404 
01405   btr_search_enabled = innobase_adaptive_hash_index ? true : false;
01406 
01407   os_use_large_pages = (ibool) innobase_use_large_pages;
01408   os_large_page_size = (ulint) innobase_large_page_size;
01409 
01410   row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
01411 
01412   srv_file_per_table = innobase_file_per_table ? true : false;
01413 
01414         srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
01415 
01416   srv_max_n_open_files = (ulint) innobase_open_files;
01417   srv_innodb_status = (ibool) innobase_create_status_file;
01418 
01419   srv_print_verbose_log = 1;
01420 
01421   /* Store the default charset-collation number of this MySQL
01422   installation */
01423 
01424   /* We cannot treat characterset here for now!! */
01425   data_mysql_default_charset_coll = (ulint)default_charset_info->number;
01426 
01427   ut_a(DATA_MYSQL_BINARY_CHARSET_COLL == my_charset_bin.number);
01428 
01429   //innobase_commit_concurrency_init_default();
01430 
01431   /* Since we in this module access directly the fields of a trx
01432         struct, and due to different headers and flags it might happen that
01433   mutex_t has a different size in this module and in InnoDB
01434   modules, we check at run time that the size is the same in
01435   these compilation modules. */
01436 
01437 
01438   /* On 5.5 srv_use_native_aio is TRUE by default. It is later reset
01439   if it is not supported by the platform in
01440   innobase_start_or_create_for_mysql(). As we don't call it in xtrabackup,
01441   we have to duplicate checks from that function here. */
01442 
01443 #ifdef __WIN__
01444   switch (os_get_os_version()) {
01445   case OS_WIN95:
01446   case OS_WIN31:
01447   case OS_WINNT:
01448     /* On Win 95, 98, ME, Win32 subsystem for Windows 3.1,
01449     and NT use simulated aio. In NT Windows provides async i/o,
01450     but when run in conjunction with InnoDB Hot Backup, it seemed
01451     to corrupt the data files. */
01452 
01453     srv_use_native_aio = FALSE;
01454     break;
01455 
01456   case OS_WIN2000:
01457   case OS_WINXP:
01458     /* On 2000 and XP, async IO is available. */
01459     srv_use_native_aio = TRUE;
01460     break;
01461 
01462   default:
01463     /* Vista and later have both async IO and condition variables */
01464     srv_use_native_aio = TRUE;
01465     srv_use_native_conditions = TRUE;
01466     break;
01467   }
01468 
01469 #elif defined(LINUX_NATIVE_AIO)
01470 
01471   if (srv_use_native_aio) {
01472     ut_print_timestamp(stderr);
01473     fprintf(stderr,
01474       " InnoDB: Using Linux native AIO\n");
01475   }
01476 #else
01477   /* Currently native AIO is supported only on windows and linux
01478   and that also when the support is compiled in. In all other
01479   cases, we ignore the setting of innodb_use_native_aio. */
01480   srv_use_native_aio = FALSE;
01481 
01482 #endif
01483 
01484   return(FALSE);
01485 
01486 error:
01487   fprintf(stderr, "xtrabackup: innodb_init_param(): Error occured.\n");
01488   return(TRUE);
01489 }
01490 
01491 static bool
01492 innodb_init(void)
01493 {
01494   int err;
01495 
01496   err = innobase_start_or_create_for_mysql();
01497 
01498   if (err != DB_SUCCESS) {
01499       free(internal_innobase_data_file_path);
01500                 goto error;
01501   }
01502 
01503   /* They may not be needed for now */
01504 //  (void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0,
01505 //          (hash_get_key) innobase_get_key, 0, 0);
01506 //        pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
01507 //        pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
01508 //        pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
01509 //        pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
01510 //        pthread_cond_init(&commit_cond, NULL);
01511 
01512   innodb_inited= 1;
01513 
01514   return(FALSE);
01515 
01516 error:
01517   fprintf(stderr, "xtrabackup: innodb_init(): Error occured.\n");
01518   return(TRUE);
01519 }
01520 
01521 static bool
01522 innodb_end(void)
01523 {
01524   srv_fast_shutdown = (ulint) innobase_fast_shutdown;
01525   innodb_inited = 0;
01526 
01527   fprintf(stderr, "xtrabackup: starting shutdown with innodb_fast_shutdown = %lu\n",
01528     srv_fast_shutdown);
01529 
01530   if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
01531     goto error;
01532   }
01533   free(internal_innobase_data_file_path);
01534 
01535   /* They may not be needed for now */
01536 //  hash_free(&innobase_open_tables);
01537 //  pthread_mutex_destroy(&innobase_share_mutex);
01538 //  pthread_mutex_destroy(&prepare_commit_mutex);
01539 //  pthread_mutex_destroy(&commit_threads_m);
01540 //  pthread_mutex_destroy(&commit_cond_m);
01541 //  pthread_cond_destroy(&commit_cond);
01542 
01543   return(FALSE);
01544 
01545 error:
01546   fprintf(stderr, "xtrabackup: innodb_end(): Error occured.\n");
01547   return(TRUE);
01548 }
01549 
01550 /* ================= common ================= */
01551 static bool
01552 xtrabackup_read_metadata(char *filename)
01553 {
01554   FILE *fp;
01555 
01556   fp = fopen(filename,"r");
01557   if(!fp) {
01558     fprintf(stderr, "xtrabackup: Error: cannot open %s\n", filename);
01559     return(TRUE);
01560   }
01561 
01562   if (fscanf(fp, "backup_type = %29s\n", metadata_type)
01563       != 1)
01564     return(TRUE);
01565   if (fscanf(fp, "from_lsn = %"PRIu64"\n", &metadata_from_lsn)
01566       != 1)
01567     return(TRUE);
01568   if (fscanf(fp, "to_lsn = %"PRIu64"\n", &metadata_to_lsn)
01569       != 1)
01570     return(TRUE);
01571   if (fscanf(fp, "last_lsn = %"PRIu64"\n", &metadata_last_lsn)
01572       != 1) {
01573     metadata_last_lsn = 0;
01574   }
01575 
01576   fclose(fp);
01577 
01578   return(FALSE);
01579 }
01580 
01581 static bool
01582 xtrabackup_write_metadata(char *filename)
01583 {
01584   FILE *fp;
01585 
01586   fp = fopen(filename,"w");
01587   if(!fp) {
01588     fprintf(stderr, "xtrabackup: Error: cannot open %s\n", filename);
01589     return(TRUE);
01590   }
01591 
01592   if (fprintf(fp, "backup_type = %s\n", metadata_type)
01593       < 0)
01594     return(TRUE);
01595   if (fprintf(fp, "from_lsn = %"PRIu64"\n", metadata_from_lsn)
01596       < 0)
01597     return(TRUE);
01598   if (fprintf(fp, "to_lsn = %"PRIu64"\n", metadata_to_lsn)
01599       < 0)
01600     return(TRUE);
01601   if (fprintf(fp, "last_lsn = %"PRIu64"\n", metadata_last_lsn)
01602       < 0)
01603     return(TRUE);
01604 
01605   fclose(fp);
01606 
01607   return(FALSE);
01608 }
01609 
01610 /***********************************************************************
01611 Read meta info for an incremental delta.
01612 @return TRUE on success, FALSE on failure. */
01613 static bool
01614 xb_read_delta_metadata(const char *filepath, xb_delta_info_t *info)
01615 {
01616   FILE *fp;
01617 
01618   memset(info, 0, sizeof(xb_delta_info_t));
01619 
01620   fp = fopen(filepath, "r");
01621   if (!fp) {
01622     /* Meta files for incremental deltas are optional */
01623     return(TRUE);
01624   }
01625 
01626   if (fscanf(fp, "page_size = %lu\n", &info->page_size) != 1)
01627     return(FALSE);
01628 
01629   fclose(fp);
01630 
01631   return(TRUE);
01632 }
01633 
01634 /***********************************************************************
01635 Write meta info for an incremental delta.
01636 @return TRUE on success, FALSE on failure. */
01637 static bool
01638 xb_write_delta_metadata(const char *filepath, const xb_delta_info_t *info)
01639 {
01640   FILE *fp;
01641 
01642   fp = fopen(filepath, "w");
01643   if (!fp) {
01644     fprintf(stderr, "xtrabackup: Error: cannot open %s\n", filepath);
01645     return(FALSE);
01646   }
01647 
01648   if (fprintf(fp, "page_size = %lu\n", info->page_size) < 0)
01649     return(FALSE);
01650 
01651   fclose(fp);
01652 
01653   return(TRUE);
01654 }
01655 
01656 /* ================= backup ================= */
01657 static void
01658 xtrabackup_io_throttling(void)
01659 {
01660   if (xtrabackup_throttle && (io_ticket--) < 0) {
01661     os_event_reset(wait_throttle);
01662     os_event_wait(wait_throttle);
01663   }
01664 }
01665 
01666 
01667 /* TODO: We may tune the behavior (e.g. by fil_aio)*/
01668 #define COPY_CHUNK 64
01669 
01670 static bool
01671 xtrabackup_copy_datafile(fil_node_t* node, uint thread_n)
01672 {
01673   os_file_t src_file = -1;
01674   os_file_t dst_file = -1;
01675   char    dst_path[FN_REFLEN];
01676   char    meta_path[FN_REFLEN];
01677   ibool   success;
01678   byte*   page;
01679   byte*   buf2 = NULL;
01680   IB_INT64  file_size;
01681   IB_INT64  offset;
01682   ulint   page_in_buffer= 0;
01683   ulint   incremental_buffers = 0;
01684   ulint   page_size;
01685   ulint   page_size_shift;
01686   ulint   zip_size;
01687   xb_delta_info_t info;
01688 
01689   info.page_size = 0;
01690 
01691 #ifdef XTRADB_BASED
01692   if (xtrabackup_tables && (!trx_sys_sys_space(node->space->id)))
01693 #else
01694   if (xtrabackup_tables && (node->space->id != 0))
01695 #endif
01696   { /* must backup id==0 */
01697     char *p;
01698     int p_len, regres= 0;
01699     char *next, *prev;
01700     char tmp;
01701     int i;
01702 
01703     p = node->name;
01704     prev = NULL;
01705     while ((next = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
01706     {
01707       prev = p;
01708       p = next + 1;
01709     }
01710     p_len = strlen(p) - strlen(".ibd");
01711 
01712     if (p_len < 1) {
01713       /* unknown situation: skip filtering */
01714       goto skip_filter;
01715     }
01716 
01717     /* TODO: Fix this lazy implementation... */
01718     tmp = p[p_len];
01719     p[p_len] = 0;
01720     *(p - 1) = '.';
01721 
01722     for (i = 0; i < tables_regex_num; i++) {
01723       regres = regexec(&tables_regex[i], prev, 1, tables_regmatch, 0);
01724       if (regres != REG_NOMATCH)
01725         break;
01726     }
01727 
01728     p[p_len] = tmp;
01729     *(p - 1) = SRV_PATH_SEPARATOR;
01730 
01731     if ( regres == REG_NOMATCH ) {
01732       printf("[%02u] Copying %s is skipped.\n",
01733              thread_n, node->name);
01734       return(FALSE);
01735     }
01736   }
01737 
01738 #ifdef XTRADB_BASED
01739   if (xtrabackup_tables_file && (!trx_sys_sys_space(node->space->id)))
01740 #else
01741   if (xtrabackup_tables_file && (node->space->id != 0))
01742 #endif
01743   { /* must backup id==0 */
01744     xtrabackup_tables_t* table;
01745     char *p;
01746     int p_len;
01747     char *next, *prev;
01748     char tmp;
01749 
01750     p = node->name;
01751     prev = NULL;
01752     while ((next = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
01753     {
01754       prev = p;
01755       p = next + 1;
01756     }
01757     p_len = strlen(p) - strlen(".ibd");
01758 
01759     if (p_len < 1) {
01760       /* unknown situation: skip filtering */
01761       goto skip_filter;
01762     }
01763 
01764     /* TODO: Fix this lazy implementation... */
01765     tmp = p[p_len];
01766     p[p_len] = 0;
01767 
01768     HASH_SEARCH(name_hash, tables_hash, ut_fold_string(prev),
01769           xtrabackup_tables_t*,
01770           table,
01771           ut_ad(table->name),
01772               !strcmp(table->name, prev));
01773 
01774     p[p_len] = tmp;
01775 
01776     if (!table) {
01777       printf("[%02u] Copying %s is skipped.\n",
01778              thread_n, node->name);
01779       return(FALSE);
01780     }
01781   }
01782 
01783 skip_filter:
01784   zip_size = fil_space_get_zip_size(node->space->id);
01785   if (zip_size == ULINT_UNDEFINED) {
01786     fprintf(stderr, "[%02u] xtrabackup: Warning: "
01787       "Failed to determine page size for %s.\n"
01788       "[%02u] xtrabackup: Warning: We assume the table was "
01789       "dropped during xtrabackup execution and ignore the "
01790       "file.\n", thread_n, node->name, thread_n);
01791     goto skip;
01792   } else if (zip_size) {
01793     page_size = zip_size;
01794     page_size_shift = get_bit_shift(page_size);
01795     fprintf(stderr, "[%02u] %s is compressed with page size = "
01796       "%lu bytes\n", thread_n, node->name, page_size);
01797     if (page_size_shift < 10 || page_size_shift > 14) {
01798       fprintf(stderr, "[%02u] xtrabackup: Error: Invalid "
01799         "page size.\n", thread_n);
01800       ut_error;
01801     }
01802   } else {
01803     page_size = UNIV_PAGE_SIZE;
01804     page_size_shift = UNIV_PAGE_SIZE_SHIFT;
01805   }
01806 
01807 #ifdef XTRADB_BASED
01808   if (trx_sys_sys_space(node->space->id))
01809 #else
01810   if (node->space->id == 0)
01811 #endif
01812   {
01813     char *next, *p;
01814     /* system datafile "/fullpath/datafilename.ibd" or "./datafilename.ibd" */
01815     p = node->name;
01816     while ((next = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
01817     {
01818       p = next + 1;
01819     }
01820     sprintf(dst_path, "%s/%s", xtrabackup_target_dir, p);
01821   } else {
01822     /* file per table style "./database/table.ibd" */
01823     sprintf(dst_path, "%s%s", xtrabackup_target_dir, strstr(node->name, SRV_PATH_SEPARATOR_STR));
01824   }
01825 
01826   if (xtrabackup_incremental) {
01827     snprintf(meta_path, sizeof(meta_path),
01828        "%s%s", dst_path, XB_DELTA_INFO_SUFFIX);
01829     strcat(dst_path, ".delta");
01830 
01831     /* clear buffer */
01832     bzero(incremental_buffer, (page_size/4) * page_size);
01833     page_in_buffer = 0;
01834     mach_write_to_4(incremental_buffer, 0x78747261UL);/*"xtra"*/
01835     page_in_buffer++;
01836 
01837     info.page_size = page_size;
01838   }
01839 
01840   /* open src_file*/
01841   if (!node->open) {
01842     src_file = os_file_create_simple_no_error_handling(
01843             0 /* dummy of innodb_file_data_key */,
01844             node->name, OS_FILE_OPEN,
01845             OS_FILE_READ_ONLY, &success);
01846     if (!success) {
01847       /* The following call prints an error message */
01848       os_file_get_last_error(TRUE);
01849 
01850       fprintf(stderr,
01851         "[%02u] xtrabackup: Warning: cannot open %s\n"
01852         "[%02u] xtrabackup: Warning: We assume the "
01853         "table was dropped during xtrabackup execution "
01854         "and ignore the file.\n",
01855         thread_n, node->name, thread_n);
01856       goto skip;
01857     }
01858 
01859     if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
01860       os_file_set_nocache(src_file, node->name, "OPEN");
01861     }
01862   } else {
01863     src_file = node->handle;
01864   }
01865 
01866 #ifdef USE_POSIX_FADVISE
01867   posix_fadvise(src_file, 0, 0, POSIX_FADV_SEQUENTIAL);
01868   posix_fadvise(src_file, 0, 0, POSIX_FADV_DONTNEED);
01869 #endif
01870 
01871   /* open dst_file */
01872   /* os_file_create reads srv_unix_file_flush_method */
01873   dst_file = os_file_create(
01874       0 /* dummy of innodb_file_data_key */,
01875       dst_path, OS_FILE_CREATE,
01876       OS_FILE_NORMAL, OS_DATA_FILE, &success);
01877                 if (!success) {
01878                         /* The following call prints an error message */
01879                         os_file_get_last_error(TRUE);
01880 
01881       fprintf(stderr,"[%02u] xtrabackup: error: "
01882         "cannot open %s\n", thread_n, dst_path);
01883                         goto error;
01884                 }
01885 
01886 #ifdef USE_POSIX_FADVISE
01887   posix_fadvise(dst_file, 0, 0, POSIX_FADV_DONTNEED);
01888 #endif
01889 
01890   /* copy : TODO: tune later */
01891   printf("[%02u] Copying %s \n     to %s\n", thread_n,
01892          node->name, dst_path);
01893 
01894   buf2 = (unsigned char*) ut_malloc(COPY_CHUNK * page_size + UNIV_PAGE_SIZE);
01895   page = (unsigned char*) ut_align(buf2, UNIV_PAGE_SIZE);
01896 
01897   success = os_file_read(src_file, page, 0, 0, UNIV_PAGE_SIZE);
01898   if (!success) {
01899     goto error;
01900   }
01901 
01902   file_size = os_file_get_size_as_iblonglong(src_file);
01903 
01904   for (offset = 0; offset < file_size; offset += COPY_CHUNK * page_size) {
01905     ulint chunk;
01906     ulint chunk_offset;
01907     ulint retry_count = 10;
01908 //copy_loop:
01909     if ((ulint)(file_size - offset) > COPY_CHUNK * page_size) {
01910       chunk = COPY_CHUNK * page_size;
01911     } else {
01912       chunk = (ulint)(file_size - offset);
01913     }
01914 
01915 read_retry:
01916     xtrabackup_io_throttling();
01917 
01918     success = os_file_read(src_file, page,
01919         (ulint)(offset & 0xFFFFFFFFUL),
01920         (ulint)(offset >> 32), chunk);
01921     if (!success) {
01922       goto error;
01923     }
01924 
01925     /* check corruption and retry */
01926     for (chunk_offset = 0; chunk_offset < chunk; chunk_offset += page_size) {
01927       if (buf_page_is_corrupted(page + chunk_offset, zip_size))
01928       {
01929         if (
01930 #ifdef XTRADB_BASED
01931             trx_sys_sys_space(node->space->id)
01932 #else
01933             node->space->id == 0
01934 #endif
01935             && ((offset + (IB_INT64)chunk_offset) >> page_size_shift)
01936                >= FSP_EXTENT_SIZE
01937             && ((offset + (IB_INT64)chunk_offset) >> page_size_shift)
01938                < FSP_EXTENT_SIZE * 3) {
01939           /* double write buffer may have old data in the end
01940              or it may contain the other format page like COMPRESSED.
01941              So, we can pass the check of double write buffer.*/
01942           ut_a(page_size == UNIV_PAGE_SIZE);
01943           fprintf(stderr, "[%02u] xtrabackup: "
01944             "Page %lu seems double write "
01945             "buffer. passing the check.\n",
01946             thread_n,
01947             (ulint)((offset +
01948                (IB_INT64)chunk_offset) >>
01949               page_size_shift));
01950         } else {
01951           retry_count--;
01952           if (retry_count == 0) {
01953             fprintf(stderr,
01954               "[%02u] xtrabackup: "
01955               "Error: 10 retries "
01956               "resulted in fail. This"
01957               "file seems to be "
01958               "corrupted.\n",
01959               thread_n);
01960             goto error;
01961           }
01962           fprintf(stderr, "[%02u] xtrabackup: "
01963             "Database page corruption "
01964             "detected at page %lu. "
01965             "retrying...\n",
01966             thread_n,
01967             (ulint)((offset +
01968                (IB_INT64)chunk_offset)
01969               >> page_size_shift));
01970           goto read_retry;
01971         }
01972       }
01973     }
01974 
01975     if (xtrabackup_incremental) {
01976       for (chunk_offset = 0; chunk_offset < chunk; chunk_offset += page_size) {
01977         /* newer page */
01978         /* This condition may be OK for header, ibuf and fsp */
01979         if (ut_dulint_cmp(incremental_lsn,
01980           MACH_READ_64(page + chunk_offset + FIL_PAGE_LSN)) < 0) {
01981   /* ========================================= */
01982   IB_INT64 offset_on_page;
01983 
01984   if (page_in_buffer == page_size/4) {
01985     /* flush buffer */
01986     success = os_file_write(dst_path, dst_file, incremental_buffer,
01987       ((incremental_buffers * (page_size/4))
01988         << page_size_shift) & 0xFFFFFFFFUL,
01989       (incremental_buffers * (page_size/4))
01990         >> (32 - page_size_shift),
01991       page_in_buffer * page_size);
01992     if (!success) {
01993       goto error;
01994     }
01995 
01996     incremental_buffers++;
01997 
01998     /* clear buffer */
01999     bzero(incremental_buffer, (page_size/4) * page_size);
02000     page_in_buffer = 0;
02001     mach_write_to_4(incremental_buffer, 0x78747261UL);/*"xtra"*/
02002     page_in_buffer++;
02003   }
02004 
02005   offset_on_page = ((offset + (IB_INT64)chunk_offset) >> page_size_shift);
02006   ut_a(offset_on_page >> 32 == 0);
02007 
02008   mach_write_to_4(incremental_buffer + page_in_buffer * 4, (ulint)offset_on_page);
02009   memcpy(incremental_buffer + page_in_buffer * page_size,
02010          page + chunk_offset, page_size);
02011 
02012   page_in_buffer++;
02013   /* ========================================= */
02014         }
02015       }
02016     } else {
02017       success = os_file_write(dst_path, dst_file, page,
02018         (ulint)(offset & 0xFFFFFFFFUL),
02019         (ulint)(offset >> 32), chunk);
02020       if (!success) {
02021         goto error;
02022       }
02023     }
02024 
02025   }
02026 
02027   if (xtrabackup_incremental) {
02028     /* termination */
02029     if (page_in_buffer != page_size/4) {
02030       mach_write_to_4(incremental_buffer + page_in_buffer * 4, 0xFFFFFFFFUL);
02031     }
02032 
02033     mach_write_to_4(incremental_buffer, 0x58545241UL);/*"XTRA"*/
02034 
02035     /* flush buffer */
02036     success = os_file_write(dst_path, dst_file, incremental_buffer,
02037       ((incremental_buffers * (page_size/4))
02038         << page_size_shift) & 0xFFFFFFFFUL,
02039       (incremental_buffers * (page_size/4))
02040         >> (32 - page_size_shift),
02041       page_in_buffer * page_size);
02042     if (!success) {
02043       goto error;
02044     }
02045     if (!xb_write_delta_metadata(meta_path, &info)) {
02046       fprintf(stderr, "[%02u] xtrabackup: Error: "
02047         "failed to write meta info for %s\n",
02048         thread_n, dst_path);
02049       goto error;
02050     }
02051   }
02052 
02053   success = os_file_flush(dst_file);
02054   if (!success) {
02055     goto error;
02056   }
02057 
02058 
02059   /* check size again */
02060   /* TODO: but is it needed ?? */
02061 //  if (file_size < os_file_get_size_as_iblonglong(src_file)) {
02062 //    offset -= COPY_CHUNK * page_size;
02063 //    file_size = os_file_get_size_as_iblonglong(src_file);
02064 //    goto copy_loop;
02065 //  }
02066 
02067   /* TODO: How should we treat double_write_buffer here? */
02068   /* (currently, don't care about. Because,
02069       the blocks is newer than the last checkpoint anyway.) */
02070 
02071   /* close */
02072   printf("[%02u]        ...done\n", thread_n);
02073   if (!node->open) {
02074     os_file_close(src_file);
02075   }
02076   os_file_close(dst_file);
02077   ut_free(buf2);
02078   return(FALSE);
02079 error:
02080   if (src_file != -1 && !node->open)
02081     os_file_close(src_file);
02082   if (dst_file != -1)
02083     os_file_close(dst_file);
02084   if (buf2)
02085     ut_free(buf2);
02086   fprintf(stderr, "[%02u] xtrabackup: Error: "
02087     "xtrabackup_copy_datafile() failed.\n", thread_n);
02088   return(TRUE); /*ERROR*/
02089 
02090 skip:
02091   if (src_file != -1 && !node->open)
02092     os_file_close(src_file);
02093   if (dst_file != -1)
02094     os_file_close(dst_file);
02095   if (buf2)
02096     ut_free(buf2);
02097   fprintf(stderr, "[%02u] xtrabackup: Warning: skipping file %s.\n",
02098     thread_n, node->name);
02099   return(FALSE);
02100 }
02101 
02102 static bool
02103 xtrabackup_copy_logfile(LSN64 from_lsn, bool is_last)
02104 {
02105   /* definition from recv_recovery_from_checkpoint_start() */
02106   log_group_t*  group;
02107   LSN64   group_scanned_lsn;
02108   LSN64   contiguous_lsn;
02109 
02110   ibool   success;
02111 
02112   if (!xtrabackup_stream)
02113     ut_a(dst_log != -1);
02114 
02115   /* read from checkpoint_lsn_start to current */
02116   contiguous_lsn = ut_dulint_align_down(from_lsn,
02117             OS_FILE_LOG_BLOCK_SIZE);
02118 
02119   /* TODO: We must check the contiguous_lsn still exists in log file.. */
02120 
02121   group = UT_LIST_GET_FIRST(log_sys->log_groups);
02122 
02123   while (group) {
02124     ibool finished;
02125     LSN64 start_lsn;
02126     LSN64 end_lsn;
02127 
02128 
02129     /* reference recv_group_scan_log_recs() */
02130   finished = FALSE;
02131 
02132   start_lsn = contiguous_lsn;
02133     
02134   while (!finished) {     
02135     end_lsn = ut_dulint_add(start_lsn, RECV_SCAN_SIZE);
02136 
02137     xtrabackup_io_throttling();
02138 
02139     log_group_read_log_seg(LOG_RECOVER, log_sys->buf,
02140             group, start_lsn, end_lsn);
02141 
02142     //printf("log read from (%lu %lu) to (%lu %lu)\n",
02143     //  start_lsn.high, start_lsn.low, end_lsn.high, end_lsn.low);
02144 
02145     /* reference recv_scan_log_recs() */
02146     {
02147   byte* log_block;
02148   ulint no;
02149   LSN64 scanned_lsn;
02150   ulint data_len;
02151 
02152   ulint scanned_checkpoint_no = 0;
02153 
02154   finished = FALSE;
02155   
02156   log_block = log_sys->buf;
02157   scanned_lsn = start_lsn;
02158 
02159   while (log_block < log_sys->buf + RECV_SCAN_SIZE && !finished) {
02160 
02161     no = log_block_get_hdr_no(log_block);
02162 
02163     if (no != log_block_convert_lsn_to_no(scanned_lsn)
02164         || !log_block_checksum_is_ok_or_old_format(log_block)) {
02165 
02166       if (no > log_block_convert_lsn_to_no(scanned_lsn)
02167           && log_block_checksum_is_ok_or_old_format(log_block)) {
02168         fprintf(stderr,
02169 ">> ###Warning###: The copying transaction log migh be overtaken already by the target.\n"
02170 ">>              : Waiting log block no %lu, but the bumber is already %lu.\n"
02171 ">>              : If the number equals %lu + n * %lu, it should be overtaken already.\n",
02172           (ulong) log_block_convert_lsn_to_no(scanned_lsn),
02173           (ulong) no,
02174           (ulong) log_block_convert_lsn_to_no(scanned_lsn),
02175           (ulong) (log_block_convert_lsn_to_no(
02176                log_group_get_capacity(group)
02177                     ) - 1));
02178 
02179       } else if (no == log_block_convert_lsn_to_no(scanned_lsn)
02180           && !log_block_checksum_is_ok_or_old_format(
02181                 log_block)) {
02182         fprintf(stderr,
02183 "xtrabackup: Log block no %lu at lsn %"PRIu64" has\n"
02184 "xtrabackup: ok header, but checksum field contains %lu, should be %lu\n",
02185         (ulong) no,
02186         scanned_lsn,
02187         (ulong) log_block_get_checksum(log_block),
02188         (ulong) log_block_calc_checksum(log_block));
02189       }
02190 
02191       /* Garbage or an incompletely written log block */
02192 
02193       finished = TRUE;
02194 
02195       break;
02196     }
02197 
02198     if (log_block_get_flush_bit(log_block)) {
02199       /* This block was a start of a log flush operation:
02200       we know that the previous flush operation must have
02201       been completed for all log groups before this block
02202       can have been flushed to any of the groups. Therefore,
02203       we know that log data is contiguous up to scanned_lsn
02204       in all non-corrupt log groups. */
02205 
02206       if (ut_dulint_cmp(scanned_lsn, contiguous_lsn) > 0) {
02207         contiguous_lsn = scanned_lsn;
02208       }
02209     }
02210 
02211     data_len = log_block_get_data_len(log_block);
02212 
02213     if (
02214         (scanned_checkpoint_no > 0)
02215         && (log_block_get_checkpoint_no(log_block)
02216            < scanned_checkpoint_no)
02217         && (scanned_checkpoint_no
02218       - log_block_get_checkpoint_no(log_block)
02219       > 0x80000000UL)) {
02220 
02221       /* Garbage from a log buffer flush which was made
02222       before the most recent database recovery */
02223 
02224       finished = TRUE;
02225       break;
02226     }       
02227 
02228     scanned_lsn = ut_dulint_add(scanned_lsn, data_len);
02229     scanned_checkpoint_no = log_block_get_checkpoint_no(log_block);
02230 
02231     if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
02232       /* Log data for this group ends here */
02233 
02234       finished = TRUE;
02235     } else {
02236       log_block += OS_FILE_LOG_BLOCK_SIZE;
02237     }
02238   } /* while (log_block < log_sys->buf + RECV_SCAN_SIZE && !finished) */
02239 
02240   group_scanned_lsn = scanned_lsn;
02241 
02242 
02243 
02244     }
02245 
02246     /* ===== write log to 'xtrabackup_logfile' ====== */
02247     {
02248     ulint write_size;
02249 
02250     if (!finished) {
02251       write_size = RECV_SCAN_SIZE;
02252     } else {
02253       write_size = ut_dulint_minus(
02254           ut_dulint_align_up(group_scanned_lsn, OS_FILE_LOG_BLOCK_SIZE),
02255           start_lsn);
02256     }
02257 
02258     //printf("Wrinting offset= %lld, size= %lu\n", log_copy_offset, write_size);
02259 
02260     if (!xtrabackup_stream) {
02261       success = os_file_write(dst_log_path, dst_log, log_sys->buf,
02262           (ulint)(log_copy_offset & 0xFFFFFFFFUL),
02263           (ulint)(log_copy_offset >> 32), write_size);
02264     } else {
02265       ulint ret;
02266       ulint stdout_write_size = write_size;
02267       if (finished && !is_last
02268           && group_scanned_lsn % OS_FILE_LOG_BLOCK_SIZE
02269          )
02270         stdout_write_size -= OS_FILE_LOG_BLOCK_SIZE;
02271       if (stdout_write_size) {
02272         ret = write(fileno(stdout), log_sys->buf, stdout_write_size);
02273         if (ret == stdout_write_size) {
02274           success = TRUE;
02275         } else {
02276           fprintf(stderr, "write: %lu > %lu\n", stdout_write_size, ret);
02277           success = FALSE;
02278         }
02279       } else {
02280         success = TRUE; /* do nothing */
02281       }
02282     }
02283 
02284     log_copy_offset += write_size;
02285 
02286     if (finished && group_scanned_lsn % OS_FILE_LOG_BLOCK_SIZE)
02287     {
02288       /* if continue, it will start from align_down(group_scanned_lsn) */
02289       log_copy_offset -= OS_FILE_LOG_BLOCK_SIZE;
02290     }
02291 
02292     if(!success) {
02293       if (!xtrabackup_stream) {
02294         fprintf(stderr, "xtrabackup: Error: os_file_write to %s\n", dst_log_path);
02295       } else {
02296         fprintf(stderr, "xtrabackup: Error: write to stdout\n");
02297       }
02298       goto error;
02299     }
02300 
02301 
02302     }
02303 
02304 
02305 
02306 
02307 
02308     start_lsn = end_lsn;
02309   }
02310 
02311 
02312 
02313     group->scanned_lsn = group_scanned_lsn;
02314     
02315 
02316     fprintf(stderr, ">> log scanned up to (%"PRIu64")\n",group->scanned_lsn);
02317 
02318     group = UT_LIST_GET_NEXT(log_groups, group);
02319 
02320     /* update global variable*/
02321     log_copy_scanned_lsn = group_scanned_lsn;
02322 
02323     /* innodb_mirrored_log_groups must be 1, no other groups */
02324     ut_a(group == NULL);
02325   }
02326 
02327 
02328   if (!xtrabackup_stream) {
02329     success = os_file_flush(dst_log);
02330   } else {
02331     fflush(stdout);
02332     success = TRUE;
02333   }
02334 
02335   if(!success) {
02336     goto error;
02337   }
02338 
02339   return(FALSE);
02340 
02341 error:
02342   if (!xtrabackup_stream)
02343     os_file_close(dst_log);
02344   fprintf(stderr, "xtrabackup: Error: xtrabackup_copy_logfile() failed.\n");
02345   return(TRUE);
02346 }
02347 
02348 /* copying logfile in background */
02349 #define SLEEPING_PERIOD 5
02350 
02351 static
02352 #ifndef __WIN__
02353 void*
02354 #else
02355 ulint
02356 #endif
02357 log_copying_thread(
02358   void* )
02359 {
02360   ulint counter = 0;
02361 
02362   if (!xtrabackup_stream)
02363     ut_a(dst_log != -1);
02364 
02365   log_copying_running = TRUE;
02366 
02367   while(log_copying) {
02368     os_thread_sleep(200000); /*0.2 sec*/
02369 
02370     counter++;
02371     if(counter >= SLEEPING_PERIOD * 5) {
02372       if(xtrabackup_copy_logfile(log_copy_scanned_lsn, FALSE))
02373         goto end;
02374       counter = 0;
02375     }
02376   }
02377 
02378   /* last copying */
02379   if(xtrabackup_copy_logfile(log_copy_scanned_lsn, TRUE))
02380     goto end;
02381 
02382   log_copying_succeed = TRUE;
02383 end:
02384   log_copying_running = FALSE;
02385   os_thread_exit(NULL);
02386 
02387   return(0);
02388 }
02389 
02390 /* io throttle watching (rough) */
02391 static
02392 #ifndef __WIN__
02393 void*
02394 #else
02395 ulint
02396 #endif
02397 io_watching_thread(
02398   void* )
02399 {
02400   /* currently, for --backup only */
02401   ut_a(xtrabackup_backup);
02402 
02403   while (log_copying) {
02404     os_thread_sleep(1000000); /*1 sec*/
02405 
02406     //for DEBUG
02407     //if (io_ticket == xtrabackup_throttle) {
02408     //  fprintf(stderr, "There seem to be no IO...?\n");
02409     //}
02410 
02411     io_ticket = xtrabackup_throttle;
02412     os_event_set(wait_throttle);
02413   }
02414 
02415   /* stop io throttle */
02416   xtrabackup_throttle = 0;
02417   os_event_set(wait_throttle);
02418 
02419   os_thread_exit(NULL);
02420 
02421   return(0);
02422 }
02423 
02424 /************************************************************************
02425 I/o-handler thread function. */
02426 static
02427 
02428 #ifndef __WIN__
02429 void*
02430 #else
02431 ulint
02432 #endif
02433 io_handler_thread(
02434 /*==============*/
02435   void* arg)
02436 {
02437   ulint segment;
02438   ulint i;
02439   
02440   segment = *((ulint*)arg);
02441 
02442   for (i = 0;; i++) {
02443     fil_aio_wait(segment);
02444   }
02445 
02446   /* We count the number of threads in os_thread_exit(). A created
02447   thread should always use that to exit and not use return() to exit.
02448   The thread actually never comes here because it is exited in an
02449   os_event_wait(). */
02450 
02451   os_thread_exit(NULL);
02452 
02453 #ifndef __WIN__
02454   return(NULL);       /* Not reached */
02455 #else
02456   return(0);
02457 #endif
02458 }
02459 
02460 /***************************************************************************
02461 Creates an output directory for a given tablespace, if it does not exist */
02462 static
02463 int
02464 xtrabackup_create_output_dir(
02465 /*==========================*/
02466         /* out: 0 if succes, -1 if failure */
02467   fil_space_t *space) /* in: tablespace */
02468 {
02469   char  path[FN_REFLEN];
02470   char  *ptr1, *ptr2;
02471 
02472   /* mkdir if not exist */
02473   ptr1 = strstr(space->name, SRV_PATH_SEPARATOR_STR);
02474   if (ptr1) {
02475     ptr2 = strstr(ptr1 + 1, SRV_PATH_SEPARATOR_STR);
02476   } else {
02477     ptr2 = NULL;
02478   }
02479 #ifdef XTRADB_BASED
02480   if(!trx_sys_sys_space(space->id) && ptr2)
02481 #else
02482   if(space->id && ptr2)
02483 #endif
02484   {
02485     /* single table space */
02486     *ptr2 = 0; /* temporary (it's my lazy..)*/
02487     snprintf(path, sizeof(path), "%s%s", xtrabackup_target_dir,
02488        ptr1);
02489     *ptr2 = SRV_PATH_SEPARATOR;
02490 
02491     if (mkdir(path, 0777) != 0 && errno != EEXIST) {
02492       fprintf(stderr,
02493         "xtrabackup: Error: cannot mkdir %d: %s\n",
02494         errno, path);
02495       return -1;
02496     }
02497   }
02498   return 0;
02499 }
02500 
02501 /**************************************************************************
02502 Datafiles copying thread.*/
02503 static
02504 os_thread_ret_t
02505 data_copy_thread_func(
02506 /*==================*/
02507   void *arg) /* thread context */
02508 {
02509   data_thread_ctxt_t  *ctxt = (data_thread_ctxt_t *) arg;
02510   uint      num = ctxt->num;
02511   fil_space_t*    space;
02512   ibool     space_changed;
02513   fil_node_t*       node;
02514 
02515   while ((node = datafiles_iter_next(ctxt->it, &space_changed)) != NULL) {
02516     space = node->space;
02517 
02518     if (space_changed && xtrabackup_create_output_dir(space))
02519       exit(EXIT_FAILURE);
02520 
02521     /* copy the datafile */
02522     if(xtrabackup_copy_datafile(node, num)) {
02523       fprintf(stderr, "[%02u] xtrabackup: Error: "
02524         "failed to copy datafile.\n",
02525         num);
02526       exit(EXIT_FAILURE);
02527     }
02528   }
02529 
02530   os_mutex_enter(ctxt->count_mutex);
02531   (*ctxt->count)--;
02532   os_mutex_exit(ctxt->count_mutex);
02533 
02534   os_thread_exit(NULL);
02535   OS_THREAD_DUMMY_RETURN;
02536 }
02537 
02538 /* CAUTION(?): Don't rename file_per_table during backup */
02539 static void
02540 xtrabackup_backup_func(void)
02541 {
02542   struct stat stat_info;
02543   LSN64 latest_cp;
02544 
02545 #ifdef USE_POSIX_FADVISE
02546   fprintf(stderr, "xtrabackup: uses posix_fadvise().\n");
02547 #endif
02548 
02549   /* cd to datadir */
02550 
02551   if (chdir(mysql_real_data_home) != 0)
02552   {
02553     fprintf(stderr, "xtrabackup: cannot my_setwd %s\n", mysql_real_data_home);
02554     exit(EXIT_FAILURE);
02555   }
02556   fprintf(stderr, "xtrabackup: cd to %s\n", mysql_real_data_home);
02557 
02558   mysql_data_home= mysql_data_home_buff;
02559   mysql_data_home[0]=FN_CURLIB;   // all paths are relative from here
02560   mysql_data_home[1]=0;
02561 
02562   /* set read only */
02563   srv_read_only = TRUE;
02564 
02565   /* initialize components */
02566         if(innodb_init_param())
02567                 exit(EXIT_FAILURE);
02568 
02569         if (srv_file_flush_method_str == NULL) {
02570           /* These are the default options */
02571     srv_unix_file_flush_method = SRV_UNIX_FSYNC;
02572 
02573     srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
02574 #ifndef __WIN__        
02575   } else if (0 == ut_strcmp(srv_file_flush_method_str, "fsync")) {
02576     srv_unix_file_flush_method = SRV_UNIX_FSYNC;
02577 
02578   } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DSYNC")) {
02579       srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
02580 
02581   } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DIRECT")) {
02582       srv_unix_file_flush_method = SRV_UNIX_O_DIRECT;
02583     fprintf(stderr,"xtrabackup: use O_DIRECT\n");
02584   } else if (0 == ut_strcmp(srv_file_flush_method_str, "littlesync")) {
02585       srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
02586 
02587   } else if (0 == ut_strcmp(srv_file_flush_method_str, "nosync")) {
02588       srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
02589 #else
02590   } else if (0 == ut_strcmp(srv_file_flush_method_str, "normal")) {
02591       srv_win_file_flush_method = SRV_WIN_IO_NORMAL;
02592       os_aio_use_native_aio = FALSE;
02593 
02594   } else if (0 == ut_strcmp(srv_file_flush_method_str, "unbuffered")) {
02595       srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
02596       os_aio_use_native_aio = FALSE;
02597 
02598   } else if (0 == ut_strcmp(srv_file_flush_method_str,
02599               "async_unbuffered")) {
02600       srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;  
02601 #endif
02602   } else {
02603       fprintf(stderr, 
02604             "xtrabackup: Unrecognized value %s for innodb_flush_method\n",
02605                   srv_file_flush_method_str);
02606       exit(EXIT_FAILURE);
02607   }
02608 
02609   if (srv_buf_pool_size >= 1000 * 1024 * 1024) {
02610                                   /* Here we still have srv_pool_size counted
02611                                   in kilobytes (in 4.0 this was in bytes)
02612           srv_boot() converts the value to
02613                                   pages; if buffer pool is less than 1000 MB,
02614                                   assume fewer threads. */
02615                 srv_max_n_threads = 50000;
02616 
02617 
02618   } else if (srv_buf_pool_size >= 8 * 1024 * 1024) {
02619 
02620                 srv_max_n_threads = 10000;
02621         } else {
02622     srv_max_n_threads = 1000;       /* saves several MB of memory,
02623                                                 especially in 64-bit
02624                                                 computers */
02625         }
02626 
02627   {
02628   ulint nr;
02629   ulint i;
02630 
02631   nr = srv_n_data_files;
02632   
02633   for (i = 0; i < nr; i++) {
02634     srv_data_file_sizes[i] = srv_data_file_sizes[i]
02635           * ((1024 * 1024) / UNIV_PAGE_SIZE);
02636   }   
02637 
02638   srv_last_file_size_max = srv_last_file_size_max
02639           * ((1024 * 1024) / UNIV_PAGE_SIZE);
02640     
02641   srv_log_file_size = srv_log_file_size / UNIV_PAGE_SIZE;
02642 
02643   srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE;
02644 
02645   srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE);
02646   }
02647 
02648   os_sync_mutex = NULL;
02649   srv_general_init();
02650 
02651   {
02652   ibool create_new_db;
02653 #ifdef XTRADB_BASED
02654   ibool create_new_doublewrite_file;
02655 #endif
02656   ibool log_file_created;
02657   ibool log_created = FALSE;
02658   ibool log_opened  = FALSE;
02659   LSN64 min_flushed_lsn;
02660   LSN64 max_flushed_lsn;
02661   ulint   sum_of_new_sizes;
02662   ulint err;
02663   ulint i;
02664 
02665 
02666 
02667 
02668 #define SRV_N_PENDING_IOS_PER_THREAD  OS_AIO_N_PENDING_IOS_PER_THREAD
02669 #define SRV_MAX_N_PENDING_SYNC_IOS  100
02670 
02671   srv_n_file_io_threads = 2 + srv_n_read_io_threads + srv_n_write_io_threads;
02672 
02673   os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD,
02674         srv_n_read_io_threads,
02675         srv_n_write_io_threads,
02676         SRV_MAX_N_PENDING_SYNC_IOS);
02677 
02678   fil_init(srv_file_per_table ? 50000 : 5000,
02679      srv_max_n_open_files);
02680 
02681   fsp_init();
02682   log_init();
02683 
02684   lock_sys_create(srv_lock_table_size);
02685 
02686   for (i = 0; i < srv_n_file_io_threads; i++) {
02687     thread_nr[i] = i;
02688 
02689     os_thread_create(io_handler_thread, thread_nr + i, thread_ids + i);
02690       }
02691 
02692   os_thread_sleep(200000); /*0.2 sec*/
02693 
02694   err = open_or_create_data_files(&create_new_db,
02695 #ifdef XTRADB_BASED
02696           &create_new_doublewrite_file,
02697 #endif
02698           &min_flushed_lsn, &max_flushed_lsn,
02699           &sum_of_new_sizes);
02700   if (err != DB_SUCCESS) {
02701           fprintf(stderr,
02702 "xtrabackup: Could not open or create data files.\n"
02703 "xtrabackup: If you tried to add new data files, and it failed here,\n"
02704 "xtrabackup: you should now edit innodb_data_file_path in my.cnf back\n"
02705 "xtrabackup: to what it was, and remove the new ibdata files InnoDB created\n"
02706 "xtrabackup: in this failed attempt. InnoDB only wrote those files full of\n"
02707 "xtrabackup: zeros, but did not yet use them in any way. But be careful: do not\n"
02708 "xtrabackup: remove old data files which contain your precious data!\n");
02709 
02710     //return((int) err);
02711     exit(EXIT_FAILURE);
02712   }
02713 
02714   /* create_new_db must not be TRUE.. */
02715   if (create_new_db) {
02716     fprintf(stderr, "xtrabackup: Something wrong with source files...\n");
02717     exit(EXIT_FAILURE);
02718   }
02719 
02720   for (i = 0; i < srv_n_log_files; i++) {
02721     err = open_or_create_log_file(create_new_db, &log_file_created,
02722                    log_opened, 0, i);
02723     if (err != DB_SUCCESS) {
02724 
02725       //return((int) err);
02726       exit(EXIT_FAILURE);
02727     }
02728 
02729     if (log_file_created) {
02730       log_created = TRUE;
02731     } else {
02732       log_opened = TRUE;
02733     }
02734     if ((log_opened && create_new_db)
02735               || (log_opened && log_created)) {
02736       fprintf(stderr, 
02737   "xtrabackup: Error: all log files must be created at the same time.\n"
02738   "xtrabackup: All log files must be created also in database creation.\n"
02739   "xtrabackup: If you want bigger or smaller log files, shut down the\n"
02740   "xtrabackup: database and make sure there were no errors in shutdown.\n"
02741   "xtrabackup: Then delete the existing log files. Edit the .cnf file\n"
02742   "xtrabackup: and start the database again.\n");
02743 
02744       //return(DB_ERROR);
02745       exit(EXIT_FAILURE);
02746     }
02747   }
02748 
02749   /* log_file_created must not be TRUE, if online */
02750   if (log_file_created) {
02751     fprintf(stderr, "xtrabackup: Something wrong with source files...\n");
02752     exit(EXIT_FAILURE);
02753   }
02754 
02755   fil_load_single_table_tablespaces();
02756 
02757   }
02758 
02759   /* create extra LSN dir if it does not exist. */
02760   if (xtrabackup_extra_lsndir
02761             && (stat(xtrabackup_extra_lsndir,&stat_info) != 0)
02762             && (mkdir(xtrabackup_extra_lsndir,0777) != 0)){
02763     fprintf(stderr,"xtrabackup: Error: cannot mkdir %d: %s\n",errno,xtrabackup_extra_lsndir);
02764     exit(EXIT_FAILURE);
02765   }
02766 
02767 
02768   if (!xtrabackup_stream) {
02769 
02770   /* create target dir if not exist */
02771   if (stat(xtrabackup_target_dir,&stat_info) != 0
02772             && (mkdir(xtrabackup_target_dir,0777) != 0)){
02773     fprintf(stderr,"xtrabackup: Error: cannot mkdir %d: %s\n",errno,xtrabackup_target_dir);
02774     exit(EXIT_FAILURE);
02775   }
02776 
02777   } else {
02778     fprintf(stderr,"xtrabackup: Stream mode.\n");
02779     /* stdout can treat binary at Linux */
02780     //setmode(fileno(stdout), O_BINARY);
02781   }
02782 
02783         {
02784         fil_system_t*   f_system = fil_system;
02785 
02786   /* definition from recv_recovery_from_checkpoint_start() */
02787   log_group_t*  max_cp_group;
02788   ulint   max_cp_field;
02789   byte*   buf;
02790   boost::scoped_array<byte> log_hdr_buf_(
02791     new byte[LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE]);
02792   byte*   log_hdr_buf;
02793   ulint   err;
02794 
02795   ibool   success;
02796 
02797   /* start back ground thread to copy newer log */
02798   os_thread_id_t log_copying_thread_id;
02799   datafiles_iter_t *it;
02800 
02801   log_hdr_buf = (byte*)ut_align(log_hdr_buf_.get(),
02802               OS_FILE_LOG_BLOCK_SIZE);
02803 
02804   /* log space */
02805   //space = UT_LIST_GET_NEXT(space_list, UT_LIST_GET_FIRST(f_system->space_list));
02806   //printf("space: name=%s, id=%d, purpose=%d, size=%d\n",
02807   //  space->name, space->id, space->purpose, space->size);
02808 
02809   /* get current checkpoint_lsn */
02810   /* Look for the latest checkpoint from any of the log groups */
02811   
02812   err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
02813 
02814   if (err != DB_SUCCESS) {
02815 
02816     exit(EXIT_FAILURE);
02817   }
02818     
02819   log_group_read_checkpoint_info(max_cp_group, max_cp_field);
02820   buf = log_sys->checkpoint_buf;
02821 
02822   checkpoint_lsn_start = MACH_READ_64(buf + LOG_CHECKPOINT_LSN);
02823   checkpoint_no_start = MACH_READ_64(buf + LOG_CHECKPOINT_NO);
02824 
02825 reread_log_header:
02826   fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, max_cp_group->space_id,
02827         0,
02828         0, 0, LOG_FILE_HDR_SIZE,
02829         log_hdr_buf, max_cp_group);
02830 
02831   /* check consistency of log file header to copy */
02832         err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
02833 
02834         if (err != DB_SUCCESS) {
02835 
02836                 exit(EXIT_FAILURE);
02837         }
02838 
02839         log_group_read_checkpoint_info(max_cp_group, max_cp_field);
02840         buf = log_sys->checkpoint_buf;
02841 
02842   if(ut_dulint_cmp(checkpoint_no_start,
02843       MACH_READ_64(buf + LOG_CHECKPOINT_NO)) != 0) {
02844     checkpoint_lsn_start = MACH_READ_64(buf + LOG_CHECKPOINT_LSN);
02845     checkpoint_no_start = MACH_READ_64(buf + LOG_CHECKPOINT_NO);
02846     goto reread_log_header;
02847   }
02848 
02849   if (!xtrabackup_stream) {
02850 
02851     /* open 'xtrabackup_logfile' */
02852     sprintf(dst_log_path, "%s%s", xtrabackup_target_dir, "/xtrabackup_logfile");
02853     srv_normalize_path_for_win(dst_log_path);
02854     /* os_file_create reads srv_unix_file_flush_method for OS_DATA_FILE*/
02855     dst_log = os_file_create(
02856         0 /* dummy of innodb_file_data_key */,
02857         dst_log_path, OS_FILE_CREATE,
02858         OS_FILE_NORMAL, OS_DATA_FILE, &success);
02859 
02860                 if (!success) {
02861                         /* The following call prints an error message */
02862                         os_file_get_last_error(TRUE);
02863 
02864                         fprintf(stderr,
02865 "xtrabackup: error: cannot open %s\n",
02866                                 dst_log_path);
02867                         exit(EXIT_FAILURE);
02868                 }
02869 
02870 #ifdef USE_POSIX_FADVISE
02871     posix_fadvise(dst_log, 0, 0, POSIX_FADV_DONTNEED);
02872 #endif
02873 
02874   }
02875 
02876   /* label it */
02877   strcpy((char*) log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
02878     "xtrabkup ");
02879   ut_sprintf_timestamp(
02880     (char*) log_hdr_buf + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
02881         + (sizeof "xtrabkup ") - 1));
02882 
02883   if (!xtrabackup_stream) {
02884     success = os_file_write(dst_log_path, dst_log, log_hdr_buf,
02885         0, 0, LOG_FILE_HDR_SIZE);
02886   } else {
02887     /* Stream */
02888     if ((write(fileno(stdout), log_hdr_buf, LOG_FILE_HDR_SIZE)
02889       - LOG_FILE_HDR_SIZE) == 0)
02890     {
02891       success = TRUE;
02892     } else {
02893       success = FALSE;
02894     }
02895   }
02896 
02897   log_copy_offset += LOG_FILE_HDR_SIZE;
02898   if (!success) {
02899     if (dst_log != -1)
02900       os_file_close(dst_log);
02901     exit(EXIT_FAILURE);
02902   }
02903 
02904   /* start flag */
02905   log_copying = TRUE;
02906 
02907   /* start io throttle */
02908   if(xtrabackup_throttle) {
02909     os_thread_id_t io_watching_thread_id;
02910 
02911     io_ticket = xtrabackup_throttle;
02912     wait_throttle = os_event_create(NULL);
02913 
02914     os_thread_create(io_watching_thread, NULL, &io_watching_thread_id);
02915   }
02916 
02917 
02918   /* copy log file by current position */
02919   if(xtrabackup_copy_logfile(checkpoint_lsn_start, FALSE))
02920     exit(EXIT_FAILURE);
02921 
02922 
02923   os_thread_create(log_copying_thread, NULL, &log_copying_thread_id);
02924 
02925 
02926 
02927   if (!xtrabackup_stream) { /* stream mode is transaction log only */
02928     uint      i;
02929     uint      count;
02930     os_mutex_t    count_mutex;
02931     data_thread_ctxt_t  *data_threads;
02932 
02933     ut_a(parallel > 0);
02934 
02935     if (parallel > 1)
02936       printf("xtrabackup: Starting %u threads for parallel "
02937              "data files transfer\n", parallel);
02938 
02939     it = datafiles_iter_new(f_system);
02940     if (it == NULL) {
02941       fprintf(stderr,
02942         "xtrabackup: Error: "
02943         "datafiles_iter_new() failed.\n");
02944       exit(EXIT_FAILURE);
02945     }
02946 
02947     /* Create data copying threads */
02948     ut_a(parallel > 0);
02949 
02950     data_threads = (data_thread_ctxt_t *)
02951       ut_malloc(sizeof(data_thread_ctxt_t) * parallel);
02952     count = parallel;
02953     count_mutex = OS_MUTEX_CREATE();
02954 
02955     for (i = 0; i < parallel; i++) {
02956       data_threads[i].it = it;
02957       data_threads[i].num = i+1;
02958       data_threads[i].count = &count;
02959       data_threads[i].count_mutex = count_mutex;
02960       os_thread_create(data_copy_thread_func,
02961            data_threads + i,
02962            &data_threads[i].id);
02963     }
02964 
02965     /* Wait for threads to exit */
02966     while (1) {
02967       os_thread_sleep(1000000);
02968       os_mutex_enter(count_mutex);
02969       if (count == 0) {
02970         os_mutex_exit(count_mutex);
02971         break;
02972       }
02973       os_mutex_exit(count_mutex);
02974     }
02975     /* NOTE: It may not needed at "--backup" for now */
02976     /* mutex_enter(&(f_system->mutex)); */
02977 
02978     os_mutex_free(count_mutex);
02979     datafiles_iter_free(it);
02980 
02981   } //if (!xtrabackup_stream)
02982 
02983         //mutex_exit(&(f_system->mutex));
02984         }
02985 
02986 
02987   /* suspend-at-end */
02988   if (xtrabackup_suspend_at_end) {
02989     os_file_t suspend_file = -1;
02990     char  suspend_path[FN_REFLEN];
02991     ibool success, exists;
02992     os_file_type_t  type;
02993 
02994     sprintf(suspend_path, "%s%s", xtrabackup_target_dir,
02995       "/xtrabackup_suspended");
02996 
02997     srv_normalize_path_for_win(suspend_path);
02998     /* os_file_create reads srv_unix_file_flush_method */
02999     suspend_file = os_file_create(
03000           0 /* dummy of innodb_file_data_key */,
03001           suspend_path, OS_FILE_OVERWRITE,
03002           OS_FILE_NORMAL, OS_DATA_FILE, &success);
03003 
03004     if (!success) {
03005       fprintf(stderr, "xtrabackup: Error: failed to create file 'xtrabackup_suspended'\n");
03006     }
03007 
03008     if (suspend_file != -1)
03009       os_file_close(suspend_file);
03010 
03011     exists = TRUE;
03012     while (exists) {
03013       os_thread_sleep(200000); /*0.2 sec*/
03014       success = os_file_status(suspend_path, &exists, &type);
03015       if (!success)
03016         break;
03017     }
03018     xtrabackup_suspend_at_end = FALSE; /* suspend is 1 time */
03019   }
03020 
03021   /* read the latest checkpoint lsn */
03022   latest_cp = ut_dulint_zero;
03023   {
03024     log_group_t*  max_cp_group;
03025     ulint max_cp_field;
03026     ulint err;
03027 
03028     err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
03029 
03030     if (err != DB_SUCCESS) {
03031       fprintf(stderr, "xtrabackup: Error: recv_find_max_checkpoint() failed.\n");
03032       goto skip_last_cp;
03033     }
03034 
03035     log_group_read_checkpoint_info(max_cp_group, max_cp_field);
03036 
03037     latest_cp = MACH_READ_64(log_sys->checkpoint_buf + LOG_CHECKPOINT_LSN);
03038 
03039     if (!xtrabackup_stream) {
03040       printf("xtrabackup: The latest check point (for incremental): '%"PRIu64"'\n",
03041         latest_cp);
03042     } else {
03043       fprintf(stderr, "xtrabackup: The latest check point (for incremental): '%"PRIu64"'\n",
03044         latest_cp);
03045     }
03046   }
03047 skip_last_cp:
03048   /* stop log_copying_thread */
03049   log_copying = FALSE;
03050   if (!xtrabackup_stream) {
03051     printf("xtrabackup: Stopping log copying thread");
03052     while (log_copying_running) {
03053       printf(".");
03054       os_thread_sleep(200000); /*0.2 sec*/
03055     }
03056     printf("\n");
03057   } else {
03058     while (log_copying_running)
03059       os_thread_sleep(200000); /*0.2 sec*/
03060   }
03061 
03062   /* output to metadata file */
03063   {
03064     char  filename[FN_REFLEN];
03065 
03066     if(!xtrabackup_incremental) {
03067       strcpy(metadata_type, "full-backuped");
03068       metadata_from_lsn = ut_dulint_zero;
03069     } else {
03070       strcpy(metadata_type, "incremental");
03071       metadata_from_lsn = incremental_lsn;
03072     }
03073     metadata_to_lsn = latest_cp;
03074     metadata_last_lsn = log_copy_scanned_lsn;
03075 
03076     sprintf(filename, "%s/%s", xtrabackup_target_dir, XTRABACKUP_METADATA_FILENAME);
03077     if (xtrabackup_write_metadata(filename))
03078       fprintf(stderr, "xtrabackup: error: xtrabackup_write_metadata(xtrabackup_target_dir)\n");
03079 
03080     if(xtrabackup_extra_lsndir) {
03081       sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_METADATA_FILENAME);
03082       if (xtrabackup_write_metadata(filename))
03083         fprintf(stderr, "xtrabackup: error: xtrabackup_write_metadata(xtrabackup_extra_lsndir)\n");
03084     }
03085   }
03086 
03087   if (!log_copying_succeed) {
03088     fprintf(stderr, "xtrabackup: Error: log_copying_thread failed.\n");
03089     exit(EXIT_FAILURE);
03090   }
03091 
03092   if (!xtrabackup_stream)
03093           os_file_close(dst_log);
03094 
03095   if (wait_throttle)
03096     os_event_free(wait_throttle);
03097 
03098   if (!xtrabackup_stream) {
03099     printf("xtrabackup: Transaction log of lsn (%"PRIu64") to (%"PRIu64") was copied.\n",
03100       checkpoint_lsn_start, log_copy_scanned_lsn);
03101   } else {
03102     fprintf(stderr, "xtrabackup: Transaction log of lsn (%"PRIu64") to (%"PRIu64") was copied.\n",
03103       checkpoint_lsn_start, log_copy_scanned_lsn);
03104     if(xtrabackup_extra_lsndir) {
03105       char  filename[FN_REFLEN];
03106       sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_METADATA_FILENAME);
03107       if (xtrabackup_write_metadata(filename))
03108         fprintf(stderr, "xtrabackup: error: xtrabackup_write_metadata(xtrabackup_extra_lsndir)\n");
03109     }
03110   }
03111 }
03112 
03113 /* ================= stats ================= */
03114 static bool
03115 xtrabackup_stats_level(
03116   dict_index_t* index,
03117   ulint   level)
03118 {
03119   ulint space;
03120   page_t* page;
03121 
03122   rec_t*  node_ptr;
03123 
03124   ulint right_page_no;
03125 
03126   page_cur_t  cursor;
03127 
03128   mtr_t mtr;
03129   mem_heap_t* heap  = mem_heap_create(256);
03130 
03131   ulint*  offsets = NULL;
03132 
03133   uint64_t n_pages, n_pages_extern;
03134   uint64_t sum_data, sum_data_extern;
03135   uint64_t n_recs;
03136   ulint page_size;
03137 
03138   n_pages = sum_data = n_recs = 0;
03139   n_pages_extern = sum_data_extern = 0;
03140 
03141   buf_block_t*  block;
03142   ulint zip_size;
03143 
03144   if (level == 0)
03145     fprintf(stdout, "        leaf pages: ");
03146   else
03147     fprintf(stdout, "     level %lu pages: ", level);
03148 
03149   mtr_start(&mtr);
03150 
03151   mtr_x_lock(&(index->lock), &mtr);
03152   block = btr_root_block_get(index, &mtr);
03153   page = buf_block_get_frame(block);
03154 
03155   space = page_get_space_id(page);
03156   zip_size = fil_space_get_zip_size(space);
03157 
03158   while (level != btr_page_get_level(page, &mtr)) {
03159 
03160     ut_a(space == buf_block_get_space(block));
03161     ut_a(space == page_get_space_id(page));
03162     ut_a(!page_is_leaf(page));
03163 
03164     page_cur_set_before_first(block, &cursor);
03165     page_cur_move_to_next(&cursor);
03166 
03167     node_ptr = page_cur_get_rec(&cursor);
03168     offsets = rec_get_offsets(node_ptr, index, offsets,
03169           ULINT_UNDEFINED, &heap);
03170 
03171     block = btr_node_ptr_get_child(node_ptr, index, offsets, &mtr);
03172     page = buf_block_get_frame(block);
03173   }
03174 
03175 loop:
03176   mem_heap_empty(heap);
03177   offsets = NULL;
03178   mtr_x_lock(&(index->lock), &mtr);
03179 
03180   right_page_no = btr_page_get_next(page, &mtr);
03181 
03182 
03183   /*=================================*/
03184   //fprintf(stdout, "%lu ", (ulint) buf_frame_get_page_no(page));
03185 
03186   n_pages++;
03187   sum_data += page_get_data_size(page);
03188   n_recs += page_get_n_recs(page);
03189 
03190 
03191   if (level == 0) {
03192     page_cur_t  cur;
03193     ulint n_fields;
03194     ulint i;
03195     mem_heap_t* local_heap  = NULL;
03196     ulint offsets_[REC_OFFS_NORMAL_SIZE];
03197     ulint*  local_offsets = offsets_;
03198 
03199     *offsets_ = (sizeof offsets_) / sizeof *offsets_;
03200 
03201     page_cur_set_before_first(block, &cur);
03202 
03203     page_cur_move_to_next(&cur);
03204 
03205     for (;;) {
03206       if (page_cur_is_after_last(&cur)) {
03207         break;
03208       }
03209 
03210       local_offsets = rec_get_offsets(cur.rec, index, local_offsets,
03211             ULINT_UNDEFINED, &local_heap);
03212       n_fields = rec_offs_n_fields(local_offsets);
03213 
03214       for (i = 0; i < n_fields; i++) {
03215         if (rec_offs_nth_extern(local_offsets, i)) {
03216           page_t* local_page;
03217           ulint space_id;
03218           ulint page_no;
03219           ulint offset;
03220           byte* blob_header;
03221           ulint part_len;
03222           mtr_t local_mtr;
03223           ulint local_len;
03224           byte* data;
03225           buf_block_t*  local_block;
03226 
03227           data = rec_get_nth_field(cur.rec, local_offsets, i, &local_len);
03228 
03229           ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
03230           local_len -= BTR_EXTERN_FIELD_REF_SIZE;
03231 
03232           space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
03233           page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
03234           offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
03235 
03236           if (offset != FIL_PAGE_DATA)
03237             fprintf(stderr, "\nWarning: several record may share same external page.\n");
03238 
03239           for (;;) {
03240             mtr_start(&local_mtr);
03241 
03242             local_block = btr_block_get(space_id, zip_size, page_no, RW_S_LATCH, &local_mtr);
03243             local_page = buf_block_get_frame(local_block);
03244 
03245             blob_header = local_page + offset;
03246 #define BTR_BLOB_HDR_PART_LEN   0
03247 #define BTR_BLOB_HDR_NEXT_PAGE_NO 4
03248             //part_len = btr_blob_get_part_len(blob_header);
03249             part_len = mach_read_from_4(blob_header + BTR_BLOB_HDR_PART_LEN);
03250 
03251             //page_no = btr_blob_get_next_page_no(blob_header);
03252             page_no = mach_read_from_4(blob_header + BTR_BLOB_HDR_NEXT_PAGE_NO);
03253 
03254             offset = FIL_PAGE_DATA;
03255 
03256 
03257 
03258 
03259             /*=================================*/
03260             //fprintf(stdout, "[%lu] ", (ulint) buf_frame_get_page_no(page));
03261 
03262             n_pages_extern++;
03263             sum_data_extern += part_len;
03264 
03265 
03266             mtr_commit(&local_mtr);
03267 
03268             if (page_no == FIL_NULL)
03269               break;
03270           }
03271         }
03272       }
03273 
03274       page_cur_move_to_next(&cur);
03275     }
03276   }
03277 
03278 
03279 
03280 
03281   mtr_commit(&mtr);
03282   if (right_page_no != FIL_NULL) {
03283     mtr_start(&mtr);
03284     block = btr_block_get(space, zip_size, right_page_no, RW_X_LATCH, &mtr);
03285     page = buf_block_get_frame(block);
03286     goto loop;
03287   }
03288   mem_heap_free(heap);
03289 
03290   if (zip_size) {
03291     page_size = zip_size;
03292   } else {
03293     page_size = UNIV_PAGE_SIZE;
03294   }
03295 
03296   if (level == 0)
03297     fprintf(stdout, "recs=%"PRIu64", ", n_recs);
03298 
03299   fprintf(stdout, "pages=%"PRIu64", data=%"PRIu64" bytes, data/pages=%"PRIu64"%%",
03300     n_pages, sum_data,
03301     ((sum_data * 100)/ page_size)/n_pages);
03302 
03303 
03304   if (level == 0 && n_pages_extern) {
03305     putc('\n', stdout);
03306     /* also scan blob pages*/
03307     fprintf(stdout, "    external pages: ");
03308 
03309     fprintf(stdout, "pages=%"PRIu64", data=%"PRIu64" bytes, data/pages=%"PRIu64"%%",
03310       n_pages_extern, sum_data_extern,
03311       ((sum_data_extern * 100)/ page_size)/n_pages_extern);
03312   }
03313 
03314   putc('\n', stdout);
03315 
03316   if (level > 0) {
03317     xtrabackup_stats_level(index, level - 1);
03318   }
03319 
03320   return(TRUE);
03321 }
03322 
03323 static void
03324 xtrabackup_stats_func(void)
03325 {
03326   ulint n;
03327 
03328   /* cd to datadir */
03329 
03330   if (chdir(mysql_real_data_home) != 0)
03331   {
03332     fprintf(stderr, "xtrabackup: cannot my_setwd %s\n", mysql_real_data_home);
03333     exit(EXIT_FAILURE);
03334   }
03335   fprintf(stderr, "xtrabackup: cd to %s\n", mysql_real_data_home);
03336 
03337   mysql_data_home= mysql_data_home_buff;
03338   mysql_data_home[0]=FN_CURLIB;   // all paths are relative from here
03339   mysql_data_home[1]=0;
03340 
03341   /* set read only */
03342   srv_read_only = TRUE;
03343   srv_fake_write = TRUE;
03344 
03345   /* initialize components */
03346   if(innodb_init_param())
03347     exit(EXIT_FAILURE);
03348 
03349   /* Check if the log files have been created, otherwise innodb_init()
03350   will crash when called with srv_read_only == TRUE */
03351   for (n = 0; n < srv_n_log_files; n++) {
03352     char    logname[FN_REFLEN];
03353     ibool   exists;
03354     os_file_type_t  type;
03355 
03356     sprintf(logname, "ib_logfile%lu", (ulong) n);
03357     if (!os_file_status(logname, &exists, &type) || !exists ||
03358         type != OS_FILE_TYPE_FILE) {
03359       fprintf(stderr, "xtrabackup: Error: "
03360         "Cannot find log file %s.\n", logname);
03361       fprintf(stderr, "xtrabackup: Error: "
03362         "to use the statistics feature, you need a "
03363         "clean copy of the database including "
03364         "correctly sized log files, so you need to "
03365         "execute with --prepare twice to use this "
03366         "functionality on a backup.\n");
03367       exit(EXIT_FAILURE);
03368     }
03369   }
03370 
03371   fprintf(stderr, "xtrabackup: Starting 'read-only' InnoDB instance to gather index statistics.\n"
03372     "xtrabackup: Using %"PRIu64" bytes for buffer pool (set by --use-memory parameter)\n",
03373     xtrabackup_use_memory);
03374 
03375   if(innodb_init())
03376     exit(EXIT_FAILURE);
03377 
03378   fprintf(stdout, "\n\n<INDEX STATISTICS>\n");
03379 
03380   /* gather stats */
03381 
03382   {
03383   dict_table_t* sys_tables;
03384   dict_index_t* sys_index;
03385   dict_table_t* table;
03386   btr_pcur_t  pcur;
03387   rec_t*    rec;
03388   byte*   field;
03389   ulint   len;
03390   mtr_t   mtr;
03391   
03392   /* Enlarge the fatal semaphore wait timeout during the InnoDB table
03393   monitor printout */
03394 
03395   mutex_enter(&kernel_mutex);
03396   srv_fatal_semaphore_wait_threshold += 72000; /* 20 hours */
03397   mutex_exit(&kernel_mutex);
03398 
03399   mutex_enter(&(dict_sys->mutex));
03400 
03401   mtr_start(&mtr);
03402 
03403   sys_tables = dict_table_get_low("SYS_TABLES");
03404   sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
03405 
03406   btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
03407                 TRUE, &mtr);
03408 loop:
03409   btr_pcur_move_to_next_user_rec(&pcur, &mtr);
03410 
03411   rec = btr_pcur_get_rec(&pcur);
03412 
03413   if (!btr_pcur_is_on_user_rec(&pcur))
03414   {
03415     /* end of index */
03416 
03417     btr_pcur_close(&pcur);
03418     mtr_commit(&mtr);
03419     
03420     mutex_exit(&(dict_sys->mutex));
03421 
03422     /* Restore the fatal semaphore wait timeout */
03423 
03424     mutex_enter(&kernel_mutex);
03425     srv_fatal_semaphore_wait_threshold -= 72000; /* 20 hours */
03426     mutex_exit(&kernel_mutex);
03427 
03428     goto end;
03429   } 
03430 
03431   field = rec_get_nth_field_old(rec, 0, &len);
03432 
03433   if (!rec_get_deleted_flag(rec, 0))
03434   {
03435 
03436     /* We found one */
03437 
03438                 char* table_name = mem_strdupl((char*) field, len);
03439 
03440     btr_pcur_store_position(&pcur, &mtr);
03441 
03442     mtr_commit(&mtr);
03443 
03444     table = dict_table_get_low(table_name);
03445     mem_free(table_name);
03446 
03447 
03448     if (xtrabackup_tables) {
03449       char *p;
03450       int regres= 0;
03451       int i;
03452 
03453       p = strstr(table->name, SRV_PATH_SEPARATOR_STR);
03454 
03455       if (p)
03456         *p = '.';
03457 
03458       for (i = 0; i < tables_regex_num; i++) {
03459         regres = regexec(&tables_regex[i], table->name, 1, tables_regmatch, 0);
03460         if (regres != REG_NOMATCH)
03461           break;
03462       }
03463 
03464       if (p)
03465         *p = SRV_PATH_SEPARATOR;
03466 
03467       if ( regres == REG_NOMATCH )
03468         goto skip;
03469     }
03470 
03471     if (xtrabackup_tables_file) {
03472       xtrabackup_tables_t*  xtable;
03473 
03474       HASH_SEARCH(name_hash, tables_hash, ut_fold_string(table->name),
03475             xtrabackup_tables_t*,
03476             xtable,
03477             ut_ad(xtable->name),
03478             !strcmp(xtable->name, table->name));
03479 
03480       if (!xtable)
03481         goto skip;
03482     }
03483 
03484 
03485     if (table == NULL) {
03486       fputs("InnoDB: Failed to load table ", stderr);
03487       ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
03488       putc('\n', stderr);
03489     } else {
03490       dict_index_t* index;
03491 
03492       /* The table definition was corrupt if there
03493       is no index */
03494 
03495       if (dict_table_get_first_index(table)) {
03496 #ifdef XTRADB_BASED
03497         dict_update_statistics(table, TRUE, FALSE);
03498 #elif defined(INNODB_VERSION_SHORT)
03499         dict_update_statistics(table, TRUE);
03500 #else
03501         dict_update_statistics_low(table, TRUE);
03502 #endif
03503       }
03504 
03505       //dict_table_print_low(table);
03506 
03507       index = UT_LIST_GET_FIRST(table->indexes);
03508       while (index != NULL) {
03509 {
03510   IB_INT64  n_vals;
03511 
03512   if (index->n_user_defined_cols > 0) {
03513     n_vals = index->stat_n_diff_key_vals[
03514           index->n_user_defined_cols];
03515   } else {
03516     n_vals = index->stat_n_diff_key_vals[1];
03517   }
03518 
03519   fprintf(stdout,
03520     "  table: %s, index: %s, space id: %lu, root page: %lu"
03521     ", zip size: %lu"
03522     "\n  estimated statistics in dictionary:\n"
03523     "    key vals: %lu, leaf pages: %lu, size pages: %lu\n"
03524     "  real statistics:\n",
03525     table->name, index->name,
03526     (ulong) index->space,
03527     (ulong) index->page,
03528     (ulong) fil_space_get_zip_size(index->space),
03529     (ulong) n_vals,
03530     (ulong) index->stat_n_leaf_pages,
03531     (ulong) index->stat_index_size);
03532 
03533   {
03534     mtr_t local_mtr;
03535     page_t* root;
03536     ulint page_level;
03537 
03538     mtr_start(&local_mtr);
03539 
03540     mtr_x_lock(&(index->lock), &local_mtr);
03541     root = btr_root_get(index, &local_mtr);
03542 
03543     page_level = btr_page_get_level(root, &local_mtr);
03544 
03545     xtrabackup_stats_level(index, page_level);
03546 
03547     mtr_commit(&local_mtr);
03548   }
03549 
03550   putc('\n', stdout);
03551 }
03552         index = UT_LIST_GET_NEXT(indexes, index);
03553       }
03554     }
03555 
03556 skip:
03557     mtr_start(&mtr);
03558 
03559     btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
03560   }
03561 
03562   goto loop;
03563   }
03564 
03565 end:
03566   putc('\n', stdout);
03567 
03568   /* shutdown InnoDB */
03569   if(innodb_end())
03570     exit(EXIT_FAILURE);
03571 }
03572 
03573 /* ================= prepare ================= */
03574 
03575 static bool
03576 xtrabackup_init_temp_log(void)
03577 {
03578   os_file_t src_file = -1;
03579   char  src_path[FN_REFLEN];
03580   char  dst_path[FN_REFLEN];
03581   ibool success;
03582 
03583   ulint field;
03584   byte* log_buf;
03585   byte* log_buf_ = NULL;
03586 
03587   IB_INT64  file_size;
03588 
03589   LSN64 max_no;
03590   LSN64 max_lsn= 0;
03591   LSN64 checkpoint_no;
03592 
03593   ulint fold;
03594 
03595   max_no = ut_dulint_zero;
03596 
03597   if(!xtrabackup_incremental_dir) {
03598     sprintf(dst_path, "%s%s", xtrabackup_target_dir, "/ib_logfile0");
03599     sprintf(src_path, "%s%s", xtrabackup_target_dir, "/xtrabackup_logfile");
03600   } else {
03601     sprintf(dst_path, "%s%s", xtrabackup_incremental_dir, "/ib_logfile0");
03602     sprintf(src_path, "%s%s", xtrabackup_incremental_dir, "/xtrabackup_logfile");
03603   }
03604 
03605   srv_normalize_path_for_win(dst_path);
03606   srv_normalize_path_for_win(src_path);
03607 retry:
03608   src_file = os_file_create_simple_no_error_handling(
03609           0 /* dummy of innodb_file_data_key */,
03610           src_path, OS_FILE_OPEN,
03611           OS_FILE_READ_WRITE /* OS_FILE_READ_ONLY */, &success);
03612   if (!success) {
03613     /* The following call prints an error message */
03614     os_file_get_last_error(TRUE);
03615 
03616     fprintf(stderr,
03617 "xtrabackup: Warning: cannot open %s. will try to find.\n",
03618       src_path);
03619 
03620     /* check if ib_logfile0 may be xtrabackup_logfile */
03621     src_file = os_file_create_simple_no_error_handling(
03622         0 /* dummy of innodb_file_data_key */,
03623         dst_path, OS_FILE_OPEN,
03624         OS_FILE_READ_WRITE /* OS_FILE_READ_ONLY */, &success);
03625     if (!success) {
03626       os_file_get_last_error(TRUE);
03627       fprintf(stderr,
03628 "  xtrabackup: Fatal error: cannot find %s.\n",
03629       src_path);
03630 
03631       goto error;
03632     }
03633 
03634     log_buf_ = (unsigned char*) ut_malloc(LOG_FILE_HDR_SIZE * 2);
03635     log_buf = (unsigned char*) ut_align(log_buf_, LOG_FILE_HDR_SIZE);
03636 
03637     success = os_file_read(src_file, log_buf, 0, 0, LOG_FILE_HDR_SIZE);
03638     if (!success) {
03639       goto error;
03640     }
03641 
03642     if ( ut_memcmp(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
03643         (byte*)"xtrabkup", (sizeof "xtrabkup") - 1) == 0) {
03644       fprintf(stderr,
03645 "  xtrabackup: 'ib_logfile0' seems to be 'xtrabackup_logfile'. will retry.\n");
03646 
03647       ut_free(log_buf_);
03648       log_buf_ = NULL;
03649 
03650       os_file_close(src_file);
03651       src_file = -1;
03652 
03653       /* rename and try again */
03654       success = os_file_rename(
03655           0 /* dummy of innodb_file_data_key */,
03656           dst_path, src_path);
03657       if (!success) {
03658         goto error;
03659       }
03660 
03661       goto retry;
03662     }
03663 
03664     fprintf(stderr,
03665 "  xtrabackup: Fatal error: cannot find %s.\n",
03666     src_path);
03667 
03668     ut_free(log_buf_);
03669     log_buf_ = NULL;
03670 
03671     os_file_close(src_file);
03672     src_file = -1;
03673 
03674     goto error;
03675   }
03676 
03677 #ifdef USE_POSIX_FADVISE
03678   posix_fadvise(src_file, 0, 0, POSIX_FADV_SEQUENTIAL);
03679   posix_fadvise(src_file, 0, 0, POSIX_FADV_DONTNEED);
03680 #endif
03681 
03682   if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
03683     os_file_set_nocache(src_file, src_path, "OPEN");
03684   }
03685 
03686   file_size = os_file_get_size_as_iblonglong(src_file);
03687 
03688 
03689   /* TODO: We should skip the following modifies, if it is not the first time. */
03690   log_buf_ = (unsigned char*) ut_malloc(UNIV_PAGE_SIZE * 129);
03691   log_buf = (unsigned char*) ut_align(log_buf_, UNIV_PAGE_SIZE);
03692 
03693   /* read log file header */
03694   success = os_file_read(src_file, log_buf, 0, 0, LOG_FILE_HDR_SIZE);
03695   if (!success) {
03696     goto error;
03697   }
03698 
03699   if ( ut_memcmp(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
03700       (byte*)"xtrabkup", (sizeof "xtrabkup") - 1) != 0 ) {
03701     printf("xtrabackup: notice: xtrabackup_logfile was already used to '--prepare'.\n");
03702     goto skip_modify;
03703   } else {
03704     /* clear it later */
03705     //memset(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
03706     //    ' ', 4);
03707   }
03708 
03709   /* read last checkpoint lsn */
03710   for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2;
03711       field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) {
03712     if (!recv_check_cp_is_consistent(log_buf + field))
03713       goto not_consistent;
03714 
03715     checkpoint_no = MACH_READ_64(log_buf + field + LOG_CHECKPOINT_NO);
03716 
03717     if (ut_dulint_cmp(checkpoint_no, max_no) >= 0) {
03718       max_no = checkpoint_no;
03719       max_lsn = MACH_READ_64(log_buf + field + LOG_CHECKPOINT_LSN);
03720 /*
03721       mach_write_to_4(log_buf + field + LOG_CHECKPOINT_OFFSET,
03722           LOG_FILE_HDR_SIZE + ut_dulint_minus(max_lsn,
03723           ut_dulint_align_down(max_lsn,OS_FILE_LOG_BLOCK_SIZE)));
03724 
03725       ulint fold;
03726       fold = ut_fold_binary(log_buf + field, LOG_CHECKPOINT_CHECKSUM_1);
03727       mach_write_to_4(log_buf + field + LOG_CHECKPOINT_CHECKSUM_1, fold);
03728 
03729       fold = ut_fold_binary(log_buf + field + LOG_CHECKPOINT_LSN,
03730         LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
03731       mach_write_to_4(log_buf + field + LOG_CHECKPOINT_CHECKSUM_2, fold);
03732 */
03733     }
03734 not_consistent:
03735     ;
03736   }
03737 
03738   if (ut_dulint_cmp(max_no, ut_dulint_zero) == 0) {
03739     fprintf(stderr, "xtrabackup: No valid checkpoint found.\n");
03740     goto error;
03741   }
03742 
03743 
03744   /* It seems to be needed to overwrite the both checkpoint area. */
03745   MACH_WRITE_64(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN, max_lsn);
03746   mach_write_to_4(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_OFFSET,
03747       LOG_FILE_HDR_SIZE + ut_dulint_minus(max_lsn,
03748       ut_dulint_align_down(max_lsn,OS_FILE_LOG_BLOCK_SIZE)));
03749 #ifdef XTRADB_BASED
03750   MACH_WRITE_64(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_ARCHIVED_LSN,
03751       (ib_uint64_t)(LOG_FILE_HDR_SIZE + ut_dulint_minus(max_lsn,
03752           ut_dulint_align_down(max_lsn,OS_FILE_LOG_BLOCK_SIZE))));
03753 #endif
03754   fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_1, LOG_CHECKPOINT_CHECKSUM_1);
03755   mach_write_to_4(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_CHECKSUM_1, fold);
03756 
03757   fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN,
03758     LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
03759   mach_write_to_4(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_CHECKSUM_2, fold);
03760 
03761   MACH_WRITE_64(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN, max_lsn);
03762         mach_write_to_4(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_OFFSET,
03763                         LOG_FILE_HDR_SIZE + ut_dulint_minus(max_lsn,
03764                         ut_dulint_align_down(max_lsn,OS_FILE_LOG_BLOCK_SIZE)));
03765 #ifdef XTRADB_BASED
03766   MACH_WRITE_64(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_ARCHIVED_LSN,
03767       (ib_uint64_t)(LOG_FILE_HDR_SIZE + ut_dulint_minus(max_lsn,
03768           ut_dulint_align_down(max_lsn,OS_FILE_LOG_BLOCK_SIZE))));
03769 #endif
03770         fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_2, LOG_CHECKPOINT_CHECKSUM_1);
03771         mach_write_to_4(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_CHECKSUM_1, fold);
03772 
03773         fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN,
03774                 LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
03775         mach_write_to_4(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_CHECKSUM_2, fold);
03776 
03777 
03778   success = os_file_write(src_path, src_file, log_buf, 0, 0, LOG_FILE_HDR_SIZE);
03779   if (!success) {
03780     goto error;
03781   }
03782 
03783   /* expand file size (9/8) and align to UNIV_PAGE_SIZE */
03784 
03785   if (file_size % UNIV_PAGE_SIZE) {
03786     memset(log_buf, 0, UNIV_PAGE_SIZE);
03787     success = os_file_write(src_path, src_file, log_buf,
03788         (ulint)(file_size & 0xFFFFFFFFUL),
03789         (ulint)(file_size >> 32),
03790         UNIV_PAGE_SIZE - (file_size % UNIV_PAGE_SIZE));
03791     if (!success) {
03792       goto error;
03793     }
03794 
03795     file_size = os_file_get_size_as_iblonglong(src_file);
03796   }
03797 
03798   /* TODO: We should judge whether the file is already expanded or not... */
03799   {
03800     ulint expand;
03801 
03802     memset(log_buf, 0, UNIV_PAGE_SIZE * 128);
03803     expand = file_size / UNIV_PAGE_SIZE / 8;
03804 
03805     for (; expand > 128; expand -= 128) {
03806       success = os_file_write(src_path, src_file, log_buf,
03807           (ulint)(file_size & 0xFFFFFFFFUL),
03808           (ulint)(file_size >> 32),
03809           UNIV_PAGE_SIZE * 128);
03810       if (!success) {
03811         goto error;
03812       }
03813       file_size += UNIV_PAGE_SIZE * 128;
03814     }
03815 
03816     if (expand) {
03817       success = os_file_write(src_path, src_file, log_buf,
03818           (ulint)(file_size & 0xFFFFFFFFUL),
03819           (ulint)(file_size >> 32),
03820           expand * UNIV_PAGE_SIZE);
03821       if (!success) {
03822         goto error;
03823       }
03824       file_size += UNIV_PAGE_SIZE * expand;
03825     }
03826   }
03827 
03828   /* make larger than 2MB */
03829   if (file_size < 2*1024*1024L) {
03830     memset(log_buf, 0, UNIV_PAGE_SIZE);
03831     while (file_size < 2*1024*1024L) {
03832       success = os_file_write(src_path, src_file, log_buf,
03833         (ulint)(file_size & 0xFFFFFFFFUL),
03834         (ulint)(file_size >> 32),
03835         UNIV_PAGE_SIZE);
03836       if (!success) {
03837         goto error;
03838       }
03839       file_size += UNIV_PAGE_SIZE;
03840     }
03841     file_size = os_file_get_size_as_iblonglong(src_file);
03842   }
03843 
03844   printf("xtrabackup: xtrabackup_logfile detected: size=%"PRIu64", start_lsn=(%"PRIu64")\n",
03845     file_size, max_lsn);
03846 
03847   os_file_close(src_file);
03848   src_file = -1;
03849 
03850   /* Backup log parameters */
03851   innobase_log_group_home_dir_backup = innobase_log_group_home_dir;
03852   innobase_log_file_size_backup      = innobase_log_file_size;
03853   innobase_log_files_in_group_backup = innobase_log_files_in_group;
03854 
03855   /* fake InnoDB */
03856   innobase_log_group_home_dir = NULL;
03857   innobase_log_file_size      = file_size;
03858   innobase_log_files_in_group = 1;
03859 
03860   srv_thread_concurrency = 0;
03861 
03862   /* rename 'xtrabackup_logfile' to 'ib_logfile0' */
03863   success = os_file_rename(
03864       0 /* dummy of innodb_file_data_key */,
03865       src_path, dst_path);
03866   if (!success) {
03867     goto error;
03868   }
03869   xtrabackup_logfile_is_renamed = TRUE;
03870 
03871   ut_free(log_buf_);
03872 
03873   return(FALSE);
03874 
03875 skip_modify:
03876   os_file_close(src_file);
03877   src_file = -1;
03878   ut_free(log_buf_);
03879   return(FALSE);
03880 
03881 error:
03882   if (src_file != -1)
03883     os_file_close(src_file);
03884   if (log_buf_)
03885     ut_free(log_buf_);
03886   fprintf(stderr, "xtrabackup: Error: xtrabackup_init_temp_log() failed.\n");
03887   return(TRUE); /*ERROR*/
03888 }
03889 
03890 /***********************************************************************
03891 Generates path to the meta file path from a given path to an incremental .delta
03892 by replacing trailing ".delta" with ".meta", or returns error if 'delta_path'
03893 does not end with the ".delta" character sequence.
03894 @return TRUE on success, FALSE on error. */
03895 static
03896 ibool
03897 get_meta_path(
03898   const char  *delta_path,  /* in: path to a .delta file */
03899   char    *meta_path) /* out: path to the corresponding .meta
03900           file */
03901 {
03902   size_t    len = strlen(delta_path);
03903 
03904   if (len <= 6 || strcmp(delta_path + len - 6, ".delta")) {
03905     return FALSE;
03906   }
03907   memcpy(meta_path, delta_path, len - 6);
03908   strcpy(meta_path + len - 6, XB_DELTA_INFO_SUFFIX);
03909 
03910   return TRUE;
03911 }
03912 
03913 static void
03914 xtrabackup_apply_delta(
03915   const char* dirname,  /* in: dir name of incremental */
03916   const char* dbname,   /* in: database name (ibdata: NULL) */
03917   const char* filename, /* in: file name (not a path),
03918           including the .delta extension */
03919   bool )
03920 {
03921   os_file_t src_file = -1;
03922   os_file_t dst_file = -1;
03923   char  src_path[FN_REFLEN];
03924   char  dst_path[FN_REFLEN];
03925   char  meta_path[FN_REFLEN];
03926   ibool success;
03927 
03928   ibool last_buffer = FALSE;
03929   ulint page_in_buffer;
03930   ulint incremental_buffers = 0;
03931 
03932   xb_delta_info_t info;
03933   ulint   page_size;
03934   ulint   page_size_shift;
03935 
03936   ut_a(xtrabackup_incremental);
03937 
03938   if (dbname) {
03939     snprintf(src_path, sizeof(src_path), "%s/%s/%s",
03940        dirname, dbname, filename);
03941     snprintf(dst_path, sizeof(dst_path), "%s/%s/%s",
03942        xtrabackup_real_target_dir, dbname, filename);
03943   } else {
03944     snprintf(src_path, sizeof(src_path), "%s/%s",
03945        dirname, filename);
03946     snprintf(dst_path, sizeof(dst_path), "%s/%s",
03947        xtrabackup_real_target_dir, filename);
03948   }
03949   dst_path[strlen(dst_path) - 6] = '\0';
03950 
03951   if (!get_meta_path(src_path, meta_path)) {
03952     goto error;
03953   }
03954 
03955   srv_normalize_path_for_win(dst_path);
03956   srv_normalize_path_for_win(src_path);
03957   srv_normalize_path_for_win(meta_path);
03958 
03959   if (!xb_read_delta_metadata(meta_path, &info)) {
03960     goto error;
03961   }
03962 
03963   page_size = info.page_size;
03964   page_size_shift = get_bit_shift(page_size);
03965   fprintf(stderr, "xtrabackup: page size for %s is %lu bytes\n",
03966     src_path, page_size);
03967   if (page_size_shift < 10 ||
03968       page_size_shift > UNIV_PAGE_SIZE_SHIFT_MAX) {
03969     fprintf(stderr,
03970       "xtrabackup: error: invalid value of page_size "
03971       "(%lu bytes) read from %s\n", page_size, meta_path);
03972     goto error;
03973   }
03974   
03975   src_file = os_file_create_simple_no_error_handling(
03976       0 /* dummy of innodb_file_data_key */,
03977       src_path, OS_FILE_OPEN, OS_FILE_READ_WRITE, &success);
03978   if (!success) {
03979     os_file_get_last_error(TRUE);
03980     fprintf(stderr,
03981       "xtrabackup: error: cannot open %s\n",
03982       src_path);
03983     goto error;
03984   }
03985 
03986 #ifdef USE_POSIX_FADVISE
03987   posix_fadvise(src_file, 0, 0, POSIX_FADV_SEQUENTIAL);
03988   posix_fadvise(src_file, 0, 0, POSIX_FADV_DONTNEED);
03989 #endif
03990 
03991   if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
03992     os_file_set_nocache(src_file, src_path, "OPEN");
03993   }
03994 
03995   dst_file = os_file_create_simple_no_error_handling(
03996       0 /* dummy of innodb_file_data_key */,
03997       dst_path, OS_FILE_OPEN, OS_FILE_READ_WRITE, &success);
03998   if (!success) {
03999     os_file_get_last_error(TRUE);
04000     fprintf(stderr,
04001       "xtrabackup: error: cannot open %s\n",
04002       dst_path);
04003     goto error;
04004   }
04005 
04006 #ifdef USE_POSIX_FADVISE
04007   posix_fadvise(dst_file, 0, 0, POSIX_FADV_DONTNEED);
04008 #endif
04009 
04010   if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
04011     os_file_set_nocache(dst_file, dst_path, "OPEN");
04012   }
04013 
04014   printf("Applying %s ...\n", src_path);
04015 
04016   while (!last_buffer) {
04017     ulint cluster_header;
04018 
04019     /* read to buffer */
04020     /* first block of block cluster */
04021     success = os_file_read(src_file, incremental_buffer,
04022                ((incremental_buffers * (page_size / 4))
04023           << page_size_shift) & 0xFFFFFFFFUL,
04024                (incremental_buffers * (page_size / 4))
04025                >> (32 - page_size_shift),
04026                page_size);
04027     if (!success) {
04028       goto error;
04029     }
04030 
04031     cluster_header = mach_read_from_4(incremental_buffer);
04032     switch(cluster_header) {
04033       case 0x78747261UL: /*"xtra"*/
04034         break;
04035       case 0x58545241UL: /*"XTRA"*/
04036         last_buffer = TRUE;
04037         break;
04038       default:
04039         fprintf(stderr,
04040           "xtrabackup: error: %s seems not .delta file.\n",
04041           src_path);
04042         goto error;
04043     }
04044 
04045     for (page_in_buffer = 1; page_in_buffer < page_size / 4;
04046          page_in_buffer++) {
04047       if (mach_read_from_4(incremental_buffer + page_in_buffer * 4)
04048           == 0xFFFFFFFFUL)
04049         break;
04050     }
04051 
04052     ut_a(last_buffer || page_in_buffer == page_size / 4);
04053 
04054     /* read whole of the cluster */
04055     success = os_file_read(src_file, incremental_buffer,
04056                ((incremental_buffers * (page_size / 4))
04057           << page_size_shift) & 0xFFFFFFFFUL,
04058                (incremental_buffers * (page_size / 4))
04059                >> (32 - page_size_shift),
04060                page_in_buffer * page_size);
04061     if (!success) {
04062       goto error;
04063     }
04064 
04065     for (page_in_buffer = 1; page_in_buffer < page_size / 4;
04066          page_in_buffer++) {
04067       ulint offset_on_page;
04068 
04069       offset_on_page = mach_read_from_4(incremental_buffer + page_in_buffer * 4);
04070 
04071       if (offset_on_page == 0xFFFFFFFFUL)
04072         break;
04073 
04074       /* apply blocks in the cluster */
04075 //      if (ut_dulint_cmp(incremental_lsn,
04076 //        MACH_READ_64(incremental_buffer
04077 //             + page_in_buffer * page_size
04078 //             + FIL_PAGE_LSN)) >= 0)
04079 //        continue;
04080 
04081       success = os_file_write(dst_path, dst_file,
04082           incremental_buffer +
04083             page_in_buffer * page_size,
04084           (offset_on_page << page_size_shift) &
04085             0xFFFFFFFFUL,
04086           offset_on_page >> (32 - page_size_shift),
04087           page_size);
04088       if (!success) {
04089         goto error;
04090       }
04091     }
04092 
04093     incremental_buffers++;
04094   }
04095 
04096   if (src_file != -1)
04097     os_file_close(src_file);
04098   if (dst_file != -1)
04099     os_file_close(dst_file);
04100   return;
04101 
04102 error:
04103   if (src_file != -1)
04104     os_file_close(src_file);
04105   if (dst_file != -1)
04106     os_file_close(dst_file);
04107   fprintf(stderr, "xtrabackup: Error: xtrabackup_apply_delta() failed.\n");
04108   return;
04109 }
04110 
04111 static void
04112 xtrabackup_apply_deltas(bool check_newer)
04113 {
04114   int   ret;
04115   char    dbpath[FN_REFLEN];
04116   os_file_dir_t dir;
04117   os_file_dir_t dbdir;
04118   os_file_stat_t  dbinfo;
04119   os_file_stat_t  fileinfo;
04120   ulint   err     = DB_SUCCESS;
04121   static char current_dir[2];
04122 
04123   current_dir[0] = FN_CURLIB;
04124   current_dir[1] = 0;
04125   srv_data_home = current_dir;
04126 
04127   /* datafile */
04128   dbdir = os_file_opendir(xtrabackup_incremental_dir, FALSE);
04129 
04130   if (dbdir != NULL) {
04131     ret = fil_file_readdir_next_file(&err, xtrabackup_incremental_dir, dbdir,
04132               &fileinfo);
04133     while (ret == 0) {
04134       if (fileinfo.type == OS_FILE_TYPE_DIR) {
04135         goto next_file_item_1;
04136       }
04137 
04138       if (strlen(fileinfo.name) > 6
04139           && 0 == strcmp(fileinfo.name + 
04140           strlen(fileinfo.name) - 6,
04141           ".delta")) {
04142         xtrabackup_apply_delta(
04143           xtrabackup_incremental_dir, NULL,
04144           fileinfo.name, check_newer);
04145       }
04146 next_file_item_1:
04147       ret = fil_file_readdir_next_file(&err,
04148               xtrabackup_incremental_dir, dbdir,
04149               &fileinfo);
04150     }
04151 
04152     os_file_closedir(dbdir);
04153   } else {
04154     fprintf(stderr, "xtrabackup: Cannot open dir %s\n", xtrabackup_incremental_dir);
04155   }
04156 
04157   /* single table tablespaces */
04158   dir = os_file_opendir(xtrabackup_incremental_dir, FALSE);
04159 
04160   if (dir == NULL) {
04161     fprintf(stderr, "xtrabackup: Cannot open dir %s\n", xtrabackup_incremental_dir);
04162   }
04163 
04164     ret = fil_file_readdir_next_file(&err, xtrabackup_incremental_dir, dir,
04165                 &dbinfo);
04166   while (ret == 0) {
04167     if (dbinfo.type == OS_FILE_TYPE_FILE
04168         || dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
04169 
04170             goto next_datadir_item;
04171     }
04172 
04173     sprintf(dbpath, "%s/%s", xtrabackup_incremental_dir,
04174                 dbinfo.name);
04175     srv_normalize_path_for_win(dbpath);
04176 
04177     dbdir = os_file_opendir(dbpath, FALSE);
04178 
04179     if (dbdir != NULL) {
04180 
04181       ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
04182                 &fileinfo);
04183       while (ret == 0) {
04184 
04185               if (fileinfo.type == OS_FILE_TYPE_DIR) {
04186 
04187                 goto next_file_item_2;
04188         }
04189 
04190         if (strlen(fileinfo.name) > 6
04191             && 0 == strcmp(fileinfo.name + 
04192             strlen(fileinfo.name) - 6,
04193             ".delta")) {
04194           /* The name ends in .delta; try opening
04195           the file */
04196           xtrabackup_apply_delta(
04197             xtrabackup_incremental_dir, dbinfo.name,
04198             fileinfo.name, check_newer);
04199         }
04200 next_file_item_2:
04201         ret = fil_file_readdir_next_file(&err,
04202                 dbpath, dbdir,
04203                 &fileinfo);
04204       }
04205 
04206       os_file_closedir(dbdir);
04207     }
04208 next_datadir_item:
04209     ret = fil_file_readdir_next_file(&err,
04210             xtrabackup_incremental_dir,
04211                 dir, &dbinfo);
04212   }
04213 
04214   os_file_closedir(dir);
04215 
04216 }
04217 
04218 static bool
04219 xtrabackup_close_temp_log(bool clear_flag)
04220 {
04221   os_file_t src_file = -1;
04222   char  src_path[FN_REFLEN];
04223   char  dst_path[FN_REFLEN];
04224   ibool success;
04225 
04226   byte* log_buf;
04227   byte* log_buf_ = NULL;
04228 
04229 
04230   if (!xtrabackup_logfile_is_renamed)
04231     return(FALSE);
04232 
04233   /* Restore log parameters */
04234   innobase_log_group_home_dir = innobase_log_group_home_dir_backup;
04235   innobase_log_file_size      = innobase_log_file_size_backup;
04236   innobase_log_files_in_group = innobase_log_files_in_group_backup;
04237 
04238   /* rename 'ib_logfile0' to 'xtrabackup_logfile' */
04239   if(!xtrabackup_incremental_dir) {
04240     sprintf(dst_path, "%s%s", xtrabackup_target_dir, "/ib_logfile0");
04241     sprintf(src_path, "%s%s", xtrabackup_target_dir, "/xtrabackup_logfile");
04242   } else {
04243     sprintf(dst_path, "%s%s", xtrabackup_incremental_dir, "/ib_logfile0");
04244     sprintf(src_path, "%s%s", xtrabackup_incremental_dir, "/xtrabackup_logfile");
04245   }
04246 
04247   srv_normalize_path_for_win(dst_path);
04248   srv_normalize_path_for_win(src_path);
04249 
04250   success = os_file_rename(
04251       0 /* dummy of innodb_file_data_key */,
04252       dst_path, src_path);
04253   if (!success) {
04254     goto error;
04255   }
04256   xtrabackup_logfile_is_renamed = FALSE;
04257 
04258   if (!clear_flag)
04259     return(FALSE);
04260 
04261   /* clear LOG_FILE_WAS_CREATED_BY_HOT_BACKUP field */
04262   src_file = os_file_create_simple_no_error_handling(
04263         0 /* dummy of innodb_file_data_key */,
04264         src_path, OS_FILE_OPEN,
04265         OS_FILE_READ_WRITE, &success);
04266   if (!success) {
04267     goto error;
04268   }
04269 
04270 #ifdef USE_POSIX_FADVISE
04271   posix_fadvise(src_file, 0, 0, POSIX_FADV_DONTNEED);
04272 #endif
04273 
04274   if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
04275     os_file_set_nocache(src_file, src_path, "OPEN");
04276   }
04277 
04278   log_buf_ = (unsigned char*) ut_malloc(LOG_FILE_HDR_SIZE * 2);
04279   log_buf = (unsigned char*) ut_align(log_buf_, LOG_FILE_HDR_SIZE);
04280 
04281   success = os_file_read(src_file, log_buf, 0, 0, LOG_FILE_HDR_SIZE);
04282   if (!success) {
04283     goto error;
04284   }
04285 
04286   memset(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, ' ', 4);
04287 
04288   success = os_file_write(src_path, src_file, log_buf, 0, 0, LOG_FILE_HDR_SIZE);
04289   if (!success) {
04290     goto error;
04291   }
04292 
04293   os_file_close(src_file);
04294   src_file = -1;
04295 
04296   return(FALSE);
04297 error:
04298   if (src_file != -1)
04299     os_file_close(src_file);
04300   if (log_buf_)
04301     ut_free(log_buf_);
04302   fprintf(stderr, "xtrabackup: Error: xtrabackup_close_temp_log() failed.\n");
04303   return(TRUE); /*ERROR*/
04304 }
04305 
04306 static void
04307 xtrabackup_prepare_func(void)
04308 {
04309   /* cd to target-dir */
04310 
04311   if (chdir(xtrabackup_real_target_dir) != 0)
04312   {
04313     fprintf(stderr, "xtrabackup: cannot my_setwd %s\n", xtrabackup_real_target_dir);
04314     exit(EXIT_FAILURE);
04315   }
04316   fprintf(stderr, "xtrabackup: cd to %s\n", xtrabackup_real_target_dir);
04317 
04318   xtrabackup_target_dir= mysql_data_home_buff;
04319   mysql_data_home_buff[0]=FN_CURLIB;    // all paths are relative from here
04320   mysql_data_home_buff[1]=0;
04321 
04322   /* read metadata of target */
04323   {
04324     char  filename[FN_REFLEN];
04325 
04326     sprintf(filename, "%s/%s", xtrabackup_target_dir, XTRABACKUP_METADATA_FILENAME);
04327 
04328     if (xtrabackup_read_metadata(filename))
04329       fprintf(stderr, "xtrabackup: error: xtrabackup_read_metadata()\n");
04330 
04331     if (!strcmp(metadata_type, "full-backuped")) {
04332       fprintf(stderr, "xtrabackup: This target seems to be not prepared yet.\n");
04333     } else if (!strcmp(metadata_type, "full-prepared")) {
04334       fprintf(stderr, "xtrabackup: This target seems to be already prepared.\n");
04335       goto skip_check;
04336     } else {
04337       fprintf(stderr, "xtrabackup: This target seems not to have correct metadata...\n");
04338     }
04339 
04340     if (xtrabackup_incremental) {
04341       fprintf(stderr,
04342       "xtrabackup: error: applying incremental backup needs target prepared.\n");
04343       exit(EXIT_FAILURE);
04344     }
04345 skip_check:
04346     if (xtrabackup_incremental
04347         && ut_dulint_cmp(metadata_to_lsn, incremental_lsn) != 0) {
04348       fprintf(stderr,
04349       "xtrabackup: error: This incremental backup seems not to be proper for the target.\n"
04350       "xtrabackup:  Check 'to_lsn' of the target and 'from_lsn' of the incremental.\n");
04351       exit(EXIT_FAILURE);
04352     }
04353   }
04354 
04355   /* Create logfiles for recovery from 'xtrabackup_logfile', before start InnoDB */
04356   srv_max_n_threads = 1000;
04357   os_sync_mutex = NULL;
04358   ut_mem_init();
04359 #ifdef XTRADB_BASED
04360   /* temporally dummy value to avoid crash */
04361   srv_page_size_shift = 14;
04362   srv_page_size = (1 << srv_page_size_shift);
04363 #endif
04364   os_sync_init();
04365   sync_init();
04366   os_io_init_simple();
04367   if(xtrabackup_init_temp_log())
04368     goto error;
04369 
04370   if(xtrabackup_incremental)
04371     xtrabackup_apply_deltas(TRUE);
04372 
04373   sync_close();
04374   sync_initialized = FALSE;
04375   os_sync_free();
04376   os_sync_mutex = NULL;
04377   ut_free_all_mem();
04378 
04379   /* check the accessibility of target-dir */
04380   /* ############# TODO ##################### */
04381 
04382   if(innodb_init_param())
04383     goto error;
04384 
04385   srv_apply_log_only = (ibool) xtrabackup_apply_log_only;
04386 
04387   /* increase IO threads */
04388   if(srv_n_file_io_threads < 10) {
04389     srv_n_file_io_threads = 10;
04390   }
04391 
04392   fprintf(stderr, "xtrabackup: Starting InnoDB instance for recovery.\n"
04393     "xtrabackup: Using %"PRIu64" bytes for buffer pool (set by --use-memory parameter)\n",
04394     xtrabackup_use_memory);
04395 
04396   if(innodb_init())
04397     goto error;
04398 
04399   //printf("Hello InnoDB world!\n");
04400 
04401   /* TEST: innodb status*/
04402 /*
04403   ulint trx_list_start = ULINT_UNDEFINED;
04404   ulint trx_list_end = ULINT_UNDEFINED;
04405   srv_printf_innodb_monitor(stdout, &trx_list_start, &trx_list_end);
04406 */
04407   /* TEST: list of datafiles and transaction log files and LSN*/
04408 /*
04409   {
04410   fil_system_t*   f_system = fil_system;
04411   fil_space_t*  space;
04412   fil_node_t* node;
04413 
04414         mutex_enter(&(f_system->mutex));
04415 
04416         space = UT_LIST_GET_FIRST(f_system->space_list);
04417 
04418         while (space != NULL) {
04419     printf("space: name=%s, id=%d, purpose=%d, size=%d\n",
04420       space->name, space->id, space->purpose, space->size);
04421 
04422                 node = UT_LIST_GET_FIRST(space->chain);
04423 
04424                 while (node != NULL) {
04425       printf("node: name=%s, open=%d, size=%d\n",
04426         node->name, node->open, node->size);
04427 
04428                         node = UT_LIST_GET_NEXT(chain, node);
04429                 }
04430                 space = UT_LIST_GET_NEXT(space_list, space);
04431         }
04432 
04433         mutex_exit(&(f_system->mutex));
04434   }
04435 */
04436   /* align space sizes along with fsp header */
04437   {
04438   fil_system_t* f_system = fil_system;
04439   fil_space_t*  space;
04440 
04441   mutex_enter(&(f_system->mutex));
04442   space = UT_LIST_GET_FIRST(f_system->space_list);
04443 
04444   while (space != NULL) {
04445     byte* header;
04446     ulint size;
04447     ulint actual_size;
04448     mtr_t mtr;
04449     buf_block_t*  block;
04450     ulint flags;
04451 
04452     if (space->purpose == FIL_TABLESPACE) {
04453       mutex_exit(&(f_system->mutex));
04454 
04455       mtr_start(&mtr);
04456 
04457       mtr_s_lock(fil_space_get_latch(space->id, &flags), &mtr);
04458 
04459       block = buf_page_get(space->id,
04460                dict_table_flags_to_zip_size(flags),
04461                0, RW_S_LATCH, &mtr);
04462       header = FIL_PAGE_DATA /*FSP_HEADER_OFFSET*/
04463         + buf_block_get_frame(block);
04464 
04465       size = mtr_read_ulint(header + 8 /* FSP_SIZE */, MLOG_4BYTES, &mtr);
04466 
04467       mtr_commit(&mtr);
04468 
04469       //printf("%d, %d\n", space->id, size);
04470 
04471       fil_extend_space_to_desired_size(&actual_size, space->id, size);
04472 
04473       mutex_enter(&(f_system->mutex));
04474     }
04475 
04476     space = UT_LIST_GET_NEXT(space_list, space);
04477   }
04478 
04479   mutex_exit(&(f_system->mutex));
04480   }
04481 
04482 
04483 
04484   if (xtrabackup_export) {
04485     printf("xtrabackup: export option is specified.\n");
04486     if (innobase_file_per_table) {
04487       fil_system_t* f_system = fil_system;
04488       fil_space_t*  space;
04489       fil_node_t* node;
04490       os_file_t info_file = -1;
04491       char    info_file_path[FN_REFLEN];
04492       ibool   success;
04493       char    table_name[FN_REFLEN];
04494 
04495       byte*   page;
04496       byte*   buf = NULL;
04497 
04498       buf = (byte*) ut_malloc(UNIV_PAGE_SIZE * 2);
04499       page = (byte*) ut_align(buf, UNIV_PAGE_SIZE);
04500 
04501       /* flush insert buffer at shutdwon */
04502       innobase_fast_shutdown = 0;
04503 
04504       mutex_enter(&(f_system->mutex));
04505 
04506       space = UT_LIST_GET_FIRST(f_system->space_list);
04507       while (space != NULL) {
04508         /* treat file_per_table only */
04509         if (space->purpose != FIL_TABLESPACE
04510 #ifdef XTRADB_BASED
04511             || trx_sys_sys_space(space->id)
04512 #else
04513             || space->id == 0
04514 #endif
04515            )
04516         {
04517           space = UT_LIST_GET_NEXT(space_list, space);
04518           continue;
04519         }
04520 
04521         node = UT_LIST_GET_FIRST(space->chain);
04522         while (node != NULL) {
04523           int len;
04524           char *next, *prev, *p;
04525           dict_table_t* table;
04526           dict_index_t* index;
04527           ulint   n_index;
04528 
04529           /* node exist == file exist, here */
04530           strncpy(info_file_path, node->name, FN_REFLEN);
04531           len = strlen(info_file_path);
04532           info_file_path[len - 3] = 'e';
04533           info_file_path[len - 2] = 'x';
04534           info_file_path[len - 1] = 'p';
04535 
04536           p = info_file_path;
04537           prev = NULL;
04538           while ((next = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
04539           {
04540             prev = p;
04541             p = next + 1;
04542           }
04543           info_file_path[len - 4] = 0;
04544           strncpy(table_name, prev, FN_REFLEN);
04545 
04546           info_file_path[len - 4] = '.';
04547 
04548           mutex_exit(&(f_system->mutex));
04549           mutex_enter(&(dict_sys->mutex));
04550 
04551           table = dict_table_get_low(table_name);
04552           if (!table) {
04553             fprintf(stderr,
04554 "xtrabackup: error: cannot find dictionary record of table %s\n", table_name);
04555             goto next_node;
04556           }
04557           index = dict_table_get_first_index(table);
04558           n_index = UT_LIST_GET_LEN(table->indexes);
04559           if (n_index > 31) {
04560             fprintf(stderr,
04561 "xtrabackup: error: sorry, cannot export over 31 indexes for now.\n");
04562             goto next_node;
04563           }
04564 
04565           /* init exp file */
04566           bzero(page, UNIV_PAGE_SIZE);
04567           mach_write_to_4(page    , 0x78706f72UL);
04568           mach_write_to_4(page + 4, 0x74696e66UL);/*"xportinf"*/
04569           mach_write_to_4(page + 8, n_index);
04570           strncpy((char*)page + 12, table_name, 500);
04571 
04572           printf(
04573 "xtrabackup: export metadata of table '%s' to file `%s` (%lu indexes)\n",
04574             table_name, info_file_path, n_index);
04575 
04576           n_index = 1;
04577           while (index) {
04578             mach_write_to_8(page + n_index * 512, index->id);
04579             mach_write_to_4(page + n_index * 512 + 8,
04580                 index->page);
04581 
04582             strncpy((char*)page + n_index * 512 + 12, index->name, 500);
04583 
04584             printf(
04585 "xtrabackup:     name=%s, id.low=%lu, page=%lu\n",
04586               index->name,
04587               (ulint)(index->id & 0xFFFFFFFFUL),
04588 
04589               (ulint) index->page);
04590 
04591             index = dict_table_get_next_index(index);
04592             n_index++;
04593           }
04594 
04595           srv_normalize_path_for_win(info_file_path);
04596           info_file = os_file_create(
04597                 0 /* dummy of innodb_file_data_key */,
04598                 info_file_path, OS_FILE_OVERWRITE,
04599                 OS_FILE_NORMAL, OS_DATA_FILE, &success);
04600           if (!success) {
04601             os_file_get_last_error(TRUE);
04602             goto next_node;
04603           }
04604           success = os_file_write(info_file_path, info_file, page,
04605                 0, 0, UNIV_PAGE_SIZE);
04606           if (!success) {
04607             os_file_get_last_error(TRUE);
04608             goto next_node;
04609           }
04610           success = os_file_flush(info_file);
04611           if (!success) {
04612             os_file_get_last_error(TRUE);
04613             goto next_node;
04614           }
04615 next_node:
04616           if (info_file != -1) {
04617             os_file_close(info_file);
04618             info_file = -1;
04619           }
04620           mutex_exit(&(dict_sys->mutex));
04621           mutex_enter(&(f_system->mutex));
04622 
04623           node = UT_LIST_GET_NEXT(chain, node);
04624         }
04625 
04626         space = UT_LIST_GET_NEXT(space_list, space);
04627       }
04628       mutex_exit(&(f_system->mutex));
04629 
04630       ut_free(buf);
04631     } else {
04632       printf("xtrabackup: export option is for file_per_table only, disabled.\n");
04633     }
04634   }
04635 
04636   /* print binlog position (again?) */
04637   printf("\n[notice (again)]\n"
04638     "  If you use binary log and don't use any hack of group commit,\n"
04639     "  the binary log position seems to be:\n");
04640 // FIXME:   trx_sys_print_mysql_binlog_offset();
04641   printf("\n");
04642 
04643   /* output to xtrabackup_binlog_pos_innodb */
04644         if (false) {
04645 //FIXME if (*trx_sys_mysql_bin_log_name != '\0') {
04646     FILE *fp;
04647 
04648     fp = fopen("xtrabackup_binlog_pos_innodb", "w");
04649     if (fp) {
04650       fprintf(fp, "%s\t%llu\n",
04651                                 "none", 0ULL);
04652                                 /* FIXME
04653         trx_sys_mysql_bin_log_name,
04654         trx_sys_mysql_bin_log_pos);*/
04655       fclose(fp);
04656     } else {
04657       printf("xtrabackup: failed to open 'xtrabackup_binlog_pos_innodb'\n");
04658     }
04659   }
04660 
04661   /* Check whether the log is applied enough or not. */
04662   if ((xtrabackup_incremental
04663        && ut_dulint_cmp(srv_start_lsn, incremental_last_lsn) < 0)
04664       ||(!xtrabackup_incremental
04665          && ut_dulint_cmp(srv_start_lsn, metadata_last_lsn) < 0)) {
04666     printf( "xtrabackup: ########################################################\n"
04667       "xtrabackup: # !!WARNING!!                                          #\n"
04668       "xtrabackup: # The transaction log file should be wrong or corrupt. #\n"
04669       "xtrabackup: # The log was not applied to the intended LSN!         #\n"
04670       "xtrabackup: ########################################################\n");
04671     if (xtrabackup_incremental) {
04672       printf("xtrabackup: The intended lsn is %"PRIu64"\n",
04673         incremental_last_lsn);
04674     } else {
04675       printf("xtrabackup: The intended lsn is %"PRIu64"\n",
04676         metadata_last_lsn);
04677     }
04678   }
04679 
04680   if(innodb_end())
04681     goto error;
04682 
04683   sync_initialized = FALSE;
04684   os_sync_mutex = NULL;
04685 
04686   /* re-init necessary components */
04687   ut_mem_init();
04688 
04689   os_sync_init();
04690   sync_init();
04691   os_io_init_simple();
04692 
04693   if(xtrabackup_close_temp_log(TRUE))
04694     exit(EXIT_FAILURE);
04695 
04696   /* output to metadata file */
04697   {
04698     char  filename[FN_REFLEN];
04699 
04700     strcpy(metadata_type, "full-prepared");
04701 
04702     if(xtrabackup_incremental
04703        && ut_dulint_cmp(metadata_to_lsn, incremental_to_lsn) < 0)
04704     {
04705       metadata_to_lsn = incremental_to_lsn;
04706       metadata_last_lsn = incremental_last_lsn;
04707     }
04708 
04709     sprintf(filename, "%s/%s", xtrabackup_target_dir, XTRABACKUP_METADATA_FILENAME);
04710     if (xtrabackup_write_metadata(filename))
04711       fprintf(stderr, "xtrabackup: error: xtrabackup_write_metadata(xtrabackup_target_dir)\n");
04712 
04713     if(xtrabackup_extra_lsndir) {
04714       sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_METADATA_FILENAME);
04715       if (xtrabackup_write_metadata(filename))
04716         fprintf(stderr, "xtrabackup: error: xtrabackup_write_metadata(xtrabackup_extra_lsndir)\n");
04717     }
04718   }
04719 
04720   if(!xtrabackup_create_ib_logfile)
04721     return;
04722 
04723   /* TODO: make more smart */
04724 
04725   printf("\n[notice]\nWe cannot call InnoDB second time during the process lifetime.\n");
04726   printf("Please re-execte to create ib_logfile*. Sorry.\n");
04727 /*
04728   printf("Restart InnoDB to create ib_logfile*.\n");
04729 
04730   if(innodb_init_param())
04731     goto error;
04732 
04733   if(innodb_init())
04734     goto error;
04735 
04736   if(innodb_end())
04737     goto error;
04738 */
04739 
04740   return;
04741 
04742 error:
04743   xtrabackup_close_temp_log(FALSE);
04744 
04745   exit(EXIT_FAILURE);
04746 }
04747 
04748 /* ================= main =================== */
04749 
04750 int main(int argc, char **argv)
04751 {
04752   po::options_description commandline_options(_("Options used only in command line"));
04753   commandline_options.add_options()
04754     ("target-dir", po::value<std::string>(), _("destination directory"))
04755           ("backup", po::value<bool>(&xtrabackup_backup)->default_value(false)->zero_tokens(), _("take backup to target-dir"))
04756   ("stats", po::value<bool>(&xtrabackup_stats)->default_value(false)->zero_tokens(), _("calc statistic of datadir (offline mysqld is recommended)"))
04757   ("prepare", po::value<bool>(&xtrabackup_prepare)->default_value(false)->zero_tokens(), _("prepare a backup for starting mysql server on the backup."))
04758   ("export", po::value<bool>(&xtrabackup_export)->default_value(false)->zero_tokens(), _("create files to import to another database when prepare."))
04759   ("apply-log-only", po::value<bool>(&xtrabackup_apply_log_only)->default_value(false)->zero_tokens(), _("stop recovery process not to progress LSN after applying log when prepare."))
04760   ("print-param", po::value<bool>(&xtrabackup_print_param)->default_value(false)->zero_tokens(), _("print parameter of mysqld needed for copyback."))
04761   ("use-memory", po::value<uint64_t>(&xtrabackup_use_memory)->default_value(100*1024*1024), _("The value is used instead of buffer_pool_size"))
04762   ("suspend-at-end", po::value<bool>(&xtrabackup_suspend_at_end)->default_value(false)->zero_tokens(), _("creates a file 'xtrabackup_suspended' and waits until the user deletes that file at the end of '--backup'"))
04763   ("throttle", po::value<long>(&xtrabackup_throttle), _("limit count of IO operations (pairs of read&write) per second to IOS values (for '--backup')"))
04764   ("log-stream", po::value<bool>(&xtrabackup_stream)->default_value(false)->zero_tokens(), _("outputs the contents of 'xtrabackup_logfile' to stdout only until the file 'xtrabackup_suspended' deleted (for '--backup')."))
04765     ("extra-lsndir", po::value<std::string>(), _("(for --backup): save an extra copy of the xtrabackup_checkpoints file in this directory."))
04766     ("incremental-lsn", po::value<std::string>(), _("(for --backup): copy only .ibd pages newer than specified LSN 'high:low'. ##ATTENTION##: checkpoint lsn must be used. anyone can detect your mistake. be carefully!"))
04767     ("incremental-basedir", po::value<std::string>(), _("(for --backup): copy only .ibd pages newer than backup at specified directory."))
04768     ("incremental-dir", po::value<std::string>(), _("(for --prepare): apply .delta files and logfile in the specified directory."))
04769     ("tables", po::value<std::string>(), _("filtering by regexp for table names."))
04770     ("tables-file", po::value<std::string>(), _("filtering by list of the exact database.table name in the file."))
04771   ("create-ib-logfile", po::value<bool>(&xtrabackup_create_ib_logfile), _("** not work for now** creates ib_logfile* also after '--prepare'. ### If you want create ib_logfile*, only re-execute this command in same options. ###"))
04772           ("datadir,h", po::value<std::string>(), _("Path to the database root."))
04773     ("tmpdir,t", po::value<std::string>(), _("Path for temporary files. Several paths may be specified, separated by a colon (:), in this case they are used in a round-robin fashion."))
04774   ("parallel", po::value<uint32_t>(&parallel)->default_value(1), _("Number of threads to use for parallel datafiles transfer. Does not have any effect in the stream mode. The default value is 1."))
04775   ("innodb-adaptive-hash-index", po::value<bool>(&innobase_adaptive_hash_index)->default_value(true), _("Enable InnoDB adaptive hash index (enabled by default).  Disable with --skip-innodb-adaptive-hash-index."))
04776   ("innodb-additional-mem-pool-size", po::value<long>(&innobase_additional_mem_pool_size)->default_value(1*1024*1024), _("Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures."))
04777   ("innodb-autoextend-increment", po::value<uint32_t>(&srv_auto_extend_increment)->default_value(8), _("Data file autoextend increment in megabytes"))
04778   ("innodb-buffer-pool-size", po::value<uint64_t>(&innobase_buffer_pool_size)->default_value(8*1024*1024), _("The size of the memory buffer InnoDB uses to cache data and indexes of its tables."))
04779   ("innodb-checksums", po::value<bool>(&innobase_use_checksums)->default_value(true), _("Enable InnoDB checksums validation (enabled by default). Disable with --skip-innodb-checksums."))
04780     ("innodb-data-file-path", po::value<std::string>(), _("Path to individual files and their sizes."))
04781     ("innodb-data-home-dir", po::value<std::string>(), _("The common part for InnoDB table spaces."))
04782   ("innodb-doublewrite", po::value<bool>(&innobase_use_doublewrite)->default_value(true), _("Enable InnoDB doublewrite buffer (enabled by default). Disable with --skip-innodb-doublewrite."))
04783   ("innodb-file-io-threads", po::value<long>(&innobase_file_io_threads)->default_value(4), _("Number of file I/O threads in InnoDB."))
04784   ("innodb-file-per-table", po::value<bool>(&innobase_file_per_table), _("Stores each InnoDB table to an .ibd file in the database dir."))
04785   ("innodb-flush-log-at-trx-commit", po::value<ulong>(&srv_flush_log_at_trx_commit)->default_value(1), _("Set to 0 (write and flush once per second), 1 (write and flush at each commit) or 2 (write at commit, flush once per second)."))
04786           ("innodb-flush-method", po::value<std::string>(), _("With which method to flush data."))
04787 /* ####### Should we use this option? ####### */
04788          ("innodb-force-recovery", po::value<long>(&innobase_force_recovery)->default_value(0), _("Helps to save your data in case the disk image of the database becomes corrupt."))
04789   ("innodb-lock-wait-timeout", po::value<long>(&innobase_lock_wait_timeout)->default_value(50), _("Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back."))
04790   ("innodb-log-buffer-size", po::value<long>(&innobase_log_buffer_size)->default_value(1024*1024), _("The size of the buffer which InnoDB uses to write log to the log files on disk."))
04791   ("innodb-log-file-size", po::value<log_file_constraint>(&innobase_log_file_size)->default_value(20*1024*1024L), _("Size of each log file in a log group."))
04792   ("innodb-log-files-in-group", po::value<long>(&innobase_log_files_in_group)->default_value(2), _("Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here."))
04793     ("innodb-log-group-home-dir", po::value<std::string>(), _("Path to InnoDB log files."))
04794   ("innodb-max_dirty-pages-pct", po::value<ulong>(&srv_max_buf_pool_modified_pct)->default_value(90), _("Percentage of dirty pages allowed in bufferpool."))
04795   ("innodb-open-files", po::value<long>(&innobase_open_files)->default_value(300), _("How many files at the maximum InnoDB keeps open at the same time."))
04796 #ifdef XTRADB_BASED
04797   ("innodb-page-size", po::value<uint32_t>(&innobase_page_size)->default_value(1 << 14), _("The universal page size of the database."))
04798   ("innodb-log-block-size", po::value<uint32_t>(&innobase_log_block_size)->default_value(512), _("###EXPERIMENTAL###: The log block size of the transaction log file. Changing for created log file is not supported. Use on your own risk!"))
04799   ("innodb-fast-checksum", po::value<bool>(&innobase_fast_checksum), _("Change the algorithm of checksum for the whole of datapage to 4-bytes word based."))
04800   ("innodb-extra-undoslots", po::value<bool>(&innobase_extra_undoslots), _("Enable to use about 4000 undo slots instead of default 1024. Not recommended to use, Because it is not change back to disable, once it is used."))
04801   ("innodb-doublewrite-file", po::value<char *>(&innobase_doublewrite_file), _("Path to special datafile for doublewrite buffer. (default is "": not used)"))
04802 #endif
04803   ;
04804 
04805   po::variables_map vm;
04806   // Disable allow_guessing, it is evil and broken
04807   int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
04808   po::store(po::command_line_parser(argc, argv).options(commandline_options).style(style).run(), vm);
04809   po::notify(vm);
04810 
04811   if (vm.count("target-dir"))
04812     xtrabackup_target_dir= vm["target-dir"].as<std::string>().c_str();
04813 
04814   if (vm.count("extra-lsndir"))
04815     xtrabackup_extra_lsndir= vm["extra-lsndir"].as<std::string>().c_str();
04816 
04817   if (vm.count("incremental-lsn"))
04818     xtrabackup_incremental= vm["incremental-lsn"].as<std::string>().c_str();
04819 
04820   if (vm.count("incremental-basedir"))
04821     xtrabackup_incremental_basedir= vm["incremental-basedir"].as<std::string>().c_str();
04822 
04823   boost::scoped_ptr<char> xtrabackup_tables_autoptr(new char[(vm.count("tables")) ? vm["tables"].as<std::string>().length() + 1: 0]);
04824   if (vm.count("tables"))
04825   {
04826     xtrabackup_tables= xtrabackup_tables_autoptr.get();
04827     strcpy(xtrabackup_tables, vm["tables"].as<std::string>().c_str());
04828   }
04829 
04830   if (vm.count("tables-file"))
04831     xtrabackup_tables_file= vm["tables-file"].as<std::string>().c_str();
04832 
04833   if (vm.count("tmpdir"))
04834     opt_mysql_tmpdir= vm["tmpdir"].as<std::string>().c_str();
04835 
04836   if (vm.count("innodb-data-file-path"))
04837     innobase_data_file_path= vm["innodb-data-file-path"].as<std::string>().c_str();
04838 
04839   boost::scoped_ptr<char> xtrabackup_incremental_dir_autoptr(new char[(vm.count("incremental-dir")) ? vm["incremental-dir"].as<std::string>().length() + 1: 0]);
04840   if (vm.count("incremental-dir"))
04841   {
04842     xtrabackup_incremental_dir= xtrabackup_incremental_dir_autoptr.get();
04843     strcpy(xtrabackup_incremental_dir, vm["incremental-dir"].as<std::string>().c_str());
04844   }
04845 
04846   boost::scoped_ptr<char> innobase_data_home_dir_autoptr(new char[(vm.count("innodb-data-home-dir")) ? vm["innodb-data-home-dir"].as<std::string>().length() + 1 : 0]);
04847   if (vm.count("innodb-data-home-dir"))
04848   {
04849     innobase_data_home_dir= innobase_data_home_dir_autoptr.get();
04850     strcpy(innobase_data_home_dir, vm["innodb-data-home-dir"].as<std::string>().c_str());
04851   }
04852 
04853   boost::scoped_ptr<char> innobase_flush_method_autoptr(new char[(vm.count("innodb-flush-method")) ? vm["innodb-flush-method"].as<std::string>().length() + 1 : 0]);
04854   if (vm.count("innodb-flush-method"))
04855   {
04856     innobase_unix_file_flush_method= innobase_flush_method_autoptr.get();
04857     strcpy(innobase_unix_file_flush_method, vm["innodb-flush-method"].as<std::string>().c_str());
04858   }
04859 
04860   boost::scoped_ptr<char> innobase_log_group_home_dir_autoptr(new char[(vm.count("innodb-log-group-home-dir")) ? vm["innodb-log-group-home-dir"].as<std::string>().length() + 1: 0]);
04861 
04862   if (vm.count("innodb-log-group-home-dir"))
04863   {
04864     innobase_log_group_home_dir= innobase_log_group_home_dir_autoptr.get();
04865     strcpy(innobase_log_group_home_dir, vm["innodb-log-group-home-dir"].as<std::string>().c_str());
04866   }
04867 
04868   xtrabackup_use_memory-= xtrabackup_use_memory % (1024*1024);
04869   if (xtrabackup_use_memory < (1024*1024)) {
04870     fprintf(stderr, "xtrabackup: use-memory out of range\n");
04871     exit(EXIT_FAILURE);
04872   }
04873 
04874   if (parallel < 1) {
04875     fprintf(stderr, "xtrabackup: parallel needs to be greater than 0\n");
04876     exit(EXIT_FAILURE);
04877   }
04878 
04879   innobase_additional_mem_pool_size-= innobase_additional_mem_pool_size % 1024;
04880   if (innobase_additional_mem_pool_size < (512*1024)) {
04881     fprintf(stderr, "xtrabackup: innodb-additional-mem-pool-size out of range\n");
04882     exit(EXIT_FAILURE);   
04883   }
04884 
04885   if ((srv_auto_extend_increment < 1) || (srv_auto_extend_increment > 8)) {
04886     fprintf(stderr, "xtrabackup: innodb-auto-extend-increment out of range\n");
04887     exit(EXIT_FAILURE);   
04888   }
04889 
04890   innobase_buffer_pool_size-= innobase_buffer_pool_size % (1024*1024);
04891   if (innobase_buffer_pool_size < (1024*1024)) {
04892     fprintf(stderr, "xtrabackup: innodb-buffer-pool-size out of range\n");
04893     exit(EXIT_FAILURE);
04894   }
04895 
04896   if ((innobase_file_io_threads < 4) || (innobase_file_io_threads > 64)) {
04897     fprintf(stderr, "xtrabackup: innodb-file-io-threads out of range\n");
04898     exit(EXIT_FAILURE);   
04899   }
04900 
04901   if (srv_flush_log_at_trx_commit > 2) {
04902     fprintf(stderr, "xtrabackup: innodb-flush-log-at-trx-commit out of range\n");
04903     exit(EXIT_FAILURE);   
04904   }
04905 
04906   if (innobase_force_recovery > 6) {
04907     fprintf(stderr, "xtrabackup: innodb-force-recovery out of range\n");
04908     exit(EXIT_FAILURE);   
04909   }
04910 
04911   if ((innobase_lock_wait_timeout < 1) || (innobase_lock_wait_timeout > (1024*1024*1024))) {
04912     fprintf(stderr, "xtrabackup: innodb-lock-wait-timeout out of range\n");
04913     exit(EXIT_FAILURE);   
04914   }
04915 
04916   innobase_log_buffer_size-= innobase_log_buffer_size % 1024;
04917   if (innobase_additional_mem_pool_size < (256*1024)) {
04918     fprintf(stderr, "xtrabackup: innodb-log-buffer-size out of range\n");
04919     exit(EXIT_FAILURE);   
04920   }
04921 
04922   if (innobase_additional_mem_pool_size < (1024*1024)) {
04923     fprintf(stderr, "xtrabackup: innodb-log-file-size out of range\n");
04924     exit(EXIT_FAILURE);   
04925   }
04926 
04927   if ((innobase_log_files_in_group < 2) || (innobase_log_files_in_group > (100))) {
04928     fprintf(stderr, "xtrabackup: innodb-log-files-in-group out of range\n");
04929     exit(EXIT_FAILURE);   
04930   }
04931 
04932   if (srv_max_buf_pool_modified_pct > 100) {
04933     fprintf(stderr, "xtrabackup: innodb-max-buf-pool-modified-pct out of range\n");
04934     exit(EXIT_FAILURE);   
04935   }
04936 
04937   if (innobase_open_files < 10) {
04938     fprintf(stderr, "xtrabackup: innodb-open-files out of range\n");
04939     exit(EXIT_FAILURE);   
04940   }
04941 
04942   if ((innobase_page_size < (1 << 12)) || (innobase_page_size > (1 << UNIV_PAGE_SIZE_SHIFT_MAX))) {
04943     fprintf(stderr, "xtrabackup: innodb-page-size out of range\n");
04944     exit(EXIT_FAILURE);   
04945   }
04946 
04947   if ((innobase_log_block_size < (512)) || (innobase_log_block_size > (1 << UNIV_PAGE_SIZE_SHIFT_MAX))) {
04948     fprintf(stderr, "xtrabackup: innodb-log-block-size out of range\n");
04949     exit(EXIT_FAILURE);   
04950   }
04951 
04952         if (vm.count("datadir"))
04953         {
04954           mysql_data_home_arg.assign(vm["datadir"].as<std::string>());
04955         }
04956         else
04957         {
04958           mysql_data_home_arg.assign(LOCALSTATEDIR);
04959         }
04960 
04961         mysql_data_home= (char*)malloc(mysql_data_home_arg.length());
04962         strcpy(mysql_data_home, mysql_data_home_arg.c_str());
04963 
04964   if ((!xtrabackup_prepare) && (strcmp(mysql_data_home, "./") == 0)) {
04965     if (!xtrabackup_print_param)
04966       usage();
04967     printf("\nxtrabackup: Error: Please set parameter 'datadir'\n");
04968     exit(EXIT_FAILURE);
04969   }
04970 
04971   if (xtrabackup_tables) {
04972     /* init regexp */
04973     char *p, *next;
04974     int i;
04975     char errbuf[100];
04976 
04977     tables_regex_num = 1;
04978 
04979     p = xtrabackup_tables;
04980     while ((p = strchr(p, ',')) != NULL) {
04981       p++;
04982       tables_regex_num++;
04983     }
04984 
04985     tables_regex = (regex_t*) ut_malloc(sizeof(regex_t) * tables_regex_num);
04986 
04987     p = xtrabackup_tables;
04988     for (i=0; i < tables_regex_num; i++) {
04989       next = strchr(p, ',');
04990       ut_a(next || i == tables_regex_num - 1);
04991 
04992       next++;
04993       if (i != tables_regex_num - 1)
04994         *(next - 1) = '\0';
04995 
04996       regerror(regcomp(&tables_regex[i],p,REG_EXTENDED),
04997           &tables_regex[i],errbuf,sizeof(errbuf));
04998       fprintf(stderr, "xtrabackup: tables regcomp(%s): %s\n",p,errbuf);
04999 
05000       if (i != tables_regex_num - 1)
05001         *(next - 1) = ',';
05002       p = next;
05003     }
05004   }
05005 
05006   if (xtrabackup_tables_file) {
05007     char name_buf[NAME_LEN*2+2];
05008     FILE *fp;
05009 
05010     if (xtrabackup_stream) {
05011       fprintf(stderr, "xtrabackup: Warning: --tables_file option doesn't affect with --stream.\n");
05012       xtrabackup_tables_file = NULL;
05013       goto skip_tables_file_register;
05014     }
05015 
05016     name_buf[NAME_LEN*2+1] = '\0';
05017 
05018     /* init tables_hash */
05019     tables_hash = hash_create(1000);
05020 
05021     /* read and store the filenames */
05022     fp = fopen(xtrabackup_tables_file,"r");
05023     if (!fp) {
05024       fprintf(stderr, "xtrabackup: cannot open %s\n", xtrabackup_tables_file);
05025       exit(EXIT_FAILURE);
05026     }
05027     for (;;) {
05028       xtrabackup_tables_t*  table;
05029       char* p = name_buf;
05030 
05031       if ( fgets(name_buf, NAME_LEN*2+1, fp) == 0 ) {
05032         break;
05033       }
05034 
05035       while (*p != '\0') {
05036         if (*p == '.') {
05037           *p = '/';
05038         }
05039         p++;
05040       }
05041       p = strchr(name_buf, '\n');
05042       if (p)
05043       {
05044         *p = '\0';
05045       }
05046 
05047       table = (xtrabackup_tables_t*) malloc(sizeof(xtrabackup_tables_t) + strlen(name_buf) + 1);
05048       memset(table, '\0', sizeof(xtrabackup_tables_t) + strlen(name_buf) + 1);
05049       table->name = ((char*)table) + sizeof(xtrabackup_tables_t);
05050       strcpy(table->name, name_buf);
05051 
05052       HASH_INSERT(xtrabackup_tables_t, name_hash, tables_hash,
05053           ut_fold_string(table->name), table);
05054 
05055       printf("xtrabackup: table '%s' is registered to the list.\n", table->name);
05056     }
05057   }
05058 skip_tables_file_register:
05059 
05060 #ifdef XTRADB_BASED
05061   /* temporary setting of enough size */
05062   srv_page_size_shift = UNIV_PAGE_SIZE_SHIFT_MAX;
05063   srv_page_size = UNIV_PAGE_SIZE_MAX;
05064   srv_log_block_size = 512;
05065 #endif
05066   if (xtrabackup_backup && xtrabackup_incremental) {
05067     /* direct specification is only for --backup */
05068     /* and the lsn is prior to the other option */
05069 
05070     char* endchar;
05071     int error = 0;
05072 
05073     incremental_lsn = strtoll(xtrabackup_incremental, &endchar, 10);
05074     if (*endchar != '\0')
05075       error = 1;
05076 
05077     if (error) {
05078       fprintf(stderr, "xtrabackup: value '%s' may be wrong format for incremental option.\n",
05079         xtrabackup_incremental);
05080       exit(EXIT_FAILURE);
05081     }
05082 
05083     /* allocate buffer for incremental backup (4096 pages) */
05084     incremental_buffer_base = (byte*) malloc((UNIV_PAGE_SIZE_MAX / 4 + 1) *
05085              UNIV_PAGE_SIZE_MAX);
05086     incremental_buffer = (byte*) ut_align(incremental_buffer_base,
05087                 UNIV_PAGE_SIZE_MAX);
05088   } else if (xtrabackup_backup && xtrabackup_incremental_basedir) {
05089     char  filename[FN_REFLEN];
05090 
05091     sprintf(filename, "%s/%s", xtrabackup_incremental_basedir, XTRABACKUP_METADATA_FILENAME);
05092 
05093     if (xtrabackup_read_metadata(filename)) {
05094       fprintf(stderr,
05095         "xtrabackup: error: failed to read metadata from %s\n",
05096         filename);
05097       exit(EXIT_FAILURE);
05098     }
05099 
05100     incremental_lsn = metadata_to_lsn;
05101     xtrabackup_incremental = xtrabackup_incremental_basedir; //dummy
05102 
05103     /* allocate buffer for incremental backup (4096 pages) */
05104     incremental_buffer_base = (byte*) malloc((UNIV_PAGE_SIZE_MAX / 4 + 1) *
05105              UNIV_PAGE_SIZE_MAX);
05106     incremental_buffer = (byte*) ut_align(incremental_buffer_base,
05107                 UNIV_PAGE_SIZE_MAX);
05108   } else if (xtrabackup_prepare && xtrabackup_incremental_dir) {
05109     char  filename[FN_REFLEN];
05110 
05111     sprintf(filename, "%s/%s", xtrabackup_incremental_dir, XTRABACKUP_METADATA_FILENAME);
05112 
05113     if (xtrabackup_read_metadata(filename)) {
05114       fprintf(stderr,
05115         "xtrabackup: error: failed to read metadata from %s\n",
05116         filename);
05117       exit(EXIT_FAILURE);
05118     }
05119 
05120     incremental_lsn = metadata_from_lsn;
05121     incremental_to_lsn = metadata_to_lsn;
05122     incremental_last_lsn = metadata_last_lsn;
05123     xtrabackup_incremental = xtrabackup_incremental_dir; //dummy
05124 
05125     /* allocate buffer for incremental backup (4096 pages) */
05126     incremental_buffer_base = (byte*) malloc((UNIV_PAGE_SIZE / 4 + 1) *
05127              UNIV_PAGE_SIZE);
05128     incremental_buffer = (byte*) ut_align(incremental_buffer_base,
05129                 UNIV_PAGE_SIZE);
05130   } else {
05131           /* allocate buffer for applying incremental (for header page only) */
05132           incremental_buffer_base = (byte*) malloc((1 + 1) * UNIV_PAGE_SIZE_MAX);
05133           incremental_buffer = (byte*) ut_align(incremental_buffer_base,
05134                                                 UNIV_PAGE_SIZE_MAX);
05135 
05136     xtrabackup_incremental = NULL;
05137   }
05138 
05139   /* --print-param */
05140   if (xtrabackup_print_param) {
05141     printf("# This MySQL options file was generated by XtraBackup.\n");
05142     printf("[mysqld]\n");
05143     printf("datadir = \"%s\"\n", mysql_data_home);
05144     printf("tmpdir = \"%s\"\n", opt_mysql_tmpdir);
05145     printf("innodb_data_home_dir = \"%s\"\n",
05146       innobase_data_home_dir ? innobase_data_home_dir : mysql_data_home);
05147     printf("innodb_data_file_path = \"%s\"\n",
05148       innobase_data_file_path ? innobase_data_file_path : "ibdata1:10M:autoextend");
05149     printf("innodb_log_group_home_dir = \"%s\"\n",
05150       innobase_log_group_home_dir ? innobase_log_group_home_dir : mysql_data_home);
05151     printf("innodb_log_files_in_group = %ld\n", innobase_log_files_in_group);
05152     printf("innodb_log_file_size = %"PRIu64"\n", (uint64_t)innobase_log_file_size);
05153     printf("innodb_flush_method = \"%s\"\n",
05154            (innobase_unix_file_flush_method != NULL) ?
05155            innobase_unix_file_flush_method : "");
05156     exit(EXIT_SUCCESS);
05157   }
05158 
05159   if (!xtrabackup_stream) {
05160     print_version();
05161     if (xtrabackup_incremental) {
05162       printf("incremental backup from %"PRIu64" is enabled.\n",
05163         incremental_lsn);
05164     }
05165   } else {
05166     if (xtrabackup_backup) {
05167       xtrabackup_suspend_at_end = TRUE;
05168       fprintf(stderr, "xtrabackup: suspend-at-end is enabled.\n");
05169     }
05170   }
05171 
05172   /* cannot execute both for now */
05173   {
05174     int num = 0;
05175 
05176     if (xtrabackup_backup) num++;
05177     if (xtrabackup_stats) num++;
05178     if (xtrabackup_prepare) num++;
05179     if (num != 1) { /* !XOR (for now) */
05180       usage();
05181       exit(EXIT_FAILURE);
05182     }
05183   }
05184 
05185   /* --backup */
05186   if (xtrabackup_backup)
05187     xtrabackup_backup_func();
05188 
05189   /* --stats */
05190   if (xtrabackup_stats)
05191     xtrabackup_stats_func();
05192 
05193   /* --prepare */
05194   if (xtrabackup_prepare)
05195     xtrabackup_prepare_func();
05196 
05197   free(incremental_buffer_base);
05198 
05199   if (xtrabackup_tables) {
05200     /* free regexp */
05201     int i;
05202 
05203     for (i = 0; i < tables_regex_num; i++) {
05204       regfree(&tables_regex[i]);
05205     }
05206     ut_free(tables_regex);
05207   }
05208 
05209   if (xtrabackup_tables_file) {
05210     ulint i;
05211 
05212     /* free the hash elements */
05213     for (i = 0; i < hash_get_n_cells(tables_hash); i++) {
05214       xtrabackup_tables_t*  table;
05215 
05216       table = (xtrabackup_tables_t*)
05217                           HASH_GET_FIRST(tables_hash, i);
05218 
05219       while (table) {
05220         xtrabackup_tables_t*  prev_table = table;
05221 
05222         table =  (xtrabackup_tables_t*)
05223                                   HASH_GET_NEXT(name_hash, prev_table);
05224 
05225         HASH_DELETE(xtrabackup_tables_t, name_hash, tables_hash,
05226             ut_fold_string(prev_table->name), prev_table);
05227         free(prev_table);
05228       }
05229     }
05230 
05231     /* free tables_hash */
05232     hash_table_free(tables_hash);
05233   }
05234 
05235   exit(EXIT_SUCCESS);
05236 }