Merge lp:~sergei.glushchenko/percona-xtrabackup/xb20-bug932623 into lp:percona-xtrabackup/2.0

Proposed by Sergei Glushchenko
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 452
Proposed branch: lp:~sergei.glushchenko/percona-xtrabackup/xb20-bug932623
Merge into: lp:percona-xtrabackup/2.0
Diff against target: 904 lines (+582/-113)
3 files modified
patches/innodb51_builtin.patch (+67/-4)
src/xtrabackup.c (+430/-109)
test/t/bug932623.sh (+85/-0)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-xtrabackup/xb20-bug932623
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+113690@code.launchpad.net

Description of the change

Bug #932623: RENAME TABLE causes incremental prepare to fail
Fixed by applying .delta changes to tablespace with matching ID.
Matching tablespace also renamed to match .delta name.
When tablespace with matching name but different ID exists in full
backup, it renamed to tmp#ID.ibd. When no matching tablespace found,
new one created.

http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.0-param/219/

#24669

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

Tables may be renamed into another database directory, which this fix doesn't take into account. I think we should do space ID verification in a different way:

let's initialize fil_system, in the same --backup or --prepare does it and then use fil_space_get_by_id() and possibly fil_space_get_by_name().

Now the problem is that fil_system will also be initialized later in --prepare when innodb_init() is called, and initializing fil_system multiple times in the same process is tricky. I had to write some extra code for that in the compact backups branch, see xb_data_files_init() and xb_data_files_close() in lp:~akopytov/percona-xtrabackup/compact-backups.

Other minor things:
- s/matchong/matching
- "cat $topdir/inc/ibdata1.meta" in the test case was probably just for debugging and doesn't make any sense as far as regression testing is concerned.

review: Needs Fixing
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Forgot to mention that the following code can be simplified:

14 if (fscanf(fp, "page_size = %lu\n", &info->page_size) != 1)
15 r= FALSE;
16 + if (!r || fscanf(fp, "space_id = %lu\n", &info->space_id) != 1)
17 + r= FALSE;

and

31 snprintf(buf, sizeof(buf), "page_size = %lu\n", info->page_size);
32 -
33 len = strlen(buf);
34 +
35 + snprintf(buf + len, sizeof(buf) - len, "space_id = %lu\n", info->space_id);
36 + len += strlen(buf + len);
37 +

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

It was really tricky to initialize fil_system, especially for built-in InnoDB and for debug builds.

Jenkins build:
http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.0-param/225/

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

Can you explain the problems with initializing fil_system (including the ones in built-in InnoDB) and how you solved them?

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Alexey,

1. fil_space_get_by_id and fil_space_get_by_name are for internal usage. I have to modify patches to make them non-static and not inline. Built-in InnoDB does not have fil_space_get_by_id and fil_space_get_by_name at all. Besides we must hold fil_system->mutex when calling these functions.

2. fil_space use hash tables, which are not working without calling mem_init on debug builds.

3. When we are applying deltas we initialize some parts of InnoDB, then releasing and closing them, and then initializing them and some other parts again. The problem with built-it InnoDB is that it doesn't have proper functions to uninitialize fil, mem, and sync. Plugin have some tricks to do it properly (for example we should close sync, which frees all muteness, then close fil, which checks that sync is closed and only after that been done, we close men. But when closing men it use men_hash_mutex, which wasn't closed in sync_close by using special hack). In case of xtrabackup I cheated and not freed mem in many *_close functions, because it will be freed when ut_free_all_mem called.

4. io_handler_thread had an infinite loop:

 for (i = 0;; i++) {
  fil_aio_wait(segment);
 }
and there was no way to finish this thread. I inserted check of srv_shutdown_state.
 for (i = 0; srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS; i++) {
    fil_aio_wait(segment);
 }

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Spellchecker did bad thing by replacing s/mem/men/ :)

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

Thanks for clarifications. My comments on the new version of the fix:

   - I wonder if it would be less invasive to define our own simple
     wrappers around "HASH_SEARCH(hash, fil_system->spaces, id, space,
     space->id == id);" so we don't have to patch InnoDB or provide our
     own implementations for built-in InnoDB, and mess with
     mutexes. I.e. can we have xb_space_get_by_*()?

  - the code in xtrabackup's version of io_handler_thread() doesn't use
    the 'i' variable, why not just copy the code from InnoDB, i.e.:

 while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) {
  fil_aio_wait(segment);
 }

  - fil_free_all_spaces() seems to be defined for built-in InnoDB, but
    is not used anywhere?

  - in fact, ut_free_all_mem() will not free anything when the system
    malloc() is used instead of the InnoDB own malloc manager, i.e. when
    srv_use_sys_malloc == TRUE, which is the default. I have some
    thoughts on how to fix that, but I suggest we'll do it later as a
    part of bigger refactoring.

  - POSIX guarantees the result of snprintf() to be always
    zero-terminated, so there's no need for things like:

+ snprintf(dest_dir, FN_REFLEN, "%s/%s",
+ xtrabackup_target_dir, dbname);
+ dest_dir[FN_REFLEN - 1] = 0;

    if you care about Windows, you should be using either my_snprintf()
    or ut_snprintf(), which do the right thing on Windows. But
    currently, xtrabackup.c just uses snprintf() in other places anyway,
    so what's the point to do some windows-specific stuff in this
    patch. We can do s/snprintf/ut_snprintf/ later, if and when we
    have to support Windows.

  - this code just uses sprintf() instead snprintf() for some reasons:

+ sprintf(tmpname, "./%s/tmp#%lu", dbname, fil_space->id);

  - I think the output in xb_delta_open_matching_space() is too
    verbose. Let's only print messages when something unexpected
    happens, i.e. remove these messages:

