Merge lp:~sergei.glushchenko/percona-xtrabackup/transportabe-tablespaces 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: 547
Proposed branch: lp:~sergei.glushchenko/percona-xtrabackup/transportabe-tablespaces
Merge into: lp:percona-xtrabackup/2.0
Diff against target: 459 lines (+403/-10)
2 files modified
src/xtrabackup.cc (+391/-4)
test/t/xb_export.sh (+12/-6)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-xtrabackup/transportabe-tablespaces
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+161073@code.launchpad.net

Description of the change

  Blueprint: Support transportable tablespaces in xtrabackup --export
  https://blueprints.launchpad.net/percona-xtrabackup/+spec/basic-56-support
  MySQL 5.6 has a feature which allows user to export InnoDB tablespaces and
  import them later. This feature is very similar to XtraDB feature.
  Xtrabackup has an option to export single table tablespace from backup.
  It dump table metadata in format which InnoDB can recognize (.exp files).
  But MySQL has it's own format of metadata stored in .cfg files.
  This patch allows Xtrabackup to produce metadata in both formats when
  export is performed. The code to support cfg export is copied from
  MySQL sources with some modifications.
  Existing testcase xb_export.sh has been modified to test export
  on MySQL 5.6 as well. It however works even when .cfg is not generated
  because bug http://bugs.mysql.com/bug.php?id=66715 is fixed in
  MySQL 5.6.8. It fails however in case of incorrect or corrupted .cfg
  file.

Will post Jenkins link later

