Merge lp:~laurynas-biveinis/percona-xtrabackup/bug1049174-2.0 into lp:percona-xtrabackup/2.0

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 469
Proposed branch: lp:~laurynas-biveinis/percona-xtrabackup/bug1049174-2.0
Merge into: lp:percona-xtrabackup/2.0
Diff against target: 304 lines (+139/-56)
1 file modified
src/xtrabackup.c (+139/-56)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-xtrabackup/bug1049174-2.0
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+124411@code.launchpad.net

Description of the change

Fix handling of compressed tablespaces, created between the last full
or incremental and the next incremental backup.

Bugs fixed:
bug 1049174 (Redundant zip_size handling at delta application
time),
bug 1044398 (Handling of compressed tablespaces with compressed page
size == server page size broken),
bug 1043762 (Incremental backups may take up to 5x more space after
the fix for bug #1022562).

In order not to include the first 64KB of a tablespace unconditionally
in every delta (bug 1043762), we need to be able to create a
tablespace on disk without relying on the presence of the first pages
of a newly-created tablespace in the delta. These pages, in the
absence of any later writes to them, get a modification LSN of 0,
causing them to be omitted from the delta.

Thus we create new tablespaces from scratch by a new function
xb_delta_create_space_file() that is similar to
fil_create_new_single_table_tablespace() in InnoDB. For this function
to work, it needs a tablespace flags value, and a default value of 0
(which assumes a regular uncompressed tablespace) will cause asserts
in trying to apply log records to it later, if the tablespace is
actually compressed and its header page was not overwritten by the
delta due to reasons above. Thus, we need the actual flags value.

For this purpose we extend the incremental backup delta metadata with
a new field zip_size. On backup preperation the presence of this flag
is optional, to keep the ability to restore from the old backups and
because its value is required only in the case describe above (a new
compressed tablespace created between the backups, no log records
touching its 1st page).

Always pass zero to fil_space_create() instead of the tablespace flags
in xb_delta_open_matching_space(). Push the flags calculation between
fil_space_create() and xb_delta_create_space_file(). Calculate these
flags for all XtraBackup flavours by conditionally defining the
required constants, to minimize the conditionally-compiled code. If
there was no zip_size in the metadata, assume flags to be zero.

Revert the changes in xtrabackup_copy_datafile() made for bug 1022562,
that is, do not store the first 64KB of every tablespace
unconditionally.

In xtrabackup_apply_delta(), remove the assumption that zip_size is
equal to page_size whenever page_size < UNIV_PAGE_SIZE, fixing bug
10443398
.

No testsuite changes, as this is non-functional case. The regular
incremental compressed backups are tested by the
xb_incremental_compressed test, an the corner case of a new compressed
tablespace that does not have its 1st page in the delta is tested by
bug1028949 test.

Jenkins: http://jenkins.percona.com/job/percona-xtrabackup-2.0-param/261/

Issue #16274

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/xtrabackup.c'
--- src/xtrabackup.c 2012-09-05 08:32:02 +0000
+++ src/xtrabackup.c 2012-09-14 12:55:19 +0000
@@ -105,6 +105,10 @@
105#define MACH_READ_64 mach_read_from_8105#define MACH_READ_64 mach_read_from_8
106#define MACH_WRITE_64 mach_write_to_8106#define MACH_WRITE_64 mach_write_to_8
107#define OS_MUTEX_CREATE() os_mutex_create(NULL)107#define OS_MUTEX_CREATE() os_mutex_create(NULL)
108#define PAGE_ZIP_MIN_SIZE_SHIFT 10
109#define DICT_TF_ZSSIZE_SHIFT 1
110#define DICT_TF_FORMAT_ZIP 1
111#define DICT_TF_FORMAT_SHIFT 5
108#else112#else
109#define IB_INT64 ib_int64_t113#define IB_INT64 ib_int64_t
110#define LSN64 ib_uint64_t114#define LSN64 ib_uint64_t
@@ -655,6 +659,7 @@
655659
656typedef struct {660typedef struct {
657 ulint page_size;661 ulint page_size;
662 ulint zip_size;
658 ulint space_id;663 ulint space_id;
659} xb_delta_info_t;664} xb_delta_info_t;
660665
@@ -2855,6 +2860,7 @@
28552860
2856 /* set defaults */2861 /* set defaults */
2857 info->page_size = ULINT_UNDEFINED;2862 info->page_size = ULINT_UNDEFINED;
2863 info->zip_size = ULINT_UNDEFINED;
2858 info->space_id = ULINT_UNDEFINED;2864 info->space_id = ULINT_UNDEFINED;
28592865
2860 fp = fopen(filepath, "r");2866 fp = fopen(filepath, "r");
@@ -2867,6 +2873,8 @@
2867 if (fscanf(fp, "%50s = %50s\n", key, value) == 2) {2873 if (fscanf(fp, "%50s = %50s\n", key, value) == 2) {
2868 if (strcmp(key, "page_size") == 0) {2874 if (strcmp(key, "page_size") == 0) {
2869 info->page_size = strtoul(value, NULL, 10);2875 info->page_size = strtoul(value, NULL, 10);
2876 } else if (strcmp(key, "zip_size") == 0) {
2877 info->zip_size = strtoul(value, NULL, 10);
2870 } else if (strcmp(key, "space_id") == 0) {2878 } else if (strcmp(key, "space_id") == 0) {
2871 info->space_id = strtoul(value, NULL, 10);2879 info->space_id = strtoul(value, NULL, 10);
2872 }2880 }
@@ -2904,8 +2912,10 @@
2904 MY_STAT mystat;2912 MY_STAT mystat;
29052913
2906 snprintf(buf, sizeof(buf),2914 snprintf(buf, sizeof(buf),
2907 "page_size = %lu\nspace_id = %lu\n",2915 "page_size = %lu\n"
2908 info->page_size, info->space_id);2916 "zip_size = %lu\n"
2917 "space_id = %lu\n",
2918 info->page_size, info->zip_size, info->space_id);
2909 len = strlen(buf);2919 len = strlen(buf);
29102920
2911 mystat.st_size = len;2921 mystat.st_size = len;
@@ -3103,14 +3113,12 @@
3103 byte* incremental_buffer_base = NULL;3113 byte* incremental_buffer_base = NULL;
3104 ulint page_size;3114 ulint page_size;
3105 ulint page_size_shift;3115 ulint page_size_shift;
3106#ifdef INNODB_VERSION_SHORT
3107 ulint zip_size;
3108#endif
3109 xb_delta_info_t info;3116 xb_delta_info_t info;
3110 datasink_t *ds = ds_ctxt->datasink;3117 datasink_t *ds = ds_ctxt->datasink;
3111 ds_file_t *dstfile = NULL;3118 ds_file_t *dstfile = NULL;
31123119
3113 info.page_size = 0;3120 info.page_size = 0;
3121 info.zip_size = 0;
3114 info.space_id = 0;3122 info.space_id = 0;
31153123
3116#ifdef XTRADB_BASED3124#ifdef XTRADB_BASED
@@ -3257,11 +3265,11 @@
3257 page_size = UNIV_PAGE_SIZE;3265 page_size = UNIV_PAGE_SIZE;
3258 page_size_shift = UNIV_PAGE_SIZE_SHIFT;3266 page_size_shift = UNIV_PAGE_SIZE_SHIFT;
3259#else3267#else
3260 zip_size = xb_get_zip_size(src_file);3268 info.zip_size = xb_get_zip_size(src_file);
3261 if (zip_size == ULINT_UNDEFINED) {3269 if (info.zip_size == ULINT_UNDEFINED) {
3262 goto skip;3270 goto skip;
3263 } else if (zip_size) {3271 } else if (info.zip_size) {
3264 page_size = zip_size;3272 page_size = info.zip_size;
3265 page_size_shift = get_bit_shift(page_size);3273 page_size_shift = get_bit_shift(page_size);
3266 msg("[%02u] %s is compressed with page size = "3274 msg("[%02u] %s is compressed with page size = "
3267 "%lu bytes\n", thread_n, node->name, page_size);3275 "%lu bytes\n", thread_n, node->name, page_size);
@@ -3367,7 +3375,8 @@
3367#ifndef INNODB_VERSION_SHORT3375#ifndef INNODB_VERSION_SHORT
3368 if (buf_page_is_corrupted(page + chunk_offset))3376 if (buf_page_is_corrupted(page + chunk_offset))
3369#else3377#else
3370 if (buf_page_is_corrupted(page + chunk_offset, zip_size))3378 if (buf_page_is_corrupted(page + chunk_offset,
3379 info.zip_size))
3371#endif3380#endif
3372 {3381 {
3373 if (3382 if (
@@ -3418,18 +3427,11 @@
3418 if (xtrabackup_incremental) {3427 if (xtrabackup_incremental) {
3419 for (chunk_offset = 0; chunk_offset < chunk; chunk_offset += page_size) {3428 for (chunk_offset = 0; chunk_offset < chunk; chunk_offset += page_size) {
3420 /* newer page */3429 /* newer page */
3421 /* This condition may be OK for header, ibuf and fsp3430 /* This condition may be OK for header, ibuf
3422 We always copy the 1st3431 and fsp. */
3423 FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE
3424 bytes of any tablespace, regardless of the LSNs
3425 of the pages there. These pages are guaranteed
3426 to be flushed upon tablespace create and they
3427 are required for InnoDB to recognize the
3428 tablespace. */
3429 if (ut_dulint_cmp(incremental_lsn,3432 if (ut_dulint_cmp(incremental_lsn,
3430 MACH_READ_64(page + chunk_offset + FIL_PAGE_LSN)) < 03433 MACH_READ_64(page + chunk_offset
3431 || (offset + chunk_offset3434 + FIL_PAGE_LSN)) < 0) {
3432 < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE)) {
3433 /* ========================================= */3435 /* ========================================= */
3434 IB_INT64 offset_on_page;3436 IB_INT64 offset_on_page;
34353437
@@ -5652,12 +5654,107 @@
5652 return TRUE;5654 return TRUE;
5653}5655}
56545656
5657/****************************************************************//**
5658Create a new tablespace on disk and return the handle to its opened
5659file. Code adopted from fil_create_new_single_table_tablespace with
5660the main difference that only disk file is created without updating
5661the InnoDB in-memory dictionary data structures.
5662
5663@return TRUE on success, FALSE on error. */
5664static
5665ibool
5666xb_delta_create_space_file(
5667/*=======================*/
5668 const char* path, /*!<in: path to tablespace */
5669 ulint space_id, /*!<in: space id */
5670 ulint flags __attribute__((unused)),/*!<in: tablespace
5671 flags */
5672 os_file_t* file) /*!<out: file handle */
5673{
5674 ibool ret;
5675 byte* buf;
5676 byte* page;
5677
5678 *file = xb_file_create_no_error_handling(path, OS_FILE_CREATE,
5679 OS_FILE_READ_WRITE, &ret);
5680 if (!ret) {
5681 msg("xtrabackup: cannot create file %s\n", path);
5682 return ret;
5683 }
5684
5685 ret = os_file_set_size(path, *file,
5686 FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE, 0);
5687 if (!ret) {
5688 msg("xtrabackup: cannot set size for file %s\n", path);
5689 os_file_close(*file);
5690 os_file_delete(path);
5691 return ret;
5692 }
5693
5694 buf = ut_malloc(3 * UNIV_PAGE_SIZE);
5695 /* Align the memory for file i/o if we might have O_DIRECT set */
5696 page = ut_align(buf, UNIV_PAGE_SIZE);
5697
5698 memset(page, '\0', UNIV_PAGE_SIZE);
5699
5700#ifdef INNODB_VERSION_SHORT
5701 fsp_header_init_fields(page, space_id, flags);
5702 mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
5703
5704 if (!(flags & DICT_TF_ZSSIZE_MASK)) {
5705 buf_flush_init_for_writing(page, NULL, 0);
5706
5707 ret = os_file_write(path, *file, page, 0, 0, UNIV_PAGE_SIZE);
5708 }
5709 else {
5710 page_zip_des_t page_zip;
5711 ulint zip_size;
5712
5713 zip_size = (PAGE_ZIP_MIN_SIZE >> 1)
5714 << ((flags & DICT_TF_ZSSIZE_MASK)
5715 >> DICT_TF_ZSSIZE_SHIFT);
5716 page_zip_set_size(&page_zip, zip_size);
5717 page_zip.data = page + UNIV_PAGE_SIZE;
5718 fprintf(stderr, "zip_size = %lu\n", zip_size);
5719
5720#ifdef UNIV_DEBUG
5721 page_zip.m_start =
5722#endif /* UNIV_DEBUG */
5723 page_zip.m_end = page_zip.m_nonempty =
5724 page_zip.n_blobs = 0;
5725
5726 buf_flush_init_for_writing(page, &page_zip, 0);
5727
5728 ret = os_file_write(path, *file, page_zip.data, 0, 0,
5729 zip_size);
5730 }
5731#else
5732 fsp_header_write_space_id(page, space_id);
5733
5734 buf_flush_init_for_writing(page, ut_dulint_zero, space_id, 0);
5735
5736 ret = os_file_write(path, *file, page, 0, 0, UNIV_PAGE_SIZE);
5737#endif
5738
5739 ut_free(buf);
5740
5741 if (!ret) {
5742 msg("xtrabackup: could not write the first page to %s\n",
5743 path);
5744 os_file_close(*file);
5745 os_file_delete(path);
5746 return ret;
5747 }
5748
5749 return TRUE;
5750}
5751
5655/***********************************************************************5752/***********************************************************************
5656Searches for matching tablespace file for given .delta file and space_id5753Searches for matching tablespace file for given .delta file and space_id
5657in given directory. When matching tablespace found, renames it to match the5754in given directory. When matching tablespace found, renames it to match the
5658name of .delta file. If there was a tablespace with matching name and5755name of .delta file. If there was a tablespace with matching name and
5659mismatching ID, renames it to xtrabackup_tmp_#ID.ibd. If there was no5756mismatching ID, renames it to xtrabackup_tmp_#ID.ibd. If there was no
5660matching file, creates a placeholder for the new tablespace.5757matching file, creates a new tablespace.
5661@return file handle of matched or created file */5758@return file handle of matched or created file */
5662static5759static
5663os_file_t5760os_file_t
@@ -5758,19 +5855,20 @@
5758 goto found;5855 goto found;
5759 }5856 }
57605857
5761 /* No matching space found. create the new one. Note that this is not5858 /* No matching space found. create the new one. */
5762 a full-fledged tablespace create, as done by
5763 fil_create_new_single_table_tablespace(): the minumum tablespace size
5764 is not ensured and the 1st page fields are not set. We rely on backup
5765 delta to contain the 1st FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE
5766 to ensure the correct tablespace image. */
57675859
5768#ifdef INNODB_VERSION_SHORT5860#ifdef INNODB_VERSION_SHORT
5769 /* Calculate correct tablespace flags for compressed tablespaces. Do5861 if (!fil_space_create(dest_space_name, space_id, 0, FIL_TABLESPACE)) {
5770 not bother to set all flags correctly, just enough for5862#else
5771 fil_space_create() to work. The full flags will be restored from the5863 if (!fil_space_create(dest_space_name, space_id, FIL_TABLESPACE)) {
5772 delta later. */5864#endif
5773 if (!zip_size) {5865 msg("xtrabackup: Cannot create tablespace %s\n",
5866 dest_space_name);
5867 goto exit;
5868 }
5869
5870 /* Calculate correct tablespace flags for compressed tablespaces. */
5871 if (!zip_size || zip_size == ULINT_UNDEFINED) {
5774 tablespace_flags = 0;5872 tablespace_flags = 0;
5775 }5873 }
5776 else {5874 else {
@@ -5780,28 +5878,14 @@
5780 << DICT_TF_ZSSIZE_SHIFT)5878 << DICT_TF_ZSSIZE_SHIFT)
5781 | DICT_TF_COMPACT5879 | DICT_TF_COMPACT
5782 | (DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT);5880 | (DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT);
5783 }5881#ifdef INNODB_VERSION_SHORT
5784 ut_a(dict_table_flags_to_zip_size(tablespace_flags) == zip_size);5882 ut_a(dict_table_flags_to_zip_size(tablespace_flags)
5785 if (!fil_space_create(dest_space_name, space_id, tablespace_flags,5883 == zip_size);
5786 FIL_TABLESPACE)) {
5787#else
5788 if (!fil_space_create(dest_space_name, space_id,
5789 FIL_TABLESPACE)) {
5790#endif5884#endif
5791 msg("xtrabackup: Cannot create tablespace %s\n",5885 }
5792 dest_space_name);5886
5793 goto exit;5887 *success = xb_delta_create_space_file(real_name, space_id,
5794 }5888 tablespace_flags, &file);
5795
5796 file = xb_file_create_no_error_handling(real_name, OS_FILE_CREATE,
5797 OS_FILE_READ_WRITE,
5798 &ok);
5799
5800 if (ok) {
5801 *success = TRUE;
5802 } else {
5803 msg("xtrabackup: Cannot open file %s\n", real_name);
5804 }
58055889
5806 goto exit;5890 goto exit;
58075891
@@ -5911,8 +5995,7 @@
5911 xb_file_set_nocache(src_file, src_path, "OPEN");5995 xb_file_set_nocache(src_file, src_path, "OPEN");
59125996
5913 dst_file = xb_delta_open_matching_space(5997 dst_file = xb_delta_open_matching_space(
5914 dbname, space_name, info.space_id,5998 dbname, space_name, info.space_id, info.zip_size,
5915 info.page_size == UNIV_PAGE_SIZE ? 0 : info.page_size,
5916 dst_path, sizeof(dst_path), &success);5999 dst_path, sizeof(dst_path), &success);
5917 if (!success) {6000 if (!success) {
5918 msg("xtrabackup: error: cannot open %s\n", dst_path);6001 msg("xtrabackup: error: cannot open %s\n", dst_path);

Subscribers

People subscribed via source and target branches