+ msg("xtrabackup: Looking for tablespace %s with id %lu by name\n",
+ dest_space_name, space_id);

and

+ msg("xtrabackup: Looking for tablespace %s with id %lu by id\n",
+ dest_space_name, space_id);

and

+ msg("xtrabackup: Found matching tablespace %s\n",
+ fil_space->name);

and

+ msg("xtrabackup: Created tablespace %s with id %lu.\n",
+ dest_space_name, space_id);

  - what's the point to rename a tablespace with the same name but a
    different ID to tmp#id? the only case when it happens is when a
    tablespace was recreated between the full backup and an incremental
    one. In which case, if we rename the dropped table, we will end up
    with ghost 'tmp...' table in the full backup.

  - this if() block can be merged:

+ if (xtrabackup_incremental) {
+ err = xb_data_files_init();
+ if (err != DB_SUCCESS) {
+ msg("xtrabackup: error: xb_data_files_init() failed with"
+ "error code %lu\n", err);
+ goto error;
+ }
+
+ if(!xtrabackup_apply_deltas(TRUE)) {
+ xb_data_files_close();
+ goto error;
+ }
+ }
+
+ if (xtrabackup_incremental) {
+ xb_data_files_close();
+ }

  - can we also a add a cross-db rename test to bug932623.sh?

review: Needs Fixing
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
Download full text (4.2 KiB)

Alexey,

> - I wonder if it would be less invasive to define our own simple
> wrappers around "HASH_SEARCH(hash, fil_system->spaces, id, space,
> space->id == id);" so we don't have to patch InnoDB or provide our
> own implementations for built-in InnoDB, and mess with
> mutexes. I.e. can we have xb_space_get_by_*()?

I've wrote xb_space_by_* wrappers. The only modification of innodb51_builtin.patch left is mem_close function.

>
> - the code in xtrabackup's version of io_handler_thread() doesn't use
> the 'i' variable, why not just copy the code from InnoDB, i.e.:
>
> while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) {
> fil_aio_wait(segment);
> }
>

fixed

> - fil_free_all_spaces() seems to be defined for built-in InnoDB, but
> is not used anywhere?
>

Yes. I forgot to put call in proper place, fixed.

> - in fact, ut_free_all_mem() will not free anything when the system
> malloc() is used instead of the InnoDB own malloc manager, i.e. when
> srv_use_sys_malloc == TRUE, which is the default. I have some
> thoughts on how to fix that, but I suggest we'll do it later as a
> part of bigger refactoring.
>

OK. Hopefully memory leaks will not be critical.

> - POSIX guarantees the result of snprintf() to be always
> zero-terminated, so there's no need for things like:
>
> + snprintf(dest_dir, FN_REFLEN, "%s/%s",
> + xtrabackup_target_dir, dbname);
> + dest_dir[FN_REFLEN - 1] = 0;
>
> if you care about Windows, you should be using either my_snprintf()
> or ut_snprintf(), which do the right thing on Windows. But
> currently, xtrabackup.c just uses snprintf() in other places anyway,
> so what's the point to do some windows-specific stuff in this
> patch. We can do s/snprintf/ut_snprintf/ later, if and when we
> have to support Windows.
>

Great! I removed implicit zero-terminating statement.

> - this code just uses sprintf() instead snprintf() for some reasons:
>
> + sprintf(tmpname, "./%s/tmp#%lu", dbname,
> fil_space->id);
>

Hmm... I expected that generated tmpname cannot be longer than FN_REFLEN. I've changed to snprintf for more safety.

> - I think the output in xb_delta_open_matching_space() is too
> verbose. Let's only print messages when something unexpected
> happens, i.e. remove these messages:
>
> + msg("xtrabackup: Looking for tablespace %s with id %lu by name\n",
> + dest_space_name, space_id);
>
> and
>
> + msg("xtrabackup: Looking for tablespace %s with id %lu by id\n",
> + dest_space_name, space_id);
>
> and
>
> + msg("xtrabackup: Found matching tablespace %s\n",
> + fil_space->name);
>
> and
>
> + msg("xtrabackup: Created tablespace %s with id %lu.\n",
> + dest_space_name, space_id);
>

Removed.

>
> - what's the point to rename a tablespace with the same name but a
> different ID to tmp#id? the only case when it happens is when a
> tablespace was recreated between the full backup and an incremental
> one....

Read more...

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Approved. Please when merging the fix to 2.1 move xb_space_get_by_*() and fil_free_all_spaces() to innodb_int.h and innodb_int.c (because those files were created exactly for things like this).

review: Approve
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