To post a comment you must log in.
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :
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.cc'
--- src/xtrabackup.cc 2013-04-24 14:09:42 +0000
+++ src/xtrabackup.cc 2013-04-26 09:10:34 +0000
@@ -292,6 +292,23 @@
292#define SRV_PATH_SEPARATOR_STR "/"292#define SRV_PATH_SEPARATOR_STR "/"
293#endif293#endif
294294
295/** The version number of the export meta-data text file. */
296#define IB_EXPORT_CFG_VERSION_V1 0x1UL
297
298/* Maximum multi-byte character length in bytes, plus 1 */
299#define DATA_MBMAX 5
300
301/* Pack mbminlen, mbmaxlen to mbminmaxlen. */
302#define DATA_MBMINMAXLEN(mbminlen, mbmaxlen) \
303 ((mbmaxlen) * DATA_MBMAX + (mbminlen))
304/* Get mbminlen from mbminmaxlen. Cast the result of UNIV_EXPECT to ulint
305because in GCC it returns a long. */
306#define DATA_MBMINLEN(mbminmaxlen) ((ulint) \
307 UNIV_EXPECT(((mbminmaxlen) % DATA_MBMAX), \
308 1))
309/* Get mbmaxlen from mbminmaxlen. */
310#define DATA_MBMAXLEN(mbminmaxlen) ((ulint) ((mbminmaxlen) / DATA_MBMAX))
311
295#ifndef UNIV_PAGE_SIZE_MAX312#ifndef UNIV_PAGE_SIZE_MAX
296#define UNIV_PAGE_SIZE_MAX UNIV_PAGE_SIZE313#define UNIV_PAGE_SIZE_MAX UNIV_PAGE_SIZE
297#endif314#endif
@@ -7336,6 +7353,370 @@
7336 return(TRUE); /*ERROR*/7353 return(TRUE); /*ERROR*/
7337}7354}
73387355
7356
7357/*********************************************************************//**
7358Write the meta data (index user fields) config file.
7359@return true in case of success otherwise false. */
7360static
7361bool
7362xb_export_cfg_write_index_fields(
7363/*===========================*/
7364 const dict_index_t* index, /*!< in: write the meta data for
7365 this index */
7366 FILE* file) /*!< in: file to write to */
7367{
7368 byte row[sizeof(ib_uint32_t) * 2];
7369
7370 for (ulint i = 0; i < index->n_fields; ++i) {
7371 byte* ptr = row;
7372 const dict_field_t* field = &index->fields[i];
7373
7374 mach_write_to_4(ptr, field->prefix_len);
7375 ptr += sizeof(ib_uint32_t);
7376
7377 mach_write_to_4(ptr, field->fixed_len);
7378
7379 if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7380
7381 msg("xtrabackup: Error: writing index fields.");
7382
7383 return(false);
7384 }
7385
7386 /* Include the NUL byte in the length. */
7387 ib_uint32_t len = strlen(field->name) + 1;
7388 ut_a(len > 1);
7389
7390 mach_write_to_4(row, len);
7391
7392 if (fwrite(row, 1, sizeof(len), file) != sizeof(len)
7393 || fwrite(field->name, 1, len, file) != len) {
7394
7395 msg("xtrabackup: Error: writing index column.");
7396
7397 return(false);
7398 }
7399 }
7400
7401 return(true);
7402}
7403
7404/*********************************************************************//**
7405Write the meta data config file index information.
7406@return true in case of success otherwise false. */
7407static __attribute__((nonnull, warn_unused_result))
7408bool
7409xb_export_cfg_write_indexes(
7410/*======================*/
7411 const dict_table_t* table, /*!< in: write the meta data for
7412 this table */
7413 FILE* file) /*!< in: file to write to */
7414{
7415 {
7416 byte row[sizeof(ib_uint32_t)];
7417
7418 /* Write the number of indexes in the table. */
7419 mach_write_to_4(row, UT_LIST_GET_LEN(table->indexes));
7420
7421 if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7422 msg("xtrabackup: Error: writing index count.");
7423
7424 return(false);
7425 }
7426 }
7427
7428 bool ret = true;
7429
7430 /* Write the index meta data. */
7431 for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
7432 index != 0 && ret;
7433 index = UT_LIST_GET_NEXT(indexes, index)) {
7434
7435 byte* ptr;
7436 byte row[sizeof(IB_UINT64)
7437 + sizeof(ib_uint32_t) * 8];
7438
7439 ptr = row;
7440
7441 ut_ad(sizeof(IB_UINT64) == 8);
7442 mach_write_to_8(ptr, index->id);
7443 ptr += sizeof(IB_UINT64);
7444
7445 mach_write_to_4(ptr, index->space);
7446 ptr += sizeof(ib_uint32_t);
7447
7448 mach_write_to_4(ptr, index->page);
7449 ptr += sizeof(ib_uint32_t);
7450
7451 mach_write_to_4(ptr, index->type);
7452 ptr += sizeof(ib_uint32_t);
7453
7454 mach_write_to_4(ptr, index->trx_id_offset);
7455 ptr += sizeof(ib_uint32_t);
7456
7457 mach_write_to_4(ptr, index->n_user_defined_cols);
7458 ptr += sizeof(ib_uint32_t);
7459
7460 mach_write_to_4(ptr, index->n_uniq);
7461 ptr += sizeof(ib_uint32_t);
7462
7463 mach_write_to_4(ptr, index->n_nullable);
7464 ptr += sizeof(ib_uint32_t);
7465
7466 mach_write_to_4(ptr, index->n_fields);
7467
7468 if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7469
7470 msg("xtrabackup: Error: writing index meta-data.");
7471
7472 return(false);
7473 }
7474
7475 /* Write the length of the index name.
7476 NUL byte is included in the length. */
7477 ib_uint32_t len = strlen(index->name) + 1;
7478 ut_a(len > 1);
7479
7480 mach_write_to_4(row, len);
7481
7482 if (fwrite(row, 1, sizeof(len), file) != sizeof(len)
7483 || fwrite(index->name, 1, len, file) != len) {
7484
7485 msg("xtrabackup: Error: writing index name.");
7486
7487 return(false);
7488 }
7489
7490 ret = xb_export_cfg_write_index_fields(index, file);
7491 }
7492
7493 return(ret);
7494}
7495
7496/*********************************************************************//**
7497Write the meta data (table columns) config file. Serialise the contents of
7498dict_col_t structure, along with the column name. All fields are serialized
7499as ib_uint32_t.
7500@return true in case of success otherwise false. */
7501static __attribute__((nonnull, warn_unused_result))
7502bool
7503xb_export_cfg_write_table(
7504/*====================*/
7505 const dict_table_t* table, /*!< in: write the meta data for
7506 this table */
7507 FILE* file) /*!< in: file to write to */
7508{
7509 dict_col_t* col;
7510 byte row[sizeof(ib_uint32_t) * 7];
7511#if (MYSQL_VERSION_ID < 50600)
7512 ulint minlen;
7513 ulint maxlen;
7514#endif
7515
7516 col = table->cols;
7517
7518 for (ulint i = 0; i < table->n_cols; ++i, ++col) {
7519 byte* ptr = row;
7520
7521 mach_write_to_4(ptr, col->prtype);
7522 ptr += sizeof(ib_uint32_t);
7523
7524 mach_write_to_4(ptr, col->mtype);
7525 ptr += sizeof(ib_uint32_t);
7526
7527 mach_write_to_4(ptr, col->len);
7528 ptr += sizeof(ib_uint32_t);
7529
7530#if (MYSQL_VERSION_ID >= 50600)
7531 mach_write_to_4(ptr, col->mbminmaxlen);
7532#else
7533 innobase_get_cset_width(dtype_get_charset_coll(col->prtype),
7534 &minlen, &maxlen);
7535 mach_write_to_4(ptr, DATA_MBMINMAXLEN(minlen, maxlen));
7536#endif
7537 ptr += sizeof(ib_uint32_t);
7538
7539 mach_write_to_4(ptr, col->ind);
7540 ptr += sizeof(ib_uint32_t);
7541
7542 mach_write_to_4(ptr, col->ord_part);
7543 ptr += sizeof(ib_uint32_t);
7544
7545#if (MYSQL_VERSION_ID >= 50600)
7546 mach_write_to_4(ptr, col->max_prefix);
7547#else
7548 mach_write_to_4(ptr, 0);
7549#endif
7550
7551 if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7552 msg("xtrabackup: Error: writing table column data.");
7553
7554 return(false);
7555 }
7556
7557 /* Write out the column name as [len, byte array]. The len
7558 includes the NUL byte. */
7559 ib_uint32_t len;
7560 const char* col_name;
7561
7562 col_name = dict_table_get_col_name(table, dict_col_get_no(col));
7563
7564 /* Include the NUL byte in the length. */
7565 len = strlen(col_name) + 1;
7566 ut_a(len > 1);
7567
7568 mach_write_to_4(row, len);
7569
7570 if (fwrite(row, 1, sizeof(len), file) != sizeof(len)
7571 || fwrite(col_name, 1, len, file) != len) {
7572
7573 msg("xtrabackup: Error: writing column name.");
7574
7575 return(false);
7576 }
7577 }
7578
7579 return(true);
7580}
7581
7582/*********************************************************************//**
7583Write the meta data config file header.
7584@return true in case of success otherwise false. */
7585static __attribute__((nonnull, warn_unused_result))
7586bool
7587xb_export_cfg_write_header(
7588/*=====================*/
7589 const dict_table_t* table, /*!< in: write the meta data for
7590 this table */
7591 FILE* file) /*!< in: file to write to */
7592{
7593 byte value[sizeof(ib_uint32_t)];
7594
7595 /* Write the meta-data version number. */
7596 mach_write_to_4(value, IB_EXPORT_CFG_VERSION_V1);
7597
7598 if (fwrite(&value, 1, sizeof(value), file) != sizeof(value)) {
7599 msg("xtrabackup: Error: writing meta-data version number.");
7600
7601 return(false);
7602 }
7603
7604 /* Write the server hostname. */
7605 ib_uint32_t len;
7606 const char* hostname = "Hostname unknown";
7607
7608 /* The server hostname includes the NUL byte. */
7609 len = strlen(hostname) + 1;
7610 mach_write_to_4(value, len);
7611
7612 if (fwrite(&value, 1, sizeof(value), file) != sizeof(value)
7613 || fwrite(hostname, 1, len, file) != len) {
7614
7615 msg("xtrabackup: Error: writing hostname.");
7616
7617 return(false);
7618 }
7619
7620 /* The table name includes the NUL byte. */
7621 ut_a(table->name != 0);
7622 len = strlen(table->name) + 1;
7623
7624 /* Write the table name. */
7625 mach_write_to_4(value, len);
7626
7627 if (fwrite(&value, 1, sizeof(value), file) != sizeof(value)
7628 || fwrite(table->name, 1, len, file) != len) {
7629
7630 msg("xtrabackup: Error: writing table name.");
7631
7632 return(false);
7633 }
7634
7635 byte row[sizeof(ib_uint32_t) * 3];
7636
7637 /* Write the next autoinc value. */
7638#ifdef INNODB_VERSION_SHORT
7639 MACH_WRITE_64(row, table->autoinc);
7640#else
7641 MACH_WRITE_64(row,
7642 ut_dulint_create((table->autoinc >> 32) & 0xFFFFFFFFUL,
7643 table->autoinc & 0xFFFFFFFFUL));
7644#endif
7645
7646 if (fwrite(row, 1, sizeof(IB_UINT64), file) != sizeof(IB_UINT64)) {
7647 msg("xtrabackup: Error: writing table autoinc value.");
7648
7649 return(false);
7650 }
7651
7652 byte* ptr = row;
7653
7654 /* Write the system page size. */
7655 mach_write_to_4(ptr, UNIV_PAGE_SIZE);
7656 ptr += sizeof(ib_uint32_t);
7657
7658 /* Write the table->flags. */
7659 mach_write_to_4(ptr, table->flags);
7660 ptr += sizeof(ib_uint32_t);
7661
7662 /* Write the number of columns in the table. */
7663 mach_write_to_4(ptr, table->n_cols);
7664
7665 if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7666 msg("xtrabackup: Error: writing table meta-data.");
7667
7668 return(false);
7669 }
7670
7671 return(true);
7672}
7673
7674/*********************************************************************//**
7675Write MySQL 5.6-style meta data config file.
7676@return true in case of success otherwise false. */
7677static
7678bool
7679xb_export_cfg_write(
7680 const fil_node_t* node,
7681 const dict_table_t* table) /*!< in: write the meta data for
7682 this table */
7683{
7684 char file_path[FN_REFLEN];
7685 FILE* file;
7686 bool success;
7687
7688 strcpy(file_path, node->name);
7689 strcpy(file_path + strlen(file_path) - 4, ".cfg");
7690
7691 file = fopen(file_path, "w+b");
7692
7693 if (file == NULL) {
7694 msg("xtrabackup: Error: cannot close %s\n", node->name);
7695
7696 success = false;
7697 } else {
7698
7699 success = xb_export_cfg_write_header(table, file);
7700
7701 if (success) {
7702 success = xb_export_cfg_write_table(table, file);
7703 }
7704
7705 if (success) {
7706 success = xb_export_cfg_write_indexes(table, file);
7707 }
7708
7709 if (fclose(file) != 0) {
7710 msg("xtrabackup: Error: cannot close %s\n", node->name);
7711 success = false;
7712 }
7713
7714 }
7715
7716 return(success);
7717
7718}
7719
7339static void7720static void
7340xtrabackup_prepare_func(void)7721xtrabackup_prepare_func(void)
7341{7722{
@@ -7581,11 +7962,12 @@
7581 ulint n_index;7962 ulint n_index;
75827963
7583 /* node exist == file exist, here */7964 /* node exist == file exist, here */
7584 strncpy(info_file_path, node->name, FN_REFLEN);7965 strcpy(info_file_path, node->name);
7966 strcpy(info_file_path +
7967 strlen(info_file_path) -
7968 4, ".exp");
7969
7585 len = strlen(info_file_path);7970 len = strlen(info_file_path);
7586 info_file_path[len - 3] = 'e';
7587 info_file_path[len - 2] = 'x';
7588 info_file_path[len - 1] = 'p';
75897971
7590 p = info_file_path;7972 p = info_file_path;
7591 prev = NULL;7973 prev = NULL;
@@ -7619,6 +8001,11 @@
7619 goto next_node;8001 goto next_node;
7620 }8002 }
76218003
8004 /* Write MySQL 5.6 .cfg file */
8005 if (!xb_export_cfg_write(node, table)) {
8006 goto next_node;
8007 }
8008
7622 /* init exp file */8009 /* init exp file */
7623 memset(page, 0, UNIV_PAGE_SIZE);8010 memset(page, 0, UNIV_PAGE_SIZE);
7624 mach_write_to_4(page , 0x78706f72UL);8011 mach_write_to_4(page , 0x78706f72UL);
76258012
=== modified file 'test/t/xb_export.sh'
--- test/t/xb_export.sh 2013-03-11 08:22:38 +0000
+++ test/t/xb_export.sh 2013-04-26 09:10:34 +0000
@@ -1,15 +1,21 @@
1. inc/common.sh1. inc/common.sh
22
3if [ -z "$XTRADB_VERSION" ]; then3if [ -z "$XTRADB_VERSION" -a ${MYSQL_VERSION:0:3} != "5.6" ]; then
4 echo "Requires XtraDB" > $SKIPPED_REASON4 echo "Requires XtraDB or MySQL 5.6" > $SKIPPED_REASON
5 exit $SKIPPED_EXIT_CODE5 exit $SKIPPED_EXIT_CODE
6fi6fi
77
8if [ ${MYSQL_VERSION:0:3} = "5.5" ]8import_option=""
9
10if [ ! -z "$XTRADB_VERSION" ]
9then11then
10 import_option="--innodb_import_table_from_xtrabackup=1"12 # additional agrument should be passed to XtraDB
11else13 if [ ${MYSQL_VERSION:0:3} = "5.5" ]
12 import_option="--innodb_expand_import=1"14 then
15 import_option="--innodb_import_table_from_xtrabackup=1"
16 else
17 import_option="--innodb_expand_import=1"
18 fi
13fi19fi
1420
15mysql_extra_args="--innodb_file_per_table $import_option \21mysql_extra_args="--innodb_file_per_table $import_option \

Subscribers

People subscribed via source and target branches