This patch regresses on compressed tablespace creation: the "flags" arg for the fil_space_create() is *not* zip_size. Please do not resubmit this MP. I have follow-up MPs depending on the code and "Approved" status of this one and I will fix this in a follow-up right now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'patches/innodb51_builtin.patch'
--- patches/innodb51_builtin.patch 2012-02-10 05:04:04 +0000
+++ patches/innodb51_builtin.patch 2012-07-18 15:36:21 +0000
@@ -613,7 +613,21 @@
613 613
614--- a/storage/innobase/include/mem0mem.h614--- a/storage/innobase/include/mem0mem.h
615+++ b/storage/innobase/include/mem0mem.h615+++ b/storage/innobase/include/mem0mem.h
616@@ -401,6 +401,7 @@616@@ -63,6 +63,13 @@
617 mem_init(
618 /*=====*/
619 ulint size); /* in: common pool size in bytes */
620+
621+/******************************************************************//**
622+Closes the memory system. */
623+void
624+mem_close(void);
625+/*===========*/
626+
627 /******************************************************************
628 Use this macro instead of the corresponding function! Macro for memory
629 heap creation. */
630@@ -401,6 +409,7 @@
617 allocated buffer frame, which can be appended as a631 allocated buffer frame, which can be appended as a
618 free block to the heap, if we need more space;632 free block to the heap, if we need more space;
619 otherwise, this is NULL */633 otherwise, this is NULL */
@@ -654,6 +668,21 @@
654 668
655 if (heap->free_block) {669 if (heap->free_block) {
656 size += UNIV_PAGE_SIZE;670 size += UNIV_PAGE_SIZE;
671--- a/storage/innobase/include/mem0pool.h
672+++ b/storage/innobase/include/mem0pool.h
673@@ -42,6 +42,12 @@
674 /*============*/
675 /* out: memory pool */
676 ulint size); /* in: pool size in bytes */
677+/********************************************************************//**
678+Frees a memory pool. */
679+void
680+mem_pool_free(
681+/*==========*/
682+ mem_pool_t* pool); /*!< in, own: memory pool */
683 /************************************************************************
684 Allocates memory from a pool. NOTE: This low-level function should only be
685 used in mem0mem.*! */
657--- a/storage/innobase/include/srv0srv.h686--- a/storage/innobase/include/srv0srv.h
658+++ b/storage/innobase/include/srv0srv.h687+++ b/storage/innobase/include/srv0srv.h
659@@ -60,6 +60,8 @@688@@ -60,6 +60,8 @@
@@ -958,7 +987,7 @@
958 /**********************************************************987 /**********************************************************
959--- a/storage/innobase/mem/mem0dbg.c988--- a/storage/innobase/mem/mem0dbg.c
960+++ b/storage/innobase/mem/mem0dbg.c989+++ b/storage/innobase/mem/mem0dbg.c
961@@ -133,6 +133,14 @@990@@ -133,9 +133,30 @@
962 mem_hash_initialized = TRUE;991 mem_hash_initialized = TRUE;
963 #endif992 #endif
964 993
@@ -973,6 +1002,22 @@
973 mem_comm_pool = mem_pool_create(size);1002 mem_comm_pool = mem_pool_create(size);
974 }1003 }
975 1004
1005+/******************************************************************//**
1006+Closes the memory system. */
1007+void
1008+mem_close(void)
1009+/*===========*/
1010+{
1011+ mem_pool_free(mem_comm_pool);
1012+ mem_comm_pool = NULL;
1013+#ifdef UNIV_MEM_DEBUG
1014+ mem_hash_initialized = FALSE;
1015+#endif /* UNIV_MEM_DEBUG */
1016+}
1017+
1018 #ifdef UNIV_MEM_DEBUG
1019 /**********************************************************************
1020 Initializes an allocated memory field in the debug version. */
976--- a/storage/innobase/mem/mem0mem.c1021--- a/storage/innobase/mem/mem0mem.c
977+++ b/storage/innobase/mem/mem0mem.c1022+++ b/storage/innobase/mem/mem0mem.c
978@@ -472,6 +472,7 @@1023@@ -472,6 +472,7 @@
@@ -1026,7 +1071,25 @@
1026 pool = ut_malloc(sizeof(mem_pool_t));1071 pool = ut_malloc(sizeof(mem_pool_t));
1027 1072
1028 /* We do not set the memory to zero (FALSE) in the pool,1073 /* We do not set the memory to zero (FALSE) in the pool,
1029@@ -333,6 +332,10 @@1074@@ -244,6 +243,17 @@
1075 return(pool);
1076 }
1077
1078+/********************************************************************//**
1079+Frees a memory pool. */
1080+void
1081+mem_pool_free(
1082+/*==========*/
1083+ mem_pool_t* pool) /*!< in, own: memory pool */
1084+{
1085+ ut_free(pool->buf);
1086+ ut_free(pool);
1087+}
1088+
1089 /************************************************************************
1090 Fills the specified free list. */
1091 static
1092@@ -333,6 +344,10 @@
1030 ulint n;1093 ulint n;
1031 ibool ret;1094 ibool ret;
1032 1095
@@ -1037,7 +1100,7 @@
1037 n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE));1100 n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE));
1038 1101
1039 mutex_enter(&(pool->mutex));1102 mutex_enter(&(pool->mutex));
1040@@ -465,6 +468,11 @@1103@@ -465,6 +480,11 @@
1041 ulint size;1104 ulint size;
1042 ulint n;1105 ulint n;
1043 1106
10441107
=== modified file 'src/xtrabackup.c'
--- src/xtrabackup.c 2012-06-20 07:36:26 +0000
+++ src/xtrabackup.c 2012-07-18 15:36:21 +0000
@@ -655,10 +655,107 @@
655655
656typedef struct {656typedef struct {
657 ulint page_size;657 ulint page_size;
658 ulint space_id;
658} xb_delta_info_t;659} xb_delta_info_t;
659660
660extern fil_system_t* fil_system;661extern fil_system_t* fil_system;
661662
663/** Value of fil_space_struct::magic_n */
664#define FIL_SPACE_MAGIC_N 89472
665
666/*******************************************************************//**
667Returns the table space by a given id, NULL if not found. */
668fil_space_t*
669xb_space_get_by_id(
670/*================*/
671 ulint id); /*!< in: space id */
672
673/*******************************************************************//**
674Returns the table space by a given name, NULL if not found. */
675fil_space_t*
676xb_space_get_by_name(
677/*==================*/
678 const char* name); /*!< in: space name */
679
680/*******************************************************************//**
681Returns the table space by a given id, NULL if not found. */
682fil_space_t*
683xb_space_get_by_id(
684/*================*/
685 ulint id) /*!< in: space id */
686{
687 fil_space_t* space;
688
689 ut_ad(mutex_own(&fil_system->mutex));
690
691#ifdef INNODB_VERSION_SHORT
692 HASH_SEARCH(hash, fil_system->spaces, id,
693 fil_space_t*, space,
694 ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
695 space->id == id);
696#else
697 HASH_SEARCH(hash, fil_system->spaces, id, space, space->id == id);
698#endif
699
700 return(space);
701}
702
703/*******************************************************************//**
704Returns the table space by a given name, NULL if not found. */
705fil_space_t*
706xb_space_get_by_name(
707/*==================*/
708 const char* name) /*!< in: space name */
709{
710 fil_space_t* space;
711 ulint fold;
712
713 ut_ad(mutex_own(&fil_system->mutex));
714
715#ifdef INNODB_VERSION_SHORT
716 fold = ut_fold_string(name);
717 HASH_SEARCH(name_hash, fil_system->name_hash, fold,
718 fil_space_t*, space,
719 ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
720 !strcmp(name, space->name));
721#else
722 HASH_SEARCH(name_hash, fil_system->name_hash, ut_fold_string(name),
723 space, 0 == strcmp(name, space->name));
724#endif
725
726 return(space);
727}
728
729#ifndef INNODB_VERSION_SHORT
730
731/*******************************************************************//**
732Free all spaces in space_list. */
733void
734fil_free_all_spaces(void)
735/*=====================*/
736{
737 fil_space_t* space;
738
739 mutex_enter(&fil_system->mutex);
740
741 space = UT_LIST_GET_FIRST(fil_system->space_list);
742
743 while (space != NULL) {
744 fil_node_t* node;
745 fil_space_t* prev_space = space;
746
747 space = UT_LIST_GET_NEXT(space_list, space);
748
749 fil_space_free(prev_space->id, FALSE);
750 }
751
752 mutex_exit(&fil_system->mutex);
753}
754
755#define SRV_SHUTDOWN_NONE 0
756
757#endif
758
662/* ==end=== definition at fil0fil.c === */759/* ==end=== definition at fil0fil.c === */
663760
664761
@@ -2752,7 +2849,8 @@
2752 return(TRUE);2849 return(TRUE);
2753 }2850 }
27542851
2755 if (fscanf(fp, "page_size = %lu\n", &info->page_size) != 1)2852 if (fscanf(fp, "page_size = %lu\nspace_id = %lu\n",
2853 &info->page_size, &info->space_id) != 2)
2756 r= FALSE;2854 r= FALSE;
27572855
2758 fclose(fp);2856 fclose(fp);
@@ -2770,14 +2868,16 @@
2770{2868{
2771 datasink_t *ds = ds_ctxt->datasink;2869 datasink_t *ds = ds_ctxt->datasink;
2772 ds_file_t *f;2870 ds_file_t *f;
2773 char buf[32];2871 char buf[64];
2774 my_bool ret;2872 my_bool ret;
2775 size_t len;2873 size_t len;
2776 MY_STAT mystat;2874 MY_STAT mystat;
27772875
2778 snprintf(buf, sizeof(buf), "page_size = %lu\n", info->page_size);2876 snprintf(buf, sizeof(buf),
27792877 "page_size = %lu\nspace_id = %lu\n",
2878 info->page_size, info->space_id);
2780 len = strlen(buf);2879 len = strlen(buf);
2880
2781 mystat.st_size = len;2881 mystat.st_size = len;
2782 mystat.st_mtime = my_time(0);2882 mystat.st_mtime = my_time(0);
27832883
@@ -2981,6 +3081,7 @@
2981 ds_file_t *dstfile = NULL;3081 ds_file_t *dstfile = NULL;
29823082
2983 info.page_size = 0;3083 info.page_size = 0;
3084 info.space_id = 0;
29843085
2985#ifdef XTRADB_BASED3086#ifdef XTRADB_BASED
2986 if (xtrabackup_tables && (!trx_sys_sys_space(node->space->id)))3087 if (xtrabackup_tables && (!trx_sys_sys_space(node->space->id)))
@@ -3163,6 +3264,7 @@
3163 page_in_buffer++;3264 page_in_buffer++;
31643265
3165 info.page_size = page_size;3266 info.page_size = page_size;
3267 info.space_id = node->space->id;
3166 } else3268 } else
3167 info.page_size = 0;3269 info.page_size = 0;
31683270
@@ -3722,11 +3824,10 @@
3722 void* arg)3824 void* arg)
3723{3825{
3724 ulint segment;3826 ulint segment;
3725 ulint i;
3726 3827
3727 segment = *((ulint*)arg);3828 segment = *((ulint*)arg);
37283829
3729 for (i = 0;; i++) {3830 while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) {
3730 fil_aio_wait(segment);3831 fil_aio_wait(segment);
3731 }3832 }
37323833
@@ -3744,6 +3845,141 @@
3744#endif3845#endif
3745}3846}
37463847
3848#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
3849#define SRV_MAX_N_PENDING_SYNC_IOS 100
3850
3851/************************************************************************
3852Initialize the tablespace memory cache and populate it by scanning for and
3853opening data files.
3854@returns DB_SUCCESS or error code.*/
3855ulint
3856xb_data_files_init(void)
3857/*====================*/
3858{
3859 ulint i;
3860 ibool create_new_db;
3861#ifdef XTRADB_BASED
3862 ibool create_new_doublewrite_file;
3863#endif
3864 ulint err;
3865 LSN64 min_flushed_lsn;
3866 LSN64 max_flushed_lsn;
3867 ulint sum_of_new_sizes;
3868
3869#ifndef INNODB_VERSION_SHORT
3870 os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD
3871 * srv_n_file_io_threads,
3872 srv_n_file_io_threads,
3873 SRV_MAX_N_PENDING_SYNC_IOS);
3874
3875 fil_init(srv_max_n_open_files);
3876#else
3877 srv_n_file_io_threads = 2 + srv_n_read_io_threads +
3878 srv_n_write_io_threads;
3879
3880 os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD,
3881 srv_n_read_io_threads,
3882 srv_n_write_io_threads,
3883 SRV_MAX_N_PENDING_SYNC_IOS);
3884
3885 fil_init(srv_file_per_table ? 50000 : 5000,
3886 srv_max_n_open_files);
3887#endif
3888
3889 fsp_init();
3890
3891 for (i = 0; i < srv_n_file_io_threads; i++) {
3892 thread_nr[i] = i;
3893
3894 os_thread_create(io_handler_thread, thread_nr + i,
3895 thread_ids + i);
3896 }
3897
3898 os_thread_sleep(200000); /*0.2 sec*/
3899
3900 err = open_or_create_data_files(&create_new_db,
3901#ifdef XTRADB_BASED
3902 &create_new_doublewrite_file,
3903#endif
3904 &min_flushed_lsn, &max_flushed_lsn,
3905 &sum_of_new_sizes);
3906 if (err != DB_SUCCESS) {
3907 msg("xtrabackup: Could not open or create data files.\n"
3908 "xtrabackup: If you tried to add new data files, and it "
3909 "failed here,\n"
3910 "xtrabackup: you should now edit innodb_data_file_path in "
3911 "my.cnf back\n"
3912 "xtrabackup: to what it was, and remove the new ibdata "
3913 "files InnoDB created\n"
3914 "xtrabackup: in this failed attempt. InnoDB only wrote "
3915 "those files full of\n"
3916 "xtrabackup: zeros, but did not yet use them in any way. "
3917 "But be careful: do not\n"
3918 "xtrabackup: remove old data files which contain your "
3919 "precious data!\n");
3920 return(err);
3921 }
3922
3923 /* create_new_db must not be TRUE.. */
3924 if (create_new_db) {
3925 msg("xtrabackup: could not find data files at the "
3926 "specified datadir\n");
3927 return(DB_ERROR);
3928 }
3929
3930 return(fil_load_single_table_tablespaces());
3931}
3932
3933/************************************************************************
3934Destroy the tablespace memory cache. */
3935void
3936xb_data_files_close(void)
3937/*====================*/
3938{
3939 ulint i;
3940
3941 /* Shutdown the aio threads. This has been copied from
3942 innobase_shutdown_for_mysql(). */
3943
3944 srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
3945
3946 for (i = 0; i < 1000; i++) {
3947 os_aio_wake_all_threads_at_shutdown();
3948
3949 os_mutex_enter(os_sync_mutex);
3950
3951 if (os_thread_count == 0) {
3952
3953 os_mutex_exit(os_sync_mutex);
3954
3955 os_thread_sleep(10000);
3956
3957 break;
3958 }
3959
3960 os_mutex_exit(os_sync_mutex);
3961
3962 os_thread_sleep(10000);
3963 }
3964
3965 if (i == 1000) {
3966 msg("xtrabackup: Warning: %lu threads created by InnoDB"
3967 " had not exited at shutdown!\n",
3968 (ulong) os_thread_count);
3969 }
3970
3971#ifdef INNODB_VERSION_SHORT
3972 os_aio_free();
3973#endif
3974 fil_close_all_files();
3975#ifndef INNODB_VERSION_SHORT
3976 fil_free_all_spaces();
3977#endif
3978 fil_system = NULL;
3979
3980 srv_shutdown_state = SRV_SHUTDOWN_NONE;
3981}
3982
3747/***************************************************************************3983/***************************************************************************
3748Creates an output directory for a given tablespace, if it does not exist */3984Creates an output directory for a given tablespace, if it does not exist */
3749static3985static
@@ -4050,85 +4286,25 @@
4050 srv_general_init();4286 srv_general_init();
40514287
4052 {4288 {
4053 ibool create_new_db;
4054#ifdef XTRADB_BASED
4055 ibool create_new_doublewrite_file;
4056#endif
4057 ibool log_file_created;4289 ibool log_file_created;
4058 ibool log_created = FALSE;4290 ibool log_created = FALSE;
4059 ibool log_opened = FALSE;4291 ibool log_opened = FALSE;
4060 LSN64 min_flushed_lsn;
4061 LSN64 max_flushed_lsn;
4062 ulint sum_of_new_sizes;
4063 ulint err;4292 ulint err;
4064 ulint i;4293 ulint i;
40654294
40664295 err = xb_data_files_init();
40674296 if (err != DB_SUCCESS) {
40684297 msg("xtrabackup: error: xb_data_files_init() failed with"
4069#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD4298 "error code %lu\n", err);
4070#define SRV_MAX_N_PENDING_SYNC_IOS 1004299 exit(EXIT_FAILURE);
40714300 }
4072#ifndef INNODB_VERSION_SHORT4301
4073 os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD
4074 * srv_n_file_io_threads,
4075 srv_n_file_io_threads,
4076 SRV_MAX_N_PENDING_SYNC_IOS);
4077
4078 fil_init(srv_max_n_open_files);
4079#else
4080 srv_n_file_io_threads = 2 + srv_n_read_io_threads + srv_n_write_io_threads;
4081
4082 os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD,
4083 srv_n_read_io_threads,
4084 srv_n_write_io_threads,
4085 SRV_MAX_N_PENDING_SYNC_IOS);
4086
4087 fil_init(srv_file_per_table ? 50000 : 5000,
4088 srv_max_n_open_files);
4089#endif
4090
4091 fsp_init();
4092 log_init();4302 log_init();
40934303
4094 lock_sys_create(srv_lock_table_size);4304 lock_sys_create(srv_lock_table_size);
40954305
4096 for (i = 0; i < srv_n_file_io_threads; i++) {
4097 thread_nr[i] = i;
4098
4099 os_thread_create(io_handler_thread, thread_nr + i, thread_ids + i);
4100 }
4101
4102 os_thread_sleep(200000); /*0.2 sec*/
4103
4104 err = open_or_create_data_files(&create_new_db,
4105#ifdef XTRADB_BASED
4106 &create_new_doublewrite_file,
4107#endif
4108 &min_flushed_lsn, &max_flushed_lsn,
4109 &sum_of_new_sizes);
4110 if (err != DB_SUCCESS) {
4111 msg(
4112"xtrabackup: Could not open or create data files.\n"
4113"xtrabackup: If you tried to add new data files, and it failed here,\n"
4114"xtrabackup: you should now edit innodb_data_file_path in my.cnf back\n"
4115"xtrabackup: to what it was, and remove the new ibdata files InnoDB created\n"
4116"xtrabackup: in this failed attempt. InnoDB only wrote those files full of\n"
4117"xtrabackup: zeros, but did not yet use them in any way. But be careful: do not\n"
4118"xtrabackup: remove old data files which contain your precious data!\n");
4119
4120 //return((int) err);
4121 exit(EXIT_FAILURE);
4122 }
4123
4124 /* create_new_db must not be TRUE.. */
4125 if (create_new_db) {
4126 msg("xtrabackup: Something wrong with source files...\n");
4127 exit(EXIT_FAILURE);
4128 }
4129
4130 for (i = 0; i < srv_n_log_files; i++) {4306 for (i = 0; i < srv_n_log_files; i++) {
4131 err = open_or_create_log_file(create_new_db, &log_file_created,4307 err = open_or_create_log_file(FALSE, &log_file_created,
4132 log_opened, 0, i);4308 log_opened, 0, i);
4133 if (err != DB_SUCCESS) {4309 if (err != DB_SUCCESS) {
41344310
@@ -4141,8 +4317,7 @@
4141 } else {4317 } else {
4142 log_opened = TRUE;4318 log_opened = TRUE;
4143 }4319 }
4144 if ((log_opened && create_new_db)4320 if ((log_opened && log_created)) {
4145 || (log_opened && log_created)) {
4146 msg(4321 msg(
4147 "xtrabackup: Error: all log files must be created at the same time.\n"4322 "xtrabackup: Error: all log files must be created at the same time.\n"
4148 "xtrabackup: All log files must be created also in database creation.\n"4323 "xtrabackup: All log files must be created also in database creation.\n"
@@ -4162,8 +4337,6 @@
4162 exit(EXIT_FAILURE);4337 exit(EXIT_FAILURE);
4163 }4338 }
41644339
4165 fil_load_single_table_tablespaces();
4166
4167 }4340 }
41684341
4169 /* create extra LSN dir if it does not exist. */4342 /* create extra LSN dir if it does not exist. */
@@ -4545,6 +4718,8 @@
4545 msg("xtrabackup: Transaction log of lsn (%llu) to (%llu) was copied.\n",4718 msg("xtrabackup: Transaction log of lsn (%llu) to (%llu) was copied.\n",
4546 checkpoint_lsn_start, log_copy_scanned_lsn);4719 checkpoint_lsn_start, log_copy_scanned_lsn);
4547#endif4720#endif
4721
4722 xb_data_files_close();
4548}4723}
45494724
4550/* ================= stats ================= */4725/* ================= stats ================= */
@@ -5434,6 +5609,154 @@
5434 return TRUE;5609 return TRUE;
5435}5610}
54365611
5612/***********************************************************************
5613Searches for matching tablespace file for given .delta file and space_id
5614in given directory. When matching tablespace found, renames it to match the
5615name of .delta file. If there was a tablespace with matching name and
5616mismatching ID, renames it to xtrabackup_tmp_#ID.ibd. If there was no
5617matching file, creates the new one.
5618@return file handle of matched or created file */
5619static
5620os_file_t
5621xb_delta_open_matching_space(
5622 const char* dbname, /* in: path to destination database dir */
5623 const char* name, /* in: name of delta file (without .delta) */
5624 ulint space_id, /* in: space id of delta file */
5625 ulint zip_size, /* in: zip_size of tablespace */
5626 char* real_name, /* out: full path of destination file */
5627 size_t real_name_len, /* out: buffer size for real_name */
5628 ibool* success) /* out: indicates error. TRUE = success */
5629{
5630 char dest_dir[FN_REFLEN];
5631 char dest_space_name[FN_REFLEN];
5632 ibool ok;
5633 fil_space_t* fil_space;
5634 os_file_t file = 0;
5635
5636 ut_a(dbname || space_id == 0);
5637
5638 *success = FALSE;
5639
5640 if (dbname) {
5641 snprintf(dest_dir, FN_REFLEN, "%s/%s",
5642 xtrabackup_target_dir, dbname);
5643 srv_normalize_path_for_win(dest_dir);
5644
5645 snprintf(dest_space_name, FN_REFLEN, "./%s/%s",
5646 dbname, name);
5647 } else {
5648 snprintf(dest_dir, FN_REFLEN, "%s", xtrabackup_target_dir);
5649 srv_normalize_path_for_win(dest_dir);
5650
5651 snprintf(dest_space_name, FN_REFLEN, "./%s", name);
5652 }
5653
5654 snprintf(real_name, real_name_len,
5655 "%s/%s",
5656 xtrabackup_target_dir, dest_space_name);
5657 srv_normalize_path_for_win(real_name);
5658
5659 /* Create the database directory if it doesn't exist yet */
5660 if (!os_file_create_directory(dest_dir, FALSE)) {
5661 msg("xtrabackup: error: cannot create dir %s\n", dest_dir);
5662 return file;
5663 }
5664
5665 mutex_enter(&fil_system->mutex);
5666 fil_space = xb_space_get_by_name(dest_space_name);
5667 mutex_exit(&fil_system->mutex);
5668
5669 if (fil_space != NULL) {
5670 if (fil_space->id == space_id) {
5671 /* we found matching space */
5672 goto found;
5673 } else {
5674
5675 char tmpname[FN_REFLEN];
5676
5677 snprintf(tmpname, FN_REFLEN, "./%s/xtrabackup_tmp_#%lu",
5678 dbname, fil_space->id);
5679
5680 msg("xtrabackup: Renaming %s to %s.ibd\n",
5681 fil_space->name, tmpname);
5682
5683 if (!fil_rename_tablespace(NULL,
5684 fil_space->id, tmpname))
5685 {
5686 msg("xtrabackup: Cannot rename %s to %s\n",
5687 fil_space->name, tmpname);
5688 goto exit;
5689 }
5690 }
5691 }
5692
5693 mutex_enter(&fil_system->mutex);
5694 fil_space = xb_space_get_by_id(space_id);
5695 mutex_exit(&fil_system->mutex);
5696 if (fil_space != NULL) {
5697 char tmpname[FN_REFLEN];
5698
5699 strncpy(tmpname, dest_space_name, FN_REFLEN);
5700 tmpname[strlen(tmpname) - 4] = 0;
5701
5702 msg("xtrabackup: Renaming %s to %s\n",
5703 fil_space->name, dest_space_name);
5704
5705 if (!fil_rename_tablespace(NULL,
5706 fil_space->id, tmpname))
5707 {
5708 msg("xtrabackup: Cannot rename %s to %s\n",
5709 fil_space->name, dest_space_name);
5710 goto exit;
5711 }
5712
5713 goto found;
5714 }
5715
5716 /* no matching space found. create the new one */
5717
5718#ifdef INNODB_VERSION_SHORT
5719 if (!fil_space_create(dest_space_name, space_id,
5720 zip_size, FIL_TABLESPACE)) {
5721#else
5722 if (!fil_space_create(dest_space_name, space_id,
5723 FIL_TABLESPACE)) {
5724#endif
5725 msg("xtrabackup: Cannot create tablespace %s\n",
5726 dest_space_name);
5727 goto exit;
5728 }
5729
5730 file = xb_file_create_no_error_handling(real_name, OS_FILE_CREATE,
5731 OS_FILE_READ_WRITE,
5732 &ok);
5733
5734 if (ok) {
5735 *success = TRUE;
5736 } else {
5737 msg("xtrabackup: Cannot open file %s\n", real_name);
5738 }
5739
5740 goto exit;
5741
5742found:
5743 /* open the file and return it's handle */
5744
5745 file = xb_file_create_no_error_handling(real_name, OS_FILE_OPEN,
5746 OS_FILE_READ_WRITE,
5747 &ok);
5748
5749 if (ok) {
5750 *success = TRUE;
5751 } else {
5752 msg("xtrabackup: Cannot open file %s\n", real_name);
5753 }
5754
5755exit:
5756
5757 return file;
5758}
5759
5437/************************************************************************5760/************************************************************************
5438Applies a given .delta file to the corresponding data file.5761Applies a given .delta file to the corresponding data file.
5439@return TRUE on success */5762@return TRUE on success */
@@ -5451,6 +5774,7 @@
5451 char src_path[FN_REFLEN];5774 char src_path[FN_REFLEN];
5452 char dst_path[FN_REFLEN];5775 char dst_path[FN_REFLEN];
5453 char meta_path[FN_REFLEN];5776 char meta_path[FN_REFLEN];
5777 char space_name[FN_REFLEN];
5454 ibool success;5778 ibool success;
54555779
5456 ibool last_buffer = FALSE;5780 ibool last_buffer = FALSE;
@@ -5478,6 +5802,9 @@
5478 }5802 }
5479 dst_path[strlen(dst_path) - 6] = '\0';5803 dst_path[strlen(dst_path) - 6] = '\0';
54805804
5805 strncpy(space_name, filename, FN_REFLEN);
5806 space_name[strlen(space_name) - 6] = 0;
5807
5481 if (!get_meta_path(src_path, meta_path)) {5808 if (!get_meta_path(src_path, meta_path)) {
5482 goto error;5809 goto error;
5483 }5810 }
@@ -5517,36 +5844,11 @@
55175844
5518 xb_file_set_nocache(src_file, src_path, "OPEN");5845 xb_file_set_nocache(src_file, src_path, "OPEN");
55195846
5520 dst_file = xb_file_create_no_error_handling(dst_path, OS_FILE_OPEN,5847 dst_file = xb_delta_open_matching_space(
5521 OS_FILE_READ_WRITE,5848 dbname, space_name, info.space_id,
5522 &success);5849 info.page_size == UNIV_PAGE_SIZE ? 0 : info.page_size,
5523again:5850 dst_path, sizeof(dst_path), &success);
5524 if (!success) {5851 if (!success) {
5525 ulint errcode = os_file_get_last_error(TRUE);
5526
5527 if (errcode == OS_FILE_NOT_FOUND) {
5528 msg("xtrabackup: target data file %s "
5529 "is not found, creating a new one\n", dst_path);
5530 /* Create the database directory if it doesn't exist yet
5531 */
5532 if (dbname) {
5533 char dst_dir[FN_REFLEN];
5534
5535 snprintf(dst_dir, sizeof(dst_dir), "%s/%s",
5536 xtrabackup_real_target_dir, dbname);
5537 srv_normalize_path_for_win(dst_dir);
5538
5539 if (!os_file_create_directory(dst_dir, FALSE))
5540 goto error;
5541 }
5542 dst_file =
5543 xb_file_create_no_error_handling(dst_path,
5544 OS_FILE_CREATE,
5545 OS_FILE_READ_WRITE,
5546 &success);
5547 goto again;
5548 }
5549
5550 msg("xtrabackup: error: cannot open %s\n", dst_path);5852 msg("xtrabackup: error: cannot open %s\n", dst_path);
5551 goto error;5853 goto error;
5552 }5854 }
@@ -5563,7 +5865,7 @@
5563 incremental_buffer = ut_align(incremental_buffer_base,5865 incremental_buffer = ut_align(incremental_buffer_base,
5564 UNIV_PAGE_SIZE_MAX);5866 UNIV_PAGE_SIZE_MAX);
55655867
5566 msg("Applying %s ...\n", src_path);5868 msg("Applying %s to %s...\n", src_path, dst_path);
55675869
5568 while (!last_buffer) {5870 while (!last_buffer) {
5569 ulint cluster_header;5871 ulint cluster_header;
@@ -5873,6 +6175,8 @@
5873static void6175static void
5874xtrabackup_prepare_func(void)6176xtrabackup_prepare_func(void)
5875{6177{
6178 ulint err;
6179
5876 /* cd to target-dir */6180 /* cd to target-dir */
58776181
5878 if (my_setwd(xtrabackup_real_target_dir,MYF(MY_WME)))6182 if (my_setwd(xtrabackup_real_target_dir,MYF(MY_WME)))
@@ -5943,12 +6247,29 @@
5943 if(xtrabackup_init_temp_log())6247 if(xtrabackup_init_temp_log())
5944 goto error;6248 goto error;
59456249
5946 if(xtrabackup_incremental && !xtrabackup_apply_deltas(TRUE))6250 if(innodb_init_param())
5947 goto error;6251 goto error;
59486252
6253 mem_init(srv_mem_pool_size);
6254 if (xtrabackup_incremental) {
6255 err = xb_data_files_init();
6256 if (err != DB_SUCCESS) {
6257 msg("xtrabackup: error: xb_data_files_init() failed with"
6258 "error code %lu\n", err);
6259 goto error;
6260 }
6261
6262 if(!xtrabackup_apply_deltas(TRUE)) {
6263 xb_data_files_close();
6264 goto error;
6265 }
6266
6267 xb_data_files_close();
6268 }
5949 sync_close();6269 sync_close();
5950 sync_initialized = FALSE;6270 sync_initialized = FALSE;
5951 os_sync_free();6271 os_sync_free();
6272 mem_close();
5952 os_sync_mutex = NULL;6273 os_sync_mutex = NULL;
5953 ut_free_all_mem();6274 ut_free_all_mem();
59546275
59556276
=== added file 'test/t/bug932623.sh'
--- test/t/bug932623.sh 1970-01-01 00:00:00 +0000
+++ test/t/bug932623.sh 2012-07-18 15:36:21 +0000
@@ -0,0 +1,85 @@
1########################################################################
2# Bug #932623: RENAME TABLE causes incremental prepare to fail
3########################################################################
4
5. inc/common.sh
6
7start_server --innodb_file_per_table
8
9run_cmd $MYSQL $MYSQL_ARGS test <<EOF
10CREATE TABLE t1_old(a INT) ENGINE=InnoDB;
11INSERT INTO t1_old VALUES (1), (2), (3);
12
13CREATE TABLE t1(a INT) ENGINE=InnoDB;
14INSERT INTO t1 VALUES (4), (5), (6);
15EOF
16
17# Full backup
18# backup root directory
19vlog "Starting backup"
20innobackupex --no-timestamp $topdir/full
21
22vlog "Rotating the table"
23
24run_cmd $MYSQL $MYSQL_ARGS test <<EOF
25CREATE TABLE t1_new(a int) ENGINE=InnoDB;
26INSERT INTO t1_new VALUES (7), (8), (9);
27
28CREATE DATABASE db2;
29RENAME TABLE t1_old TO db2.t1;
30
31RENAME TABLE t1 TO t1_old;
32RENAME TABLE t1_new TO t1;
33
34INSERT INTO t1_old VALUES (10), (11), (12);
35INSERT INTO t1 VALUES (13), (14), (15);
36
37EOF
38
39vlog "Creating incremental backup"
40
41innobackupex --incremental --no-timestamp \
42 --incremental-basedir=$topdir/full $topdir/inc
43
44vlog "Preparing backup"
45
46innobackupex --apply-log --redo-only $topdir/full
47vlog "Log applied to full backup"
48
49innobackupex --apply-log --redo-only --incremental-dir=$topdir/inc \
50 $topdir/full
51vlog "Delta applied to full backup"
52
53innobackupex --apply-log $topdir/full
54vlog "Data prepared for restore"
55
56checksum_t1_a=`checksum_table test t1`
57checksum_t1_old_a=`checksum_table test t1_old`
58checksum_t1_db2_a=`checksum_table db2 t1`
59
60# Destroying mysql data
61stop_server
62rm -rf $mysql_datadir/*
63vlog "Data destroyed"
64
65# Restore backup
66vlog "Copying files"
67
68innobackupex --copy-back $topdir/full
69vlog "Data restored"
70
71start_server --innodb_file_per_table
72
73vlog "Checking checksums"
74checksum_t1_b=`checksum_table test t1`
75checksum_t1_old_b=`checksum_table test t1_old`
76checksum_t1_db2_b=`checksum_table db2 t1`
77
78if [ "$checksum_t1_a" != "$checksum_t1_b" -o "$checksum_t1_old_a" != "$checksum_t1_old_b" \
79 -o "$checksum_t1_db2_a" != "$checksum_t1_db2_b" ]
80then
81 vlog "Checksums do not match"
82 exit -1
83fi
84
85vlog "Checksums are OK"

Subscribers

People subscribed via source and target branches