diff options
Diffstat (limited to 'extra')
54 files changed, 6493 insertions, 3537 deletions
diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index 3e4ac442fb8..d9c424f2803 100644 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -72,6 +72,20 @@ IF(WITH_INNOBASE_STORAGE_ENGINE OR WITH_XTRADB_STORAGE_ENGINE) # We use the InnoDB code directly in case the code changes. ADD_DEFINITIONS("-DUNIV_INNOCHECKSUM") + IF(WITH_INNODB_BUG_ENDIAN_CRC32) + ADD_DEFINITIONS(-DINNODB_BUG_ENDIAN_CRC32) + ENDIF() + + # Avoid generating Hardware Capabilities due to crc32 instructions + IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_SYSTEM_PROCESSOR MATCHES "i386") + MY_CHECK_CXX_COMPILER_FLAG("-Wa,-nH") + IF(have_CXX__Wa__nH) + ADD_COMPILE_FLAGS( + ../storage/innobase/ut/ut0crc32.cc + COMPILE_FLAGS "-Wa,-nH" + ) + ENDIF() + ENDIF() SET(INNOBASE_SOURCES ../storage/innobase/buf/buf0checksum.cc @@ -82,13 +96,6 @@ IF(WITH_INNOBASE_STORAGE_ENGINE OR WITH_XTRADB_STORAGE_ENGINE) ../storage/innobase/fil/fil0crypt.cc ) - IF(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le") - enable_language(ASM) - LIST(APPEND INNOBASE_SOURCES - ../storage/innobase/ut/crc32_power8/crc32.S - ../storage/innobase/ut/crc32_power8/crc32_wrapper.c - ) - ENDIF() MYSQL_ADD_EXECUTABLE(innochecksum innochecksum.cc ${INNOBASE_SOURCES}) TARGET_LINK_LIBRARIES(innochecksum mysys mysys_ssl) diff --git a/extra/comp_err.c b/extra/comp_err.c index 2212654336c..39b2915bc00 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -32,9 +32,11 @@ #include <my_getopt.h> #include <my_dir.h> -#define MAX_ROWS 2000 +#define MAX_ROWS 3000 +#define ERRORS_PER_RANGE 1000 +#define MAX_SECTIONS 4 #define HEADER_LENGTH 32 /* Length of header in errmsg.sys */ -#define ERRMSG_VERSION 3 /* Version number of errmsg.sys */ +#define ERRMSG_VERSION 4 /* Version number of errmsg.sys */ #define DEFAULT_CHARSET_DIR "../sql/share/charsets" #define ER_PREFIX "ER_" #define ER_PREFIX2 "MARIA_ER_" @@ -53,6 +55,8 @@ static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace"; uchar file_head[]= { 254, 254, 2, ERRMSG_VERSION }; /* Store positions to each error message row to store in errmsg.sys header */ uint file_pos[MAX_ROWS+1]; +uint section_count,section_start; +uchar section_header[MAX_SECTIONS*2]; const char *empty_string= ""; /* For empty states */ /* @@ -131,7 +135,7 @@ static struct my_option my_long_options[]= }; -static struct errors *generate_empty_message(uint dcode); +static struct errors *generate_empty_message(uint dcode, my_bool skip); static struct languages *parse_charset_string(char *str); static struct errors *parse_error_string(char *ptr, int er_count); static struct message *parse_message_string(struct message *new_message, @@ -140,8 +144,9 @@ static struct message *find_message(struct errors *err, const char *lang, my_bool no_default); static int check_message_format(struct errors *err, const char* mess); -static int parse_input_file(const char *file_name, struct errors **top_error, - struct languages **top_language); +static uint parse_input_file(const char *file_name, struct errors **top_error, + struct languages **top_language, + uint *error_count); static int get_options(int *argc, char ***argv); static void print_version(void); static void usage(void); @@ -158,47 +163,55 @@ static char *find_end_of_word(char *str); static void clean_up(struct languages *lang_head, struct errors *error_head); static int create_header_files(struct errors *error_head); static int create_sys_files(struct languages *lang_head, - struct errors *error_head, uint row_count); + struct errors *error_head, uint max_error, + uint error_count); int main(int argc, char *argv[]) { MY_INIT(argv[0]); { - uint row_count; - struct errors *error_head; - struct languages *lang_head; + uint max_error, error_count; + struct errors *error_head= NULL; + struct languages *lang_head= NULL; DBUG_ENTER("main"); charsets_dir= DEFAULT_CHARSET_DIR; my_umask_dir= 0777; if (get_options(&argc, &argv)) - DBUG_RETURN(1); - if (!(row_count= parse_input_file(TXTFILE, &error_head, &lang_head))) + goto err; + if (!(max_error= parse_input_file(TXTFILE, &error_head, &lang_head, + &error_count))) { fprintf(stderr, "Failed to parse input file %s\n", TXTFILE); - DBUG_RETURN(1); + goto err; } if (lang_head == NULL || error_head == NULL) { fprintf(stderr, "Failed to parse input file %s\n", TXTFILE); - DBUG_RETURN(1); + goto err; } if (create_header_files(error_head)) { fprintf(stderr, "Failed to create header files\n"); - DBUG_RETURN(1); + goto err; } - if (create_sys_files(lang_head, error_head, row_count)) + if (create_sys_files(lang_head, error_head, max_error, error_count)) { fprintf(stderr, "Failed to create sys files\n"); - DBUG_RETURN(1); + goto err; } clean_up(lang_head, error_head); DBUG_LEAVE; /* Can't use dbug after my_end() */ my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); return 0; + +err: + clean_up(lang_head, error_head); + DBUG_LEAVE; /* Can't use dbug after my_end() */ + my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); + exit(1); } } @@ -226,6 +239,7 @@ static void print_escaped_string(FILE *f, const char *str) static int create_header_files(struct errors *error_head) { uint er_last= 0; + uint section= 1; FILE *er_definef, *sql_statef, *er_namef; struct errors *tmp_error; struct message *er_msg; @@ -253,6 +267,7 @@ static int create_header_files(struct errors *error_head) fprintf(sql_statef, "/* Autogenerated file, please don't edit */\n\n"); fprintf(er_namef, "/* Autogenerated file, please don't edit */\n\n"); + fprintf(er_definef, "#ifndef ER_ERROR_FIRST\n"); fprintf(er_definef, "#define ER_ERROR_FIRST %d\n", error_head->d_code); current_d_code= error_head->d_code -1; @@ -266,8 +281,19 @@ static int create_header_files(struct errors *error_head) if (!tmp_error->er_name) continue; /* Placeholder for gap */ - if (tmp_error->d_code > current_d_code + 1) + while (tmp_error->d_code > current_d_code + 1) + { + uint next_range= (((current_d_code + ERRORS_PER_RANGE) / + ERRORS_PER_RANGE) * ERRORS_PER_RANGE); + + fprintf(er_definef, "#define ER_ERROR_LAST_SECTION_%d %d\n", section, + current_d_code); fprintf(er_definef, "\n/* New section */\n\n"); + fprintf(er_definef, "#define ER_ERROR_FIRST_SECTION_%d %d\n", section+1, + MY_MIN(tmp_error->d_code, next_range)); + section++; + current_d_code= MY_MIN(tmp_error->d_code, next_range); + } current_d_code= tmp_error->d_code; fprintf(er_definef, "#define %s %u\n", tmp_error->er_name, @@ -289,6 +315,7 @@ static int create_header_files(struct errors *error_head) } /* finishing off with mysqld_error.h */ fprintf(er_definef, "#define ER_ERROR_LAST %d\n", er_last); + fprintf(er_definef, "#endif /* ER_ERROR_FIRST */\n"); my_fclose(er_definef, MYF(0)); my_fclose(sql_statef, MYF(0)); my_fclose(er_namef, MYF(0)); @@ -297,17 +324,19 @@ static int create_header_files(struct errors *error_head) static int create_sys_files(struct languages *lang_head, - struct errors *error_head, uint row_count) + struct errors *error_head, + uint max_error, + uint error_count) { FILE *to; - uint csnum= 0, length, i, row_nr; - uchar head[32]; + uint csnum= 0, i, row_nr; + ulong length; + uchar head[HEADER_LENGTH]; char outfile[FN_REFLEN], *outfile_end; long start_pos; struct message *tmp; struct languages *tmp_lang; struct errors *tmp_error; - MY_STAT stat_info; DBUG_ENTER("create_sys_files"); @@ -331,7 +360,7 @@ static int create_sys_files(struct languages *lang_head, { if (my_mkdir(outfile, 0777,MYF(0)) < 0) { - fprintf(stderr, "Can't create output directory for %s\n", + fprintf(stderr, "Can't creqate output directory for %s\n", outfile); DBUG_RETURN(1); } @@ -343,8 +372,8 @@ static int create_sys_files(struct languages *lang_head, DBUG_RETURN(1); /* 2 is for 2 bytes to store row position / error message */ - start_pos= (long) (HEADER_LENGTH + row_count * 2); - fseek(to, start_pos, 0); + start_pos= (long) (HEADER_LENGTH + (error_count + section_count) * 2); + my_fseek(to, start_pos, 0, MYF(0)); row_nr= 0; for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error) { @@ -358,29 +387,38 @@ static int create_sys_files(struct languages *lang_head, "language\n", tmp_error->er_name, tmp_lang->lang_short_name); goto err; } - if (copy_rows(to, tmp->text, row_nr, start_pos)) + if (tmp->text) /* If not skipped row */ { - fprintf(stderr, "Failed to copy rows to %s\n", outfile); - goto err; + if (copy_rows(to, tmp->text, row_nr, start_pos)) + { + fprintf(stderr, "Failed to copy rows to %s\n", outfile); + goto err; + } + row_nr++; } - row_nr++; } + DBUG_ASSERT(error_count == row_nr); /* continue with header of the errmsg.sys file */ - length= ftell(to) - HEADER_LENGTH - row_count * 2; + length= (ulong) (my_ftell(to, MYF(0)) - HEADER_LENGTH - + (error_count + section_count) * 2); bzero((uchar*) head, HEADER_LENGTH); - bmove((uchar *) head, (uchar *) file_head, 4); + bmove((uchar*) head, (uchar*) file_head, 4); head[4]= 1; int4store(head + 6, length); - int2store(head + 10, row_count); + int2store(head + 10, max_error); /* Max error */ + int2store(head + 12, row_nr); + int2store(head + 14, section_count); head[30]= csnum; my_fseek(to, 0l, MY_SEEK_SET, MYF(0)); - if (my_fwrite(to, (uchar*) head, HEADER_LENGTH, MYF(MY_WME | MY_FNABP))) + if (my_fwrite(to, (uchar*) head, HEADER_LENGTH, MYF(MY_WME | MY_FNABP)) || + my_fwrite(to, (uchar*) section_header, section_count*2, + MYF(MY_WME | MY_FNABP))) goto err; - file_pos[row_count]= (ftell(to) - start_pos); - for (i= 0; i < row_count; i++) + file_pos[row_nr]= (ftell(to) - start_pos); + for (i= 0; i < row_nr; i++) { /* Store length of each string */ int2store(head, file_pos[i+1] - file_pos[i]); @@ -437,24 +475,29 @@ static void clean_up(struct languages *lang_head, struct errors *error_head) } -static int parse_input_file(const char *file_name, struct errors **top_error, - struct languages **top_lang) +static uint parse_input_file(const char *file_name, struct errors **top_error, + struct languages **top_lang, uint *error_count) { FILE *file; char *str, buff[1000]; struct errors *current_error= 0, **tail_error= top_error; struct message current_message; - uint rcount= 0; + uint rcount= 0, skiped_errors= 0; my_bool er_offset_found= 0; DBUG_ENTER("parse_input_file"); *top_error= 0; *top_lang= 0; + *error_count= 0; + section_start= er_offset; + section_count= 0; + if (!(file= my_fopen(file_name, O_RDONLY | O_SHARE, MYF(MY_WME)))) DBUG_RETURN(0); while ((str= fgets(buff, sizeof(buff), file))) { + my_bool skip; if (is_prefix(str, "language")) { if (!(*top_lang= parse_charset_string(str))) @@ -464,18 +507,34 @@ static int parse_input_file(const char *file_name, struct errors **top_error, } continue; } - if (is_prefix(str, "start-error-number")) + skip= 0; + if (is_prefix(str, "start-error-number") || + (skip= is_prefix(str, "skip-to-error-number"))) { uint tmp_er_offset; + if (!(tmp_er_offset= parse_error_offset(str))) { fprintf(stderr, "Failed to parse the error offset string!\n"); DBUG_RETURN(0); } + if (skip) + { + if (section_count >= MAX_SECTIONS-1) + { + fprintf(stderr, "Found too many skip-to-error-number entries. " + "We only support %d entries\n", MAX_SECTIONS); + DBUG_RETURN(0); + } + int2store(section_header + section_count*2, + er_offset +rcount - section_start); + section_count++; + section_start= tmp_er_offset; + } if (!er_offset_found) { er_offset_found= 1; - er_offset= tmp_er_offset; + er_offset= section_start= tmp_er_offset; } else { @@ -487,7 +546,8 @@ static int parse_input_file(const char *file_name, struct errors **top_error, } for ( ; er_offset + rcount < tmp_er_offset ; rcount++) { - current_error= generate_empty_message(er_offset + rcount); + skiped_errors+= skip != 0; + current_error= generate_empty_message(er_offset + rcount, skip); *tail_error= current_error; tail_error= ¤t_error->next_error; } @@ -559,6 +619,11 @@ static int parse_input_file(const char *file_name, struct errors **top_error, fprintf(stderr, "Wrong input file format. Stop!\nLine: %s\n", str); DBUG_RETURN(0); } + int2store(section_header + section_count*2, + er_offset + rcount - section_start); + section_count++; + *error_count= rcount - skiped_errors; + *tail_error= 0; /* Mark end of list */ my_fclose(file, MYF(0)); @@ -887,7 +952,7 @@ static struct message *parse_message_string(struct message *new_message, } -static struct errors *generate_empty_message(uint d_code) +static struct errors *generate_empty_message(uint d_code, my_bool skip) { struct errors *new_error; struct message message; @@ -896,7 +961,8 @@ static struct errors *generate_empty_message(uint d_code) if (!(new_error= (struct errors *) my_malloc(sizeof(*new_error), MYF(MY_WME)))) return(0); - if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 1, MYF(0))) + if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 1, + MYF(0))) return(0); /* OOM: Fatal error */ new_error->er_name= NULL; @@ -904,8 +970,10 @@ static struct errors *generate_empty_message(uint d_code) new_error->sql_code1= empty_string; new_error->sql_code2= empty_string; + message.text= 0; /* If skip set, don't generate a text */ + if (!(message.lang_short_name= my_strdup(default_language, MYF(MY_WME))) || - !(message.text= my_strdup("", MYF(MY_WME)))) + (!skip && !(message.text= my_strdup("", MYF(MY_WME))))) return(0); /* Can't fail as msg is preallocated */ @@ -1071,10 +1139,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), switch (optid) { case 'V': print_version(); + my_end(0); exit(0); break; case '?': usage(); + my_end(0); exit(0); break; case '#': diff --git a/extra/crc32-vpmsum/CMakeLists.txt b/extra/crc32-vpmsum/CMakeLists.txt new file mode 100644 index 00000000000..0bb254bea6a --- /dev/null +++ b/extra/crc32-vpmsum/CMakeLists.txt @@ -0,0 +1,2 @@ +ENABLE_LANGUAGE(ASM) +ADD_CONVENIENCE_LIBRARY(${CRC32_VPMSUM_LIBRARY} crc32c.S crc32c_wrapper.c crc32ieee.S crc32ieee_wrapper.c) diff --git a/extra/crc32-vpmsum/crc32.iS b/extra/crc32-vpmsum/crc32.iS new file mode 100644 index 00000000000..4e7c18922da --- /dev/null +++ b/extra/crc32-vpmsum/crc32.iS @@ -0,0 +1,734 @@ +/* + * Calculate the checksum of data that is 16 byte aligned and a multiple of + * 16 bytes. + * + * The first step is to reduce it to 1024 bits. We do this in 8 parallel + * chunks in order to mask the latency of the vpmsum instructions. If we + * have more than 32 kB of data to checksum we repeat this step multiple + * times, passing in the previous 1024 bits. + * + * The next step is to reduce the 1024 bits to 64 bits. This step adds + * 32 bits of 0s to the end - this matches what a CRC does. We just + * calculate constants that land the data in this 32 bits. + * + * We then use fixed point Barrett reduction to compute a mod n over GF(2) + * for n = CRC using POWER8 instructions. We use x = 32. + * + * http://en.wikipedia.org/wiki/Barrett_reduction + * + * Copyright (C) 2015 Anton Blanchard <anton@au.ibm.com>, IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifdef __powerpc__ + +#include <ppc-asm.h> +#include "ppc-opcode.h" + +#undef toc + +#ifndef r1 +#define r1 1 +#endif + +#ifndef r2 +#define r2 2 +#endif + + .section .rodata +.balign 16 + +.byteswap_constant: + /* byte reverse permute constant */ + .octa 0x0F0E0D0C0B0A09080706050403020100 + + .text + +#define off16 r25 +#define off32 r26 +#define off48 r27 +#define off64 r28 +#define off80 r29 +#define off96 r30 +#define off112 r31 + +#define const1 v24 +#define const2 v25 + +#define byteswap v26 +#define mask_32bit v27 +#define mask_64bit v28 +#define zeroes v29 + +#ifdef BYTESWAP_DATA +#define VPERM(A, B, C, D) vperm A, B, C, D +#else +#define VPERM(A, B, C, D) +#endif + +/* unsigned int __crc32_vpmsum(unsigned int crc, void *p, unsigned long len) */ +FUNC_START(__F) + std r31,-8(r1) + std r30,-16(r1) + std r29,-24(r1) + std r28,-32(r1) + std r27,-40(r1) + std r26,-48(r1) + std r25,-56(r1) + + li off16,16 + li off32,32 + li off48,48 + li off64,64 + li off80,80 + li off96,96 + li off112,112 + li r0,0 + + /* Enough room for saving 10 non volatile VMX registers */ + subi r6,r1,56+10*16 + subi r7,r1,56+2*16 + + stvx v20,0,r6 + stvx v21,off16,r6 + stvx v22,off32,r6 + stvx v23,off48,r6 + stvx v24,off64,r6 + stvx v25,off80,r6 + stvx v26,off96,r6 + stvx v27,off112,r6 + stvx v28,0,r7 + stvx v29,off16,r7 + + mr r10,r3 + + vxor zeroes,zeroes,zeroes + vspltisw v0,-1 + + vsldoi mask_32bit,zeroes,v0,4 + vsldoi mask_64bit,zeroes,v0,8 + + /* Get the initial value into v8 */ + vxor v8,v8,v8 + MTVRD(v8, r3) + + vsldoi v8,zeroes,v8,8 /* shift into bottom 32 bits */ + + addis r3,r2,.byteswap_constant@toc@ha + addi r3,r3,.byteswap_constant@toc@l + + lvx byteswap,0,r3 + addi r3,r3,16 + + cmpdi r5,256 + blt .Lshort + + rldicr r6,r5,0,56 + + /* Checksum in blocks of MAX_SIZE */ +1: lis r7,MAX_SIZE@h + ori r7,r7,MAX_SIZE@l + mr r9,r7 + cmpd r6,r7 + bgt 2f + mr r7,r6 +2: subf r6,r7,r6 + + /* our main loop does 128 bytes at a time */ + srdi r7,r7,7 + + /* + * Work out the offset into the constants table to start at. Each + * constant is 16 bytes, and it is used against 128 bytes of input + * data - 128 / 16 = 8 + */ + sldi r8,r7,4 + srdi r9,r9,3 + subf r8,r8,r9 + + /* We reduce our final 128 bytes in a separate step */ + addi r7,r7,-1 + mtctr r7 + + addis r3,r2,CONSTANTS@toc@ha + addi r3,r3,CONSTANTS@toc@l + + /* Find the start of our constants */ + add r3,r3,r8 + + /* zero v0-v7 which will contain our checksums */ + vxor v0,v0,v0 + vxor v1,v1,v1 + vxor v2,v2,v2 + vxor v3,v3,v3 + vxor v4,v4,v4 + vxor v5,v5,v5 + vxor v6,v6,v6 + vxor v7,v7,v7 + + lvx const1,0,r3 + + /* + * If we are looping back to consume more data we use the values + * already in v16-v23. + */ + cmpdi r0,1 + beq 2f + + /* First warm up pass */ + lvx v16,0,r4 + lvx v17,off16,r4 + VPERM(v16,v16,v16,byteswap) + VPERM(v17,v17,v17,byteswap) + lvx v18,off32,r4 + lvx v19,off48,r4 + VPERM(v18,v18,v18,byteswap) + VPERM(v19,v19,v19,byteswap) + lvx v20,off64,r4 + lvx v21,off80,r4 + VPERM(v20,v20,v20,byteswap) + VPERM(v21,v21,v21,byteswap) + lvx v22,off96,r4 + lvx v23,off112,r4 + VPERM(v22,v22,v22,byteswap) + VPERM(v23,v23,v23,byteswap) + addi r4,r4,8*16 + + /* xor in initial value */ + vxor v16,v16,v8 + +2: bdz .Lfirst_warm_up_done + + addi r3,r3,16 + lvx const2,0,r3 + + /* Second warm up pass */ + VPMSUMD(v8,v16,const1) + lvx v16,0,r4 + VPERM(v16,v16,v16,byteswap) + ori r2,r2,0 + + VPMSUMD(v9,v17,const1) + lvx v17,off16,r4 + VPERM(v17,v17,v17,byteswap) + ori r2,r2,0 + + VPMSUMD(v10,v18,const1) + lvx v18,off32,r4 + VPERM(v18,v18,v18,byteswap) + ori r2,r2,0 + + VPMSUMD(v11,v19,const1) + lvx v19,off48,r4 + VPERM(v19,v19,v19,byteswap) + ori r2,r2,0 + + VPMSUMD(v12,v20,const1) + lvx v20,off64,r4 + VPERM(v20,v20,v20,byteswap) + ori r2,r2,0 + + VPMSUMD(v13,v21,const1) + lvx v21,off80,r4 + VPERM(v21,v21,v21,byteswap) + ori r2,r2,0 + + VPMSUMD(v14,v22,const1) + lvx v22,off96,r4 + VPERM(v22,v22,v22,byteswap) + ori r2,r2,0 + + VPMSUMD(v15,v23,const1) + lvx v23,off112,r4 + VPERM(v23,v23,v23,byteswap) + + addi r4,r4,8*16 + + bdz .Lfirst_cool_down + + /* + * main loop. We modulo schedule it such that it takes three iterations + * to complete - first iteration load, second iteration vpmsum, third + * iteration xor. + */ + .balign 16 +4: lvx const1,0,r3 + addi r3,r3,16 + ori r2,r2,0 + + vxor v0,v0,v8 + VPMSUMD(v8,v16,const2) + lvx v16,0,r4 + VPERM(v16,v16,v16,byteswap) + ori r2,r2,0 + + vxor v1,v1,v9 + VPMSUMD(v9,v17,const2) + lvx v17,off16,r4 + VPERM(v17,v17,v17,byteswap) + ori r2,r2,0 + + vxor v2,v2,v10 + VPMSUMD(v10,v18,const2) + lvx v18,off32,r4 + VPERM(v18,v18,v18,byteswap) + ori r2,r2,0 + + vxor v3,v3,v11 + VPMSUMD(v11,v19,const2) + lvx v19,off48,r4 + VPERM(v19,v19,v19,byteswap) + lvx const2,0,r3 + ori r2,r2,0 + + vxor v4,v4,v12 + VPMSUMD(v12,v20,const1) + lvx v20,off64,r4 + VPERM(v20,v20,v20,byteswap) + ori r2,r2,0 + + vxor v5,v5,v13 + VPMSUMD(v13,v21,const1) + lvx v21,off80,r4 + VPERM(v21,v21,v21,byteswap) + ori r2,r2,0 + + vxor v6,v6,v14 + VPMSUMD(v14,v22,const1) + lvx v22,off96,r4 + VPERM(v22,v22,v22,byteswap) + ori r2,r2,0 + + vxor v7,v7,v15 + VPMSUMD(v15,v23,const1) + lvx v23,off112,r4 + VPERM(v23,v23,v23,byteswap) + + addi r4,r4,8*16 + + bdnz 4b + +.Lfirst_cool_down: + /* First cool down pass */ + lvx const1,0,r3 + addi r3,r3,16 + + vxor v0,v0,v8 + VPMSUMD(v8,v16,const1) + ori r2,r2,0 + + vxor v1,v1,v9 + VPMSUMD(v9,v17,const1) + ori r2,r2,0 + + vxor v2,v2,v10 + VPMSUMD(v10,v18,const1) + ori r2,r2,0 + + vxor v3,v3,v11 + VPMSUMD(v11,v19,const1) + ori r2,r2,0 + + vxor v4,v4,v12 + VPMSUMD(v12,v20,const1) + ori r2,r2,0 + + vxor v5,v5,v13 + VPMSUMD(v13,v21,const1) + ori r2,r2,0 + + vxor v6,v6,v14 + VPMSUMD(v14,v22,const1) + ori r2,r2,0 + + vxor v7,v7,v15 + VPMSUMD(v15,v23,const1) + ori r2,r2,0 + +.Lsecond_cool_down: + /* Second cool down pass */ + vxor v0,v0,v8 + vxor v1,v1,v9 + vxor v2,v2,v10 + vxor v3,v3,v11 + vxor v4,v4,v12 + vxor v5,v5,v13 + vxor v6,v6,v14 + vxor v7,v7,v15 + + /* + * vpmsumd produces a 96 bit result in the least significant bits + * of the register. Since we are bit reflected we have to shift it + * left 32 bits so it occupies the least significant bits in the + * bit reflected domain. + */ + vsldoi v0,v0,zeroes,4 + vsldoi v1,v1,zeroes,4 + vsldoi v2,v2,zeroes,4 + vsldoi v3,v3,zeroes,4 + vsldoi v4,v4,zeroes,4 + vsldoi v5,v5,zeroes,4 + vsldoi v6,v6,zeroes,4 + vsldoi v7,v7,zeroes,4 + + /* xor with last 1024 bits */ + lvx v8,0,r4 + lvx v9,off16,r4 + VPERM(v8,v8,v8,byteswap) + VPERM(v9,v9,v9,byteswap) + lvx v10,off32,r4 + lvx v11,off48,r4 + VPERM(v10,v10,v10,byteswap) + VPERM(v11,v11,v11,byteswap) + lvx v12,off64,r4 + lvx v13,off80,r4 + VPERM(v12,v12,v12,byteswap) + VPERM(v13,v13,v13,byteswap) + lvx v14,off96,r4 + lvx v15,off112,r4 + VPERM(v14,v14,v14,byteswap) + VPERM(v15,v15,v15,byteswap) + + addi r4,r4,8*16 + + vxor v16,v0,v8 + vxor v17,v1,v9 + vxor v18,v2,v10 + vxor v19,v3,v11 + vxor v20,v4,v12 + vxor v21,v5,v13 + vxor v22,v6,v14 + vxor v23,v7,v15 + + li r0,1 + cmpdi r6,0 + addi r6,r6,128 + bne 1b + + /* Work out how many bytes we have left */ + andi. r5,r5,127 + + /* Calculate where in the constant table we need to start */ + subfic r6,r5,128 + add r3,r3,r6 + + /* How many 16 byte chunks are in the tail */ + srdi r7,r5,4 + mtctr r7 + + /* + * Reduce the previously calculated 1024 bits to 64 bits, shifting + * 32 bits to include the trailing 32 bits of zeros + */ + lvx v0,0,r3 + lvx v1,off16,r3 + lvx v2,off32,r3 + lvx v3,off48,r3 + lvx v4,off64,r3 + lvx v5,off80,r3 + lvx v6,off96,r3 + lvx v7,off112,r3 + addi r3,r3,8*16 + + VPMSUMW(v0,v16,v0) + VPMSUMW(v1,v17,v1) + VPMSUMW(v2,v18,v2) + VPMSUMW(v3,v19,v3) + VPMSUMW(v4,v20,v4) + VPMSUMW(v5,v21,v5) + VPMSUMW(v6,v22,v6) + VPMSUMW(v7,v23,v7) + + /* Now reduce the tail (0 - 112 bytes) */ + cmpdi r7,0 + beq 1f + + lvx v16,0,r4 + lvx v17,0,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + bdz 1f + + lvx v16,off16,r4 + lvx v17,off16,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + bdz 1f + + lvx v16,off32,r4 + lvx v17,off32,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + bdz 1f + + lvx v16,off48,r4 + lvx v17,off48,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + bdz 1f + + lvx v16,off64,r4 + lvx v17,off64,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + bdz 1f + + lvx v16,off80,r4 + lvx v17,off80,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + bdz 1f + + lvx v16,off96,r4 + lvx v17,off96,r3 + VPERM(v16,v16,v16,byteswap) + VPMSUMW(v16,v16,v17) + vxor v0,v0,v16 + + /* Now xor all the parallel chunks together */ +1: vxor v0,v0,v1 + vxor v2,v2,v3 + vxor v4,v4,v5 + vxor v6,v6,v7 + + vxor v0,v0,v2 + vxor v4,v4,v6 + + vxor v0,v0,v4 + +.Lbarrett_reduction: + /* Barrett constants */ + addis r3,r2,BARRETT_CONSTANTS@toc@ha + addi r3,r3,BARRETT_CONSTANTS@toc@l + + lvx const1,0,r3 + lvx const2,off16,r3 + + vsldoi v1,v0,v0,8 + vxor v0,v0,v1 /* xor two 64 bit results together */ + + /* shift left one bit */ + vspltisb v1,1 + vsl v0,v0,v1 + + vand v0,v0,mask_64bit + + /* + * The reflected version of Barrett reduction. Instead of bit + * reflecting our data (which is expensive to do), we bit reflect our + * constants and our algorithm, which means the intermediate data in + * our vector registers goes from 0-63 instead of 63-0. We can reflect + * the algorithm because we don't carry in mod 2 arithmetic. + */ + vand v1,v0,mask_32bit /* bottom 32 bits of a */ + VPMSUMD(v1,v1,const1) /* ma */ + vand v1,v1,mask_32bit /* bottom 32bits of ma */ + VPMSUMD(v1,v1,const2) /* qn */ + vxor v0,v0,v1 /* a - qn, subtraction is xor in GF(2) */ + + /* + * Since we are bit reflected, the result (ie the low 32 bits) is in + * the high 32 bits. We just need to shift it left 4 bytes + * V0 [ 0 1 X 3 ] + * V0 [ 0 X 2 3 ] + */ + vsldoi v0,v0,zeroes,4 /* shift result into top 64 bits of */ + +.Lout: + subi r6,r1,56+10*16 + subi r7,r1,56+2*16 + + lvx v20,0,r6 + lvx v21,off16,r6 + lvx v22,off32,r6 + lvx v23,off48,r6 + lvx v24,off64,r6 + lvx v25,off80,r6 + lvx v26,off96,r6 + lvx v27,off112,r6 + lvx v28,0,r7 + lvx v29,off16,r7 + + /* Get it into r3 */ + MFVRD(r3, v0) + + ld r31,-8(r1) + ld r30,-16(r1) + ld r29,-24(r1) + ld r28,-32(r1) + ld r27,-40(r1) + ld r26,-48(r1) + ld r25,-56(r1) + + blr + +.Lfirst_warm_up_done: + lvx const1,0,r3 + addi r3,r3,16 + + VPMSUMD(v8,v16,const1) + VPMSUMD(v9,v17,const1) + VPMSUMD(v10,v18,const1) + VPMSUMD(v11,v19,const1) + VPMSUMD(v12,v20,const1) + VPMSUMD(v13,v21,const1) + VPMSUMD(v14,v22,const1) + VPMSUMD(v15,v23,const1) + + b .Lsecond_cool_down + +.Lshort: + cmpdi r5,0 + beq .Lzero + + addis r3,r2,SHORT_CONSTANTS@toc@ha + addi r3,r3,SHORT_CONSTANTS@toc@l + + /* Calculate where in the constant table we need to start */ + subfic r6,r5,256 + add r3,r3,r6 + + /* How many 16 byte chunks? */ + srdi r7,r5,4 + mtctr r7 + + vxor v19,v19,v19 + vxor v20,v20,v20 + + lvx v0,0,r4 + lvx v16,0,r3 + VPERM(v0,v0,v16,byteswap) + vxor v0,v0,v8 /* xor in initial value */ + VPMSUMW(v0,v0,v16) + bdz .Lv0 + + lvx v1,off16,r4 + lvx v17,off16,r3 + VPERM(v1,v1,v17,byteswap) + VPMSUMW(v1,v1,v17) + bdz .Lv1 + + lvx v2,off32,r4 + lvx v16,off32,r3 + VPERM(v2,v2,v16,byteswap) + VPMSUMW(v2,v2,v16) + bdz .Lv2 + + lvx v3,off48,r4 + lvx v17,off48,r3 + VPERM(v3,v3,v17,byteswap) + VPMSUMW(v3,v3,v17) + bdz .Lv3 + + lvx v4,off64,r4 + lvx v16,off64,r3 + VPERM(v4,v4,v16,byteswap) + VPMSUMW(v4,v4,v16) + bdz .Lv4 + + lvx v5,off80,r4 + lvx v17,off80,r3 + VPERM(v5,v5,v17,byteswap) + VPMSUMW(v5,v5,v17) + bdz .Lv5 + + lvx v6,off96,r4 + lvx v16,off96,r3 + VPERM(v6,v6,v16,byteswap) + VPMSUMW(v6,v6,v16) + bdz .Lv6 + + lvx v7,off112,r4 + lvx v17,off112,r3 + VPERM(v7,v7,v17,byteswap) + VPMSUMW(v7,v7,v17) + bdz .Lv7 + + addi r3,r3,128 + addi r4,r4,128 + + lvx v8,0,r4 + lvx v16,0,r3 + VPERM(v8,v8,v16,byteswap) + VPMSUMW(v8,v8,v16) + bdz .Lv8 + + lvx v9,off16,r4 + lvx v17,off16,r3 + VPERM(v9,v9,v17,byteswap) + VPMSUMW(v9,v9,v17) + bdz .Lv9 + + lvx v10,off32,r4 + lvx v16,off32,r3 + VPERM(v10,v10,v16,byteswap) + VPMSUMW(v10,v10,v16) + bdz .Lv10 + + lvx v11,off48,r4 + lvx v17,off48,r3 + VPERM(v11,v11,v17,byteswap) + VPMSUMW(v11,v11,v17) + bdz .Lv11 + + lvx v12,off64,r4 + lvx v16,off64,r3 + VPERM(v12,v12,v16,byteswap) + VPMSUMW(v12,v12,v16) + bdz .Lv12 + + lvx v13,off80,r4 + lvx v17,off80,r3 + VPERM(v13,v13,v17,byteswap) + VPMSUMW(v13,v13,v17) + bdz .Lv13 + + lvx v14,off96,r4 + lvx v16,off96,r3 + VPERM(v14,v14,v16,byteswap) + VPMSUMW(v14,v14,v16) + bdz .Lv14 + + lvx v15,off112,r4 + lvx v17,off112,r3 + VPERM(v15,v15,v17,byteswap) + VPMSUMW(v15,v15,v17) + +.Lv15: vxor v19,v19,v15 +.Lv14: vxor v20,v20,v14 +.Lv13: vxor v19,v19,v13 +.Lv12: vxor v20,v20,v12 +.Lv11: vxor v19,v19,v11 +.Lv10: vxor v20,v20,v10 +.Lv9: vxor v19,v19,v9 +.Lv8: vxor v20,v20,v8 +.Lv7: vxor v19,v19,v7 +.Lv6: vxor v20,v20,v6 +.Lv5: vxor v19,v19,v5 +.Lv4: vxor v20,v20,v4 +.Lv3: vxor v19,v19,v3 +.Lv2: vxor v20,v20,v2 +.Lv1: vxor v19,v19,v1 +.Lv0: vxor v20,v20,v0 + + vxor v0,v19,v20 + + b .Lbarrett_reduction + +.Lzero: + mr r3,r10 + b .Lout + +FUNC_END(__F) + +#endif /* __powerpc__ */ diff --git a/extra/crc32-vpmsum/crc32_wrapper.ic b/extra/crc32-vpmsum/crc32_wrapper.ic new file mode 100644 index 00000000000..750e971f83e --- /dev/null +++ b/extra/crc32-vpmsum/crc32_wrapper.ic @@ -0,0 +1,52 @@ +#ifdef __powerpc__ + + +#define VMX_ALIGN 16 +#define VMX_ALIGN_MASK (VMX_ALIGN-1) + +static unsigned int crc32_align(unsigned int crc, unsigned char *p, + unsigned long len) +{ + while (len--) + crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8); + return crc; +} + +unsigned int __F(unsigned int crc, unsigned char *p, + unsigned long len); + +unsigned int F(unsigned int crc, unsigned char *p, + unsigned long len) +{ + unsigned int prealign; + unsigned int tail; + + crc ^= 0xffffffff; + + if (len < VMX_ALIGN + VMX_ALIGN_MASK) { + crc = crc32_align(crc, p, len); + goto out; + } + + if ((unsigned long)p & VMX_ALIGN_MASK) { + prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK); + crc = crc32_align(crc, p, prealign); + len -= prealign; + p += prealign; + } + + crc = __F(crc, p, len & ~VMX_ALIGN_MASK); + + tail = len & VMX_ALIGN_MASK; + if (tail) { + p += len & ~VMX_ALIGN_MASK; + crc = crc32_align(crc, p, tail); + } + +out: + crc ^= 0xffffffff; + + return crc; +} + +#endif /* __powerpc__ */ diff --git a/extra/crc32-vpmsum/crc32c.S b/extra/crc32-vpmsum/crc32c.S new file mode 100644 index 00000000000..390c4bf0660 --- /dev/null +++ b/extra/crc32-vpmsum/crc32c.S @@ -0,0 +1,14 @@ +#ifdef __powerpc__ + +#define CONSTANTS .crc32c_constants +#define SHORT_CONSTANTS .crc32c_short_constants +#define BARRETT_CONSTANTS .crc32c_barrett_constants + +#include "crc32c_constants.h" + +#define __F __crc32c_vpmsum + +#include "crc32.iS" + +#endif + diff --git a/extra/crc32-vpmsum/crc32c_constants.h b/extra/crc32-vpmsum/crc32c_constants.h new file mode 100644 index 00000000000..555b785ce9f --- /dev/null +++ b/extra/crc32-vpmsum/crc32c_constants.h @@ -0,0 +1,837 @@ +#ifndef CRC32_CONSTANTS_H +#define CRC32_CONSTANTS_H + +#ifdef __powerpc__ + +#define CRC 0x1edc6f41 + +#define MAX_SIZE 32768 +CONSTANTS: + + /* Reduce 262144 kbits to 1024 bits */ + /* x^261120 mod p(x)` << 1, x^261184 mod p(x)` << 1 */ + .octa 0x00000000b6ca9e20000000009c37c408 + + /* x^260096 mod p(x)` << 1, x^260160 mod p(x)` << 1 */ + .octa 0x00000000350249a800000001b51df26c + + /* x^259072 mod p(x)` << 1, x^259136 mod p(x)` << 1 */ + .octa 0x00000001862dac54000000000724b9d0 + + /* x^258048 mod p(x)` << 1, x^258112 mod p(x)` << 1 */ + .octa 0x00000001d87fb48c00000001c00532fe + + /* x^257024 mod p(x)` << 1, x^257088 mod p(x)` << 1 */ + .octa 0x00000001f39b699e00000000f05a9362 + + /* x^256000 mod p(x)` << 1, x^256064 mod p(x)` << 1 */ + .octa 0x0000000101da11b400000001e1007970 + + /* x^254976 mod p(x)` << 1, x^255040 mod p(x)` << 1 */ + .octa 0x00000001cab571e000000000a57366ee + + /* x^253952 mod p(x)` << 1, x^254016 mod p(x)` << 1 */ + .octa 0x00000000c7020cfe0000000192011284 + + /* x^252928 mod p(x)` << 1, x^252992 mod p(x)` << 1 */ + .octa 0x00000000cdaed1ae0000000162716d9a + + /* x^251904 mod p(x)` << 1, x^251968 mod p(x)` << 1 */ + .octa 0x00000001e804effc00000000cd97ecde + + /* x^250880 mod p(x)` << 1, x^250944 mod p(x)` << 1 */ + .octa 0x0000000077c3ea3a0000000058812bc0 + + /* x^249856 mod p(x)` << 1, x^249920 mod p(x)` << 1 */ + .octa 0x0000000068df31b40000000088b8c12e + + /* x^248832 mod p(x)` << 1, x^248896 mod p(x)` << 1 */ + .octa 0x00000000b059b6c200000001230b234c + + /* x^247808 mod p(x)` << 1, x^247872 mod p(x)` << 1 */ + .octa 0x0000000145fb8ed800000001120b416e + + /* x^246784 mod p(x)` << 1, x^246848 mod p(x)` << 1 */ + .octa 0x00000000cbc0916800000001974aecb0 + + /* x^245760 mod p(x)` << 1, x^245824 mod p(x)` << 1 */ + .octa 0x000000005ceeedc2000000008ee3f226 + + /* x^244736 mod p(x)` << 1, x^244800 mod p(x)` << 1 */ + .octa 0x0000000047d74e8600000001089aba9a + + /* x^243712 mod p(x)` << 1, x^243776 mod p(x)` << 1 */ + .octa 0x00000001407e9e220000000065113872 + + /* x^242688 mod p(x)` << 1, x^242752 mod p(x)` << 1 */ + .octa 0x00000001da967bda000000005c07ec10 + + /* x^241664 mod p(x)` << 1, x^241728 mod p(x)` << 1 */ + .octa 0x000000006c8983680000000187590924 + + /* x^240640 mod p(x)` << 1, x^240704 mod p(x)` << 1 */ + .octa 0x00000000f2d14c9800000000e35da7c6 + + /* x^239616 mod p(x)` << 1, x^239680 mod p(x)` << 1 */ + .octa 0x00000001993c6ad4000000000415855a + + /* x^238592 mod p(x)` << 1, x^238656 mod p(x)` << 1 */ + .octa 0x000000014683d1ac0000000073617758 + + /* x^237568 mod p(x)` << 1, x^237632 mod p(x)` << 1 */ + .octa 0x00000001a7c93e6c0000000176021d28 + + /* x^236544 mod p(x)` << 1, x^236608 mod p(x)` << 1 */ + .octa 0x000000010211e90a00000001c358fd0a + + /* x^235520 mod p(x)` << 1, x^235584 mod p(x)` << 1 */ + .octa 0x000000001119403e00000001ff7a2c18 + + /* x^234496 mod p(x)` << 1, x^234560 mod p(x)` << 1 */ + .octa 0x000000001c3261aa00000000f2d9f7e4 + + /* x^233472 mod p(x)` << 1, x^233536 mod p(x)` << 1 */ + .octa 0x000000014e37a634000000016cf1f9c8 + + /* x^232448 mod p(x)` << 1, x^232512 mod p(x)` << 1 */ + .octa 0x0000000073786c0c000000010af9279a + + /* x^231424 mod p(x)` << 1, x^231488 mod p(x)` << 1 */ + .octa 0x000000011dc037f80000000004f101e8 + + /* x^230400 mod p(x)` << 1, x^230464 mod p(x)` << 1 */ + .octa 0x0000000031433dfc0000000070bcf184 + + /* x^229376 mod p(x)` << 1, x^229440 mod p(x)` << 1 */ + .octa 0x000000009cde8348000000000a8de642 + + /* x^228352 mod p(x)` << 1, x^228416 mod p(x)` << 1 */ + .octa 0x0000000038d3c2a60000000062ea130c + + /* x^227328 mod p(x)` << 1, x^227392 mod p(x)` << 1 */ + .octa 0x000000011b25f26000000001eb31cbb2 + + /* x^226304 mod p(x)` << 1, x^226368 mod p(x)` << 1 */ + .octa 0x000000001629e6f00000000170783448 + + /* x^225280 mod p(x)` << 1, x^225344 mod p(x)` << 1 */ + .octa 0x0000000160838b4c00000001a684b4c6 + + /* x^224256 mod p(x)` << 1, x^224320 mod p(x)` << 1 */ + .octa 0x000000007a44011c00000000253ca5b4 + + /* x^223232 mod p(x)` << 1, x^223296 mod p(x)` << 1 */ + .octa 0x00000000226f417a0000000057b4b1e2 + + /* x^222208 mod p(x)` << 1, x^222272 mod p(x)` << 1 */ + .octa 0x0000000045eb2eb400000000b6bd084c + + /* x^221184 mod p(x)` << 1, x^221248 mod p(x)` << 1 */ + .octa 0x000000014459d70c0000000123c2d592 + + /* x^220160 mod p(x)` << 1, x^220224 mod p(x)` << 1 */ + .octa 0x00000001d406ed8200000000159dafce + + /* x^219136 mod p(x)` << 1, x^219200 mod p(x)` << 1 */ + .octa 0x0000000160c8e1a80000000127e1a64e + + /* x^218112 mod p(x)` << 1, x^218176 mod p(x)` << 1 */ + .octa 0x0000000027ba80980000000056860754 + + /* x^217088 mod p(x)` << 1, x^217152 mod p(x)` << 1 */ + .octa 0x000000006d92d01800000001e661aae8 + + /* x^216064 mod p(x)` << 1, x^216128 mod p(x)` << 1 */ + .octa 0x000000012ed7e3f200000000f82c6166 + + /* x^215040 mod p(x)` << 1, x^215104 mod p(x)` << 1 */ + .octa 0x000000002dc8778800000000c4f9c7ae + + /* x^214016 mod p(x)` << 1, x^214080 mod p(x)` << 1 */ + .octa 0x0000000018240bb80000000074203d20 + + /* x^212992 mod p(x)` << 1, x^213056 mod p(x)` << 1 */ + .octa 0x000000001ad381580000000198173052 + + /* x^211968 mod p(x)` << 1, x^212032 mod p(x)` << 1 */ + .octa 0x00000001396b78f200000001ce8aba54 + + /* x^210944 mod p(x)` << 1, x^211008 mod p(x)` << 1 */ + .octa 0x000000011a68133400000001850d5d94 + + /* x^209920 mod p(x)` << 1, x^209984 mod p(x)` << 1 */ + .octa 0x000000012104732e00000001d609239c + + /* x^208896 mod p(x)` << 1, x^208960 mod p(x)` << 1 */ + .octa 0x00000000a140d90c000000001595f048 + + /* x^207872 mod p(x)` << 1, x^207936 mod p(x)` << 1 */ + .octa 0x00000001b7215eda0000000042ccee08 + + /* x^206848 mod p(x)` << 1, x^206912 mod p(x)` << 1 */ + .octa 0x00000001aaf1df3c000000010a389d74 + + /* x^205824 mod p(x)` << 1, x^205888 mod p(x)` << 1 */ + .octa 0x0000000029d15b8a000000012a840da6 + + /* x^204800 mod p(x)` << 1, x^204864 mod p(x)` << 1 */ + .octa 0x00000000f1a96922000000001d181c0c + + /* x^203776 mod p(x)` << 1, x^203840 mod p(x)` << 1 */ + .octa 0x00000001ac80d03c0000000068b7d1f6 + + /* x^202752 mod p(x)` << 1, x^202816 mod p(x)` << 1 */ + .octa 0x000000000f11d56a000000005b0f14fc + + /* x^201728 mod p(x)` << 1, x^201792 mod p(x)` << 1 */ + .octa 0x00000001f1c022a20000000179e9e730 + + /* x^200704 mod p(x)` << 1, x^200768 mod p(x)` << 1 */ + .octa 0x0000000173d00ae200000001ce1368d6 + + /* x^199680 mod p(x)` << 1, x^199744 mod p(x)` << 1 */ + .octa 0x00000001d4ffe4ac0000000112c3a84c + + /* x^198656 mod p(x)` << 1, x^198720 mod p(x)` << 1 */ + .octa 0x000000016edc5ae400000000de940fee + + /* x^197632 mod p(x)` << 1, x^197696 mod p(x)` << 1 */ + .octa 0x00000001f1a0214000000000fe896b7e + + /* x^196608 mod p(x)` << 1, x^196672 mod p(x)` << 1 */ + .octa 0x00000000ca0b28a000000001f797431c + + /* x^195584 mod p(x)` << 1, x^195648 mod p(x)` << 1 */ + .octa 0x00000001928e30a20000000053e989ba + + /* x^194560 mod p(x)` << 1, x^194624 mod p(x)` << 1 */ + .octa 0x0000000097b1b002000000003920cd16 + + /* x^193536 mod p(x)` << 1, x^193600 mod p(x)` << 1 */ + .octa 0x00000000b15bf90600000001e6f579b8 + + /* x^192512 mod p(x)` << 1, x^192576 mod p(x)` << 1 */ + .octa 0x00000000411c5d52000000007493cb0a + + /* x^191488 mod p(x)` << 1, x^191552 mod p(x)` << 1 */ + .octa 0x00000001c36f330000000001bdd376d8 + + /* x^190464 mod p(x)` << 1, x^190528 mod p(x)` << 1 */ + .octa 0x00000001119227e0000000016badfee6 + + /* x^189440 mod p(x)` << 1, x^189504 mod p(x)` << 1 */ + .octa 0x00000000114d47020000000071de5c58 + + /* x^188416 mod p(x)` << 1, x^188480 mod p(x)` << 1 */ + .octa 0x00000000458b5b9800000000453f317c + + /* x^187392 mod p(x)` << 1, x^187456 mod p(x)` << 1 */ + .octa 0x000000012e31fb8e0000000121675cce + + /* x^186368 mod p(x)` << 1, x^186432 mod p(x)` << 1 */ + .octa 0x000000005cf619d800000001f409ee92 + + /* x^185344 mod p(x)` << 1, x^185408 mod p(x)` << 1 */ + .octa 0x0000000063f4d8b200000000f36b9c88 + + /* x^184320 mod p(x)` << 1, x^184384 mod p(x)` << 1 */ + .octa 0x000000004138dc8a0000000036b398f4 + + /* x^183296 mod p(x)` << 1, x^183360 mod p(x)` << 1 */ + .octa 0x00000001d29ee8e000000001748f9adc + + /* x^182272 mod p(x)` << 1, x^182336 mod p(x)` << 1 */ + .octa 0x000000006a08ace800000001be94ec00 + + /* x^181248 mod p(x)` << 1, x^181312 mod p(x)` << 1 */ + .octa 0x0000000127d4201000000000b74370d6 + + /* x^180224 mod p(x)` << 1, x^180288 mod p(x)` << 1 */ + .octa 0x0000000019d76b6200000001174d0b98 + + /* x^179200 mod p(x)` << 1, x^179264 mod p(x)` << 1 */ + .octa 0x00000001b1471f6e00000000befc06a4 + + /* x^178176 mod p(x)` << 1, x^178240 mod p(x)` << 1 */ + .octa 0x00000001f64c19cc00000001ae125288 + + /* x^177152 mod p(x)` << 1, x^177216 mod p(x)` << 1 */ + .octa 0x00000000003c0ea00000000095c19b34 + + /* x^176128 mod p(x)` << 1, x^176192 mod p(x)` << 1 */ + .octa 0x000000014d73abf600000001a78496f2 + + /* x^175104 mod p(x)` << 1, x^175168 mod p(x)` << 1 */ + .octa 0x00000001620eb84400000001ac5390a0 + + /* x^174080 mod p(x)` << 1, x^174144 mod p(x)` << 1 */ + .octa 0x0000000147655048000000002a80ed6e + + /* x^173056 mod p(x)` << 1, x^173120 mod p(x)` << 1 */ + .octa 0x0000000067b5077e00000001fa9b0128 + + /* x^172032 mod p(x)` << 1, x^172096 mod p(x)` << 1 */ + .octa 0x0000000010ffe20600000001ea94929e + + /* x^171008 mod p(x)` << 1, x^171072 mod p(x)` << 1 */ + .octa 0x000000000fee8f1e0000000125f4305c + + /* x^169984 mod p(x)` << 1, x^170048 mod p(x)` << 1 */ + .octa 0x00000001da26fbae00000001471e2002 + + /* x^168960 mod p(x)` << 1, x^169024 mod p(x)` << 1 */ + .octa 0x00000001b3a8bd880000000132d2253a + + /* x^167936 mod p(x)` << 1, x^168000 mod p(x)` << 1 */ + .octa 0x00000000e8f3898e00000000f26b3592 + + /* x^166912 mod p(x)` << 1, x^166976 mod p(x)` << 1 */ + .octa 0x00000000b0d0d28c00000000bc8b67b0 + + /* x^165888 mod p(x)` << 1, x^165952 mod p(x)` << 1 */ + .octa 0x0000000030f2a798000000013a826ef2 + + /* x^164864 mod p(x)` << 1, x^164928 mod p(x)` << 1 */ + .octa 0x000000000fba10020000000081482c84 + + /* x^163840 mod p(x)` << 1, x^163904 mod p(x)` << 1 */ + .octa 0x00000000bdb9bd7200000000e77307c2 + + /* x^162816 mod p(x)` << 1, x^162880 mod p(x)` << 1 */ + .octa 0x0000000075d3bf5a00000000d4a07ec8 + + /* x^161792 mod p(x)` << 1, x^161856 mod p(x)` << 1 */ + .octa 0x00000000ef1f98a00000000017102100 + + /* x^160768 mod p(x)` << 1, x^160832 mod p(x)` << 1 */ + .octa 0x00000000689c760200000000db406486 + + /* x^159744 mod p(x)` << 1, x^159808 mod p(x)` << 1 */ + .octa 0x000000016d5fa5fe0000000192db7f88 + + /* x^158720 mod p(x)` << 1, x^158784 mod p(x)` << 1 */ + .octa 0x00000001d0d2b9ca000000018bf67b1e + + /* x^157696 mod p(x)` << 1, x^157760 mod p(x)` << 1 */ + .octa 0x0000000041e7b470000000007c09163e + + /* x^156672 mod p(x)` << 1, x^156736 mod p(x)` << 1 */ + .octa 0x00000001cbb6495e000000000adac060 + + /* x^155648 mod p(x)` << 1, x^155712 mod p(x)` << 1 */ + .octa 0x000000010052a0b000000000bd8316ae + + /* x^154624 mod p(x)` << 1, x^154688 mod p(x)` << 1 */ + .octa 0x00000001d8effb5c000000019f09ab54 + + /* x^153600 mod p(x)` << 1, x^153664 mod p(x)` << 1 */ + .octa 0x00000001d969853c0000000125155542 + + /* x^152576 mod p(x)` << 1, x^152640 mod p(x)` << 1 */ + .octa 0x00000000523ccce2000000018fdb5882 + + /* x^151552 mod p(x)` << 1, x^151616 mod p(x)` << 1 */ + .octa 0x000000001e2436bc00000000e794b3f4 + + /* x^150528 mod p(x)` << 1, x^150592 mod p(x)` << 1 */ + .octa 0x00000000ddd1c3a2000000016f9bb022 + + /* x^149504 mod p(x)` << 1, x^149568 mod p(x)` << 1 */ + .octa 0x0000000019fcfe3800000000290c9978 + + /* x^148480 mod p(x)` << 1, x^148544 mod p(x)` << 1 */ + .octa 0x00000001ce95db640000000083c0f350 + + /* x^147456 mod p(x)` << 1, x^147520 mod p(x)` << 1 */ + .octa 0x00000000af5828060000000173ea6628 + + /* x^146432 mod p(x)` << 1, x^146496 mod p(x)` << 1 */ + .octa 0x00000001006388f600000001c8b4e00a + + /* x^145408 mod p(x)` << 1, x^145472 mod p(x)` << 1 */ + .octa 0x0000000179eca00a00000000de95d6aa + + /* x^144384 mod p(x)` << 1, x^144448 mod p(x)` << 1 */ + .octa 0x0000000122410a6a000000010b7f7248 + + /* x^143360 mod p(x)` << 1, x^143424 mod p(x)` << 1 */ + .octa 0x000000004288e87c00000001326e3a06 + + /* x^142336 mod p(x)` << 1, x^142400 mod p(x)` << 1 */ + .octa 0x000000016c5490da00000000bb62c2e6 + + /* x^141312 mod p(x)` << 1, x^141376 mod p(x)` << 1 */ + .octa 0x00000000d1c71f6e0000000156a4b2c2 + + /* x^140288 mod p(x)` << 1, x^140352 mod p(x)` << 1 */ + .octa 0x00000001b4ce08a6000000011dfe763a + + /* x^139264 mod p(x)` << 1, x^139328 mod p(x)` << 1 */ + .octa 0x00000001466ba60c000000007bcca8e2 + + /* x^138240 mod p(x)` << 1, x^138304 mod p(x)` << 1 */ + .octa 0x00000001f6c488a40000000186118faa + + /* x^137216 mod p(x)` << 1, x^137280 mod p(x)` << 1 */ + .octa 0x000000013bfb06820000000111a65a88 + + /* x^136192 mod p(x)` << 1, x^136256 mod p(x)` << 1 */ + .octa 0x00000000690e9e54000000003565e1c4 + + /* x^135168 mod p(x)` << 1, x^135232 mod p(x)` << 1 */ + .octa 0x00000000281346b6000000012ed02a82 + + /* x^134144 mod p(x)` << 1, x^134208 mod p(x)` << 1 */ + .octa 0x000000015646402400000000c486ecfc + + /* x^133120 mod p(x)` << 1, x^133184 mod p(x)` << 1 */ + .octa 0x000000016063a8dc0000000001b951b2 + + /* x^132096 mod p(x)` << 1, x^132160 mod p(x)` << 1 */ + .octa 0x0000000116a663620000000048143916 + + /* x^131072 mod p(x)` << 1, x^131136 mod p(x)` << 1 */ + .octa 0x000000017e8aa4d200000001dc2ae124 + + /* x^130048 mod p(x)` << 1, x^130112 mod p(x)` << 1 */ + .octa 0x00000001728eb10c00000001416c58d6 + + /* x^129024 mod p(x)` << 1, x^129088 mod p(x)` << 1 */ + .octa 0x00000001b08fd7fa00000000a479744a + + /* x^128000 mod p(x)` << 1, x^128064 mod p(x)` << 1 */ + .octa 0x00000001092a16e80000000096ca3a26 + + /* x^126976 mod p(x)` << 1, x^127040 mod p(x)` << 1 */ + .octa 0x00000000a505637c00000000ff223d4e + + /* x^125952 mod p(x)` << 1, x^126016 mod p(x)` << 1 */ + .octa 0x00000000d94869b2000000010e84da42 + + /* x^124928 mod p(x)` << 1, x^124992 mod p(x)` << 1 */ + .octa 0x00000001c8b203ae00000001b61ba3d0 + + /* x^123904 mod p(x)` << 1, x^123968 mod p(x)` << 1 */ + .octa 0x000000005704aea000000000680f2de8 + + /* x^122880 mod p(x)` << 1, x^122944 mod p(x)` << 1 */ + .octa 0x000000012e295fa2000000008772a9a8 + + /* x^121856 mod p(x)` << 1, x^121920 mod p(x)` << 1 */ + .octa 0x000000011d0908bc0000000155f295bc + + /* x^120832 mod p(x)` << 1, x^120896 mod p(x)` << 1 */ + .octa 0x0000000193ed97ea00000000595f9282 + + /* x^119808 mod p(x)` << 1, x^119872 mod p(x)` << 1 */ + .octa 0x000000013a0f1c520000000164b1c25a + + /* x^118784 mod p(x)` << 1, x^118848 mod p(x)` << 1 */ + .octa 0x000000010c2c40c000000000fbd67c50 + + /* x^117760 mod p(x)` << 1, x^117824 mod p(x)` << 1 */ + .octa 0x00000000ff6fac3e0000000096076268 + + /* x^116736 mod p(x)` << 1, x^116800 mod p(x)` << 1 */ + .octa 0x000000017b3609c000000001d288e4cc + + /* x^115712 mod p(x)` << 1, x^115776 mod p(x)` << 1 */ + .octa 0x0000000088c8c92200000001eaac1bdc + + /* x^114688 mod p(x)` << 1, x^114752 mod p(x)` << 1 */ + .octa 0x00000001751baae600000001f1ea39e2 + + /* x^113664 mod p(x)` << 1, x^113728 mod p(x)` << 1 */ + .octa 0x000000010795297200000001eb6506fc + + /* x^112640 mod p(x)` << 1, x^112704 mod p(x)` << 1 */ + .octa 0x0000000162b00abe000000010f806ffe + + /* x^111616 mod p(x)` << 1, x^111680 mod p(x)` << 1 */ + .octa 0x000000000d7b404c000000010408481e + + /* x^110592 mod p(x)` << 1, x^110656 mod p(x)` << 1 */ + .octa 0x00000000763b13d40000000188260534 + + /* x^109568 mod p(x)` << 1, x^109632 mod p(x)` << 1 */ + .octa 0x00000000f6dc22d80000000058fc73e0 + + /* x^108544 mod p(x)` << 1, x^108608 mod p(x)` << 1 */ + .octa 0x000000007daae06000000000391c59b8 + + /* x^107520 mod p(x)` << 1, x^107584 mod p(x)` << 1 */ + .octa 0x000000013359ab7c000000018b638400 + + /* x^106496 mod p(x)` << 1, x^106560 mod p(x)` << 1 */ + .octa 0x000000008add438a000000011738f5c4 + + /* x^105472 mod p(x)` << 1, x^105536 mod p(x)` << 1 */ + .octa 0x00000001edbefdea000000008cf7c6da + + /* x^104448 mod p(x)` << 1, x^104512 mod p(x)` << 1 */ + .octa 0x000000004104e0f800000001ef97fb16 + + /* x^103424 mod p(x)` << 1, x^103488 mod p(x)` << 1 */ + .octa 0x00000000b48a82220000000102130e20 + + /* x^102400 mod p(x)` << 1, x^102464 mod p(x)` << 1 */ + .octa 0x00000001bcb4684400000000db968898 + + /* x^101376 mod p(x)` << 1, x^101440 mod p(x)` << 1 */ + .octa 0x000000013293ce0a00000000b5047b5e + + /* x^100352 mod p(x)` << 1, x^100416 mod p(x)` << 1 */ + .octa 0x00000001710d0844000000010b90fdb2 + + /* x^99328 mod p(x)` << 1, x^99392 mod p(x)` << 1 */ + .octa 0x0000000117907f6e000000004834a32e + + /* x^98304 mod p(x)` << 1, x^98368 mod p(x)` << 1 */ + .octa 0x0000000087ddf93e0000000059c8f2b0 + + /* x^97280 mod p(x)` << 1, x^97344 mod p(x)` << 1 */ + .octa 0x000000005970e9b00000000122cec508 + + /* x^96256 mod p(x)` << 1, x^96320 mod p(x)` << 1 */ + .octa 0x0000000185b2b7d0000000000a330cda + + /* x^95232 mod p(x)` << 1, x^95296 mod p(x)` << 1 */ + .octa 0x00000001dcee0efc000000014a47148c + + /* x^94208 mod p(x)` << 1, x^94272 mod p(x)` << 1 */ + .octa 0x0000000030da27220000000042c61cb8 + + /* x^93184 mod p(x)` << 1, x^93248 mod p(x)` << 1 */ + .octa 0x000000012f925a180000000012fe6960 + + /* x^92160 mod p(x)` << 1, x^92224 mod p(x)` << 1 */ + .octa 0x00000000dd2e357c00000000dbda2c20 + + /* x^91136 mod p(x)` << 1, x^91200 mod p(x)` << 1 */ + .octa 0x00000000071c80de000000011122410c + + /* x^90112 mod p(x)` << 1, x^90176 mod p(x)` << 1 */ + .octa 0x000000011513140a00000000977b2070 + + /* x^89088 mod p(x)` << 1, x^89152 mod p(x)` << 1 */ + .octa 0x00000001df876e8e000000014050438e + + /* x^88064 mod p(x)` << 1, x^88128 mod p(x)` << 1 */ + .octa 0x000000015f81d6ce0000000147c840e8 + + /* x^87040 mod p(x)` << 1, x^87104 mod p(x)` << 1 */ + .octa 0x000000019dd94dbe00000001cc7c88ce + + /* x^86016 mod p(x)` << 1, x^86080 mod p(x)` << 1 */ + .octa 0x00000001373d206e00000001476b35a4 + + /* x^84992 mod p(x)` << 1, x^85056 mod p(x)` << 1 */ + .octa 0x00000000668ccade000000013d52d508 + + /* x^83968 mod p(x)` << 1, x^84032 mod p(x)` << 1 */ + .octa 0x00000001b192d268000000008e4be32e + + /* x^82944 mod p(x)` << 1, x^83008 mod p(x)` << 1 */ + .octa 0x00000000e30f3a7800000000024120fe + + /* x^81920 mod p(x)` << 1, x^81984 mod p(x)` << 1 */ + .octa 0x000000010ef1f7bc00000000ddecddb4 + + /* x^80896 mod p(x)` << 1, x^80960 mod p(x)` << 1 */ + .octa 0x00000001f5ac738000000000d4d403bc + + /* x^79872 mod p(x)` << 1, x^79936 mod p(x)` << 1 */ + .octa 0x000000011822ea7000000001734b89aa + + /* x^78848 mod p(x)` << 1, x^78912 mod p(x)` << 1 */ + .octa 0x00000000c3a33848000000010e7a58d6 + + /* x^77824 mod p(x)` << 1, x^77888 mod p(x)` << 1 */ + .octa 0x00000001bd151c2400000001f9f04e9c + + /* x^76800 mod p(x)` << 1, x^76864 mod p(x)` << 1 */ + .octa 0x0000000056002d7600000000b692225e + + /* x^75776 mod p(x)` << 1, x^75840 mod p(x)` << 1 */ + .octa 0x000000014657c4f4000000019b8d3f3e + + /* x^74752 mod p(x)` << 1, x^74816 mod p(x)` << 1 */ + .octa 0x0000000113742d7c00000001a874f11e + + /* x^73728 mod p(x)` << 1, x^73792 mod p(x)` << 1 */ + .octa 0x000000019c5920ba000000010d5a4254 + + /* x^72704 mod p(x)` << 1, x^72768 mod p(x)` << 1 */ + .octa 0x000000005216d2d600000000bbb2f5d6 + + /* x^71680 mod p(x)` << 1, x^71744 mod p(x)` << 1 */ + .octa 0x0000000136f5ad8a0000000179cc0e36 + + /* x^70656 mod p(x)` << 1, x^70720 mod p(x)` << 1 */ + .octa 0x000000018b07beb600000001dca1da4a + + /* x^69632 mod p(x)` << 1, x^69696 mod p(x)` << 1 */ + .octa 0x00000000db1e93b000000000feb1a192 + + /* x^68608 mod p(x)` << 1, x^68672 mod p(x)` << 1 */ + .octa 0x000000000b96fa3a00000000d1eeedd6 + + /* x^67584 mod p(x)` << 1, x^67648 mod p(x)` << 1 */ + .octa 0x00000001d9968af0000000008fad9bb4 + + /* x^66560 mod p(x)` << 1, x^66624 mod p(x)` << 1 */ + .octa 0x000000000e4a77a200000001884938e4 + + /* x^65536 mod p(x)` << 1, x^65600 mod p(x)` << 1 */ + .octa 0x00000000508c2ac800000001bc2e9bc0 + + /* x^64512 mod p(x)` << 1, x^64576 mod p(x)` << 1 */ + .octa 0x0000000021572a8000000001f9658a68 + + /* x^63488 mod p(x)` << 1, x^63552 mod p(x)` << 1 */ + .octa 0x00000001b859daf2000000001b9224fc + + /* x^62464 mod p(x)` << 1, x^62528 mod p(x)` << 1 */ + .octa 0x000000016f7884740000000055b2fb84 + + /* x^61440 mod p(x)` << 1, x^61504 mod p(x)` << 1 */ + .octa 0x00000001b438810e000000018b090348 + + /* x^60416 mod p(x)` << 1, x^60480 mod p(x)` << 1 */ + .octa 0x0000000095ddc6f2000000011ccbd5ea + + /* x^59392 mod p(x)` << 1, x^59456 mod p(x)` << 1 */ + .octa 0x00000001d977c20c0000000007ae47f8 + + /* x^58368 mod p(x)` << 1, x^58432 mod p(x)` << 1 */ + .octa 0x00000000ebedb99a0000000172acbec0 + + /* x^57344 mod p(x)` << 1, x^57408 mod p(x)` << 1 */ + .octa 0x00000001df9e9e9200000001c6e3ff20 + + /* x^56320 mod p(x)` << 1, x^56384 mod p(x)` << 1 */ + .octa 0x00000001a4a3f95200000000e1b38744 + + /* x^55296 mod p(x)` << 1, x^55360 mod p(x)` << 1 */ + .octa 0x00000000e2f5122000000000791585b2 + + /* x^54272 mod p(x)` << 1, x^54336 mod p(x)` << 1 */ + .octa 0x000000004aa01f3e00000000ac53b894 + + /* x^53248 mod p(x)` << 1, x^53312 mod p(x)` << 1 */ + .octa 0x00000000b3e90a5800000001ed5f2cf4 + + /* x^52224 mod p(x)` << 1, x^52288 mod p(x)` << 1 */ + .octa 0x000000000c9ca2aa00000001df48b2e0 + + /* x^51200 mod p(x)` << 1, x^51264 mod p(x)` << 1 */ + .octa 0x000000015168231600000000049c1c62 + + /* x^50176 mod p(x)` << 1, x^50240 mod p(x)` << 1 */ + .octa 0x0000000036fce78c000000017c460c12 + + /* x^49152 mod p(x)` << 1, x^49216 mod p(x)` << 1 */ + .octa 0x000000009037dc10000000015be4da7e + + /* x^48128 mod p(x)` << 1, x^48192 mod p(x)` << 1 */ + .octa 0x00000000d3298582000000010f38f668 + + /* x^47104 mod p(x)` << 1, x^47168 mod p(x)` << 1 */ + .octa 0x00000001b42e8ad60000000039f40a00 + + /* x^46080 mod p(x)` << 1, x^46144 mod p(x)` << 1 */ + .octa 0x00000000142a983800000000bd4c10c4 + + /* x^45056 mod p(x)` << 1, x^45120 mod p(x)` << 1 */ + .octa 0x0000000109c7f1900000000042db1d98 + + /* x^44032 mod p(x)` << 1, x^44096 mod p(x)` << 1 */ + .octa 0x0000000056ff931000000001c905bae6 + + /* x^43008 mod p(x)` << 1, x^43072 mod p(x)` << 1 */ + .octa 0x00000001594513aa00000000069d40ea + + /* x^41984 mod p(x)` << 1, x^42048 mod p(x)` << 1 */ + .octa 0x00000001e3b5b1e8000000008e4fbad0 + + /* x^40960 mod p(x)` << 1, x^41024 mod p(x)` << 1 */ + .octa 0x000000011dd5fc080000000047bedd46 + + /* x^39936 mod p(x)` << 1, x^40000 mod p(x)` << 1 */ + .octa 0x00000001675f0cc20000000026396bf8 + + /* x^38912 mod p(x)` << 1, x^38976 mod p(x)` << 1 */ + .octa 0x00000000d1c8dd4400000000379beb92 + + /* x^37888 mod p(x)` << 1, x^37952 mod p(x)` << 1 */ + .octa 0x0000000115ebd3d8000000000abae54a + + /* x^36864 mod p(x)` << 1, x^36928 mod p(x)` << 1 */ + .octa 0x00000001ecbd0dac0000000007e6a128 + + /* x^35840 mod p(x)` << 1, x^35904 mod p(x)` << 1 */ + .octa 0x00000000cdf67af2000000000ade29d2 + + /* x^34816 mod p(x)` << 1, x^34880 mod p(x)` << 1 */ + .octa 0x000000004c01ff4c00000000f974c45c + + /* x^33792 mod p(x)` << 1, x^33856 mod p(x)` << 1 */ + .octa 0x00000000f2d8657e00000000e77ac60a + + /* x^32768 mod p(x)` << 1, x^32832 mod p(x)` << 1 */ + .octa 0x000000006bae74c40000000145895816 + + /* x^31744 mod p(x)` << 1, x^31808 mod p(x)` << 1 */ + .octa 0x0000000152af8aa00000000038e362be + + /* x^30720 mod p(x)` << 1, x^30784 mod p(x)` << 1 */ + .octa 0x0000000004663802000000007f991a64 + + /* x^29696 mod p(x)` << 1, x^29760 mod p(x)` << 1 */ + .octa 0x00000001ab2f5afc00000000fa366d3a + + /* x^28672 mod p(x)` << 1, x^28736 mod p(x)` << 1 */ + .octa 0x0000000074a4ebd400000001a2bb34f0 + + /* x^27648 mod p(x)` << 1, x^27712 mod p(x)` << 1 */ + .octa 0x00000001d7ab3a4c0000000028a9981e + + /* x^26624 mod p(x)` << 1, x^26688 mod p(x)` << 1 */ + .octa 0x00000001a8da60c600000001dbc672be + + /* x^25600 mod p(x)` << 1, x^25664 mod p(x)` << 1 */ + .octa 0x000000013cf6382000000000b04d77f6 + + /* x^24576 mod p(x)` << 1, x^24640 mod p(x)` << 1 */ + .octa 0x00000000bec12e1e0000000124400d96 + + /* x^23552 mod p(x)` << 1, x^23616 mod p(x)` << 1 */ + .octa 0x00000001c6368010000000014ca4b414 + + /* x^22528 mod p(x)` << 1, x^22592 mod p(x)` << 1 */ + .octa 0x00000001e6e78758000000012fe2c938 + + /* x^21504 mod p(x)` << 1, x^21568 mod p(x)` << 1 */ + .octa 0x000000008d7f2b3c00000001faed01e6 + + /* x^20480 mod p(x)` << 1, x^20544 mod p(x)` << 1 */ + .octa 0x000000016b4a156e000000007e80ecfe + + /* x^19456 mod p(x)` << 1, x^19520 mod p(x)` << 1 */ + .octa 0x00000001c63cfeb60000000098daee94 + + /* x^18432 mod p(x)` << 1, x^18496 mod p(x)` << 1 */ + .octa 0x000000015f902670000000010a04edea + + /* x^17408 mod p(x)` << 1, x^17472 mod p(x)` << 1 */ + .octa 0x00000001cd5de11e00000001c00b4524 + + /* x^16384 mod p(x)` << 1, x^16448 mod p(x)` << 1 */ + .octa 0x000000001acaec540000000170296550 + + /* x^15360 mod p(x)` << 1, x^15424 mod p(x)` << 1 */ + .octa 0x000000002bd0ca780000000181afaa48 + + /* x^14336 mod p(x)` << 1, x^14400 mod p(x)` << 1 */ + .octa 0x0000000032d63d5c0000000185a31ffa + + /* x^13312 mod p(x)` << 1, x^13376 mod p(x)` << 1 */ + .octa 0x000000001c6d4e4c000000002469f608 + + /* x^12288 mod p(x)` << 1, x^12352 mod p(x)` << 1 */ + .octa 0x0000000106a60b92000000006980102a + + /* x^11264 mod p(x)` << 1, x^11328 mod p(x)` << 1 */ + .octa 0x00000000d3855e120000000111ea9ca8 + + /* x^10240 mod p(x)` << 1, x^10304 mod p(x)` << 1 */ + .octa 0x00000000e312563600000001bd1d29ce + + /* x^9216 mod p(x)` << 1, x^9280 mod p(x)` << 1 */ + .octa 0x000000009e8f7ea400000001b34b9580 + + /* x^8192 mod p(x)` << 1, x^8256 mod p(x)` << 1 */ + .octa 0x00000001c82e562c000000003076054e + + /* x^7168 mod p(x)` << 1, x^7232 mod p(x)` << 1 */ + .octa 0x00000000ca9f09ce000000012a608ea4 + + /* x^6144 mod p(x)` << 1, x^6208 mod p(x)` << 1 */ + .octa 0x00000000c63764e600000000784d05fe + + /* x^5120 mod p(x)` << 1, x^5184 mod p(x)` << 1 */ + .octa 0x0000000168d2e49e000000016ef0d82a + + /* x^4096 mod p(x)` << 1, x^4160 mod p(x)` << 1 */ + .octa 0x00000000e986c1480000000075bda454 + + /* x^3072 mod p(x)` << 1, x^3136 mod p(x)` << 1 */ + .octa 0x00000000cfb65894000000003dc0a1c4 + + /* x^2048 mod p(x)` << 1, x^2112 mod p(x)` << 1 */ + .octa 0x0000000111cadee400000000e9a5d8be + + /* x^1024 mod p(x)` << 1, x^1088 mod p(x)` << 1 */ + .octa 0x0000000171fb63ce00000001609bc4b4 + +SHORT_CONSTANTS: + + /* Reduce final 1024-2048 bits to 64 bits, shifting 32 bits to include the trailing 32 bits of zeros */ + /* x^1952 mod p(x)`, x^1984 mod p(x)`, x^2016 mod p(x)`, x^2048 mod p(x)` */ + .octa 0x7fec2963e5bf80485cf015c388e56f72 + + /* x^1824 mod p(x)`, x^1856 mod p(x)`, x^1888 mod p(x)`, x^1920 mod p(x)` */ + .octa 0x38e888d4844752a9963a18920246e2e6 + + /* x^1696 mod p(x)`, x^1728 mod p(x)`, x^1760 mod p(x)`, x^1792 mod p(x)` */ + .octa 0x42316c00730206ad419a441956993a31 + + /* x^1568 mod p(x)`, x^1600 mod p(x)`, x^1632 mod p(x)`, x^1664 mod p(x)` */ + .octa 0x543d5c543e65ddf9924752ba2b830011 + + /* x^1440 mod p(x)`, x^1472 mod p(x)`, x^1504 mod p(x)`, x^1536 mod p(x)` */ + .octa 0x78e87aaf56767c9255bd7f9518e4a304 + + /* x^1312 mod p(x)`, x^1344 mod p(x)`, x^1376 mod p(x)`, x^1408 mod p(x)` */ + .octa 0x8f68fcec1903da7f6d76739fe0553f1e + + /* x^1184 mod p(x)`, x^1216 mod p(x)`, x^1248 mod p(x)`, x^1280 mod p(x)` */ + .octa 0x3f4840246791d588c133722b1fe0b5c3 + + /* x^1056 mod p(x)`, x^1088 mod p(x)`, x^1120 mod p(x)`, x^1152 mod p(x)` */ + .octa 0x34c96751b04de25a64b67ee0e55ef1f3 + + /* x^928 mod p(x)`, x^960 mod p(x)`, x^992 mod p(x)`, x^1024 mod p(x)` */ + .octa 0x156c8e180b4a395b069db049b8fdb1e7 + + /* x^800 mod p(x)`, x^832 mod p(x)`, x^864 mod p(x)`, x^896 mod p(x)` */ + .octa 0xe0b99ccbe661f7bea11bfaf3c9e90b9e + + /* x^672 mod p(x)`, x^704 mod p(x)`, x^736 mod p(x)`, x^768 mod p(x)` */ + .octa 0x041d37768cd75659817cdc5119b29a35 + + /* x^544 mod p(x)`, x^576 mod p(x)`, x^608 mod p(x)`, x^640 mod p(x)` */ + .octa 0x3a0777818cfaa9651ce9d94b36c41f1c + + /* x^416 mod p(x)`, x^448 mod p(x)`, x^480 mod p(x)`, x^512 mod p(x)` */ + .octa 0x0e148e8252377a554f256efcb82be955 + + /* x^288 mod p(x)`, x^320 mod p(x)`, x^352 mod p(x)`, x^384 mod p(x)` */ + .octa 0x9c25531d19e65ddeec1631edb2dea967 + + /* x^160 mod p(x)`, x^192 mod p(x)`, x^224 mod p(x)`, x^256 mod p(x)` */ + .octa 0x790606ff9957c0a65d27e147510ac59a + + /* x^32 mod p(x)`, x^64 mod p(x)`, x^96 mod p(x)`, x^128 mod p(x)` */ + .octa 0x82f63b786ea2d55ca66805eb18b8ea18 + + +BARRETT_CONSTANTS: + /* 33 bit reflected Barrett constant m - (4^32)/n */ + .octa 0x000000000000000000000000dea713f1 /* x^64 div p(x)` */ + /* 33 bit reflected Barrett constant n */ + .octa 0x00000000000000000000000105ec76f1 + +#endif /* __powerpc__ */ + +#endif diff --git a/extra/crc32-vpmsum/crc32c_wrapper.c b/extra/crc32-vpmsum/crc32c_wrapper.c new file mode 100644 index 00000000000..b121d3e8c41 --- /dev/null +++ b/extra/crc32-vpmsum/crc32c_wrapper.c @@ -0,0 +1,78 @@ +#ifdef __powerpc__ + +#define F crc32c_vpmsum +#define __F __crc32c_vpmsum + +#define CRC 0x1edc6f41 + +static const unsigned int crc_table[] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,}; + + +#include "crc32_wrapper.ic" + +#endif + diff --git a/extra/crc32-vpmsum/crc32ieee.S b/extra/crc32-vpmsum/crc32ieee.S new file mode 100644 index 00000000000..42c4f77630f --- /dev/null +++ b/extra/crc32-vpmsum/crc32ieee.S @@ -0,0 +1,14 @@ +#ifdef __powerpc__ + +#define CONSTANTS .crc32_constants +#define SHORT_CONSTANTS .crc32_short_constants +#define BARRETT_CONSTANTS .crc32_barrett_constants + +#include "crc32ieee_constants.h" + +#define __F __crc32ieee_vpmsum + +#include "crc32.iS" + +#endif + diff --git a/extra/crc32-vpmsum/crc32ieee_constants.h b/extra/crc32-vpmsum/crc32ieee_constants.h new file mode 100644 index 00000000000..a99b1c0d859 --- /dev/null +++ b/extra/crc32-vpmsum/crc32ieee_constants.h @@ -0,0 +1,835 @@ +#ifndef CRC32_CONSTANTS_H +#define CRC32_CONSTANTS_H + +#ifdef __powerpc__ + +#define MAX_SIZE 32768 +CONSTANTS: + + /* Reduce 262144 kbits to 1024 bits */ + /* x^261120 mod p(x)` << 1, x^261184 mod p(x)` << 1 */ + .octa 0x00000001651797d20000000099ea94a8 + + /* x^260096 mod p(x)` << 1, x^260160 mod p(x)` << 1 */ + .octa 0x0000000021e0d56c00000000945a8420 + + /* x^259072 mod p(x)` << 1, x^259136 mod p(x)` << 1 */ + .octa 0x000000000f95ecaa0000000030762706 + + /* x^258048 mod p(x)` << 1, x^258112 mod p(x)` << 1 */ + .octa 0x00000001ebd224ac00000001a52fc582 + + /* x^257024 mod p(x)` << 1, x^257088 mod p(x)` << 1 */ + .octa 0x000000000ccb97ca00000001a4a7167a + + /* x^256000 mod p(x)` << 1, x^256064 mod p(x)` << 1 */ + .octa 0x00000001006ec8a8000000000c18249a + + /* x^254976 mod p(x)` << 1, x^255040 mod p(x)` << 1 */ + .octa 0x000000014f58f19600000000a924ae7c + + /* x^253952 mod p(x)` << 1, x^254016 mod p(x)` << 1 */ + .octa 0x00000001a7192ca600000001e12ccc12 + + /* x^252928 mod p(x)` << 1, x^252992 mod p(x)` << 1 */ + .octa 0x000000019a64bab200000000a0b9d4ac + + /* x^251904 mod p(x)` << 1, x^251968 mod p(x)` << 1 */ + .octa 0x0000000014f4ed2e0000000095e8ddfe + + /* x^250880 mod p(x)` << 1, x^250944 mod p(x)` << 1 */ + .octa 0x000000011092b6a200000000233fddc4 + + /* x^249856 mod p(x)` << 1, x^249920 mod p(x)` << 1 */ + .octa 0x00000000c8a1629c00000001b4529b62 + + /* x^248832 mod p(x)` << 1, x^248896 mod p(x)` << 1 */ + .octa 0x000000017bf32e8e00000001a7fa0e64 + + /* x^247808 mod p(x)` << 1, x^247872 mod p(x)` << 1 */ + .octa 0x00000001f8cc658200000001b5334592 + + /* x^246784 mod p(x)` << 1, x^246848 mod p(x)` << 1 */ + .octa 0x000000008631ddf0000000011f8ee1b4 + + /* x^245760 mod p(x)` << 1, x^245824 mod p(x)` << 1 */ + .octa 0x000000007e5a76d0000000006252e632 + + /* x^244736 mod p(x)` << 1, x^244800 mod p(x)` << 1 */ + .octa 0x000000002b09b31c00000000ab973e84 + + /* x^243712 mod p(x)` << 1, x^243776 mod p(x)` << 1 */ + .octa 0x00000001b2df1f84000000007734f5ec + + /* x^242688 mod p(x)` << 1, x^242752 mod p(x)` << 1 */ + .octa 0x00000001d6f56afc000000007c547798 + + /* x^241664 mod p(x)` << 1, x^241728 mod p(x)` << 1 */ + .octa 0x00000001b9b5e70c000000007ec40210 + + /* x^240640 mod p(x)` << 1, x^240704 mod p(x)` << 1 */ + .octa 0x0000000034b626d200000001ab1695a8 + + /* x^239616 mod p(x)` << 1, x^239680 mod p(x)` << 1 */ + .octa 0x000000014c53479a0000000090494bba + + /* x^238592 mod p(x)` << 1, x^238656 mod p(x)` << 1 */ + .octa 0x00000001a6d179a400000001123fb816 + + /* x^237568 mod p(x)` << 1, x^237632 mod p(x)` << 1 */ + .octa 0x000000015abd16b400000001e188c74c + + /* x^236544 mod p(x)` << 1, x^236608 mod p(x)` << 1 */ + .octa 0x00000000018f985200000001c2d3451c + + /* x^235520 mod p(x)` << 1, x^235584 mod p(x)` << 1 */ + .octa 0x000000001fb3084a00000000f55cf1ca + + /* x^234496 mod p(x)` << 1, x^234560 mod p(x)` << 1 */ + .octa 0x00000000c53dfb0400000001a0531540 + + /* x^233472 mod p(x)` << 1, x^233536 mod p(x)` << 1 */ + .octa 0x00000000e10c9ad60000000132cd7ebc + + /* x^232448 mod p(x)` << 1, x^232512 mod p(x)` << 1 */ + .octa 0x0000000025aa994a0000000073ab7f36 + + /* x^231424 mod p(x)` << 1, x^231488 mod p(x)` << 1 */ + .octa 0x00000000fa3a74c40000000041aed1c2 + + /* x^230400 mod p(x)` << 1, x^230464 mod p(x)` << 1 */ + .octa 0x0000000033eb3f400000000136c53800 + + /* x^229376 mod p(x)` << 1, x^229440 mod p(x)` << 1 */ + .octa 0x000000017193f2960000000126835a30 + + /* x^228352 mod p(x)` << 1, x^228416 mod p(x)` << 1 */ + .octa 0x0000000043f6c86a000000006241b502 + + /* x^227328 mod p(x)` << 1, x^227392 mod p(x)` << 1 */ + .octa 0x000000016b513ec600000000d5196ad4 + + /* x^226304 mod p(x)` << 1, x^226368 mod p(x)` << 1 */ + .octa 0x00000000c8f25b4e000000009cfa769a + + /* x^225280 mod p(x)` << 1, x^225344 mod p(x)` << 1 */ + .octa 0x00000001a45048ec00000000920e5df4 + + /* x^224256 mod p(x)` << 1, x^224320 mod p(x)` << 1 */ + .octa 0x000000000c4410040000000169dc310e + + /* x^223232 mod p(x)` << 1, x^223296 mod p(x)` << 1 */ + .octa 0x000000000e17cad60000000009fc331c + + /* x^222208 mod p(x)` << 1, x^222272 mod p(x)` << 1 */ + .octa 0x00000001253ae964000000010d94a81e + + /* x^221184 mod p(x)` << 1, x^221248 mod p(x)` << 1 */ + .octa 0x00000001d7c88ebc0000000027a20ab2 + + /* x^220160 mod p(x)` << 1, x^220224 mod p(x)` << 1 */ + .octa 0x00000001e7ca913a0000000114f87504 + + /* x^219136 mod p(x)` << 1, x^219200 mod p(x)` << 1 */ + .octa 0x0000000033ed078a000000004b076d96 + + /* x^218112 mod p(x)` << 1, x^218176 mod p(x)` << 1 */ + .octa 0x00000000e1839c7800000000da4d1e74 + + /* x^217088 mod p(x)` << 1, x^217152 mod p(x)` << 1 */ + .octa 0x00000001322b267e000000001b81f672 + + /* x^216064 mod p(x)` << 1, x^216128 mod p(x)` << 1 */ + .octa 0x00000000638231b6000000009367c988 + + /* x^215040 mod p(x)` << 1, x^215104 mod p(x)` << 1 */ + .octa 0x00000001ee7f16f400000001717214ca + + /* x^214016 mod p(x)` << 1, x^214080 mod p(x)` << 1 */ + .octa 0x0000000117d9924a000000009f47d820 + + /* x^212992 mod p(x)` << 1, x^213056 mod p(x)` << 1 */ + .octa 0x00000000e1a9e0c4000000010d9a47d2 + + /* x^211968 mod p(x)` << 1, x^212032 mod p(x)` << 1 */ + .octa 0x00000001403731dc00000000a696c58c + + /* x^210944 mod p(x)` << 1, x^211008 mod p(x)` << 1 */ + .octa 0x00000001a5ea9682000000002aa28ec6 + + /* x^209920 mod p(x)` << 1, x^209984 mod p(x)` << 1 */ + .octa 0x0000000101c5c57800000001fe18fd9a + + /* x^208896 mod p(x)` << 1, x^208960 mod p(x)` << 1 */ + .octa 0x00000000dddf6494000000019d4fc1ae + + /* x^207872 mod p(x)` << 1, x^207936 mod p(x)` << 1 */ + .octa 0x00000000f1c3db2800000001ba0e3dea + + /* x^206848 mod p(x)` << 1, x^206912 mod p(x)` << 1 */ + .octa 0x000000013112fb9c0000000074b59a5e + + /* x^205824 mod p(x)` << 1, x^205888 mod p(x)` << 1 */ + .octa 0x00000000b680b90600000000f2b5ea98 + + /* x^204800 mod p(x)` << 1, x^204864 mod p(x)` << 1 */ + .octa 0x000000001a2829320000000187132676 + + /* x^203776 mod p(x)` << 1, x^203840 mod p(x)` << 1 */ + .octa 0x0000000089406e7e000000010a8c6ad4 + + /* x^202752 mod p(x)` << 1, x^202816 mod p(x)` << 1 */ + .octa 0x00000001def6be8c00000001e21dfe70 + + /* x^201728 mod p(x)` << 1, x^201792 mod p(x)` << 1 */ + .octa 0x000000007525872800000001da0050e4 + + /* x^200704 mod p(x)` << 1, x^200768 mod p(x)` << 1 */ + .octa 0x000000019536090a00000000772172ae + + /* x^199680 mod p(x)` << 1, x^199744 mod p(x)` << 1 */ + .octa 0x00000000f2455bfc00000000e47724aa + + /* x^198656 mod p(x)` << 1, x^198720 mod p(x)` << 1 */ + .octa 0x000000018c40baf4000000003cd63ac4 + + /* x^197632 mod p(x)` << 1, x^197696 mod p(x)` << 1 */ + .octa 0x000000004cd390d400000001bf47d352 + + /* x^196608 mod p(x)` << 1, x^196672 mod p(x)` << 1 */ + .octa 0x00000001e4ece95a000000018dc1d708 + + /* x^195584 mod p(x)` << 1, x^195648 mod p(x)` << 1 */ + .octa 0x000000001a3ee918000000002d4620a4 + + /* x^194560 mod p(x)` << 1, x^194624 mod p(x)` << 1 */ + .octa 0x000000007c652fb80000000058fd1740 + + /* x^193536 mod p(x)` << 1, x^193600 mod p(x)` << 1 */ + .octa 0x000000011c67842c00000000dadd9bfc + + /* x^192512 mod p(x)` << 1, x^192576 mod p(x)` << 1 */ + .octa 0x00000000254f759c00000001ea2140be + + /* x^191488 mod p(x)` << 1, x^191552 mod p(x)` << 1 */ + .octa 0x000000007ece94ca000000009de128ba + + /* x^190464 mod p(x)` << 1, x^190528 mod p(x)` << 1 */ + .octa 0x0000000038f258c2000000013ac3aa8e + + /* x^189440 mod p(x)` << 1, x^189504 mod p(x)` << 1 */ + .octa 0x00000001cdf17b000000000099980562 + + /* x^188416 mod p(x)` << 1, x^188480 mod p(x)` << 1 */ + .octa 0x000000011f882c1600000001c1579c86 + + /* x^187392 mod p(x)` << 1, x^187456 mod p(x)` << 1 */ + .octa 0x0000000100093fc80000000068dbbf94 + + /* x^186368 mod p(x)` << 1, x^186432 mod p(x)` << 1 */ + .octa 0x00000001cd684f16000000004509fb04 + + /* x^185344 mod p(x)` << 1, x^185408 mod p(x)` << 1 */ + .octa 0x000000004bc6a70a00000001202f6398 + + /* x^184320 mod p(x)` << 1, x^184384 mod p(x)` << 1 */ + .octa 0x000000004fc7e8e4000000013aea243e + + /* x^183296 mod p(x)` << 1, x^183360 mod p(x)` << 1 */ + .octa 0x0000000130103f1c00000001b4052ae6 + + /* x^182272 mod p(x)` << 1, x^182336 mod p(x)` << 1 */ + .octa 0x0000000111b0024c00000001cd2a0ae8 + + /* x^181248 mod p(x)` << 1, x^181312 mod p(x)` << 1 */ + .octa 0x000000010b3079da00000001fe4aa8b4 + + /* x^180224 mod p(x)` << 1, x^180288 mod p(x)` << 1 */ + .octa 0x000000010192bcc200000001d1559a42 + + /* x^179200 mod p(x)` << 1, x^179264 mod p(x)` << 1 */ + .octa 0x0000000074838d5000000001f3e05ecc + + /* x^178176 mod p(x)` << 1, x^178240 mod p(x)` << 1 */ + .octa 0x000000001b20f5200000000104ddd2cc + + /* x^177152 mod p(x)` << 1, x^177216 mod p(x)` << 1 */ + .octa 0x0000000050c3590a000000015393153c + + /* x^176128 mod p(x)` << 1, x^176192 mod p(x)` << 1 */ + .octa 0x00000000b41cac8e0000000057e942c6 + + /* x^175104 mod p(x)` << 1, x^175168 mod p(x)` << 1 */ + .octa 0x000000000c72cc78000000012c633850 + + /* x^174080 mod p(x)` << 1, x^174144 mod p(x)` << 1 */ + .octa 0x0000000030cdb03200000000ebcaae4c + + /* x^173056 mod p(x)` << 1, x^173120 mod p(x)` << 1 */ + .octa 0x000000013e09fc32000000013ee532a6 + + /* x^172032 mod p(x)` << 1, x^172096 mod p(x)` << 1 */ + .octa 0x000000001ed624d200000001bf0cbc7e + + /* x^171008 mod p(x)` << 1, x^171072 mod p(x)` << 1 */ + .octa 0x00000000781aee1a00000000d50b7a5a + + /* x^169984 mod p(x)` << 1, x^170048 mod p(x)` << 1 */ + .octa 0x00000001c4d8348c0000000002fca6e8 + + /* x^168960 mod p(x)` << 1, x^169024 mod p(x)` << 1 */ + .octa 0x0000000057a40336000000007af40044 + + /* x^167936 mod p(x)` << 1, x^168000 mod p(x)` << 1 */ + .octa 0x00000000855449400000000016178744 + + /* x^166912 mod p(x)` << 1, x^166976 mod p(x)` << 1 */ + .octa 0x000000019cd21e80000000014c177458 + + /* x^165888 mod p(x)` << 1, x^165952 mod p(x)` << 1 */ + .octa 0x000000013eb95bc0000000011b6ddf04 + + /* x^164864 mod p(x)` << 1, x^164928 mod p(x)` << 1 */ + .octa 0x00000001dfc9fdfc00000001f3e29ccc + + /* x^163840 mod p(x)` << 1, x^163904 mod p(x)` << 1 */ + .octa 0x00000000cd028bc20000000135ae7562 + + /* x^162816 mod p(x)` << 1, x^162880 mod p(x)` << 1 */ + .octa 0x0000000090db8c440000000190ef812c + + /* x^161792 mod p(x)` << 1, x^161856 mod p(x)` << 1 */ + .octa 0x000000010010a4ce0000000067a2c786 + + /* x^160768 mod p(x)` << 1, x^160832 mod p(x)` << 1 */ + .octa 0x00000001c8f4c72c0000000048b9496c + + /* x^159744 mod p(x)` << 1, x^159808 mod p(x)` << 1 */ + .octa 0x000000001c26170c000000015a422de6 + + /* x^158720 mod p(x)` << 1, x^158784 mod p(x)` << 1 */ + .octa 0x00000000e3fccf6800000001ef0e3640 + + /* x^157696 mod p(x)` << 1, x^157760 mod p(x)` << 1 */ + .octa 0x00000000d513ed2400000001006d2d26 + + /* x^156672 mod p(x)` << 1, x^156736 mod p(x)` << 1 */ + .octa 0x00000000141beada00000001170d56d6 + + /* x^155648 mod p(x)` << 1, x^155712 mod p(x)` << 1 */ + .octa 0x000000011071aea000000000a5fb613c + + /* x^154624 mod p(x)` << 1, x^154688 mod p(x)` << 1 */ + .octa 0x000000012e19080a0000000040bbf7fc + + /* x^153600 mod p(x)` << 1, x^153664 mod p(x)` << 1 */ + .octa 0x0000000100ecf826000000016ac3a5b2 + + /* x^152576 mod p(x)` << 1, x^152640 mod p(x)` << 1 */ + .octa 0x0000000069b0941200000000abf16230 + + /* x^151552 mod p(x)` << 1, x^151616 mod p(x)` << 1 */ + .octa 0x0000000122297bac00000001ebe23fac + + /* x^150528 mod p(x)` << 1, x^150592 mod p(x)` << 1 */ + .octa 0x00000000e9e4b068000000008b6a0894 + + /* x^149504 mod p(x)` << 1, x^149568 mod p(x)` << 1 */ + .octa 0x000000004b38651a00000001288ea478 + + /* x^148480 mod p(x)` << 1, x^148544 mod p(x)` << 1 */ + .octa 0x00000001468360e2000000016619c442 + + /* x^147456 mod p(x)` << 1, x^147520 mod p(x)` << 1 */ + .octa 0x00000000121c24080000000086230038 + + /* x^146432 mod p(x)` << 1, x^146496 mod p(x)` << 1 */ + .octa 0x00000000da7e7d08000000017746a756 + + /* x^145408 mod p(x)` << 1, x^145472 mod p(x)` << 1 */ + .octa 0x00000001058d76520000000191b8f8f8 + + /* x^144384 mod p(x)` << 1, x^144448 mod p(x)` << 1 */ + .octa 0x000000014a098a90000000008e167708 + + /* x^143360 mod p(x)` << 1, x^143424 mod p(x)` << 1 */ + .octa 0x0000000020dbe72e0000000148b22d54 + + /* x^142336 mod p(x)` << 1, x^142400 mod p(x)` << 1 */ + .octa 0x000000011e7323e80000000044ba2c3c + + /* x^141312 mod p(x)` << 1, x^141376 mod p(x)` << 1 */ + .octa 0x00000000d5d4bf9400000000b54d2b52 + + /* x^140288 mod p(x)` << 1, x^140352 mod p(x)` << 1 */ + .octa 0x0000000199d8746c0000000005a4fd8a + + /* x^139264 mod p(x)` << 1, x^139328 mod p(x)` << 1 */ + .octa 0x00000000ce9ca8a00000000139f9fc46 + + /* x^138240 mod p(x)` << 1, x^138304 mod p(x)` << 1 */ + .octa 0x00000000136edece000000015a1fa824 + + /* x^137216 mod p(x)` << 1, x^137280 mod p(x)` << 1 */ + .octa 0x000000019b92a068000000000a61ae4c + + /* x^136192 mod p(x)` << 1, x^136256 mod p(x)` << 1 */ + .octa 0x0000000071d622060000000145e9113e + + /* x^135168 mod p(x)` << 1, x^135232 mod p(x)` << 1 */ + .octa 0x00000000dfc50158000000006a348448 + + /* x^134144 mod p(x)` << 1, x^134208 mod p(x)` << 1 */ + .octa 0x00000001517626bc000000004d80a08c + + /* x^133120 mod p(x)` << 1, x^133184 mod p(x)` << 1 */ + .octa 0x0000000148d1e4fa000000014b6837a0 + + /* x^132096 mod p(x)` << 1, x^132160 mod p(x)` << 1 */ + .octa 0x0000000094d8266e000000016896a7fc + + /* x^131072 mod p(x)` << 1, x^131136 mod p(x)` << 1 */ + .octa 0x00000000606c5e34000000014f187140 + + /* x^130048 mod p(x)` << 1, x^130112 mod p(x)` << 1 */ + .octa 0x000000019766beaa000000019581b9da + + /* x^129024 mod p(x)` << 1, x^129088 mod p(x)` << 1 */ + .octa 0x00000001d80c506c00000001091bc984 + + /* x^128000 mod p(x)` << 1, x^128064 mod p(x)` << 1 */ + .octa 0x000000001e73837c000000001067223c + + /* x^126976 mod p(x)` << 1, x^127040 mod p(x)` << 1 */ + .octa 0x0000000064d587de00000001ab16ea02 + + /* x^125952 mod p(x)` << 1, x^126016 mod p(x)` << 1 */ + .octa 0x00000000f4a507b0000000013c4598a8 + + /* x^124928 mod p(x)` << 1, x^124992 mod p(x)` << 1 */ + .octa 0x0000000040e342fc00000000b3735430 + + /* x^123904 mod p(x)` << 1, x^123968 mod p(x)` << 1 */ + .octa 0x00000001d5ad9c3a00000001bb3fc0c0 + + /* x^122880 mod p(x)` << 1, x^122944 mod p(x)` << 1 */ + .octa 0x0000000094a691a400000001570ae19c + + /* x^121856 mod p(x)` << 1, x^121920 mod p(x)` << 1 */ + .octa 0x00000001271ecdfa00000001ea910712 + + /* x^120832 mod p(x)` << 1, x^120896 mod p(x)` << 1 */ + .octa 0x000000009e54475a0000000167127128 + + /* x^119808 mod p(x)` << 1, x^119872 mod p(x)` << 1 */ + .octa 0x00000000c9c099ee0000000019e790a2 + + /* x^118784 mod p(x)` << 1, x^118848 mod p(x)` << 1 */ + .octa 0x000000009a2f736c000000003788f710 + + /* x^117760 mod p(x)` << 1, x^117824 mod p(x)` << 1 */ + .octa 0x00000000bb9f499600000001682a160e + + /* x^116736 mod p(x)` << 1, x^116800 mod p(x)` << 1 */ + .octa 0x00000001db688050000000007f0ebd2e + + /* x^115712 mod p(x)` << 1, x^115776 mod p(x)` << 1 */ + .octa 0x00000000e9b10af4000000002b032080 + + /* x^114688 mod p(x)` << 1, x^114752 mod p(x)` << 1 */ + .octa 0x000000012d4545e400000000cfd1664a + + /* x^113664 mod p(x)` << 1, x^113728 mod p(x)` << 1 */ + .octa 0x000000000361139c00000000aa1181c2 + + /* x^112640 mod p(x)` << 1, x^112704 mod p(x)` << 1 */ + .octa 0x00000001a5a1a3a800000000ddd08002 + + /* x^111616 mod p(x)` << 1, x^111680 mod p(x)` << 1 */ + .octa 0x000000006844e0b000000000e8dd0446 + + /* x^110592 mod p(x)` << 1, x^110656 mod p(x)` << 1 */ + .octa 0x00000000c3762f2800000001bbd94a00 + + /* x^109568 mod p(x)` << 1, x^109632 mod p(x)` << 1 */ + .octa 0x00000001d26287a200000000ab6cd180 + + /* x^108544 mod p(x)` << 1, x^108608 mod p(x)` << 1 */ + .octa 0x00000001f6f0bba80000000031803ce2 + + /* x^107520 mod p(x)` << 1, x^107584 mod p(x)` << 1 */ + .octa 0x000000002ffabd620000000024f40b0c + + /* x^106496 mod p(x)` << 1, x^106560 mod p(x)` << 1 */ + .octa 0x00000000fb4516b800000001ba1d9834 + + /* x^105472 mod p(x)` << 1, x^105536 mod p(x)` << 1 */ + .octa 0x000000018cfa961c0000000104de61aa + + /* x^104448 mod p(x)` << 1, x^104512 mod p(x)` << 1 */ + .octa 0x000000019e588d520000000113e40d46 + + /* x^103424 mod p(x)` << 1, x^103488 mod p(x)` << 1 */ + .octa 0x00000001180f0bbc00000001415598a0 + + /* x^102400 mod p(x)` << 1, x^102464 mod p(x)` << 1 */ + .octa 0x00000000e1d9177a00000000bf6c8c90 + + /* x^101376 mod p(x)` << 1, x^101440 mod p(x)` << 1 */ + .octa 0x0000000105abc27c00000001788b0504 + + /* x^100352 mod p(x)` << 1, x^100416 mod p(x)` << 1 */ + .octa 0x00000000972e4a580000000038385d02 + + /* x^99328 mod p(x)` << 1, x^99392 mod p(x)` << 1 */ + .octa 0x0000000183499a5e00000001b6c83844 + + /* x^98304 mod p(x)` << 1, x^98368 mod p(x)` << 1 */ + .octa 0x00000001c96a8cca0000000051061a8a + + /* x^97280 mod p(x)` << 1, x^97344 mod p(x)` << 1 */ + .octa 0x00000001a1a5b60c000000017351388a + + /* x^96256 mod p(x)` << 1, x^96320 mod p(x)` << 1 */ + .octa 0x00000000e4b6ac9c0000000132928f92 + + /* x^95232 mod p(x)` << 1, x^95296 mod p(x)` << 1 */ + .octa 0x00000001807e7f5a00000000e6b4f48a + + /* x^94208 mod p(x)` << 1, x^94272 mod p(x)` << 1 */ + .octa 0x000000017a7e3bc80000000039d15e90 + + /* x^93184 mod p(x)` << 1, x^93248 mod p(x)` << 1 */ + .octa 0x00000000d73975da00000000312d6074 + + /* x^92160 mod p(x)` << 1, x^92224 mod p(x)` << 1 */ + .octa 0x000000017375d038000000017bbb2cc4 + + /* x^91136 mod p(x)` << 1, x^91200 mod p(x)` << 1 */ + .octa 0x00000000193680bc000000016ded3e18 + + /* x^90112 mod p(x)` << 1, x^90176 mod p(x)` << 1 */ + .octa 0x00000000999b06f600000000f1638b16 + + /* x^89088 mod p(x)` << 1, x^89152 mod p(x)` << 1 */ + .octa 0x00000001f685d2b800000001d38b9ecc + + /* x^88064 mod p(x)` << 1, x^88128 mod p(x)` << 1 */ + .octa 0x00000001f4ecbed2000000018b8d09dc + + /* x^87040 mod p(x)` << 1, x^87104 mod p(x)` << 1 */ + .octa 0x00000000ba16f1a000000000e7bc27d2 + + /* x^86016 mod p(x)` << 1, x^86080 mod p(x)` << 1 */ + .octa 0x0000000115aceac400000000275e1e96 + + /* x^84992 mod p(x)` << 1, x^85056 mod p(x)` << 1 */ + .octa 0x00000001aeff629200000000e2e3031e + + /* x^83968 mod p(x)` << 1, x^84032 mod p(x)` << 1 */ + .octa 0x000000009640124c00000001041c84d8 + + /* x^82944 mod p(x)` << 1, x^83008 mod p(x)` << 1 */ + .octa 0x0000000114f41f0200000000706ce672 + + /* x^81920 mod p(x)` << 1, x^81984 mod p(x)` << 1 */ + .octa 0x000000009c5f3586000000015d5070da + + /* x^80896 mod p(x)` << 1, x^80960 mod p(x)` << 1 */ + .octa 0x00000001878275fa0000000038f9493a + + /* x^79872 mod p(x)` << 1, x^79936 mod p(x)` << 1 */ + .octa 0x00000000ddc42ce800000000a3348a76 + + /* x^78848 mod p(x)` << 1, x^78912 mod p(x)` << 1 */ + .octa 0x0000000181d2c73a00000001ad0aab92 + + /* x^77824 mod p(x)` << 1, x^77888 mod p(x)` << 1 */ + .octa 0x0000000141c9320a000000019e85f712 + + /* x^76800 mod p(x)` << 1, x^76864 mod p(x)` << 1 */ + .octa 0x000000015235719a000000005a871e76 + + /* x^75776 mod p(x)` << 1, x^75840 mod p(x)` << 1 */ + .octa 0x00000000be27d804000000017249c662 + + /* x^74752 mod p(x)` << 1, x^74816 mod p(x)` << 1 */ + .octa 0x000000006242d45a000000003a084712 + + /* x^73728 mod p(x)` << 1, x^73792 mod p(x)` << 1 */ + .octa 0x000000009a53638e00000000ed438478 + + /* x^72704 mod p(x)` << 1, x^72768 mod p(x)` << 1 */ + .octa 0x00000001001ecfb600000000abac34cc + + /* x^71680 mod p(x)` << 1, x^71744 mod p(x)` << 1 */ + .octa 0x000000016d7c2d64000000005f35ef3e + + /* x^70656 mod p(x)` << 1, x^70720 mod p(x)` << 1 */ + .octa 0x00000001d0ce46c00000000047d6608c + + /* x^69632 mod p(x)` << 1, x^69696 mod p(x)` << 1 */ + .octa 0x0000000124c907b4000000002d01470e + + /* x^68608 mod p(x)` << 1, x^68672 mod p(x)` << 1 */ + .octa 0x0000000018a555ca0000000158bbc7b0 + + /* x^67584 mod p(x)` << 1, x^67648 mod p(x)` << 1 */ + .octa 0x000000006b0980bc00000000c0a23e8e + + /* x^66560 mod p(x)` << 1, x^66624 mod p(x)` << 1 */ + .octa 0x000000008bbba96400000001ebd85c88 + + /* x^65536 mod p(x)` << 1, x^65600 mod p(x)` << 1 */ + .octa 0x00000001070a5a1e000000019ee20bb2 + + /* x^64512 mod p(x)` << 1, x^64576 mod p(x)` << 1 */ + .octa 0x000000002204322a00000001acabf2d6 + + /* x^63488 mod p(x)` << 1, x^63552 mod p(x)` << 1 */ + .octa 0x00000000a27524d000000001b7963d56 + + /* x^62464 mod p(x)` << 1, x^62528 mod p(x)` << 1 */ + .octa 0x0000000020b1e4ba000000017bffa1fe + + /* x^61440 mod p(x)` << 1, x^61504 mod p(x)` << 1 */ + .octa 0x0000000032cc27fc000000001f15333e + + /* x^60416 mod p(x)` << 1, x^60480 mod p(x)` << 1 */ + .octa 0x0000000044dd22b8000000018593129e + + /* x^59392 mod p(x)` << 1, x^59456 mod p(x)` << 1 */ + .octa 0x00000000dffc9e0a000000019cb32602 + + /* x^58368 mod p(x)` << 1, x^58432 mod p(x)` << 1 */ + .octa 0x00000001b7a0ed140000000142b05cc8 + + /* x^57344 mod p(x)` << 1, x^57408 mod p(x)` << 1 */ + .octa 0x00000000c784248800000001be49e7a4 + + /* x^56320 mod p(x)` << 1, x^56384 mod p(x)` << 1 */ + .octa 0x00000001c02a4fee0000000108f69d6c + + /* x^55296 mod p(x)` << 1, x^55360 mod p(x)` << 1 */ + .octa 0x000000003c273778000000006c0971f0 + + /* x^54272 mod p(x)` << 1, x^54336 mod p(x)` << 1 */ + .octa 0x00000001d63f8894000000005b16467a + + /* x^53248 mod p(x)` << 1, x^53312 mod p(x)` << 1 */ + .octa 0x000000006be557d600000001551a628e + + /* x^52224 mod p(x)` << 1, x^52288 mod p(x)` << 1 */ + .octa 0x000000006a7806ea000000019e42ea92 + + /* x^51200 mod p(x)` << 1, x^51264 mod p(x)` << 1 */ + .octa 0x000000016155aa0c000000012fa83ff2 + + /* x^50176 mod p(x)` << 1, x^50240 mod p(x)` << 1 */ + .octa 0x00000000908650ac000000011ca9cde0 + + /* x^49152 mod p(x)` << 1, x^49216 mod p(x)` << 1 */ + .octa 0x00000000aa5a808400000000c8e5cd74 + + /* x^48128 mod p(x)` << 1, x^48192 mod p(x)` << 1 */ + .octa 0x0000000191bb500a0000000096c27f0c + + /* x^47104 mod p(x)` << 1, x^47168 mod p(x)` << 1 */ + .octa 0x0000000064e9bed0000000002baed926 + + /* x^46080 mod p(x)` << 1, x^46144 mod p(x)` << 1 */ + .octa 0x000000009444f302000000017c8de8d2 + + /* x^45056 mod p(x)` << 1, x^45120 mod p(x)` << 1 */ + .octa 0x000000019db07d3c00000000d43d6068 + + /* x^44032 mod p(x)` << 1, x^44096 mod p(x)` << 1 */ + .octa 0x00000001359e3e6e00000000cb2c4b26 + + /* x^43008 mod p(x)` << 1, x^43072 mod p(x)` << 1 */ + .octa 0x00000001e4f10dd20000000145b8da26 + + /* x^41984 mod p(x)` << 1, x^42048 mod p(x)` << 1 */ + .octa 0x0000000124f5735e000000018fff4b08 + + /* x^40960 mod p(x)` << 1, x^41024 mod p(x)` << 1 */ + .octa 0x0000000124760a4c0000000150b58ed0 + + /* x^39936 mod p(x)` << 1, x^40000 mod p(x)` << 1 */ + .octa 0x000000000f1fc18600000001549f39bc + + /* x^38912 mod p(x)` << 1, x^38976 mod p(x)` << 1 */ + .octa 0x00000000150e4cc400000000ef4d2f42 + + /* x^37888 mod p(x)` << 1, x^37952 mod p(x)` << 1 */ + .octa 0x000000002a6204e800000001b1468572 + + /* x^36864 mod p(x)` << 1, x^36928 mod p(x)` << 1 */ + .octa 0x00000000beb1d432000000013d7403b2 + + /* x^35840 mod p(x)` << 1, x^35904 mod p(x)` << 1 */ + .octa 0x0000000135f3f1f000000001a4681842 + + /* x^34816 mod p(x)` << 1, x^34880 mod p(x)` << 1 */ + .octa 0x0000000074fe22320000000167714492 + + /* x^33792 mod p(x)` << 1, x^33856 mod p(x)` << 1 */ + .octa 0x000000001ac6e2ba00000001e599099a + + /* x^32768 mod p(x)` << 1, x^32832 mod p(x)` << 1 */ + .octa 0x0000000013fca91e00000000fe128194 + + /* x^31744 mod p(x)` << 1, x^31808 mod p(x)` << 1 */ + .octa 0x0000000183f4931e0000000077e8b990 + + /* x^30720 mod p(x)` << 1, x^30784 mod p(x)` << 1 */ + .octa 0x00000000b6d9b4e400000001a267f63a + + /* x^29696 mod p(x)` << 1, x^29760 mod p(x)` << 1 */ + .octa 0x00000000b518865600000001945c245a + + /* x^28672 mod p(x)` << 1, x^28736 mod p(x)` << 1 */ + .octa 0x0000000027a81a840000000149002e76 + + /* x^27648 mod p(x)` << 1, x^27712 mod p(x)` << 1 */ + .octa 0x000000012569925800000001bb8310a4 + + /* x^26624 mod p(x)` << 1, x^26688 mod p(x)` << 1 */ + .octa 0x00000001b23de796000000019ec60bcc + + /* x^25600 mod p(x)` << 1, x^25664 mod p(x)` << 1 */ + .octa 0x00000000fe4365dc000000012d8590ae + + /* x^24576 mod p(x)` << 1, x^24640 mod p(x)` << 1 */ + .octa 0x00000000c68f497a0000000065b00684 + + /* x^23552 mod p(x)` << 1, x^23616 mod p(x)` << 1 */ + .octa 0x00000000fbf521ee000000015e5aeadc + + /* x^22528 mod p(x)` << 1, x^22592 mod p(x)` << 1 */ + .octa 0x000000015eac337800000000b77ff2b0 + + /* x^21504 mod p(x)` << 1, x^21568 mod p(x)` << 1 */ + .octa 0x0000000134914b900000000188da2ff6 + + /* x^20480 mod p(x)` << 1, x^20544 mod p(x)` << 1 */ + .octa 0x0000000016335cfe0000000063da929a + + /* x^19456 mod p(x)` << 1, x^19520 mod p(x)` << 1 */ + .octa 0x000000010372d10c00000001389caa80 + + /* x^18432 mod p(x)` << 1, x^18496 mod p(x)` << 1 */ + .octa 0x000000015097b908000000013db599d2 + + /* x^17408 mod p(x)` << 1, x^17472 mod p(x)` << 1 */ + .octa 0x00000001227a75720000000122505a86 + + /* x^16384 mod p(x)` << 1, x^16448 mod p(x)` << 1 */ + .octa 0x000000009a8f75c0000000016bd72746 + + /* x^15360 mod p(x)` << 1, x^15424 mod p(x)` << 1 */ + .octa 0x00000000682c77a200000001c3faf1d4 + + /* x^14336 mod p(x)` << 1, x^14400 mod p(x)` << 1 */ + .octa 0x00000000231f091c00000001111c826c + + /* x^13312 mod p(x)` << 1, x^13376 mod p(x)` << 1 */ + .octa 0x000000007d4439f200000000153e9fb2 + + /* x^12288 mod p(x)` << 1, x^12352 mod p(x)` << 1 */ + .octa 0x000000017e221efc000000002b1f7b60 + + /* x^11264 mod p(x)` << 1, x^11328 mod p(x)` << 1 */ + .octa 0x0000000167457c3800000000b1dba570 + + /* x^10240 mod p(x)` << 1, x^10304 mod p(x)` << 1 */ + .octa 0x00000000bdf081c400000001f6397b76 + + /* x^9216 mod p(x)` << 1, x^9280 mod p(x)` << 1 */ + .octa 0x000000016286d6b00000000156335214 + + /* x^8192 mod p(x)` << 1, x^8256 mod p(x)` << 1 */ + .octa 0x00000000c84f001c00000001d70e3986 + + /* x^7168 mod p(x)` << 1, x^7232 mod p(x)` << 1 */ + .octa 0x0000000064efe7c0000000003701a774 + + /* x^6144 mod p(x)` << 1, x^6208 mod p(x)` << 1 */ + .octa 0x000000000ac2d90400000000ac81ef72 + + /* x^5120 mod p(x)` << 1, x^5184 mod p(x)` << 1 */ + .octa 0x00000000fd226d140000000133212464 + + /* x^4096 mod p(x)` << 1, x^4160 mod p(x)` << 1 */ + .octa 0x000000011cfd42e000000000e4e45610 + + /* x^3072 mod p(x)` << 1, x^3136 mod p(x)` << 1 */ + .octa 0x000000016e5a5678000000000c1bd370 + + /* x^2048 mod p(x)` << 1, x^2112 mod p(x)` << 1 */ + .octa 0x00000001d888fe2200000001a7b9e7a6 + + /* x^1024 mod p(x)` << 1, x^1088 mod p(x)` << 1 */ + .octa 0x00000001af77fcd4000000007d657a10 + +SHORT_CONSTANTS: + + /* Reduce final 1024-2048 bits to 64 bits, shifting 32 bits to include the trailing 32 bits of zeros */ + /* x^1952 mod p(x)`, x^1984 mod p(x)`, x^2016 mod p(x)`, x^2048 mod p(x)` */ + .octa 0xed837b2613e8221e99168a18ec447f11 + + /* x^1824 mod p(x)`, x^1856 mod p(x)`, x^1888 mod p(x)`, x^1920 mod p(x)` */ + .octa 0xc8acdd8147b9ce5ae23e954e8fd2cd3c + + /* x^1696 mod p(x)`, x^1728 mod p(x)`, x^1760 mod p(x)`, x^1792 mod p(x)` */ + .octa 0xd9ad6d87d4277e2592f8befe6b1d2b53 + + /* x^1568 mod p(x)`, x^1600 mod p(x)`, x^1632 mod p(x)`, x^1664 mod p(x)` */ + .octa 0xc10ec5e033fbca3bf38a3556291ea462 + + /* x^1440 mod p(x)`, x^1472 mod p(x)`, x^1504 mod p(x)`, x^1536 mod p(x)` */ + .octa 0xc0b55b0e82e02e2f974ac56262b6ca4b + + /* x^1312 mod p(x)`, x^1344 mod p(x)`, x^1376 mod p(x)`, x^1408 mod p(x)` */ + .octa 0x71aa1df0e172334d855712b3784d2a56 + + /* x^1184 mod p(x)`, x^1216 mod p(x)`, x^1248 mod p(x)`, x^1280 mod p(x)` */ + .octa 0xfee3053e3969324da5abe9f80eaee722 + + /* x^1056 mod p(x)`, x^1088 mod p(x)`, x^1120 mod p(x)`, x^1152 mod p(x)` */ + .octa 0xf44779b93eb2bd081fa0943ddb54814c + + /* x^928 mod p(x)`, x^960 mod p(x)`, x^992 mod p(x)`, x^1024 mod p(x)` */ + .octa 0xf5449b3f00cc3374a53ff440d7bbfe6a + + /* x^800 mod p(x)`, x^832 mod p(x)`, x^864 mod p(x)`, x^896 mod p(x)` */ + .octa 0x6f8346e1d777606eebe7e3566325605c + + /* x^672 mod p(x)`, x^704 mod p(x)`, x^736 mod p(x)`, x^768 mod p(x)` */ + .octa 0xe3ab4f2ac0b95347c65a272ce5b592b8 + + /* x^544 mod p(x)`, x^576 mod p(x)`, x^608 mod p(x)`, x^640 mod p(x)` */ + .octa 0xaa2215ea329ecc115705a9ca4721589f + + /* x^416 mod p(x)`, x^448 mod p(x)`, x^480 mod p(x)`, x^512 mod p(x)` */ + .octa 0x1ed8f66ed95efd26e3720acb88d14467 + + /* x^288 mod p(x)`, x^320 mod p(x)`, x^352 mod p(x)`, x^384 mod p(x)` */ + .octa 0x78ed02d5a700e96aba1aca0315141c31 + + /* x^160 mod p(x)`, x^192 mod p(x)`, x^224 mod p(x)`, x^256 mod p(x)` */ + .octa 0xba8ccbe832b39da3ad2a31b3ed627dae + + /* x^32 mod p(x)`, x^64 mod p(x)`, x^96 mod p(x)`, x^128 mod p(x)` */ + .octa 0xedb88320b1e6b0926655004fa06a2517 + + +BARRETT_CONSTANTS: + /* 33 bit reflected Barrett constant m - (4^32)/n */ + .octa 0x000000000000000000000001f7011641 /* x^64 div p(x)` */ + /* 33 bit reflected Barrett constant n */ + .octa 0x000000000000000000000001db710641 + +#endif /* __powerpc__ */ + +#endif diff --git a/extra/crc32-vpmsum/crc32ieee_wrapper.c b/extra/crc32-vpmsum/crc32ieee_wrapper.c new file mode 100644 index 00000000000..41c1f980097 --- /dev/null +++ b/extra/crc32-vpmsum/crc32ieee_wrapper.c @@ -0,0 +1,75 @@ +#ifdef __powerpc__ + +#define F crc32ieee_vpmsum +#define __F __crc32ieee_vpmsum + +static const unsigned int crc_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,}; + +#include "crc32_wrapper.ic" + +#endif + diff --git a/extra/crc32-vpmsum/ppc-opcode.h b/extra/crc32-vpmsum/ppc-opcode.h new file mode 100644 index 00000000000..5942bd4923a --- /dev/null +++ b/extra/crc32-vpmsum/ppc-opcode.h @@ -0,0 +1,23 @@ +#ifndef __OPCODES_H +#define __OPCODES_H + +#define __PPC_RA(a) (((a) & 0x1f) << 16) +#define __PPC_RB(b) (((b) & 0x1f) << 11) +#define __PPC_XA(a) ((((a) & 0x1f) << 16) | (((a) & 0x20) >> 3)) +#define __PPC_XB(b) ((((b) & 0x1f) << 11) | (((b) & 0x20) >> 4)) +#define __PPC_XS(s) ((((s) & 0x1f) << 21) | (((s) & 0x20) >> 5)) +#define __PPC_XT(s) __PPC_XS(s) +#define VSX_XX3(t, a, b) (__PPC_XT(t) | __PPC_XA(a) | __PPC_XB(b)) +#define VSX_XX1(s, a, b) (__PPC_XS(s) | __PPC_RA(a) | __PPC_RB(b)) + +#define PPC_INST_VPMSUMW 0x10000488 +#define PPC_INST_VPMSUMD 0x100004c8 +#define PPC_INST_MFVSRD 0x7c000066 +#define PPC_INST_MTVSRD 0x7c000166 + +#define VPMSUMW(t, a, b) .long PPC_INST_VPMSUMW | VSX_XX3((t), a, b) +#define VPMSUMD(t, a, b) .long PPC_INST_VPMSUMD | VSX_XX3((t), a, b) +#define MFVRD(a, t) .long PPC_INST_MFVSRD | VSX_XX1((t)+32, a, 0) +#define MTVRD(t, a) .long PPC_INST_MTVSRD | VSX_XX1((t)+32, a, 0) + +#endif diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc index 00ca3e20339..a1ec663ee1a 100644 --- a/extra/innochecksum.cc +++ b/extra/innochecksum.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2014, 2017, MariaDB Corporation. + Copyright (c) 2014, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,15 +44,17 @@ The parts not included are excluded by #ifndef UNIV_INNOCHECKSUM. */ typedef void fil_space_t; -#include "univ.i" /* include all of this */ +#include "page0size.h" #define FLST_BASE_NODE_SIZE (4 + 2 * FIL_ADDR_SIZE) #define FLST_NODE_SIZE (2 * FIL_ADDR_SIZE) #define FSEG_PAGE_DATA FIL_PAGE_DATA -#define MLOG_1BYTE (1) +#define FSEG_HEADER_SIZE 10 +#define UT_BITS_IN_BYTES(b) (((b) + 7) / 8) #include "ut0ut.h" #include "ut0byte.h" +#include "mtr0types.h" #include "mach0data.h" #include "fsp0types.h" #include "rem0rec.h" @@ -67,7 +69,6 @@ typedef void fil_space_t; #include "ut0crc32.h" /* ut_crc32_init() */ #include "fsp0pagecompress.h" /* fil_get_compression_alg_name */ #include "fil0crypt.h" /* fil_space_verify_crypt_checksum */ -#include "page0size.h" #include <string.h> @@ -91,7 +92,7 @@ static bool use_end_page; static bool do_one_page; static my_bool do_leaf; static my_bool per_page_details; -static ulong n_merge; +static ulint n_merge; extern ulong srv_checksum_algorithm; static ulong physical_page_size; /* Page size in bytes on disk. */ static ulong logical_page_size; /* Page size when uncompressed. */ @@ -99,6 +100,8 @@ ulong srv_page_size; page_size_t univ_page_size(0, 0, false); /* Current page number (0 based). */ unsigned long long cur_page_num; +/* Current space. */ +unsigned long long cur_space; /* Skip the checksum verification. */ static bool no_check; /* Enabled for strict checksum verification. */ @@ -450,6 +453,27 @@ ulong read_file( return bytes; } +/** Check whether the page contains all zeroes. +@param[in] buf page +@param[in] size physical size of the page +@return true if the page is all zeroes; else false */ +static bool is_page_all_zeroes( + byte* buf, + ulint size) +{ + /* On pages that are not all zero, the page number + must match. */ + const ulint* p = reinterpret_cast<const ulint*>(buf); + const ulint* const end = reinterpret_cast<const ulint*>(buf + size); + do { + if (*p++) { + return false; + } + } while (p != end); + + return true; +} + /** Check if page is corrupted or not. @param[in] buf page frame @param[in] page_size page size @@ -461,10 +485,10 @@ ulong read_file( static bool is_page_corrupted( - byte* buf, + byte* buf, const page_size_t& page_size, - bool is_encrypted, - bool is_compressed) + bool is_encrypted, + bool is_compressed) { /* enable if page is corrupted. */ @@ -477,6 +501,24 @@ is_page_corrupted( ulint space_id = mach_read_from_4( buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + if (mach_read_from_4(buf + FIL_PAGE_OFFSET) != cur_page_num + || space_id != cur_space) { + /* On pages that are not all zero, the page number + must match. */ + if (is_page_all_zeroes(buf, page_size.physical())) { + return false; + } + + if (is_log_enabled) { + fprintf(log_file, + "page id mismatch space::" ULINTPF + " page::%llu \n", + space_id, cur_page_num); + } + + return true; + } + /* We can't trust only a page type, thus we take account also fsp_flags or crypt_data on page 0 */ if ((page_type == FIL_PAGE_PAGE_COMPRESSED && is_compressed) || @@ -492,8 +534,8 @@ is_page_corrupted( for uncompressed tablespace. */ logseq = mach_read_from_4(buf + FIL_PAGE_LSN + 4); logseqfield = mach_read_from_4( - buf + page_size.logical() - - FIL_PAGE_END_LSN_OLD_CHKSUM + 4); + buf + page_size.logical() - + FIL_PAGE_END_LSN_OLD_CHKSUM + 4); if (is_log_enabled) { fprintf(log_file, @@ -522,12 +564,12 @@ is_page_corrupted( normal method. */ if (is_encrypted && key_version != 0) { is_corrupted = !fil_space_verify_crypt_checksum(buf, - page_size.is_compressed() ? page_size.physical() : 0); + page_size); if (is_corrupted && log_file) { fprintf(log_file, "[page id: space=" ULINTPF ", page_number=%llu] may be corrupted;" - " key_version=" ULINTPF "\n", + " key_version=%u\n", space_id, cur_page_num, mach_read_from_4( FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION @@ -539,7 +581,7 @@ is_page_corrupted( if (is_corrupted) { is_corrupted = buf_page_is_corrupted( - true, buf, page_size.is_compressed() ? page_size.physical() : 0, NULL); + true, buf, page_size, NULL); } return(is_corrupted); @@ -584,6 +626,7 @@ is_page_empty( return (false); } } + return (true); } @@ -853,12 +896,10 @@ parse_page( /* data_bytes is bigger than logical_page_size */ size_range_id = SIZE_RANGES_FOR_PAGE + 1; } - if (per_page_details) { printf("index id=%llu page " ULINTPF " leaf %d n_recs " ULINTPF " data_bytes " ULINTPF "\n", id, page_no, is_leaf, n_recs, data_bytes); } - /* update per-index statistics */ { if (index_ids.count(id) == 0) { @@ -1175,6 +1216,7 @@ print_summary( page_type.n_fil_page_type_page_compressed_encrypted); fprintf(fil_out, "%8d\tOther type of page\n", page_type.n_fil_page_type_other); + fprintf(fil_out, "\n===============================================\n"); fprintf(fil_out, "Additional information:\n"); fprintf(fil_out, "Undo page type: %d insert, %d update, %d other\n", @@ -1231,7 +1273,7 @@ static struct my_option innochecksum_options[] = { {"verbose", 'v', "Verbose (prints progress every 5 seconds).", &verbose, &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF - {"debug", '#', "Output debug log. See " REFMAN "dbug-package.html", + {"debug", '#', "Output debug log. See https://mariadb.com/kb/en/library/creating-a-trace-file/", &dbug_setting, &dbug_setting, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif /* !DBUG_OFF */ {"count", 'c', "Print the count of pages in the file and exits.", @@ -1298,7 +1340,8 @@ static void usage(void) "[-p <page>] [-i] [-v] [-a <allow mismatches>] [-n] " "[-C <strict-check>] [-w <write>] [-S] [-D <page type dump>] " "[-l <log>] [-l] [-m <merge pages>] <filename or [-]>\n", my_progname); - printf("See " REFMAN "innochecksum.html for usage hints.\n"); + printf("See https://mariadb.com/kb/en/library/innochecksum/" + " for usage hints.\n"); my_print_help(innochecksum_options); my_print_variables(innochecksum_options); } @@ -1546,7 +1589,7 @@ int main( byte* buf = NULL; byte* xdes = NULL; /* bytes read count */ - ulong bytes; + ulint bytes; /* current time */ time_t now; /* last time */ @@ -1575,9 +1618,6 @@ int main( FILE* fil_page_type = NULL; fpos_t pos; - /* Use to check the space id of given file. If space_id is zero, - then check whether page is doublewrite buffer.*/ - ulint space_id = 0UL; /* enable when space_id of given file is zero. */ bool is_system_tablespace = false; @@ -1626,6 +1666,7 @@ int main( my_print_variables(innochecksum_options); } + buf_ptr = (byte*) malloc(UNIV_PAGE_SIZE_MAX * 2); xdes_ptr = (byte*)malloc(UNIV_PAGE_SIZE_MAX * 2); buf = (byte *) ut_align(buf_ptr, UNIV_PAGE_SIZE_MAX); @@ -1633,6 +1674,7 @@ int main( /* The file name is not optional. */ for (int i = 0; i < argc; ++i) { + /* Reset parameters for each file. */ filename = argv[i]; memset(&page_type, 0, sizeof(innodb_page_type)); @@ -1681,7 +1723,7 @@ int main( } /* Read the minimum page size. */ - bytes = ulong(fread(buf, 1, UNIV_ZIP_SIZE_MIN, fil_in)); + bytes = fread(buf, 1, UNIV_ZIP_SIZE_MIN, fil_in); partial_page_read = true; if (bytes != UNIV_ZIP_SIZE_MIN) { @@ -1697,13 +1739,13 @@ int main( /* enable variable is_system_tablespace when space_id of given file is zero. Use to skip the checksum verification and rewrite for doublewrite pages. */ - is_system_tablespace = (!memcmp(&space_id, buf + - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4)) - ? true : false; + cur_space = mach_read_from_4(buf + FIL_PAGE_SPACE_ID); + cur_page_num = mach_read_from_4(buf + FIL_PAGE_OFFSET); /* Determine page size, zip_size and page compression from fsp_flags and encryption metadata from page 0 */ const page_size_t& page_size = get_page_size(buf); + ulint flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf); ulint zip_size = page_size.is_compressed() ? page_size.logical() : 0; logical_page_size = page_size.is_compressed() ? zip_size : 0; @@ -1711,7 +1753,9 @@ int main( srv_page_size = page_size.logical(); bool is_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); - if (page_size.physical() > UNIV_ZIP_SIZE_MIN) { + if (physical_page_size == UNIV_ZIP_SIZE_MIN) { + partial_page_read = false; + } else { /* Read rest of the page 0 to determine crypt_data */ bytes = ulong(read_file(buf, partial_page_read, page_size.physical(), fil_in)); @@ -1727,6 +1771,7 @@ int main( partial_page_read = false; } + /* Now that we have full page 0 in buffer, check encryption */ bool is_encrypted = check_encryption(filename, page_size, buf); @@ -1737,7 +1782,9 @@ int main( unsigned long long tmp_allow_mismatches = allow_mismatches; allow_mismatches = 0; - exit_status = verify_checksum(buf, page_size, is_encrypted, is_compressed, &mismatch_count); + exit_status = verify_checksum( + buf, page_size, is_encrypted, + is_compressed, &mismatch_count); if (exit_status) { fprintf(stderr, "Error: Page 0 checksum mismatch, can't continue. \n"); @@ -1801,6 +1848,36 @@ int main( } } + off_t cur_offset = 0; + /* Find the first non all-zero page and fetch the + space id from there. */ + while (is_page_all_zeroes(buf, physical_page_size)) { + bytes = ulong(read_file( + buf, false, physical_page_size, + fil_in)); + + if (feof(fil_in)) { + fprintf(stderr, "All are " + "zero-filled pages."); + goto my_exit; + } + + cur_offset++; + } + + cur_space = mach_read_from_4(buf + FIL_PAGE_SPACE_ID); + is_system_tablespace = (cur_space == 0); + + if (cur_offset > 0) { + /* Re-read the non-zero page to check the + checksum. So move the file pointer to + previous position and reset the page number too. */ + cur_page_num = mach_read_from_4(buf + FIL_PAGE_OFFSET); + if (!start_page) { + goto first_non_zero; + } + } + /* seek to the necessary position */ if (start_page) { if (!read_from_stdin) { @@ -1868,6 +1945,7 @@ int main( /* main checksumming loop */ cur_page_num = start_page ? start_page : cur_page_num + 1; + lastt = 0; while (!feof(fil_in)) { @@ -1897,6 +1975,7 @@ int main( goto my_exit; } +first_non_zero: if (is_system_tablespace) { /* enable when page is double write buffer.*/ skip_page = is_page_doublewritebuffer(buf); @@ -1917,8 +1996,10 @@ int main( checksum verification.*/ if (!no_check && !skip_page - && (exit_status = verify_checksum(buf, page_size, - is_encrypted, is_compressed, &mismatch_count))) { + && (exit_status = verify_checksum( + buf, page_size, + is_encrypted, is_compressed, + &mismatch_count))) { goto my_exit; } diff --git a/extra/mariabackup/CMakeLists.txt b/extra/mariabackup/CMakeLists.txt index 9e5b8506658..8562ded85a1 100644 --- a/extra/mariabackup/CMakeLists.txt +++ b/extra/mariabackup/CMakeLists.txt @@ -30,7 +30,6 @@ ENDIF() INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/storage/xtradb/include ${CMAKE_SOURCE_DIR}/sql ${CMAKE_CURRENT_SOURCE_DIR}/quicklz ${CMAKE_CURRENT_SOURCE_DIR} @@ -58,25 +57,25 @@ MYSQL_ADD_EXECUTABLE(mariabackup xtrabackup.cc innobackupex.cc changed_page_bitmap.cc - datasink.c - ds_buffer.c - ds_compress.c + datasink.cc + ds_buffer.cc + ds_compress.cc ds_local.cc - ds_stdout.c - ds_tmpfile.c - ds_xbstream.c + ds_stdout.cc + ds_tmpfile.cc + ds_xbstream.cc fil_cur.cc quicklz/quicklz.c read_filt.cc write_filt.cc wsrep.cc - xbstream_write.c + xbstream_write.cc backup_mysql.cc backup_copy.cc encryption_plugin.cc - ${PROJECT_SOURCE_DIR}/libmysql/libmysql.c ${PROJECT_SOURCE_DIR}/sql/net_serv.cc ${NT_SERVICE_SOURCE} + ${PROJECT_SOURCE_DIR}/libmysqld/libmysql.c COMPONENT backup ) @@ -97,13 +96,13 @@ ENDIF() # xbstream binary ######################################################################## MYSQL_ADD_EXECUTABLE(mbstream - ds_buffer.c + ds_buffer.cc ds_local.cc - ds_stdout.c - datasink.c - xbstream.c - xbstream_read.c - xbstream_write.c + ds_stdout.cc + datasink.cc + xbstream.cc + xbstream_read.cc + xbstream_write.cc COMPONENT backup ) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index b31edfd65c5..28e5728bd3e 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -46,6 +46,7 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <ut0mem.h> #include <srv0start.h> #include <fil0fil.h> +#include <trx0sys.h> #include <set> #include <string> #include <mysqld.h> @@ -58,6 +59,7 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <btr0btr.h> #include "xb0xb.h" +#define ROCKSDB_BACKUP_DIR "#rocksdb" /* list of files to sync for --rsync mode */ static std::set<std::string> rsync_list; @@ -67,6 +69,21 @@ static std::map<std::string, std::string> tablespace_locations; /* Whether LOCK BINLOG FOR BACKUP has been issued during backup */ bool binlog_locked; +static void rocksdb_create_checkpoint(); +static bool has_rocksdb_plugin(); +static void copy_or_move_dir(const char *from, const char *to, bool copy, bool allow_hardlinks); +static void rocksdb_backup_checkpoint(); +static void rocksdb_copy_back(); + +static bool is_abs_path(const char *path) +{ +#ifdef _WIN32 + return path[0] && path[1] == ':' && (path[2] == '/' || path[2] == '\\'); +#else + return path[0] == '/'; +#endif +} + /************************************************************************ Struct represents file or directory. */ struct datadir_node_t { @@ -89,7 +106,7 @@ struct datadir_iter_t { ulint filepath_len; char *filepath_rel; ulint filepath_rel_len; - os_ib_mutex_t mutex; + pthread_mutex_t mutex; os_file_dir_t dir; os_file_dir_t dbdir; os_file_stat_t dbinfo; @@ -107,7 +124,7 @@ struct datadir_thread_ctxt_t { datadir_iter_t *it; uint n_thread; uint *count; - os_ib_mutex_t count_mutex; + pthread_mutex_t* count_mutex; os_thread_id_t id; bool ret; }; @@ -134,12 +151,12 @@ datadir_node_fill(datadir_node_t *node, datadir_iter_t *it) { if (node->filepath_len < it->filepath_len) { free(node->filepath); - node->filepath = (char*)(ut_malloc(it->filepath_len)); + node->filepath = (char*)(malloc(it->filepath_len)); node->filepath_len = it->filepath_len; } if (node->filepath_rel_len < it->filepath_rel_len) { free(node->filepath_rel); - node->filepath_rel = (char*)(ut_malloc(it->filepath_rel_len)); + node->filepath_rel = (char*)(malloc(it->filepath_rel_len)); node->filepath_rel_len = it->filepath_rel_len; } @@ -153,8 +170,8 @@ static void datadir_node_free(datadir_node_t *node) { - ut_free(node->filepath); - ut_free(node->filepath_rel); + free(node->filepath); + free(node->filepath_rel); memset(node, 0, sizeof(datadir_node_t)); } @@ -178,10 +195,10 @@ datadir_iter_new(const char *path, bool skip_first_level = true) { datadir_iter_t *it; - it = static_cast<datadir_iter_t *>(ut_malloc(sizeof(datadir_iter_t))); + it = static_cast<datadir_iter_t *>(malloc(sizeof(datadir_iter_t))); memset(it, 0, sizeof(datadir_iter_t)); - it->mutex = os_mutex_create(); + pthread_mutex_init(&it->mutex, NULL); it->datadir_path = strdup(path); it->dir = os_file_opendir(it->datadir_path, TRUE); @@ -194,20 +211,20 @@ datadir_iter_new(const char *path, bool skip_first_level = true) it->err = DB_SUCCESS; it->dbpath_len = FN_REFLEN; - it->dbpath = static_cast<char*>(ut_malloc(it->dbpath_len)); + it->dbpath = static_cast<char*>(malloc(it->dbpath_len)); it->filepath_len = FN_REFLEN; - it->filepath = static_cast<char*>(ut_malloc(it->filepath_len)); + it->filepath = static_cast<char*>(malloc(it->filepath_len)); it->filepath_rel_len = FN_REFLEN; - it->filepath_rel = static_cast<char*>(ut_malloc(it->filepath_rel_len)); + it->filepath_rel = static_cast<char*>(malloc(it->filepath_rel_len)); it->skip_first_level = skip_first_level; return(it); error: - ut_free(it); + free(it); return(NULL); } @@ -220,7 +237,7 @@ datadir_iter_next_database(datadir_iter_t *it) if (os_file_closedir(it->dbdir) != 0) { msg("Warning: could not" - " close database directory %s\n", it->dbpath); + " close database directory %s", it->dbpath); it->err = DB_ERROR; @@ -246,19 +263,14 @@ datadir_iter_next_database(datadir_iter_t *it) + strlen (it->dbinfo.name) + 2; if (len > it->dbpath_len) { it->dbpath_len = len; + free(it->dbpath); - if (it->dbpath) { - - ut_free(it->dbpath); - } - - it->dbpath = static_cast<char*> - (ut_malloc(it->dbpath_len)); + it->dbpath = static_cast<char*>( + malloc(it->dbpath_len)); } - ut_snprintf(it->dbpath, it->dbpath_len, - "%s/%s", it->datadir_path, - it->dbinfo.name); - srv_normalize_path_for_win(it->dbpath); + snprintf(it->dbpath, it->dbpath_len, "%s/%s", + it->datadir_path, it->dbinfo.name); + os_normalize_path(it->dbpath); if (it->dbinfo.type == OS_FILE_TYPE_FILE) { it->is_file = true; @@ -266,7 +278,7 @@ datadir_iter_next_database(datadir_iter_t *it) } if (check_if_skip_database_by_path(it->dbpath)) { - msg("Skipping db: %s\n", it->dbpath); + msg("Skipping db: %s", it->dbpath); continue; } @@ -306,8 +318,8 @@ make_path_n(int n, char **path, ulint *path_len, ...) va_end(vl); if (len_needed < *path_len) { - ut_free(*path); - *path = static_cast<char*>(ut_malloc(len_needed)); + free(*path); + *path = static_cast<char*>(malloc(len_needed)); } va_start(vl, path_len); @@ -378,7 +390,7 @@ datadir_iter_next(datadir_iter_t *it, datadir_node_t *node) { bool ret = true; - os_mutex_enter(it->mutex); + pthread_mutex_lock(&it->mutex); if (datadir_iter_next_file(it)) { @@ -413,7 +425,7 @@ datadir_iter_next(datadir_iter_t *it, datadir_node_t *node) ret = false; done: - os_mutex_exit(it->mutex); + pthread_mutex_unlock(&it->mutex); return(ret); } @@ -427,7 +439,7 @@ static void datadir_iter_free(datadir_iter_t *it) { - os_mutex_free(it->mutex); + pthread_mutex_destroy(&it->mutex); if (it->dbdir) { @@ -439,11 +451,11 @@ datadir_iter_free(datadir_iter_t *it) os_file_closedir(it->dir); } - ut_free(it->dbpath); - ut_free(it->filepath); - ut_free(it->filepath_rel); + free(it->dbpath); + free(it->filepath); + free(it->filepath_rel); free(it->datadir_path); - ut_free(it); + free(it); } @@ -481,17 +493,17 @@ static void datafile_close(datafile_cur_t *cursor) { - if (cursor->file != 0) { + if (cursor->file != OS_FILE_CLOSED) { os_file_close(cursor->file); } - ut_free(cursor->buf); + free(cursor->buf); } static bool datafile_open(const char *file, datafile_cur_t *cursor, uint thread_n) { - ulint success; + bool success; new (cursor) datafile_cur_t(file); @@ -504,35 +516,29 @@ datafile_open(const char *file, datafile_cur_t *cursor, uint thread_n) (sizeof cursor->rel_path) - 1); cursor->rel_path[(sizeof cursor->rel_path) - 1] = '\0'; - cursor->file = os_file_create_simple_no_error_handling(0, - cursor->abs_path, - OS_FILE_OPEN, - OS_FILE_READ_ONLY, - &success, 0); + cursor->file = os_file_create_simple_no_error_handling( + 0, cursor->abs_path, + OS_FILE_OPEN, OS_FILE_READ_ALLOW_DELETE, true, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); - msg("[%02u] error: cannot open " - "file %s\n", - thread_n, cursor->abs_path); + msg(thread_n,"error: cannot open " + "file %s", cursor->abs_path); return(false); } if (!my_stat(cursor->abs_path, &cursor->statinfo, 0)) { - msg("[%02u] error: cannot stat %s\n", - thread_n, cursor->abs_path); - + msg(thread_n, "error: cannot stat %s", cursor->abs_path); datafile_close(cursor); - return(false); } posix_fadvise(cursor->file, 0, 0, POSIX_FADV_SEQUENTIAL); cursor->buf_size = 10 * 1024 * 1024; - cursor->buf = static_cast<byte *>(ut_malloc((ulint)cursor->buf_size)); + cursor->buf = static_cast<byte *>(malloc((ulint)cursor->buf_size)); return(true); } @@ -542,7 +548,6 @@ static xb_fil_cur_result_t datafile_read(datafile_cur_t *cursor) { - ulint success; ulint to_read; xtrabackup_io_throttling(); @@ -554,14 +559,14 @@ datafile_read(datafile_cur_t *cursor) return(XB_FIL_CUR_EOF); } - success = os_file_read(cursor->file, cursor->buf, cursor->buf_offset, - to_read); - if (!success) { + if (os_file_read(IORequestRead, + cursor->file, cursor->buf, cursor->buf_offset, + to_read) != DB_SUCCESS) { return(XB_FIL_CUR_ERROR); } posix_fadvise(cursor->file, cursor->buf_offset, to_read, - POSIX_FADV_DONTNEED); + POSIX_FADV_DONTNEED); cursor->buf_read = to_read; cursor->buf_offset += to_read; @@ -615,7 +620,6 @@ trim_dotslash(const char *path) /************************************************************************ Check if string ends with given suffix. @return true if string ends with given suffix. */ -static bool ends_with(const char *str, const char *suffix) { @@ -646,7 +650,7 @@ mkdirp(const char *pathname, int Flags, myf MyFlags) memcpy(parent, pathname, len); for (p = parent + strlen(parent); - !is_path_separator(*p) && p != parent; p--); + !is_path_separator(*p) && p != parent; p--) ; *p = 0; @@ -720,9 +724,8 @@ directory_exists(const char *dir, bool create) if (mkdirp(dir, 0777, MYF(0)) < 0) { my_strerror(errbuf, sizeof(errbuf), my_errno); - msg("Can not create directory %s: %s\n", dir, errbuf); + msg("Can not create directory %s: %s", dir, errbuf); return(false); - } } @@ -731,7 +734,7 @@ directory_exists(const char *dir, bool create) if (os_dir == NULL) { my_strerror(errbuf, sizeof(errbuf), my_errno); - msg("Can not open directory %s: %s\n", dir, + msg("Can not open directory %s: %s", dir, errbuf); return(false); @@ -760,7 +763,7 @@ directory_exists_and_empty(const char *dir, const char *comment) os_dir = os_file_opendir(dir, FALSE); if (os_dir == NULL) { - msg("%s can not open directory %s\n", comment, dir); + msg("%s can not open directory %s", comment, dir); return(false); } @@ -769,7 +772,7 @@ directory_exists_and_empty(const char *dir, const char *comment) os_file_closedir(os_dir); if (!empty) { - msg("%s directory %s is not empty!\n", comment, dir); + msg("%s directory %s is not empty!", comment, dir); } return(empty); @@ -818,7 +821,7 @@ datafile_copy_backup(const char *filepath, uint thread_n) of the filters value. */ if (check_if_skip_table(filepath)) { - msg_ts("[%02u] Skipping %s.\n", thread_n, filepath); + msg(thread_n,"Skipping %s.", filepath); return(true); } @@ -884,14 +887,13 @@ backup_file_vprintf(const char *filename, const char *fmt, va_list ap) dstfile = ds_open(ds_data, filename, &stat); if (dstfile == NULL) { - msg("[%02u] error: " - "cannot open the destination stream for %s\n", - 0, filename); + msg("error: Can't open the destination stream for %s", + filename); goto error; } action = xb_get_copy_action("Writing"); - msg_ts("[%02u] %s %s\n", 0, action, filename); + msg("%s %s", action, filename); if (buf_len == -1) { goto error; @@ -902,7 +904,7 @@ backup_file_vprintf(const char *filename, const char *fmt, va_list ap) } /* close */ - msg_ts("[%02u] ...done\n", 0); + msg(" ...done"); free(buf); if (ds_close(dstfile)) { @@ -918,7 +920,7 @@ error: } error_close: - msg("[%02u] Error: backup file failed.\n", 0); + msg("Error: backup file failed."); return(false); /*ERROR*/ } @@ -944,49 +946,108 @@ run_data_threads(datadir_iter_t *it, os_thread_func_t func, uint n) { datadir_thread_ctxt_t *data_threads; uint i, count; - os_ib_mutex_t count_mutex; + pthread_mutex_t count_mutex; bool ret; data_threads = (datadir_thread_ctxt_t*) - (ut_malloc(sizeof(datadir_thread_ctxt_t) * n)); + malloc(sizeof(datadir_thread_ctxt_t) * n); - count_mutex = os_mutex_create(); + pthread_mutex_init(&count_mutex, NULL); count = n; for (i = 0; i < n; i++) { data_threads[i].it = it; data_threads[i].n_thread = i + 1; data_threads[i].count = &count; - data_threads[i].count_mutex = count_mutex; + data_threads[i].count_mutex = &count_mutex; os_thread_create(func, data_threads + i, &data_threads[i].id); } /* Wait for threads to exit */ while (1) { os_thread_sleep(100000); - os_mutex_enter(count_mutex); + pthread_mutex_lock(&count_mutex); if (count == 0) { - os_mutex_exit(count_mutex); + pthread_mutex_unlock(&count_mutex); break; } - os_mutex_exit(count_mutex); + pthread_mutex_unlock(&count_mutex); } - os_mutex_free(count_mutex); + pthread_mutex_destroy(&count_mutex); ret = true; for (i = 0; i < n; i++) { ret = data_threads[i].ret && ret; if (!data_threads[i].ret) { - msg("Error: thread %u failed.\n", i); + msg("Error: thread %u failed.", i); } } - ut_free(data_threads); + free(data_threads); return(ret); } +#ifdef _WIN32 +#include <windows.h> +#include <accctrl.h> +#include <aclapi.h> +/* + On Windows, fix permission of the file after "copyback" + We assume that after copyback, mysqld will run as service as NetworkService + user, thus well give full permission on given file to that user. +*/ + +static int fix_win_file_permissions(const char *file) +{ + struct { + TOKEN_USER tokenUser; + BYTE buffer[SECURITY_MAX_SID_SIZE]; + } tokenInfoBuffer; + HANDLE hFile = CreateFile(file, READ_CONTROL | WRITE_DAC, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + ACL* pOldDACL; + SECURITY_DESCRIPTOR* pSD = NULL; + EXPLICIT_ACCESS ea = { 0 }; + BOOL isWellKnownSID = FALSE; + PSID pSid = NULL; + + GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, + &pOldDACL, NULL, (void**)&pSD); + DWORD size = SECURITY_MAX_SID_SIZE; + pSid = (PSID)tokenInfoBuffer.buffer; + if (!CreateWellKnownSid(WinNetworkServiceSid, NULL, pSid, + &size)) + { + return 1; + } + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.ptstrName = (LPTSTR)pSid; + + ea.grfAccessMode = GRANT_ACCESS; + ea.grfAccessPermissions = GENERIC_ALL; + ea.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE; + ea.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ACL* pNewDACL = 0; + DWORD err = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL); + if (pNewDACL) + { + SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, + pNewDACL, NULL); + } + if (pSD != NULL) + LocalFree((HLOCAL)pSD); + if (pNewDACL != NULL) + LocalFree((HLOCAL)pNewDACL); + CloseHandle(hFile); + return 0; +} + +#endif + /************************************************************************ Copy file for backup/restore. @@ -1001,7 +1062,6 @@ copy_file(ds_ctxt_t *datasink, ds_file_t *dstfile = NULL; datafile_cur_t cursor; xb_fil_cur_result_t res; - const char *action; const char *dst_path = (xtrabackup_copy_back || xtrabackup_move_back)? dst_file_path : trim_dotslash(dst_file_path); @@ -1014,15 +1074,12 @@ copy_file(ds_ctxt_t *datasink, dstfile = ds_open(datasink, dst_path, &cursor.statinfo); if (dstfile == NULL) { - msg("[%02u] error: " - "cannot open the destination stream for %s\n", - thread_n, dst_name); + msg(thread_n,"error: " + "cannot open the destination stream for %s", dst_name); goto error; } - action = xb_get_copy_action(); - msg_ts("[%02u] %s %s to %s\n", - thread_n, action, src_file_path, dstfile->path); + msg(thread_n, "%s %s to %s", xb_get_copy_action(), src_file_path, dstfile->path); /* The main copy loop */ while ((res = datafile_read(&cursor)) == XB_FIL_CUR_SUCCESS) { @@ -1037,8 +1094,12 @@ copy_file(ds_ctxt_t *datasink, } /* close */ - msg_ts("[%02u] ...done\n", thread_n); + msg(thread_n," ...done"); datafile_close(&cursor); +#ifdef _WIN32 + if (xtrabackup_copy_back || xtrabackup_move_back) + ut_a(!fix_win_file_permissions(dstfile->path)); +#endif if (ds_close(dstfile)) { goto error_close; } @@ -1051,7 +1112,7 @@ error: } error_close: - msg("[%02u] Error: copy_file() failed.\n", thread_n); + msg(thread_n,"Error: copy_file() failed."); return(false); /*ERROR*/ } @@ -1072,8 +1133,8 @@ move_file(ds_ctxt_t *datasink, char dst_dir_abs[FN_REFLEN]; size_t dirname_length; - ut_snprintf(dst_file_path_abs, sizeof(dst_file_path_abs), - "%s/%s", dst_dir, dst_file_path); + snprintf(dst_file_path_abs, sizeof(dst_file_path_abs), + "%s/%s", dst_dir, dst_file_path); dirname_part(dst_dir_abs, dst_file_path_abs, &dirname_length); @@ -1083,36 +1144,37 @@ move_file(ds_ctxt_t *datasink, if (file_exists(dst_file_path_abs)) { msg("Error: Move file %s to %s failed: Destination " - "file exists\n", - src_file_path, dst_file_path_abs); + "file exists", src_file_path, dst_file_path_abs); return(false); } - msg_ts("[%02u] Moving %s to %s\n", - thread_n, src_file_path, dst_file_path_abs); + msg(thread_n,"Moving %s to %s", src_file_path, dst_file_path_abs); if (my_rename(src_file_path, dst_file_path_abs, MYF(0)) != 0) { if (my_errno == EXDEV) { bool ret; ret = copy_file(datasink, src_file_path, dst_file_path, thread_n); - msg_ts("[%02u] Removing %s\n", thread_n, src_file_path); + msg(thread_n,"Removing %s", src_file_path); if (unlink(src_file_path) != 0) { my_strerror(errbuf, sizeof(errbuf), errno); - msg("Error: unlink %s failed: %s\n", + msg("Error: unlink %s failed: %s", src_file_path, errbuf); } return(ret); } my_strerror(errbuf, sizeof(errbuf), my_errno); - msg("Can not move file %s to %s: %s\n", + msg("Can not move file %s to %s: %s", src_file_path, dst_file_path_abs, errbuf); return(false); } - - msg_ts("[%02u] ...done\n", thread_n); +#ifdef _WIN32 + if (xtrabackup_copy_back || xtrabackup_move_back) + ut_a(!fix_win_file_permissions(dst_file_path_abs)); +#endif + msg(thread_n," ...done"); return(true); } @@ -1140,7 +1202,7 @@ read_link_file(const char *ibd_filepath, const char *link_filepath) while (lastch > 4 && filepath[lastch] <= 0x20) { filepath[lastch--] = 0x00; } - srv_normalize_path_for_win(filepath); + os_normalize_path(filepath); } tablespace_locations[ibd_filepath] = filepath; @@ -1177,7 +1239,8 @@ bool copy_or_move_file(const char *src_file_path, const char *dst_file_path, const char *dst_dir, - uint thread_n) + uint thread_n, + bool copy = xtrabackup_copy_back) { ds_ctxt_t *datasink = ds_data; /* copy to datadir by default */ char filedir[FN_REFLEN]; @@ -1226,7 +1289,7 @@ copy_or_move_file(const char *src_file_path, free(link_filepath); } - ret = (xtrabackup_copy_back ? + ret = (copy ? copy_file(datasink, src_file_path, dst_file_path, thread_n) : move_file(datasink, src_file_path, dst_file_path, dst_dir, thread_n)); @@ -1243,6 +1306,7 @@ cleanup: +static bool backup_files(const char *from, bool prep_mode) { @@ -1263,13 +1327,13 @@ backup_files(const char *from, bool prep_mode) prep_mode ? 1 : 2); rsync_tmpfile = fopen(rsync_tmpfile_name, "w"); if (rsync_tmpfile == NULL) { - msg("Error: can't create file %s\n", + msg("Error: can't create file %s", rsync_tmpfile_name); return(false); } } - msg_ts("Starting %s non-InnoDB tables and files\n", + msg("Starting %s non-InnoDB tables and files", prep_mode ? "prep copy of" : "to backup"); datadir_node_init(&node); @@ -1285,17 +1349,17 @@ backup_files(const char *from, bool prep_mode) ret = datafile_copy_backup(node.filepath, 1); } if (!ret) { - msg("Failed to copy file %s\n", node.filepath); + msg("Failed to copy file %s", node.filepath); goto out; } } else if (!prep_mode) { /* backup fake file into empty directory */ char path[FN_REFLEN]; - ut_snprintf(path, sizeof(path), - "%s/db.opt", node.filepath); + snprintf(path, sizeof(path), + "%s/db.opt", node.filepath); if (!(ret = backup_file_printf( trim_dotslash(path), "%s", ""))) { - msg("Failed to create file %s\n", path); + msg("Failed to create file %s", path); goto out; } } @@ -1320,13 +1384,13 @@ backup_files(const char *from, bool prep_mode) cmd << "rsync -t . --files-from=" << rsync_tmpfile_name << " " << xtrabackup_target_dir; - msg_ts("Starting rsync as: %s\n", cmd.str().c_str()); + msg("Starting rsync as: %s", cmd.str().c_str()); if ((err = system(cmd.str().c_str()) && !prep_mode) != 0) { - msg_ts("Error: rsync failed with error code %d\n", err); + msg("Error: rsync failed with error code %d", err); ret = false; goto out; } - msg_ts("rsync finished successfully.\n"); + msg("rsync finished successfully."); if (!prep_mode && !opt_no_lock) { char path[FN_REFLEN]; @@ -1342,9 +1406,10 @@ backup_files(const char *from, bool prep_mode) rsync_tmpfile = fopen(rsync_tmpfile_name, "r"); if (rsync_tmpfile == NULL) { - msg("Error: can't open file %s\n", + msg("Error: can't open file %s", rsync_tmpfile_name); - return(false); + ret = false; + goto out; } while (fgets(path, sizeof(path), rsync_tmpfile)) { @@ -1357,7 +1422,7 @@ backup_files(const char *from, bool prep_mode) snprintf(dst_path, sizeof(dst_path), "%s/%s", xtrabackup_target_dir, path); - msg_ts("Removing %s\n", dst_path); + msg("Removing %s", dst_path); unlink(dst_path); } } @@ -1367,7 +1432,7 @@ backup_files(const char *from, bool prep_mode) } } - msg_ts("Finished %s non-InnoDB tables and files\n", + msg("Finished %s non-InnoDB tables and files", prep_mode ? "a prep copy of" : "backing up"); out: @@ -1381,8 +1446,32 @@ out: return(ret); } -bool -backup_start() +void backup_fix_ddl(void); + +static lsn_t get_current_lsn(MYSQL *connection) +{ + static const char lsn_prefix[] = "\nLog sequence number "; + lsn_t lsn = 0; + if (MYSQL_RES *res = xb_mysql_query(connection, + "SHOW ENGINE INNODB STATUS", + true, false)) { + if (MYSQL_ROW row = mysql_fetch_row(res)) { + const char *p= strstr(row[2], lsn_prefix); + DBUG_ASSERT(p); + if (p) { + p += sizeof lsn_prefix - 1; + lsn = lsn_t(strtoll(p, NULL, 10)); + } + } + mysql_free_result(res); + } + return lsn; +} + +lsn_t server_lsn_after_lock; +extern void backup_wait_for_lsn(lsn_t lsn); +/** Start --backup */ +bool backup_start() { if (!opt_no_lock) { if (opt_safe_slave_backup) { @@ -1400,6 +1489,7 @@ backup_start() if (!lock_tables(mysql_connection)) { return(false); } + server_lsn_after_lock = get_current_lsn(mysql_connection); } if (!backup_files(fil_path_to_mysql_datadir, false)) { @@ -1410,6 +1500,14 @@ backup_start() return false; } + if (has_rocksdb_plugin()) { + rocksdb_create_checkpoint(); + } + + msg("Waiting for log copy thread to read lsn %llu", (ulonglong)server_lsn_after_lock); + backup_wait_for_lsn(server_lsn_after_lock); + backup_fix_ddl(); + // There is no need to stop slave thread before coping non-Innodb data when // --no-lock option is used because --no-lock option requires that no DDL or // DML to non-transaction tables can occur. @@ -1448,8 +1546,8 @@ backup_start() write_binlog_info(mysql_connection); } - if (have_flush_engine_logs) { - msg_ts("Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS...\n"); + if (have_flush_engine_logs && !opt_no_lock) { + msg("Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS..."); xb_mysql_query(mysql_connection, "FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS", false); } @@ -1457,9 +1555,8 @@ backup_start() return(true); } - -bool -backup_finish() +/** Release resources after backup_start() */ +void backup_release() { /* release all locks */ if (!opt_no_lock) { @@ -1469,12 +1566,20 @@ backup_finish() history_lock_time = time(NULL) - history_lock_time; } + if (opt_lock_ddl_per_table) { + mdl_unlock_all(); + } + if (opt_safe_slave_backup && sql_thread_started) { - msg("Starting slave SQL thread\n"); + msg("Starting slave SQL thread"); xb_mysql_query(mysql_connection, "START SLAVE SQL_THREAD", false); } +} +/** Finish after backup_start() and backup_release() */ +bool backup_finish() +{ /* Copy buffer pool dump or LRU dump */ if (!opt_rsync) { if (buffer_pool_filename && file_exists(buffer_pool_filename)) { @@ -1488,12 +1593,16 @@ backup_finish() } } - msg_ts("Backup created in directory '%s'\n", xtrabackup_target_dir); + if (has_rocksdb_plugin()) { + rocksdb_backup_checkpoint(); + } + + msg("Backup created in directory '%s'", xtrabackup_target_dir); if (mysql_binlog_position != NULL) { - msg("MySQL binlog position: %s\n", mysql_binlog_position); + msg("MySQL binlog position: %s", mysql_binlog_position); } if (mysql_slave_position && opt_slave_info) { - msg("MySQL slave binlog position: %s\n", + msg("MySQL slave binlog position: %s", mysql_slave_position); } @@ -1501,12 +1610,10 @@ backup_finish() return(false); } - if (!write_xtrabackup_info(mysql_connection)) { + if (!write_xtrabackup_info(mysql_connection, XTRABACKUP_INFO, opt_history != 0)) { return(false); } - - return(true); } @@ -1555,7 +1662,7 @@ ibx_copy_incremental_over_full() if (!(ret = copy_file(ds_data, node.filepath, node.filepath_rel, 1))) { - msg("Failed to copy file %s\n", + msg("Failed to copy file %s", node.filepath); goto cleanup; } @@ -1593,8 +1700,21 @@ ibx_copy_incremental_over_full() } } + if (directory_exists(ROCKSDB_BACKUP_DIR, false)) { + if (my_rmtree(ROCKSDB_BACKUP_DIR, MYF(0))) { + die("Can't remove " ROCKSDB_BACKUP_DIR); + } + } + snprintf(path, sizeof(path), "%s/" ROCKSDB_BACKUP_DIR, xtrabackup_incremental_dir); + if (directory_exists(path, false)) { + if (my_mkdir(ROCKSDB_BACKUP_DIR, 0777, MYF(0))) { + die("my_mkdir failed for " ROCKSDB_BACKUP_DIR); + } + copy_or_move_dir(path, ROCKSDB_BACKUP_DIR, true, true); + } } + cleanup: if (it != NULL) { datadir_iter_free(it); @@ -1659,14 +1779,9 @@ apply_log_finish() return(true); } -extern void -os_io_init_simple(void); - bool copy_back() { - char *innobase_data_file_path_copy; - ulint i; bool ret; datadir_iter_t *it = NULL; datadir_node_t node; @@ -1700,7 +1815,7 @@ copy_back() /* cd to backup directory */ if (my_setwd(xtrabackup_target_dir, MYF(MY_WME))) { - msg("cannot my_setwd %s\n", xtrabackup_target_dir); + msg("Can't my_setwd %s", xtrabackup_target_dir); return(false); } @@ -1709,24 +1824,16 @@ copy_back() if (!innobase_data_file_path) { innobase_data_file_path = (char*) "ibdata1:10M:autoextend"; } - innobase_data_file_path_copy = strdup(innobase_data_file_path); - if (!(ret = srv_parse_data_file_paths_and_sizes( - innobase_data_file_path_copy))) { - msg("syntax error in innodb_data_file_path\n"); + srv_sys_space.set_path("."); + + if (!srv_sys_space.parse_params(innobase_data_file_path, true)) { + msg("syntax error in innodb_data_file_path"); return(false); } srv_max_n_threads = 1000; - //os_sync_mutex = NULL; - ut_mem_init(); - /* temporally dummy value to avoid crash */ - srv_page_size_shift = 14; - srv_page_size = (1 << srv_page_size_shift); - os_sync_init(); - sync_init(); - os_io_init_simple(); - mem_init(srv_mem_pool_size); + sync_check_init(); ut_crc32_init(); /* copy undo tablespaces */ @@ -1737,14 +1844,14 @@ copy_back() ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); - for (i = 1; ; i++) { + for (uint i = 1; i <= TRX_SYS_MAX_UNDO_SPACES; i++) { char filename[20]; - sprintf(filename, "undo%03u", (uint)i); + sprintf(filename, "undo%03u", i); if (!file_exists(filename)) { break; } if (!(ret = copy_or_move_file(filename, filename, - dst_dir, 1))) { + dst_dir, 1))) { goto cleanup; } } @@ -1755,26 +1862,30 @@ copy_back() /* copy redo logs */ dst_dir = (srv_log_group_home_dir && *srv_log_group_home_dir) - ? srv_log_group_home_dir : mysql_data_home; + ? srv_log_group_home_dir : mysql_data_home; - ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); - - for (i = 0; i < (ulong)innobase_log_files_in_group; i++) { - char filename[20]; - sprintf(filename, "ib_logfile%lu", i); - - if (!file_exists(filename)) { - continue; - } + /* --backup generates a single ib_logfile0, which we must copy + if it exists. */ - if (!(ret = copy_or_move_file(filename, filename, - dst_dir, 1))) { - goto cleanup; + ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); + MY_STAT stat_arg; + if (!my_stat("ib_logfile0", &stat_arg, MYF(0)) || !stat_arg.st_size) { + /* After completed --prepare, redo log files are redundant. + We must delete any redo logs at the destination, so that + the database will not jump to a different log sequence number + (LSN). */ + + for (uint i = 0; i <= SRV_N_LOG_FILES_MAX + 1; i++) { + char filename[FN_REFLEN]; + snprintf(filename, sizeof filename, "%s/ib_logfile%u", + dst_dir, i); + unlink(filename); } + } else if (!(ret = copy_or_move_file("ib_logfile0", "ib_logfile0", + dst_dir, 1))) { + goto cleanup; } - ds_destroy(ds_data); - ds_data = NULL; /* copy innodb system tablespace(s) */ @@ -1783,17 +1894,19 @@ copy_back() ds_data = ds_create(dst_dir, DS_TYPE_LOCAL); - for (i = 0; i < srv_n_data_files; i++) { - const char *filename = base_name(srv_data_file_names[i]); + for (Tablespace::const_iterator iter(srv_sys_space.begin()), + end(srv_sys_space.end()); + iter != end; + ++iter) { + const char *filename = base_name(iter->name()); - if (!(ret = copy_or_move_file(filename, srv_data_file_names[i], + if (!(ret = copy_or_move_file(filename, iter->name(), dst_dir, 1))) { goto cleanup; } } ds_destroy(ds_data); - ds_data = NULL; /* copy the rest of tablespaces */ ds_data = ds_create(mysql_data_home, DS_TYPE_LOCAL); @@ -1803,7 +1916,7 @@ copy_back() datadir_node_init(&node); while (datadir_iter_next(it, &node)) { - const char *ext_list[] = {"backup-my.cnf", "xtrabackup_logfile", + const char *ext_list[] = {"backup-my.cnf", "xtrabackup_binary", "xtrabackup_binlog_info", "xtrabackup_checkpoints", ".qp", ".pmap", ".tmp", NULL}; @@ -1812,6 +1925,16 @@ copy_back() int i_tmp; bool is_ibdata_file; + if (strstr(node.filepath,"/" ROCKSDB_BACKUP_DIR "/") +#ifdef _WIN32 + || strstr(node.filepath,"\\" ROCKSDB_BACKUP_DIR "\\") +#endif + ) + { + // copied at later step + continue; + } + /* create empty directories */ if (node.is_empty_dir) { char path[FN_REFLEN]; @@ -1819,12 +1942,12 @@ copy_back() snprintf(path, sizeof(path), "%s/%s", mysql_data_home, node.filepath_rel); - msg_ts("[%02u] Creating directory %s\n", 1, path); + msg("Creating directory %s", path); if (mkdirp(path, 0777, MYF(0)) < 0) { char errbuf[MYSYS_STRERROR_SIZE]; my_strerror(errbuf, sizeof(errbuf), my_errno); - msg("Can not create directory %s: %s\n", + msg("Can not create directory %s: %s", path, errbuf); ret = false; @@ -1832,7 +1955,7 @@ copy_back() } - msg_ts("[%02u] ...done.", 1); + msg(" ...done."); continue; } @@ -1849,21 +1972,19 @@ copy_back() continue; } - /* skip redo logs */ - if (sscanf(filename, "ib_logfile%d%c", &i_tmp, &c_tmp) == 1) { + /* skip the redo log (it was already copied) */ + if (!strcmp(filename, "ib_logfile0")) { continue; } /* skip innodb data files */ is_ibdata_file = false; - for (i = 0; i < srv_n_data_files; i++) { - const char *ibfile; - - ibfile = base_name(srv_data_file_names[i]); - + for (Tablespace::const_iterator iter(srv_sys_space.begin()), + end(srv_sys_space.end()); iter != end; ++iter) { + const char *ibfile = base_name(iter->name()); if (strcmp(ibfile, filename) == 0) { is_ibdata_file = true; - continue; + break; } } if (is_ibdata_file) { @@ -1898,6 +2019,8 @@ copy_back() } } + rocksdb_copy_back(); + cleanup: if (it != NULL) { datadir_iter_free(it); @@ -1905,20 +2028,13 @@ cleanup: datadir_node_free(&node); - free(innobase_data_file_path_copy); - if (ds_data != NULL) { ds_destroy(ds_data); } ds_data = NULL; - //os_sync_free(); - mem_close(); - //os_sync_mutex = NULL; - ut_free_all_mem(); - sync_close(); - sync_initialized = FALSE; + sync_check_close(); return(ret); } @@ -1949,18 +2065,18 @@ decrypt_decompress_file(const char *filepath, uint thread_n) if (needs_action) { - msg_ts("[%02u] %s\n", thread_n, message.str().c_str()); + msg(thread_n,"%s\n", message.str().c_str()); if (system(cmd.str().c_str()) != 0) { return(false); } - if (opt_remove_original) { - msg_ts("[%02u] removing %s\n", thread_n, filepath); - if (my_delete(filepath, MYF(MY_WME)) != 0) { - return(false); - } - } + if (opt_remove_original) { + msg(thread_n, "Removing %s", filepath); + if (my_delete(filepath, MYF(MY_WME)) != 0) { + return(false); + } + } } return(true); @@ -1997,13 +2113,13 @@ cleanup: datadir_node_free(&node); - os_mutex_enter(ctxt->count_mutex); + pthread_mutex_lock(ctxt->count_mutex); --(*ctxt->count); - os_mutex_exit(ctxt->count_mutex); + pthread_mutex_unlock(ctxt->count_mutex); ctxt->ret = ret; - os_thread_exit(NULL); + os_thread_exit(); OS_THREAD_DUMMY_RETURN; } @@ -2014,15 +2130,12 @@ decrypt_decompress() datadir_iter_t *it = NULL; srv_max_n_threads = 1000; - //os_sync_mutex = NULL; - ut_mem_init(); - os_sync_init(); - sync_init(); + sync_check_init(); /* cd to backup directory */ if (my_setwd(xtrabackup_target_dir, MYF(MY_WME))) { - msg("cannot my_setwd %s\n", xtrabackup_target_dir); + msg("Can't my_setwd %s", xtrabackup_target_dir); return(false); } @@ -2046,11 +2159,7 @@ decrypt_decompress() ds_data = NULL; - sync_close(); - sync_initialized = FALSE; - //os_sync_free(); - //os_sync_mutex = NULL; - ut_free_all_mem(); + sync_check_close(); return(ret); } @@ -2088,3 +2197,234 @@ static bool backup_files_from_datadir(const char *dir_path) os_file_closedir(dir); return ret; } + + +static int rocksdb_remove_checkpoint_directory() +{ + xb_mysql_query(mysql_connection, "set global rocksdb_remove_mariabackup_checkpoint=ON", false); + return 0; +} + +static bool has_rocksdb_plugin() +{ + static bool first_time = true; + static bool has_plugin= false; + if (!first_time || !xb_backup_rocksdb) + return has_plugin; + + const char *query = "SELECT COUNT(*) FROM information_schema.plugins WHERE plugin_name='rocksdb'"; + MYSQL_RES* result = xb_mysql_query(mysql_connection, query, true); + MYSQL_ROW row = mysql_fetch_row(result); + if (row) + has_plugin = !strcmp(row[0], "1"); + mysql_free_result(result); + first_time = false; + return has_plugin; +} + +static char *trim_trailing_dir_sep(char *path) +{ + size_t path_len = strlen(path); + while (path_len) + { + char c = path[path_len - 1]; + if (c == '/' IF_WIN(|| c == '\\', )) + path_len--; + else + break; + } + path[path_len] = 0; + return path; +} + +/* +Create a file hardlink. +@return true on success, false on error. +*/ +static bool make_hardlink(const char *from_path, const char *to_path) +{ + DBUG_EXECUTE_IF("no_hardlinks", return false;); + char to_path_full[FN_REFLEN]; + if (!is_abs_path(to_path)) + { + fn_format(to_path_full, to_path, ds_data->root, "", MYF(MY_RELATIVE_PATH)); + } + else + { + strncpy(to_path_full, to_path, sizeof(to_path_full)); + } +#ifdef _WIN32 + return CreateHardLink(to_path_full, from_path, NULL); +#else + return !link(from_path, to_path_full); +#endif +} + +/* + Copies or moves a directory (non-recursively so far). + Helper function used to backup rocksdb checkpoint, or copy-back the + rocksdb files. + + Has optimization that allows to use hardlinks when possible + (source and destination are directories on the same device) +*/ +static void copy_or_move_dir(const char *from, const char *to, bool do_copy, bool allow_hardlinks) +{ + datadir_node_t node; + datadir_node_init(&node); + datadir_iter_t *it = datadir_iter_new(from, false); + + while (datadir_iter_next(it, &node)) + { + char to_path[FN_REFLEN]; + const char *from_path = node.filepath; + snprintf(to_path, sizeof(to_path), "%s/%s", to, base_name(from_path)); + bool rc = false; + if (do_copy && allow_hardlinks) + { + rc = make_hardlink(from_path, to_path); + if (rc) + { + msg("Creating hardlink from %s to %s",from_path, to_path); + } + else + { + allow_hardlinks = false; + } + } + + if (!rc) + { + rc = (do_copy ? + copy_file(ds_data, from_path, to_path, 1) : + move_file(ds_data, from_path, node.filepath_rel, + to, 1)); + } + if (!rc) + die("copy or move file failed"); + } + datadir_iter_free(it); + datadir_node_free(&node); + +} + +/* + Obtain user level lock , to protect the checkpoint directory of the server + from being user/overwritten by different backup processes, if backups are + running in parallel. + + This lock will be acquired before rocksdb checkpoint is created, held + while all files from it are being copied to their final backup destination, + and finally released after the checkpoint is removed. +*/ +static void rocksdb_lock_checkpoint() +{ + msg("Obtaining rocksdb checkpoint lock."); + MYSQL_RES *res = + xb_mysql_query(mysql_connection, "SELECT GET_LOCK('mariabackup_rocksdb_checkpoint',3600)", true, true); + + MYSQL_ROW r = mysql_fetch_row(res); + if (r && r[0] && strcmp(r[0], "1")) + { + msg("Could not obtain rocksdb checkpont lock."); + exit(EXIT_FAILURE); + } + mysql_free_result(res); +} + +static void rocksdb_unlock_checkpoint() +{ + xb_mysql_query(mysql_connection, + "SELECT RELEASE_LOCK('mariabackup_rocksdb_checkpoint')", false, true); +} + + +/* + Create temporary checkpoint in $rocksdb_datadir/mariabackup-checkpoint + directory. + A (user-level) lock named 'mariabackup_rocksdb_checkpoint' will also be + acquired be this function. +*/ +#define MARIADB_CHECKPOINT_DIR "mariabackup-checkpoint" +static char rocksdb_checkpoint_dir[FN_REFLEN]; + +static void rocksdb_create_checkpoint() +{ + MYSQL_RES *result = xb_mysql_query(mysql_connection, "SELECT @@rocksdb_datadir,@@datadir", true, true); + MYSQL_ROW row = mysql_fetch_row(result); + + DBUG_ASSERT(row && row[0] && row[1]); + + char *rocksdbdir = row[0]; + char *datadir = row[1]; + + if (is_abs_path(rocksdbdir)) + { + snprintf(rocksdb_checkpoint_dir, sizeof(rocksdb_checkpoint_dir), + "%s/" MARIADB_CHECKPOINT_DIR, trim_trailing_dir_sep(rocksdbdir)); + } + else + { + snprintf(rocksdb_checkpoint_dir, sizeof(rocksdb_checkpoint_dir), + "%s/%s/" MARIADB_CHECKPOINT_DIR, trim_trailing_dir_sep(datadir), + trim_dotslash(rocksdbdir)); + } + mysql_free_result(result); + +#ifdef _WIN32 + for (char *p = rocksdb_checkpoint_dir; *p; p++) + if (*p == '\\') *p = '/'; +#endif + + rocksdb_lock_checkpoint(); + + if (!access(rocksdb_checkpoint_dir, 0)) + { + msg("Removing rocksdb checkpoint from previous backup attempt."); + rocksdb_remove_checkpoint_directory(); + } + + char query[FN_REFLEN + 32]; + snprintf(query, sizeof(query), "SET GLOBAL rocksdb_create_checkpoint='%s'", rocksdb_checkpoint_dir); + xb_mysql_query(mysql_connection, query, false, true); +} + +/* + Copy files from rocksdb temporary checkpoint to final destination. + remove temp.checkpoint directory (in server's datadir) + and release user level lock acquired inside rocksdb_create_checkpoint(). +*/ +static void rocksdb_backup_checkpoint() +{ + msg("Backing up rocksdb files."); + char rocksdb_backup_dir[FN_REFLEN]; + snprintf(rocksdb_backup_dir, sizeof(rocksdb_backup_dir), "%s/" ROCKSDB_BACKUP_DIR , xtrabackup_target_dir); + bool backup_to_directory = xtrabackup_backup && xtrabackup_stream_fmt == XB_STREAM_FMT_NONE; + if (backup_to_directory) + { + if (my_mkdir(rocksdb_backup_dir, 0777, MYF(0))){ + die("Can't create rocksdb backup directory %s", rocksdb_backup_dir); + } + } + copy_or_move_dir(rocksdb_checkpoint_dir, ROCKSDB_BACKUP_DIR, true, backup_to_directory); + rocksdb_remove_checkpoint_directory(); + rocksdb_unlock_checkpoint(); +} + +/* + Copies #rocksdb directory to the $rockdb_data_dir, on copy-back +*/ +static void rocksdb_copy_back() { + if (access(ROCKSDB_BACKUP_DIR, 0)) + return; + char rocksdb_home_dir[FN_REFLEN]; + if (xb_rocksdb_datadir && is_abs_path(xb_rocksdb_datadir)) { + strncpy(rocksdb_home_dir, xb_rocksdb_datadir, sizeof rocksdb_home_dir - 1); + rocksdb_home_dir[sizeof rocksdb_home_dir - 1] = '\0'; + } else { + snprintf(rocksdb_home_dir, sizeof(rocksdb_home_dir), "%s/%s", mysql_data_home, + xb_rocksdb_datadir?trim_dotslash(xb_rocksdb_datadir): ROCKSDB_BACKUP_DIR); + } + mkdirp(rocksdb_home_dir, 0777, MYF(0)); + copy_or_move_dir(ROCKSDB_BACKUP_DIR, rocksdb_home_dir, xtrabackup_copy_back, xtrabackup_copy_back); +} diff --git a/extra/mariabackup/backup_copy.h b/extra/mariabackup/backup_copy.h index 4b829982764..fbc09eaded3 100644 --- a/extra/mariabackup/backup_copy.h +++ b/extra/mariabackup/backup_copy.h @@ -31,10 +31,12 @@ copy_file(ds_ctxt_t *datasink, const char *dst_file_path, uint thread_n); -bool -backup_start(); -bool -backup_finish(); +/** Start --backup */ +bool backup_start(); +/** Release resources after backup_start() */ +void backup_release(); +/** Finish after backup_start() and backup_release() */ +bool backup_finish(); bool apply_log_finish(); bool diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 543fd4102f2..4c29b1e10c9 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -54,6 +54,7 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include "mysqld.h" #include "encryption_plugin.h" #include <sstream> +#include <sql_error.h> #include "page0zip.h" char *tool_name; @@ -101,7 +102,7 @@ xb_mysql_connect() sprintf(mysql_port_str, "%d", opt_port); if (connection == NULL) { - msg("Failed to init MySQL struct: %s.\n", + msg("Failed to init MySQL struct: %s.", mysql_error(connection)); return(NULL); } @@ -115,9 +116,10 @@ xb_mysql_connect() mysql_options(connection, MYSQL_PLUGIN_DIR, xb_plugin_dir); } mysql_options(connection, MYSQL_OPT_PROTOCOL, &opt_protocol); + mysql_options(connection,MYSQL_SET_CHARSET_NAME, "utf8"); - msg_ts("Connecting to MySQL server host: %s, user: %s, password: %s, " - "port: %s, socket: %s\n", opt_host ? opt_host : "localhost", + msg("Connecting to MySQL server host: %s, user: %s, password: %s, " + "port: %s, socket: %s", opt_host ? opt_host : "localhost", opt_user ? opt_user : "not set", opt_password ? "set" : "not set", opt_port != 0 ? mysql_port_str : "not set", @@ -143,13 +145,12 @@ xb_mysql_connect() opt_password, "" /*database*/, opt_port, opt_socket, 0)) { - msg("Failed to connect to MySQL server: %s.\n", - mysql_error(connection)); + msg("Failed to connect to MySQL server: %s.", mysql_error(connection)); mysql_close(connection); return(NULL); } - xb_mysql_query(connection, "SET SESSION wait_timeout=2147483", + xb_mysql_query(connection, "SET SESSION wait_timeout=2147483, max_statement_time=0", false, true); return(connection); @@ -164,10 +165,10 @@ xb_mysql_query(MYSQL *connection, const char *query, bool use_result, MYSQL_RES *mysql_result = NULL; if (mysql_query(connection, query)) { - msg("Error: failed to execute query %s: %s\n", query, - mysql_error(connection)); if (die_on_error) { - exit(EXIT_FAILURE); + die("failed to execute query %s: %s", query, mysql_error(connection)); + } else { + msg("Error: failed to execute query %s: %s", query, mysql_error(connection)); } return(NULL); } @@ -175,13 +176,13 @@ xb_mysql_query(MYSQL *connection, const char *query, bool use_result, /* store result set on client if there is a result */ if (mysql_field_count(connection) > 0) { if ((mysql_result = mysql_store_result(connection)) == NULL) { - msg("Error: failed to fetch query result %s: %s\n", + die("failed to fetch query result %s: %s", query, mysql_error(connection)); - exit(EXIT_FAILURE); } if (!use_result) { mysql_free_result(mysql_result); + mysql_result = NULL; } } @@ -311,11 +312,11 @@ check_server_version(unsigned long version_number, msg("Error: Built-in InnoDB in MySQL 5.1 is not " "supported in this release. You can either use " "Percona XtraBackup 2.0, or upgrade to InnoDB " - "plugin.\n"); + "plugin."); } else if (!version_supported) { msg("Error: Unsupported server version: '%s'. Please " "report a bug at " - "https://bugs.launchpad.net/percona-xtrabackup\n", + "https://bugs.launchpad.net/percona-xtrabackup", version_string); } @@ -394,7 +395,6 @@ get_mysql_vars(MYSQL *connection) opt_binlog_info = BINLOG_INFO_OFF; } - if (lock_wait_timeout_var != NULL) { have_lock_wait_timeout = true; } @@ -429,7 +429,7 @@ get_mysql_vars(MYSQL *connection) have_gtid_slave = true; } - msg("Using server version %s\n", version_var); + msg("Using server version %s", version_var); if (!(ret = detect_mysql_capabilities_for_backup())) { goto out; @@ -439,17 +439,17 @@ get_mysql_vars(MYSQL *connection) if (check_if_param_set("datadir")) { if (!directory_exists(mysql_data_home, false)) { msg("Warning: option 'datadir' points to " - "nonexistent directory '%s'\n", mysql_data_home); + "nonexistent directory '%s'", mysql_data_home); } if (!directory_exists(datadir_var, false)) { msg("Warning: MySQL variable 'datadir' points to " - "nonexistent directory '%s'\n", datadir_var); + "nonexistent directory '%s'", datadir_var); } if (!equal_paths(mysql_data_home, datadir_var)) { msg("Warning: option 'datadir' has different " "values:\n" " '%s' in defaults file\n" - " '%s' in SHOW VARIABLES\n", + " '%s' in SHOW VARIABLES", mysql_data_home, datadir_var); } } @@ -482,13 +482,13 @@ get_mysql_vars(MYSQL *connection) } if (innodb_log_files_in_group_var) { - innobase_log_files_in_group = strtol( + srv_n_log_files = strtol( innodb_log_files_in_group_var, &endptr, 10); ut_ad(*endptr == 0); } if (innodb_log_file_size_var) { - innobase_log_file_size = strtoll( + srv_log_file_size = strtoll( innodb_log_file_size_var, &endptr, 10); ut_ad(*endptr == 0); } @@ -554,14 +554,14 @@ detect_mysql_capabilities_for_backup() if (opt_galera_info && !have_galera_enabled) { msg("--galera-info is specified on the command " "line, but the server does not support Galera " - "replication. Ignoring the option.\n"); + "replication. Ignoring the option."); opt_galera_info = false; } if (opt_slave_info && have_multi_threaded_slave && !have_gtid_slave) { msg("The --slave-info option requires GTID enabled for a " - "multi-threaded slave.\n"); + "multi-threaded slave."); return(false); } @@ -573,7 +573,6 @@ bool select_incremental_lsn_from_history(lsn_t *incremental_lsn) { MYSQL_RES *mysql_result; - MYSQL_ROW row; char query[1000]; char buf[100]; @@ -581,7 +580,7 @@ select_incremental_lsn_from_history(lsn_t *incremental_lsn) mysql_real_escape_string(mysql_connection, buf, opt_incremental_history_name, (unsigned long)strlen(opt_incremental_history_name)); - ut_snprintf(query, sizeof(query), + snprintf(query, sizeof(query), "SELECT innodb_to_lsn " "FROM PERCONA_SCHEMA.xtrabackup_history " "WHERE name = '%s' " @@ -594,7 +593,7 @@ select_incremental_lsn_from_history(lsn_t *incremental_lsn) mysql_real_escape_string(mysql_connection, buf, opt_incremental_history_uuid, (unsigned long)strlen(opt_incremental_history_uuid)); - ut_snprintf(query, sizeof(query), + snprintf(query, sizeof(query), "SELECT innodb_to_lsn " "FROM PERCONA_SCHEMA.xtrabackup_history " "WHERE uuid = '%s' " @@ -606,27 +605,27 @@ select_incremental_lsn_from_history(lsn_t *incremental_lsn) mysql_result = xb_mysql_query(mysql_connection, query, true); ut_ad(mysql_num_fields(mysql_result) == 1); - if (!(row = mysql_fetch_row(mysql_result))) { + const MYSQL_ROW row = mysql_fetch_row(mysql_result); + if (row) { + *incremental_lsn = strtoull(row[0], NULL, 10); + msg("Found and using lsn: " LSN_PF " for %s %s", + *incremental_lsn, + opt_incremental_history_uuid ? "uuid" : "name", + opt_incremental_history_uuid ? + opt_incremental_history_uuid : + opt_incremental_history_name); + } else { msg("Error while attempting to find history record " - "for %s %s\n", + "for %s %s", opt_incremental_history_uuid ? "uuid" : "name", opt_incremental_history_uuid ? opt_incremental_history_uuid : opt_incremental_history_name); - return(false); } - *incremental_lsn = strtoull(row[0], NULL, 10); - mysql_free_result(mysql_result); - msg("Found and using lsn: " LSN_PF " for %s %s\n", *incremental_lsn, - opt_incremental_history_uuid ? "uuid" : "name", - opt_incremental_history_uuid ? - opt_incremental_history_uuid : - opt_incremental_history_name); - - return(true); + return(row != NULL); } static @@ -713,59 +712,58 @@ static bool have_queries_to_wait_for(MYSQL *connection, uint threshold) { - MYSQL_RES *result; - MYSQL_ROW row; - bool all_queries; + MYSQL_RES *result = xb_mysql_query(connection, "SHOW FULL PROCESSLIST", + true); + const bool all_queries = (opt_lock_wait_query_type == QUERY_TYPE_ALL); + bool have_to_wait = false; - result = xb_mysql_query(connection, "SHOW FULL PROCESSLIST", true); - - all_queries = (opt_lock_wait_query_type == QUERY_TYPE_ALL); - while ((row = mysql_fetch_row(result)) != NULL) { + while (MYSQL_ROW row = mysql_fetch_row(result)) { const char *info = row[7]; - int duration = atoi(row[5]); + int duration = row[5] ? atoi(row[5]) : 0; char *id = row[0]; if (info != NULL && duration >= (int)threshold && ((all_queries && is_query(info)) || is_update_query(info))) { - msg_ts("Waiting for query %s (duration %d sec): %s", + msg("Waiting for query %s (duration %d sec): %s", id, duration, info); - return(true); + have_to_wait = true; + break; } } - return(false); + mysql_free_result(result); + return(have_to_wait); } static void kill_long_queries(MYSQL *connection, time_t timeout) { - MYSQL_RES *result; - MYSQL_ROW row; - bool all_queries; char kill_stmt[100]; - result = xb_mysql_query(connection, "SHOW FULL PROCESSLIST", true); - - all_queries = (opt_kill_long_query_type == QUERY_TYPE_ALL); - while ((row = mysql_fetch_row(result)) != NULL) { + MYSQL_RES *result = xb_mysql_query(connection, "SHOW FULL PROCESSLIST", + true); + const bool all_queries = (opt_kill_long_query_type == QUERY_TYPE_ALL); + while (MYSQL_ROW row = mysql_fetch_row(result)) { const char *info = row[7]; - long long duration = atoll(row[5]); + long long duration = row[5]? atoll(row[5]) : 0; char *id = row[0]; if (info != NULL && (time_t)duration >= timeout && ((all_queries && is_query(info)) || is_select_query(info))) { - msg_ts("Killing query %s (duration %d sec): %s\n", + msg("Killing query %s (duration %d sec): %s", id, (int)duration, info); - ut_snprintf(kill_stmt, sizeof(kill_stmt), + snprintf(kill_stmt, sizeof(kill_stmt), "KILL %s", id); xb_mysql_query(connection, kill_stmt, false, false); } } + + mysql_free_result(result); } static @@ -776,8 +774,8 @@ wait_for_no_updates(MYSQL *connection, uint timeout, uint threshold) start_time = time(NULL); - msg_ts("Waiting %u seconds for queries running longer than %u seconds " - "to finish\n", timeout, threshold); + msg("Waiting %u seconds for queries running longer than %u seconds " + "to finish", timeout, threshold); while (time(NULL) <= (time_t)(start_time + timeout)) { if (!have_queries_to_wait_for(connection, threshold)) { @@ -786,7 +784,7 @@ wait_for_no_updates(MYSQL *connection, uint timeout, uint threshold) os_thread_sleep(1000000); } - msg_ts("Unable to obtain lock. Please try again later."); + msg("Unable to obtain lock. Please try again later."); return(false); } @@ -804,7 +802,7 @@ kill_query_thread( os_event_set(kill_query_thread_started); - msg_ts("Kill query timeout %d seconds.\n", + msg("Kill query timeout %d seconds.", opt_kill_long_queries_timeout); while (time(NULL) - start_time < @@ -816,7 +814,7 @@ kill_query_thread( } if ((mysql = xb_mysql_connect()) == NULL) { - msg("Error: kill query thread failed\n"); + msg("Error: kill query thread failed"); goto stop_thread; } @@ -831,11 +829,11 @@ kill_query_thread( mysql_close(mysql); stop_thread: - msg_ts("Kill query thread stopped\n"); + msg("Kill query thread stopped"); os_event_set(kill_query_thread_stopped); - os_thread_exit(NULL); + os_thread_exit(); OS_THREAD_DUMMY_RETURN; } @@ -844,9 +842,9 @@ static void start_query_killer() { - kill_query_thread_stop = os_event_create(); - kill_query_thread_started = os_event_create(); - kill_query_thread_stopped = os_event_create(); + kill_query_thread_stop = os_event_create(0); + kill_query_thread_started = os_event_create(0); + kill_query_thread_stopped = os_event_create(0); os_thread_create(kill_query_thread, NULL, &kill_query_thread_id); @@ -861,6 +859,83 @@ stop_query_killer() os_event_wait_time(kill_query_thread_stopped, 60000); } + +/* +Killing connections that wait for MDL lock. +If lock-ddl-per-table is used, there can be some DDL statements + +FLUSH TABLES would hang infinitely, if DDL statements are waiting for +MDL lock, which mariabackup currently holds. Therefore we start killing +those statements from a dedicated thread, until FLUSH TABLES WITH READ LOCK +succeeds. +*/ + +static os_event_t mdl_killer_stop_event; +static os_event_t mdl_killer_finished_event; + +static +os_thread_ret_t +DECLARE_THREAD(kill_mdl_waiters_thread(void *)) +{ + MYSQL *mysql; + if ((mysql = xb_mysql_connect()) == NULL) { + msg("Error: kill mdl waiters thread failed to connect"); + goto stop_thread; + } + + for(;;){ + if (os_event_wait_time(mdl_killer_stop_event, 1000) == 0) + break; + + MYSQL_RES *result = xb_mysql_query(mysql, + "SELECT ID, COMMAND, INFO FROM INFORMATION_SCHEMA.PROCESSLIST " + " WHERE State='Waiting for table metadata lock'", + true, true); + while (MYSQL_ROW row = mysql_fetch_row(result)) + { + char query[64]; + + if (row[1] && !strcmp(row[1], "Killed")) + continue; + + msg("Killing MDL waiting %s ('%s') on connection %s", + row[1], row[2], row[0]); + snprintf(query, sizeof(query), "KILL QUERY %s", row[0]); + if (mysql_query(mysql, query) && (mysql_errno(mysql) != ER_NO_SUCH_THREAD)) { + die("failed to execute query %s: %s", query,mysql_error(mysql)); + } + } + mysql_free_result(result); + } + + mysql_close(mysql); + +stop_thread: + msg("Kill mdl waiters thread stopped"); + os_event_set(mdl_killer_finished_event); + os_thread_exit(); + return os_thread_ret_t(0); +} + + +static void start_mdl_waiters_killer() +{ + mdl_killer_stop_event = os_event_create(0); + mdl_killer_finished_event = os_event_create(0); + os_thread_create(kill_mdl_waiters_thread, 0, 0); +} + + +/* Tell MDL killer to stop and finish for its completion*/ +static void stop_mdl_waiters_killer() +{ + os_event_set(mdl_killer_stop_event); + os_event_wait(mdl_killer_finished_event); + + os_event_destroy(mdl_killer_stop_event); + os_event_destroy(mdl_killer_finished_event); +} + /*********************************************************************//** Function acquires either a backup tables lock, if supported by the server, or a global read lock (FLUSH TABLES WITH READ LOCK) @@ -878,11 +953,15 @@ lock_tables(MYSQL *connection) } if (have_backup_locks) { - msg_ts("Executing LOCK TABLES FOR BACKUP...\n"); + msg("Executing LOCK TABLES FOR BACKUP..."); xb_mysql_query(connection, "LOCK TABLES FOR BACKUP", false); return(true); } + if (opt_lock_ddl_per_table) { + start_mdl_waiters_killer(); + } + if (!opt_lock_wait_timeout && !opt_kill_long_queries_timeout) { /* We do first a FLUSH TABLES. If a long update is running, the @@ -897,7 +976,7 @@ lock_tables(MYSQL *connection) compatible with this trick. */ - msg_ts("Executing FLUSH NO_WRITE_TO_BINLOG TABLES...\n"); + msg("Executing FLUSH NO_WRITE_TO_BINLOG TABLES..."); xb_mysql_query(connection, "FLUSH NO_WRITE_TO_BINLOG TABLES", false); @@ -910,7 +989,7 @@ lock_tables(MYSQL *connection) } } - msg_ts("Executing FLUSH TABLES WITH READ LOCK...\n"); + msg("Executing FLUSH TABLES WITH READ LOCK..."); if (opt_kill_long_queries_timeout) { start_query_killer(); @@ -923,6 +1002,10 @@ lock_tables(MYSQL *connection) xb_mysql_query(connection, "FLUSH TABLES WITH READ LOCK", false); + if (opt_lock_ddl_per_table) { + stop_mdl_waiters_killer(); + } + if (opt_kill_long_queries_timeout) { stop_query_killer(); } @@ -939,7 +1022,7 @@ bool lock_binlog_maybe(MYSQL *connection) { if (have_backup_locks && !opt_no_lock && !binlog_locked) { - msg_ts("Executing LOCK BINLOG FOR BACKUP...\n"); + msg("Executing LOCK BINLOG FOR BACKUP..."); xb_mysql_query(connection, "LOCK BINLOG FOR BACKUP", false); binlog_locked = true; @@ -958,20 +1041,20 @@ void unlock_all(MYSQL *connection) { if (opt_debug_sleep_before_unlock) { - msg_ts("Debug sleep for %u seconds\n", + msg("Debug sleep for %u seconds", opt_debug_sleep_before_unlock); os_thread_sleep(opt_debug_sleep_before_unlock * 1000); } if (binlog_locked) { - msg_ts("Executing UNLOCK BINLOG\n"); + msg("Executing UNLOCK BINLOG"); xb_mysql_query(connection, "UNLOCK BINLOG", false); } - msg_ts("Executing UNLOCK TABLES\n"); + msg("Executing UNLOCK TABLES"); xb_mysql_query(connection, "UNLOCK TABLES", false); - msg_ts("All tables unlocked\n"); + msg("All tables unlocked"); } @@ -1022,7 +1105,7 @@ wait_for_safe_slave(MYSQL *connection) if (!(read_master_log_pos && slave_sql_running)) { msg("Not checking slave open temp tables for " - "--safe-slave-backup because host is not a slave\n"); + "--safe-slave-backup because host is not a slave"); goto cleanup; } @@ -1036,36 +1119,36 @@ wait_for_safe_slave(MYSQL *connection) } open_temp_tables = get_open_temp_tables(connection); - msg_ts("Slave open temp tables: %d\n", open_temp_tables); + msg("Slave open temp tables: %d", open_temp_tables); while (open_temp_tables && n_attempts--) { - msg_ts("Starting slave SQL thread, waiting %d seconds, then " + msg("Starting slave SQL thread, waiting %d seconds, then " "checking Slave_open_temp_tables again (%d attempts " - "remaining)...\n", sleep_time, n_attempts); + "remaining)...", sleep_time, n_attempts); xb_mysql_query(connection, "START SLAVE SQL_THREAD", false); os_thread_sleep(sleep_time * 1000000); xb_mysql_query(connection, "STOP SLAVE SQL_THREAD", false); open_temp_tables = get_open_temp_tables(connection); - msg_ts("Slave open temp tables: %d\n", open_temp_tables); + msg("Slave open temp tables: %d", open_temp_tables); } /* Restart the slave if it was running at start */ if (open_temp_tables == 0) { - msg_ts("Slave is safe to backup\n"); + msg("Slave is safe to backup"); goto cleanup; } result = false; if (sql_thread_started) { - msg_ts("Restarting slave SQL thread.\n"); + msg("Restarting slave SQL thread."); xb_mysql_query(connection, "START SLAVE SQL_THREAD", false); } - msg_ts("Slave_open_temp_tables did not become zero after " - "%d seconds\n", opt_safe_slave_backup_timeout); + msg("Slave_open_temp_tables did not become zero after " + "%d seconds", opt_safe_slave_backup_timeout); cleanup: free_mysql_variables(status); @@ -1107,10 +1190,8 @@ write_slave_info(MYSQL *connection) if (master == NULL || filename == NULL || position == NULL) { msg("Failed to get master binlog coordinates " - "from SHOW SLAVE STATUS\n"); - msg("This means that the server is not a " - "replication slave. Ignoring the --slave-info " - "option\n"); + "from SHOW SLAVE STATUS.This means that the server is not a " + "replication slave. Ignoring the --slave-info option"); /* we still want to continue the backup */ result = true; goto cleanup; @@ -1193,7 +1274,7 @@ write_galera_info(MYSQL *connection) if ((state_uuid == NULL && state_uuid55 == NULL) || (last_committed == NULL && last_committed55 == NULL)) { - msg("Failed to get master wsrep state from SHOW STATUS.\n"); + msg("Failed to get master wsrep state from SHOW STATUS."); result = false; goto cleanup; } @@ -1281,8 +1362,8 @@ write_current_binlog_file(MYSQL *connection) goto cleanup; } - ut_snprintf(filepath, sizeof(filepath), "%s%c%s", - log_bin_dir, FN_LIBCHAR, log_bin_file); + snprintf(filepath, sizeof(filepath), "%s%c%s", + log_bin_dir, FN_LIBCHAR, log_bin_file); result = copy_file(ds_data, filepath, log_bin_file, 0); } @@ -1362,17 +1443,27 @@ cleanup: return(result); } -static string escape_and_quote(MYSQL *mysql,const char *str) +struct escape_and_quote +{ + escape_and_quote(MYSQL *mysql, const char *str) + : mysql(mysql), str(str) {} + MYSQL * const mysql; + const char * const str; +}; + +static +std::ostream& +operator<<(std::ostream& s, const escape_and_quote& eq) { - if (!str) - return "NULL"; - size_t len = strlen(str); - char* escaped = (char *)alloca(2 * len + 3); - escaped[0] = '\''; - size_t new_len = mysql_real_escape_string(mysql, escaped+1, str, len); - escaped[new_len + 1] = '\''; - escaped[new_len + 2] = 0; - return string(escaped); + if (!eq.str) + return s << "NULL"; + s << '\''; + size_t len = strlen(eq.str); + char* escaped = (char *)alloca(2 * len + 1); + len = mysql_real_escape_string(eq.mysql, escaped, eq.str, len); + s << std::string(escaped, len); + s << '\''; + return s; } /*********************************************************************//** @@ -1381,7 +1472,7 @@ PERCONA_SCHEMA.xtrabackup_history and writes a new history record to the table containing all the history info particular to the just completed backup. */ bool -write_xtrabackup_info(MYSQL *connection) +write_xtrabackup_info(MYSQL *connection, const char * filename, bool history) { char *uuid = NULL; @@ -1389,10 +1480,9 @@ write_xtrabackup_info(MYSQL *connection) char buf_start_time[100]; char buf_end_time[100]; tm tm; - ostringstream oss; + std::ostringstream oss; const char *xb_stream_name[] = {"file", "tar", "xbstream"}; - uuid = read_mysql_one_value(connection, "SELECT UUID()"); server_version = read_mysql_one_value(connection, "SELECT VERSION()"); localtime_r(&history_start_time, &tm); @@ -1410,7 +1500,7 @@ write_xtrabackup_info(MYSQL *connection) || xtrabackup_databases_exclude ); - backup_file_printf(XTRABACKUP_INFO, + backup_file_printf(filename, "uuid = %s\n" "name = %s\n" "tool_name = %s\n" @@ -1447,7 +1537,7 @@ write_xtrabackup_info(MYSQL *connection) xb_stream_name[xtrabackup_stream_fmt], /* format */ xtrabackup_compress ? "compressed" : "N"); /* compressed */ - if (!opt_history) { + if (!history) { goto cleanup; } @@ -1558,30 +1648,23 @@ bool write_backup_config_file() "# The MySQL server\n" "[mysqld]\n" "innodb_checksum_algorithm=%s\n" - "innodb_log_checksum_algorithm=%s\n" "innodb_data_file_path=%s\n" "innodb_log_files_in_group=%lu\n" - "innodb_log_file_size=%lld\n" + "innodb_log_file_size=%llu\n" "innodb_page_size=%lu\n" - "innodb_log_block_size=%lu\n" "innodb_undo_directory=%s\n" "innodb_undo_tablespaces=%lu\n" "innodb_compression_level=%u\n" "%s%s\n" - "%s%s\n" "%s\n", innodb_checksum_algorithm_names[srv_checksum_algorithm], - innodb_checksum_algorithm_names[srv_log_checksum_algorithm], make_local_paths(innobase_data_file_path).c_str(), srv_n_log_files, - innobase_log_file_size, + srv_log_file_size, srv_page_size, - srv_log_block_size, srv_undo_dir, srv_undo_tablespaces, page_zip_level, - innobase_doublewrite_file ? "innodb_doublewrite_file=" : "", - innobase_doublewrite_file ? innobase_doublewrite_file : "", innobase_buffer_pool_filename ? "innodb_buffer_pool_filename=" : "", innobase_buffer_pool_filename ? @@ -1605,8 +1688,8 @@ char *make_argv(char *buf, size_t len, int argc, char **argv) if (strncmp(*argv, "--password", strlen("--password")) == 0) { arg = "--password=..."; } - left-= ut_snprintf(buf + len - left, left, - "%s%c", arg, argc > 1 ? ' ' : 0); + left-= snprintf(buf + len - left, left, + "%s%c", arg, argc > 1 ? ' ' : 0); ++argv; --argc; } @@ -1662,3 +1745,64 @@ backup_cleanup() mysql_close(mysql_connection); } } + + +static MYSQL *mdl_con = NULL; + +std::map<ulint, std::string> spaceid_to_tablename; + +void +mdl_lock_init() +{ + mdl_con = xb_mysql_connect(); + if (!mdl_con) + { + msg("FATAL: cannot create connection for MDL locks"); + exit(1); + } + const char *query = + "SELECT NAME, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%%/%%'"; + + MYSQL_RES *mysql_result = xb_mysql_query(mdl_con, query, true, true); + while (MYSQL_ROW row = mysql_fetch_row(mysql_result)) { + int err; + ulint id = (ulint)my_strtoll10(row[1], 0, &err); + spaceid_to_tablename[id] = ut_get_name(0, row[0]); + } + mysql_free_result(mysql_result); + + xb_mysql_query(mdl_con, "BEGIN", false, true); +} + +void +mdl_lock_table(ulint space_id) +{ + if (space_id == 0) + return; + + std::string full_table_name = spaceid_to_tablename[space_id]; + + DBUG_EXECUTE_IF("rename_during_mdl_lock_table", + if (full_table_name == "`test`.`t1`") + xb_mysql_query(mysql_connection, "RENAME TABLE test.t1 to test.t2", false, true); + ); + + std::ostringstream lock_query; + lock_query << "SELECT 1 FROM " << full_table_name << " LIMIT 0"; + msg("Locking MDL for %s", full_table_name.c_str()); + if (mysql_query(mdl_con, lock_query.str().c_str())) { + msg("Warning : locking MDL failed for space id %zu, name %s", space_id, full_table_name.c_str()); + } else { + MYSQL_RES *r = mysql_store_result(mdl_con); + mysql_free_result(r); + } +} + +void +mdl_unlock_all() +{ + msg("Unlocking MDL for all tables"); + xb_mysql_query(mdl_con, "COMMIT", false, true); + mysql_close(mdl_con); + spaceid_to_tablename.clear(); +} diff --git a/extra/mariabackup/backup_mysql.h b/extra/mariabackup/backup_mysql.h index 3ccd7bdb613..e2c56f88a8c 100644 --- a/extra/mariabackup/backup_mysql.h +++ b/extra/mariabackup/backup_mysql.h @@ -68,7 +68,7 @@ bool write_binlog_info(MYSQL *connection); bool -write_xtrabackup_info(MYSQL *connection); +write_xtrabackup_info(MYSQL *connection, const char * filename, bool history); bool write_backup_config_file(); diff --git a/extra/mariabackup/backup_wsrep.h b/extra/mariabackup/backup_wsrep.h index 0807da8a59a..50a8a3a53e7 100644 --- a/extra/mariabackup/backup_wsrep.h +++ b/extra/mariabackup/backup_wsrep.h @@ -19,8 +19,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *******************************************************/ -#ifndef MARIABACKUP_WSREP_H -#define MARIABACKUP_WSREP_H +#ifndef BACKUP_WSREP_H +#define BACKUP_WSREP_H /*********************************************************************** Store Galera checkpoint info in the 'xtrabackup_galera_info' file, if that diff --git a/extra/mariabackup/changed_page_bitmap.cc b/extra/mariabackup/changed_page_bitmap.cc index 372d5b62a1d..373af9451f9 100644 --- a/extra/mariabackup/changed_page_bitmap.cc +++ b/extra/mariabackup/changed_page_bitmap.cc @@ -193,16 +193,16 @@ log_online_read_bitmap_page( ut_a(bitmap_file->offset <= bitmap_file->size - MODIFIED_PAGE_BLOCK_SIZE); ut_a(bitmap_file->offset % MODIFIED_PAGE_BLOCK_SIZE == 0); - - success = os_file_read(bitmap_file->file, page, bitmap_file->offset, - MODIFIED_PAGE_BLOCK_SIZE); + success = os_file_read(IORequestRead, + bitmap_file->file, page, bitmap_file->offset, + MODIFIED_PAGE_BLOCK_SIZE) == DB_SUCCESS; if (UNIV_UNLIKELY(!success)) { /* The following call prints an error message */ os_file_get_last_error(TRUE); msg("InnoDB: Warning: failed reading changed page bitmap " - "file \'%s\'\n", bitmap_file->name); + "file \'%s\'", bitmap_file->name); return FALSE; } @@ -281,7 +281,7 @@ log_online_setup_bitmap_file_range( bitmap_dir = os_file_opendir(srv_data_home, FALSE); if (UNIV_UNLIKELY(!bitmap_dir)) { - msg("InnoDB: Error: failed to open bitmap directory \'%s\'\n", + msg("InnoDB: Error: failed to open bitmap directory \'%s\'", srv_data_home); return FALSE; } @@ -331,7 +331,7 @@ log_online_setup_bitmap_file_range( if (UNIV_UNLIKELY(os_file_closedir(bitmap_dir))) { os_file_get_last_error(TRUE); - msg("InnoDB: Error: cannot close \'%s\'\n",srv_data_home); + msg("InnoDB: Error: cannot close \'%s\'",srv_data_home); return FALSE; } @@ -348,15 +348,14 @@ log_online_setup_bitmap_file_range( bitmap_dir = os_file_opendir(srv_data_home, FALSE); if (UNIV_UNLIKELY(!bitmap_dir)) { - msg("InnoDB: Error: failed to open bitmap directory \'%s\'\n", + msg("InnoDB: Error: failed to open bitmap directory \'%s\'", srv_data_home); return FALSE; } bitmap_files->files = static_cast<log_online_bitmap_file_range_t::files_t *> - (ut_malloc(bitmap_files->count - * sizeof(bitmap_files->files[0]))); + (malloc(bitmap_files->count * sizeof(bitmap_files->files[0]))); memset(bitmap_files->files, 0, bitmap_files->count * sizeof(bitmap_files->files[0])); @@ -380,7 +379,7 @@ log_online_setup_bitmap_file_range( if (UNIV_UNLIKELY(array_pos >= bitmap_files->count)) { msg("InnoDB: Error: inconsistent bitmap file " - "directory\n"); + "directory"); os_file_closedir(bitmap_dir); free(bitmap_files->files); return FALSE; @@ -401,7 +400,7 @@ log_online_setup_bitmap_file_range( if (UNIV_UNLIKELY(os_file_closedir(bitmap_dir))) { os_file_get_last_error(TRUE); - msg("InnoDB: Error: cannot close \'%s\'\n", srv_data_home); + msg("InnoDB: Error: cannot close \'%s\'", srv_data_home); free(bitmap_files->files); return FALSE; } @@ -427,9 +426,9 @@ log_online_setup_bitmap_file_range( /****************************************************************//** Open a bitmap file for reading. -@return TRUE if opened successfully */ +@return whether opened successfully */ static -ibool +bool log_online_open_bitmap_file_read_only( /*==================================*/ const char* name, /*!<in: bitmap file @@ -439,23 +438,21 @@ log_online_open_bitmap_file_read_only( log_online_bitmap_file_t* bitmap_file) /*!<out: opened bitmap file */ { - ibool success = FALSE; + bool success = false; xb_ad(name[0] != '\0'); - ut_snprintf(bitmap_file->name, FN_REFLEN, "%s%s", srv_data_home, name); - bitmap_file->file - = os_file_create_simple_no_error_handling(0, bitmap_file->name, - OS_FILE_OPEN, - OS_FILE_READ_ONLY, - &success,0); + snprintf(bitmap_file->name, FN_REFLEN, "%s%s", srv_data_home, name); + bitmap_file->file = os_file_create_simple_no_error_handling( + 0, bitmap_file->name, + OS_FILE_OPEN, OS_FILE_READ_ONLY, true, &success); if (UNIV_UNLIKELY(!success)) { /* Here and below assume that bitmap file names do not contain apostrophes, thus no need for ut_print_filename(). */ msg("InnoDB: Warning: error opening the changed page " - "bitmap \'%s\'\n", bitmap_file->name); - return FALSE; + "bitmap \'%s\'", bitmap_file->name); + return success; } bitmap_file->size = os_file_get_size(bitmap_file->file); @@ -466,7 +463,7 @@ log_online_open_bitmap_file_read_only( posix_fadvise(bitmap_file->file, 0, 0, POSIX_FADV_NOREUSE); #endif - return TRUE; + return success; } /****************************************************************//** @@ -498,7 +495,7 @@ log_online_diagnose_bitmap_eof( itself. */ msg("InnoDB: Warning: junk at the end of changed " - "page bitmap file \'%s\'.\n", bitmap_file->name); + "page bitmap file \'%s\'.", bitmap_file->name); } if (UNIV_UNLIKELY(!last_page_in_run)) { @@ -509,7 +506,7 @@ log_online_diagnose_bitmap_eof( for the whole server */ msg("InnoDB: Warning: changed page bitmap " "file \'%s\' does not contain a complete run " - "at the end.\n", bitmap_file->name); + "at the end.", bitmap_file->name); return FALSE; } } @@ -540,7 +537,7 @@ xb_msg_missing_lsn_data( lsn_t missing_interval_end) /*!<in: interval end */ { msg("mariabackup: warning: changed page data missing for LSNs between " - LSN_PF " and " LSN_PF "\n", missing_interval_start, + LSN_PF " and " LSN_PF, missing_interval_start, missing_interval_end); } @@ -618,7 +615,7 @@ xb_page_bitmap_init(void) msg("mariabackup: incremental backup LSN " LSN_PF " is larger than than the last checkpoint LSN " LSN_PF - "\n", bmp_start_lsn, bmp_end_lsn); + , bmp_start_lsn, bmp_end_lsn); return NULL; } @@ -702,7 +699,7 @@ xb_page_bitmap_init(void) bmp_start_lsn))) { msg("mariabackup: Warning: changed page bitmap file " - "\'%s\' corrupted\n", bitmap_file.name); + "\'%s\' corrupted", bitmap_file.name); rbt_free(result); free(bitmap_files.files); os_file_close(bitmap_file.file); @@ -807,7 +804,7 @@ xb_page_bitmap_init(void) if (UNIV_UNLIKELY(!last_page_ok)) { msg("mariabackup: warning: changed page bitmap file " - "\'%s\' corrupted.\n", bitmap_file.name); + "\'%s\' corrupted.", bitmap_file.name); rbt_free(result); free(bitmap_files.files); os_file_close(bitmap_file.file); @@ -910,6 +907,37 @@ xb_page_bitmap_setup_next_page( return TRUE; } +/** Find the node with the smallest key that greater than equal to search key. +@param[in] tree red-black tree +@param[in] key search key +@return node with the smallest greater-than-or-equal key +@retval NULL if none was found */ +static +const ib_rbt_node_t* +rbt_lower_bound(const ib_rbt_t* tree, const void* key) +{ + ut_ad(!tree->cmp_arg); + const ib_rbt_node_t* ge = NULL; + + for (const ib_rbt_node_t *node = tree->root->left; + node != tree->nil; ) { + int result = tree->compare(node->value, key); + + if (result < 0) { + node = node->right; + } else { + ge = node; + if (result == 0) { + break; + } + + node = node->left; + } + } + + return(ge); +} + /****************************************************************//** Set up a new bitmap range iterator over a given space id changed pages in a given bitmap. @@ -923,8 +951,7 @@ xb_page_bitmap_range_init( { byte search_page[MODIFIED_PAGE_BLOCK_SIZE]; xb_page_bitmap_range *result - = static_cast<xb_page_bitmap_range *> - (ut_malloc(sizeof(*result))); + = static_cast<xb_page_bitmap_range *>(malloc(sizeof(*result))); memset(result, 0, sizeof(*result)); result->bitmap = bitmap; @@ -1015,5 +1042,5 @@ xb_page_bitmap_range_deinit( /*========================*/ xb_page_bitmap_range* bitmap_range) /*! in/out: bitmap range */ { - ut_free(bitmap_range); + free(bitmap_range); } diff --git a/extra/mariabackup/common.h b/extra/mariabackup/common.h index 8fd636a5963..1973512ad82 100644 --- a/extra/mariabackup/common.h +++ b/extra/mariabackup/common.h @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include <mysql_version.h> #include <fcntl.h> #include <stdarg.h> +#include <my_sys.h> /** Determine if (i) is a user tablespace id or not. */ @@ -71,7 +72,7 @@ static inline int asprintf(char **strp, const char *fmt,...) #define xb_a(expr) \ do { \ if (!(expr)) { \ - msg("Assertion \"%s\" failed at %s:%lu\n", \ + fprintf(stderr,"Assertion \"%s\" failed at %s:%lu\n", \ #expr, __FILE__, (ulong) __LINE__); \ abort(); \ } \ @@ -85,42 +86,55 @@ static inline int asprintf(char **strp, const char *fmt,...) #define XB_DELTA_INFO_SUFFIX ".meta" -static inline int msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); -static inline int msg(const char *fmt, ...) +static inline int msg1(uint thread_num, const char *prefix, const char *fmt, va_list args) { - int result; - va_list args; - - va_start(args, fmt); - result = vfprintf(stderr, fmt, args); - va_end(args); - - return result; + int result; + time_t t = time(NULL); + char date[100]; + char *line; + strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&t)); + result = vasprintf(&line, fmt, args); + if (result != -1) { + if (fmt && fmt[strlen(fmt)] != '\n') + result = fprintf(stderr, "[%02u] %s%s %s\n", thread_num, prefix, date, line); + else + result = fprintf(stderr, "[%02u] %s%s %s", thread_num, prefix, date, line); + free(line); + } + return result; } -static inline int msg_ts(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); -static inline int msg_ts(const char *fmt, ...) +static inline ATTRIBUTE_FORMAT(printf, 2, 3) int msg(unsigned int thread_num, const char *fmt, ...) { - int result; - time_t t = time(NULL); - char date[100]; - char *line; - va_list args; - - strftime(date, sizeof(date), "%y%m%d %H:%M:%S", localtime(&t)); - - va_start(args, fmt); - result = vasprintf(&line, fmt, args); - va_end(args); + int result; + va_list args; + va_start(args, fmt); + result = msg1(thread_num,"", fmt, args); + va_end(args); + return result; +} - if (result != -1) { - result = fprintf(stderr, "%s %s", date, line); - free(line); - } +static inline ATTRIBUTE_FORMAT(printf, 1, 2) int msg(const char *fmt, ...) +{ + int result; + va_list args; + va_start(args, fmt); + result = msg1(0, "", fmt, args); + va_end(args); + return result; +} - return result; +static inline ATTRIBUTE_FORMAT(printf, 1,2) ATTRIBUTE_NORETURN void die(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + msg1(0, "FATAL ERROR: ", fmt, args); + va_end(args); + fflush(stderr); + _exit(EXIT_FAILURE); } + /* Use POSIX_FADV_NORMAL when available */ #ifdef POSIX_FADV_NORMAL diff --git a/extra/mariabackup/datasink.c b/extra/mariabackup/datasink.cc index 4ce54891d68..4235a46ea00 100644 --- a/extra/mariabackup/datasink.c +++ b/extra/mariabackup/datasink.cc @@ -48,8 +48,7 @@ ds_create(const char *root, ds_type_t type) #ifdef HAVE_LIBARCHIVE ds = &datasink_archive; #else - msg("Error : mariabackup was built without libarchive support"); - exit(EXIT_FAILURE); + die("mariabackup was built without libarchive support"); #endif break; case DS_TYPE_XBSTREAM: @@ -60,8 +59,7 @@ ds_create(const char *root, ds_type_t type) break; case DS_TYPE_ENCRYPT: case DS_TYPE_DECRYPT: - msg("Error : mariabackup does not support encrypted backups."); - exit(EXIT_FAILURE); + die("mariabackup does not support encrypted backups."); break; case DS_TYPE_TMPFILE: @@ -71,7 +69,7 @@ ds_create(const char *root, ds_type_t type) ds = &datasink_buffer; break; default: - msg("Unknown datasink type: %d\n", type); + msg("Unknown datasink type: %d", type); xb_ad(0); return NULL; } @@ -80,8 +78,7 @@ ds_create(const char *root, ds_type_t type) if (ctxt != NULL) { ctxt->datasink = ds; } else { - msg("Error: failed to initialize datasink.\n"); - exit(EXIT_FAILURE); + die("failed to initialize datasink."); } return ctxt; @@ -108,6 +105,9 @@ Write to a datasink file. int ds_write(ds_file_t *file, const void *buf, size_t len) { + if (len == 0) { + return 0; + } return file->datasink->write(file, (const uchar *)buf, len); } diff --git a/extra/mariabackup/ds_archive.c b/extra/mariabackup/ds_archive.cc index 3826029e120..3826029e120 100644 --- a/extra/mariabackup/ds_archive.c +++ b/extra/mariabackup/ds_archive.cc diff --git a/extra/mariabackup/ds_buffer.c b/extra/mariabackup/ds_buffer.cc index 32c7a90d8e4..e906edc9e84 100644 --- a/extra/mariabackup/ds_buffer.c +++ b/extra/mariabackup/ds_buffer.cc @@ -71,7 +71,7 @@ buffer_init(const char *root) ds_ctxt_t *ctxt; ds_buffer_ctxt_t *buffer_ctxt; - ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_buffer_ctxt_t), + ctxt = (ds_ctxt_t *)my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_buffer_ctxt_t), MYF(MY_FAE)); buffer_ctxt = (ds_buffer_ctxt_t *) (ctxt + 1); buffer_ctxt->buffer_size = DS_DEFAULT_BUFFER_SIZE; @@ -96,7 +96,7 @@ buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) dst_file = ds_open(pipe_ctxt, path, mystat); if (dst_file == NULL) { - exit(EXIT_FAILURE); + die("ds_open(%s) failed", path); } buffer_ctxt = (ds_buffer_ctxt_t *) ctxt->ptr; diff --git a/extra/mariabackup/ds_compress.c b/extra/mariabackup/ds_compress.cc index 5237b24fae9..fb4f3a75bb6 100644 --- a/extra/mariabackup/ds_compress.c +++ b/extra/mariabackup/ds_compress.cc @@ -95,7 +95,7 @@ compress_init(const char *root) /* Create and initialize the worker threads */ threads = create_worker_threads(xtrabackup_compress_threads); if (threads == NULL) { - msg("compress: failed to create worker threads.\n"); + msg("compress: failed to create worker threads."); return NULL; } @@ -243,7 +243,7 @@ compress_write(ds_file_t *file, const uchar *buf, size_t len) write_uint64_le(dest_file, comp_file->bytes_processed)) { msg("compress: write to the destination stream " - "failed.\n"); + "failed."); return 1; } @@ -253,7 +253,7 @@ compress_write(ds_file_t *file, const uchar *buf, size_t len) ds_write(dest_file, threads[i].to, threads[i].to_len)) { msg("compress: write to the destination stream " - "failed.\n"); + "failed."); return 1; } @@ -367,7 +367,7 @@ create_worker_threads(uint n) if (pthread_create(&thd->id, NULL, compress_worker_thread_func, thd)) { msg("compress: pthread_create() failed: " - "errno = %d\n", errno); + "errno = %d", errno); goto err; } } diff --git a/extra/mariabackup/ds_local.cc b/extra/mariabackup/ds_local.cc index 40a47b48e0c..0f13ddfe9a9 100644 --- a/extra/mariabackup/ds_local.cc +++ b/extra/mariabackup/ds_local.cc @@ -24,7 +24,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include <mysys_err.h> #include "common.h" #include "datasink.h" -#include "univ.i" #include "fsp0fsp.h" #ifdef _WIN32 #include <winioctl.h> diff --git a/extra/mariabackup/ds_stdout.c b/extra/mariabackup/ds_stdout.cc index b5820e30541..9398482feb9 100644 --- a/extra/mariabackup/ds_stdout.c +++ b/extra/mariabackup/ds_stdout.cc @@ -48,7 +48,7 @@ stdout_init(const char *root) { ds_ctxt_t *ctxt; - ctxt = my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); + ctxt = (ds_ctxt_t *)my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); ctxt->root = my_strdup(root, MYF(MY_FAE)); diff --git a/extra/mariabackup/ds_tmpfile.c b/extra/mariabackup/ds_tmpfile.cc index d9b5bc0b578..ddb23bf469d 100644 --- a/extra/mariabackup/ds_tmpfile.c +++ b/extra/mariabackup/ds_tmpfile.cc @@ -60,7 +60,7 @@ tmpfile_init(const char *root) ds_ctxt_t *ctxt; ds_tmpfile_ctxt_t *tmpfile_ctxt; - ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_tmpfile_ctxt_t), + ctxt = (ds_ctxt_t *)my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_tmpfile_ctxt_t), MYF(MY_FAE)); tmpfile_ctxt = (ds_tmpfile_ctxt_t *) (ctxt + 1); tmpfile_ctxt->file_list = NULL; @@ -191,12 +191,11 @@ tmpfile_deinit(ds_ctxt_t *ctxt) /* Walk the files in the order they have been added */ list = list_reverse(list); while (list != NULL) { - tmp_file = list->data; + tmp_file = (ds_tmp_file_t *)list->data; /* Stat the file to replace size and mtime on the original * mystat struct */ if (my_fstat(tmp_file->fd, &mystat, MYF(0))) { - msg("error: my_fstat() failed.\n"); - exit(EXIT_FAILURE); + die("my_fstat() failed."); } tmp_file->mystat.st_size = mystat.st_size; tmp_file->mystat.st_mtime = mystat.st_mtime; @@ -204,32 +203,29 @@ tmpfile_deinit(ds_ctxt_t *ctxt) dst_file = ds_open(pipe_ctxt, tmp_file->orig_path, &tmp_file->mystat); if (dst_file == NULL) { - msg("error: could not stream a temporary file to " - "'%s'\n", tmp_file->orig_path); - exit(EXIT_FAILURE); + die("could not stream a temporary file to " + "'%s'", tmp_file->orig_path); } /* copy to the destination datasink */ posix_fadvise(tmp_file->fd, 0, 0, POSIX_FADV_SEQUENTIAL); if (my_seek(tmp_file->fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) { - msg("error: my_seek() failed for '%s', errno = %d.\n", + die("my_seek() failed for '%s', errno = %d.", tmp_file->file->path, my_errno); - exit(EXIT_FAILURE); } offset = 0; - while ((bytes = my_read(tmp_file->fd, buf, buf_size, + while ((bytes = my_read(tmp_file->fd, (unsigned char *)buf, buf_size, MYF(MY_WME))) > 0) { posix_fadvise(tmp_file->fd, offset, buf_size, POSIX_FADV_DONTNEED); offset += buf_size; if (ds_write(dst_file, buf, bytes)) { - msg("error: cannot write to stream for '%s'.\n", + die("cannot write to stream for '%s'.", tmp_file->orig_path); - exit(EXIT_FAILURE); } } if (bytes == (size_t) -1) { - exit(EXIT_FAILURE); + die("my_read failed for %s", tmp_file->orig_path); } my_close(tmp_file->fd, MYF(MY_WME)); diff --git a/extra/mariabackup/ds_xbstream.c b/extra/mariabackup/ds_xbstream.cc index b09a4552e0c..105c89d05f7 100644 --- a/extra/mariabackup/ds_xbstream.c +++ b/extra/mariabackup/ds_xbstream.cc @@ -79,18 +79,18 @@ xbstream_init(const char *root __attribute__((unused))) ds_stream_ctxt_t *stream_ctxt; xb_wstream_t *xbstream; - ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_stream_ctxt_t), + ctxt = (ds_ctxt_t *)my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_stream_ctxt_t), MYF(MY_FAE)); stream_ctxt = (ds_stream_ctxt_t *)(ctxt + 1); if (pthread_mutex_init(&stream_ctxt->mutex, NULL)) { - msg("xbstream_init: pthread_mutex_init() failed.\n"); + msg("xbstream_init: pthread_mutex_init() failed."); goto err; } xbstream = xb_stream_write_new(); if (xbstream == NULL) { - msg("xb_stream_write_new() failed.\n"); + msg("xb_stream_write_new() failed."); goto err; } stream_ctxt->xbstream = xbstream; @@ -143,7 +143,7 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) my_xbstream_write_callback); if (xbstream_file == NULL) { - msg("xb_stream_write_open() failed.\n"); + msg("xb_stream_write_open() failed."); goto err; } @@ -177,7 +177,7 @@ xbstream_write(ds_file_t *file, const uchar *buf, size_t len) xbstream_file = stream_file->xbstream_file; if (xb_stream_write_data(xbstream_file, buf, len)) { - msg("xb_stream_write_data() failed.\n"); + msg("xb_stream_write_data() failed."); return 1; } @@ -209,7 +209,7 @@ xbstream_deinit(ds_ctxt_t *ctxt) stream_ctxt = (ds_stream_ctxt_t *) ctxt->ptr; if (xb_stream_write_done(stream_ctxt->xbstream)) { - msg("xb_stream_done() failed.\n"); + msg("xb_stream_done() failed."); } if (stream_ctxt->dest_file) { diff --git a/extra/mariabackup/encryption_plugin.cc b/extra/mariabackup/encryption_plugin.cc index b5acd385d0a..8f1978e967a 100644 --- a/extra/mariabackup/encryption_plugin.cc +++ b/extra/mariabackup/encryption_plugin.cc @@ -8,6 +8,7 @@ #include <vector> #include <common.h> #include <backup_mysql.h> +#include <log0crypt.h> extern struct st_maria_plugin *mysql_optional_plugins[]; @@ -18,14 +19,14 @@ extern char *xb_plugin_load; extern char *xb_plugin_dir; const int PLUGIN_MAX_ARGS = 1024; -vector<string> backup_plugins_args; +std::vector<std::string> backup_plugins_args; const char *QUERY_PLUGIN = "SELECT plugin_name, plugin_library, @@plugin_dir" " FROM information_schema.plugins WHERE plugin_type='ENCRYPTION'" " AND plugin_status='ACTIVE'"; -string encryption_plugin_config; +std::string encryption_plugin_config; static void add_to_plugin_load_list(const char *plugin_def) { @@ -34,11 +35,40 @@ static void add_to_plugin_load_list(const char *plugin_def) static char XTRABACKUP_EXE[] = "xtrabackup"; +/* + Read "plugin-load" value (encryption plugin) from backup-my.cnf during + prepare phase. + The value is stored during backup phase. +*/ +static std::string get_encryption_plugin_from_cnf() +{ + FILE *f = fopen("backup-my.cnf", "r"); + if (!f) + { + die("Can't open backup-my.cnf for reading"); + } + char line[512]; + std::string plugin_load; + while (fgets(line, sizeof(line), f)) + { + if (strncmp(line, "plugin_load=", 12) == 0) + { + plugin_load = line + 12; + // remote \n at the end of string + plugin_load.resize(plugin_load.size() - 1); + break; + } + } + fclose(f); + return plugin_load; +} + + void encryption_plugin_backup_init(MYSQL *mysql) { MYSQL_RES *result; MYSQL_ROW row; - ostringstream oss; + std::ostringstream oss; char *argv[PLUGIN_MAX_ARGS]; int argc; @@ -59,18 +89,28 @@ void encryption_plugin_backup_init(MYSQL *mysql) if (*p == '\\') *p = '/'; #endif - string plugin_load(name); + std::string plugin_load(name); if (library) - plugin_load += string("=") + library; + { + /* Remove shared library suffixes, in case we'll prepare on different OS.*/ + const char *extensions[] = { ".dll", ".so", 0 }; + for (size_t i = 0; extensions[i]; i++) + { + const char *ext = extensions[i]; + if (ends_with(library, ext)) + library[strlen(library) - strlen(ext)] = 0; + } + plugin_load += std::string("=") + library; + } - oss << "plugin_load=" << plugin_load << endl; + oss << "plugin_load=" << plugin_load << std::endl; /* Required to load the plugin later.*/ add_to_plugin_load_list(plugin_load.c_str()); strncpy(opt_plugin_dir, dir, FN_REFLEN - 1); opt_plugin_dir[FN_REFLEN - 1] = '\0'; - oss << "plugin_dir=" << '"' << dir << '"' << endl; + oss << "plugin_dir=" << '"' << dir << '"' << std::endl; /* Read plugin variables. */ @@ -81,12 +121,12 @@ void encryption_plugin_backup_init(MYSQL *mysql) result = xb_mysql_query(mysql, query, true, true); while ((row = mysql_fetch_row(result))) { - string arg("--"); + std::string arg("--"); arg += row[0]; arg += "="; arg += row[1]; backup_plugins_args.push_back(arg); - oss << row[0] << "=" << row[1] << endl; + oss << row[0] << "=" << row[1] << std::endl; } mysql_free_result(result); @@ -95,7 +135,7 @@ void encryption_plugin_backup_init(MYSQL *mysql) result = xb_mysql_query(mysql, "select @@innodb_encrypt_log", true, true); row = mysql_fetch_row(result); srv_encrypt_log = (row != 0 && row[0][0] == '1'); - oss << "innodb_encrypt_log=" << row[0] << endl; + oss << "innodb_encrypt_log=" << row[0] << std::endl; mysql_free_result(result); @@ -124,14 +164,18 @@ extern int finalize_encryption_plugin(st_plugin_int *plugin); void encryption_plugin_prepare_init(int argc, char **argv) { - - if (!xb_plugin_load) + std::string plugin_load= get_encryption_plugin_from_cnf(); + if (plugin_load.size()) + { + msg("Loading encryption plugin from %s", plugin_load.c_str()); + } + else { finalize_encryption_plugin(0); return; } - add_to_plugin_load_list(xb_plugin_load); + add_to_plugin_load_list(plugin_load.c_str()); if (xb_plugin_dir) { @@ -152,9 +196,9 @@ static void encryption_plugin_init(int argc, char **argv) { /* Patch optional and mandatory plugins, we only need to load the one in xb_plugin_load. */ mysql_optional_plugins[0] = mysql_mandatory_plugins[0] = 0; - msg("Loading encryption plugin\n"); + msg("Loading encryption plugin"); for (int i= 1; i < argc; i++) - msg("\t Encryption plugin parameter : '%s'\n", argv[i]); + msg("\t Encryption plugin parameter : '%s'", argv[i]); plugin_init(&argc, argv, PLUGIN_INIT_SKIP_PLUGIN_TABLE); } diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index f0825d8c39d..dce0f9ba6f2 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -24,8 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include <my_base.h> -#include <univ.i> #include <fil0fil.h> +#include <fsp0fsp.h> #include <srv0start.h> #include <trx0sys.h> @@ -65,7 +65,7 @@ xb_get_relative_path( prev = NULL; cur = path; - while ((next = strchr(cur, SRV_PATH_SEPARATOR)) != NULL) { + while ((next = strchr(cur, OS_PATH_SEPARATOR)) != NULL) { prev = cur; cur = next + 1; @@ -98,7 +98,7 @@ xb_fil_node_close_file( ut_a(node->n_pending_flushes == 0); ut_a(!node->being_extended); - if (!node->open) { + if (!node->is_open()) { mutex_exit(&fil_system->mutex); @@ -108,19 +108,18 @@ xb_fil_node_close_file( ret = os_file_close(node->handle); ut_a(ret); - node->open = FALSE; + node->handle = OS_FILE_CLOSED; ut_a(fil_system->n_open > 0); fil_system->n_open--; - fil_n_file_opened--; - if (node->space->purpose == FIL_TABLESPACE && + if (node->space->purpose == FIL_TYPE_TABLESPACE && fil_is_user_tablespace_id(node->space->id)) { ut_a(UT_LIST_GET_LEN(fil_system->LRU) > 0); /* The node is in the LRU list, remove it */ - UT_LIST_REMOVE(LRU, fil_system->LRU, node); + UT_LIST_REMOVE(fil_system->LRU, node); } mutex_exit(&fil_system->mutex); @@ -133,122 +132,115 @@ Open a source file cursor and initialize the associated read filter. be skipped and XB_FIL_CUR_ERROR on error. */ xb_fil_cur_result_t xb_fil_cur_open( -/*============*/ + /*============*/ xb_fil_cur_t* cursor, /*!< out: source file cursor */ xb_read_filt_t* read_filter, /*!< in/out: the read filter */ fil_node_t* node, /*!< in: source tablespace node */ - uint thread_n) /*!< thread number for diagnostics */ + uint thread_n, /*!< thread number for diagnostics */ + ulonglong max_file_size) { - ulint page_size; - ulint page_size_shift; - ulint zip_size; - ibool success; - + bool success; + int err; /* Initialize these first so xb_fil_cur_close() handles them correctly in case of error */ cursor->orig_buf = NULL; cursor->node = NULL; cursor->space_id = node->space->id; - cursor->is_system = !fil_is_user_tablespace_id(node->space->id); strncpy(cursor->abs_path, node->name, (sizeof cursor->abs_path) - 1); cursor->abs_path[(sizeof cursor->abs_path) - 1] = '\0'; /* Get the relative path for the destination tablespace name, i.e. the one that can be appended to the backup root directory. Non-system - tablespaces may have absolute paths for remote tablespaces in MySQL - 5.6+. We want to make "local" copies for the backup. */ + tablespaces may have absolute paths for DATA DIRECTORY. + We want to make "local" copies for the backup. */ strncpy(cursor->rel_path, - xb_get_relative_path(cursor->abs_path, cursor->is_system), + xb_get_relative_path(cursor->abs_path, cursor->is_system()), (sizeof cursor->rel_path) - 1); cursor->rel_path[(sizeof cursor->rel_path) - 1] = '\0'; /* In the backup mode we should already have a tablespace handle created - by fil_load_single_table_tablespace() unless it is a system + by fil_ibd_load() unless it is a system tablespace. Otherwise we open the file here. */ - if (cursor->is_system || !srv_backup_mode || srv_close_files) { - node->handle = - os_file_create_simple_no_error_handling(0, node->name, - OS_FILE_OPEN, - OS_FILE_READ_ONLY, - &success,0); + if (!node->is_open()) { + ut_ad(cursor->is_system() + || srv_operation == SRV_OPERATION_RESTORE_DELTA + || xb_close_files); + + node->handle = os_file_create_simple_no_error_handling( + 0, node->name, + OS_FILE_OPEN, + OS_FILE_READ_ALLOW_DELETE, true, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); - msg("[%02u] mariabackup: error: cannot open " - "tablespace %s\n", - thread_n, cursor->abs_path); + msg(thread_n, "mariabackup: error: cannot open " + "tablespace %s", cursor->abs_path); - return(XB_FIL_CUR_ERROR); + return(XB_FIL_CUR_SKIP); } mutex_enter(&fil_system->mutex); - node->open = TRUE; - fil_system->n_open++; - fil_n_file_opened++; - if (node->space->purpose == FIL_TABLESPACE && + if (node->space->purpose == FIL_TYPE_TABLESPACE && fil_is_user_tablespace_id(node->space->id)) { /* Put the node to the LRU list */ - UT_LIST_ADD_FIRST(LRU, fil_system->LRU, node); + UT_LIST_ADD_FIRST(fil_system->LRU, node); } mutex_exit(&fil_system->mutex); } - ut_ad(node->open); + ut_ad(node->is_open()); cursor->node = node; cursor->file = node->handle; - - if (stat(cursor->abs_path, &cursor->statinfo)) { - msg("[%02u] mariabackup: error: cannot stat %s\n", - thread_n, cursor->abs_path); +#ifdef _WIN32 + HANDLE hDup; + DuplicateHandle(GetCurrentProcess(),cursor->file.m_file, + GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS); + int filenr = _open_osfhandle((intptr_t)hDup, 0); + if (filenr < 0) { + err = EINVAL; + } + else { + err = _fstat64(filenr, &cursor->statinfo); + close(filenr); + } +#else + err = fstat(cursor->file.m_file, &cursor->statinfo); +#endif + if (max_file_size < (ulonglong)cursor->statinfo.st_size) { + cursor->statinfo.st_size = (ulonglong)max_file_size; + } + if (err) { + msg(thread_n, "mariabackup: error: cannot fstat %s", + cursor->abs_path); xb_fil_cur_close(cursor); - return(XB_FIL_CUR_ERROR); + return(XB_FIL_CUR_SKIP); } - if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT - || srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC) { + if (srv_file_flush_method == SRV_O_DIRECT + || srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) { os_file_set_nocache(cursor->file, node->name, "OPEN"); } posix_fadvise(cursor->file, 0, 0, POSIX_FADV_SEQUENTIAL); - /* Determine the page size */ - zip_size = xb_get_zip_size(node); - if (zip_size == ULINT_UNDEFINED) { - xb_fil_cur_close(cursor); - return(XB_FIL_CUR_SKIP); - } else if (zip_size) { - page_size = zip_size; - page_size_shift = get_bit_shift(page_size); - msg("[%02u] %s is compressed with page size = " - "%lu bytes\n", thread_n, node->name, page_size); - if (page_size_shift < 10 || page_size_shift > 14) { - msg("[%02u] mariabackup: Error: Invalid " - "page size: %lu.\n", thread_n, page_size); - ut_error; - } - } else { - page_size = UNIV_PAGE_SIZE; - page_size_shift = UNIV_PAGE_SIZE_SHIFT; - } + const page_size_t page_size(node->space->flags); cursor->page_size = page_size; - cursor->page_size_shift = page_size_shift; - cursor->zip_size = zip_size; /* Allocate read buffer */ - cursor->buf_size = XB_FIL_CUR_PAGES * page_size; + cursor->buf_size = XB_FIL_CUR_PAGES * page_size.physical(); cursor->orig_buf = static_cast<byte *> - (ut_malloc(cursor->buf_size + UNIV_PAGE_SIZE)); + (malloc(cursor->buf_size + UNIV_PAGE_SIZE)); cursor->buf = static_cast<byte *> (ut_align(cursor->orig_buf, UNIV_PAGE_SIZE)); @@ -258,7 +250,21 @@ xb_fil_cur_open( cursor->buf_page_no = 0; cursor->thread_n = thread_n; - cursor->space_size = (ulint)(cursor->statinfo.st_size / page_size); + if (!node->space->crypt_data + && os_file_read(IORequestRead, + node->handle, cursor->buf, 0, + page_size.physical()) == DB_SUCCESS) { + mutex_enter(&fil_system->mutex); + if (!node->space->crypt_data) { + node->space->crypt_data + = fil_space_read_crypt_data(page_size, + cursor->buf); + } + mutex_exit(&fil_system->mutex); + } + + cursor->space_size = (ulint)(cursor->statinfo.st_size + / page_size.physical()); cursor->read_filter = read_filter; cursor->read_filter->init(&cursor->read_filter_ctxt, cursor, @@ -271,21 +277,21 @@ static bool page_is_corrupted(const byte *page, ulint page_no, const xb_fil_cur_t *cursor, const fil_space_t *space) { - byte tmp_frame[UNIV_PAGE_SIZE_MAX]; - byte tmp_page[UNIV_PAGE_SIZE_MAX]; - + byte tmp_frame[UNIV_PAGE_SIZE_MAX]; + byte tmp_page[UNIV_PAGE_SIZE_MAX]; + const ulint page_size = cursor->page_size.physical(); ulint page_type = mach_read_from_2(page + FIL_PAGE_TYPE); /* We ignore the doublewrite buffer pages.*/ if (cursor->space_id == TRX_SYS_SPACE - && page_no >= FSP_EXTENT_SIZE - && page_no < FSP_EXTENT_SIZE * 3) { - return false; + && page_no >= FSP_EXTENT_SIZE + && page_no < FSP_EXTENT_SIZE * 3) { + return false; } /* Validate page number. */ if (mach_read_from_4(page + FIL_PAGE_OFFSET) != page_no - && space->id != TRX_SYS_SPACE) { + && cursor->space_id != TRX_SYS_SPACE) { /* On pages that are not all zero, the page number must match. @@ -299,7 +305,7 @@ static bool page_is_corrupted(const byte *page, ulint page_no, The first 38 and last 8 bytes are never encrypted. */ const ulint* p = reinterpret_cast<const ulint*>(page); const ulint* const end = reinterpret_cast<const ulint*>( - page + cursor->page_size); + page + page_size); do { if (*p++) { return true; @@ -318,18 +324,20 @@ static bool page_is_corrupted(const byte *page, ulint page_no, page_no first. */ if (page_no && mach_read_from_4(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) - && (opt_backup_encrypted + && (opt_encrypted_backup || (space->crypt_data && space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED))) { - if (!fil_space_verify_crypt_checksum(page, cursor->zip_size)) + if (!fil_space_verify_crypt_checksum(page, cursor->page_size)) return true; - /* Compressed encrypted need to be unencryped and uncompressed for verification. */ - if (page_type != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED && !opt_extended_validation) + /* Compressed encrypted need to be decrypted + and decompressed for verification. */ + if (page_type != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED + && !opt_extended_validation) return false; - memcpy(tmp_page, page, cursor->page_size); + memcpy(tmp_page, page, page_size); bool decrypted = false; if (!space->crypt_data @@ -340,27 +348,32 @@ static bool page_is_corrupted(const byte *page, ulint page_no, } if (page_type != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { - return buf_page_is_corrupted(true, tmp_page, cursor->zip_size, space); + return buf_page_is_corrupted(true, tmp_page, + cursor->page_size, space); } } if (page_type == FIL_PAGE_PAGE_COMPRESSED) { - memcpy(tmp_page, page, cursor->page_size); + memcpy(tmp_page, page, page_size); } - if (page_type == FIL_PAGE_PAGE_COMPRESSED || page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { + if (page_type == FIL_PAGE_PAGE_COMPRESSED + || page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { ulint decomp = fil_page_decompress(tmp_frame, tmp_page); page_type = mach_read_from_2(tmp_page + FIL_PAGE_TYPE); return (!decomp - || (decomp != srv_page_size && cursor->zip_size) + || (decomp != srv_page_size + && cursor->page_size.is_compressed()) || page_type == FIL_PAGE_PAGE_COMPRESSED - || page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED - || buf_page_is_corrupted(true, tmp_page, cursor->zip_size, space)); + || page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED + || buf_page_is_corrupted(true, tmp_page, + cursor->page_size, space)); } - return buf_page_is_corrupted(true, page, cursor->zip_size, space); + return buf_page_is_corrupted(true, page, cursor->page_size, space); } + /************************************************************************ Reads and verifies the next block of pages from the source file. Positions the cursor after the last read non-corrupted page. @@ -372,7 +385,6 @@ xb_fil_cur_read( /*============*/ xb_fil_cur_t* cursor) /*!< in/out: source file cursor */ { - ibool success; byte* page; ulint i; ulint npages; @@ -380,6 +392,8 @@ xb_fil_cur_read( xb_fil_cur_result_t ret; ib_int64_t offset; ib_int64_t to_read; + const ulint page_size = cursor->page_size.physical(); + xb_ad(!cursor->is_system() || page_size == UNIV_PAGE_SIZE); cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt, &offset, &to_read); @@ -394,82 +408,76 @@ xb_fil_cur_read( xb_a(to_read > 0 && to_read <= 0xFFFFFFFFLL); - if (to_read % cursor->page_size != 0 && - offset + to_read == cursor->statinfo.st_size) { - - if (to_read < (ib_int64_t) cursor->page_size) { - msg("[%02u] mariabackup: Warning: junk at the end of " - "%s:\n", cursor->thread_n, cursor->abs_path); - msg("[%02u] mariabackup: Warning: offset = %llu, " - "to_read = %llu\n", - cursor->thread_n, - (unsigned long long) offset, - (unsigned long long) to_read); + if ((to_read & ~(page_size - 1)) + && offset + to_read == cursor->statinfo.st_size) { + if (to_read < (ib_int64_t) page_size) { + msg(cursor->thread_n, "Warning: junk at the end of " + "%s, offset = %llu, to_read = %llu",cursor->abs_path, (ulonglong) offset, (ulonglong) to_read); return(XB_FIL_CUR_EOF); } to_read = (ib_int64_t) (((ulint) to_read) & - ~(cursor->page_size - 1)); + ~(page_size - 1)); } - xb_a(to_read % cursor->page_size == 0); + xb_a((to_read & (page_size - 1)) == 0); - npages = (ulint) (to_read >> cursor->page_size_shift); + npages = (ulint) (to_read / page_size); retry_count = 10; ret = XB_FIL_CUR_SUCCESS; + fil_space_t *space = fil_space_acquire_for_io(cursor->space_id); + + if (!space) { + return XB_FIL_CUR_ERROR; + } + read_retry: xtrabackup_io_throttling(); cursor->buf_read = 0; cursor->buf_npages = 0; cursor->buf_offset = offset; - cursor->buf_page_no = (ulint)(offset >> cursor->page_size_shift); + cursor->buf_page_no = (ulint)(offset / page_size); - success = os_file_read(cursor->file, cursor->buf, offset, - (ulint)to_read); - if (!success) { - return(XB_FIL_CUR_ERROR); + if (os_file_read(IORequestRead, cursor->file, cursor->buf, offset, + (ulint) to_read) != DB_SUCCESS) { + ret = XB_FIL_CUR_ERROR; + goto func_exit; } - - fil_space_t *space = fil_space_acquire_for_io(cursor->space_id); - /* check pages for corruption and re-read if necessary. i.e. in case of partially written pages */ for (page = cursor->buf, i = 0; i < npages; - page += cursor->page_size, i++) { + page += page_size, i++) { ulint page_no = cursor->buf_page_no + i; if (page_is_corrupted(page, page_no, cursor, space)){ retry_count--; if (retry_count == 0) { - msg("[%02u] mariabackup: " + msg(cursor->thread_n, "Error: failed to read page after " "10 retries. File %s seems to be " - "corrupted.\n", cursor->thread_n, - cursor->abs_path); + "corrupted.", cursor->abs_path); ret = XB_FIL_CUR_ERROR; buf_page_print(page, cursor->page_size); break; } - msg("[%02u] mariabackup: " - "Database page corruption detected at page " - ULINTPF ", retrying...\n", cursor->thread_n, + msg(cursor->thread_n, "Database page corruption detected at page " + ULINTPF ", retrying...", page_no); - os_thread_sleep(100000); goto read_retry; } - cursor->buf_read += cursor->page_size; + cursor->buf_read += page_size; cursor->buf_npages++; } posix_fadvise(cursor->file, offset, to_read, POSIX_FADV_DONTNEED); +func_exit: fil_space_release_for_io(space); - return(ret); } @@ -481,13 +489,14 @@ xb_fil_cur_close( /*=============*/ xb_fil_cur_t *cursor) /*!< in/out: source file cursor */ { - cursor->read_filter->deinit(&cursor->read_filter_ctxt); - - if (cursor->orig_buf != NULL) { - ut_free(cursor->orig_buf); + if (cursor->read_filter) { + cursor->read_filter->deinit(&cursor->read_filter_ctxt); } + + free(cursor->orig_buf); + if (cursor->node != NULL) { xb_fil_node_close_file(cursor->node); - cursor->file = XB_FILE_UNDEFINED; + cursor->file = OS_FILE_CLOSED; } } diff --git a/extra/mariabackup/fil_cur.h b/extra/mariabackup/fil_cur.h index 0c37fd154c3..d4a7c0d5b39 100644 --- a/extra/mariabackup/fil_cur.h +++ b/extra/mariabackup/fil_cur.h @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include <my_dir.h> #include "read_filt.h" +#include "srv0start.h" struct xb_fil_cur_t { pfs_os_file_t file; /*!< source file handle */ @@ -36,14 +37,7 @@ struct xb_fil_cur_t { char abs_path[FN_REFLEN]; /*!< absolute file path */ MY_STAT statinfo; /*!< information about the file */ - ulint zip_size; /*!< compressed page size in bytes or 0 - for uncompressed pages */ - ulint page_size; /*!< = zip_size for compressed pages or - UNIV_PAGE_SIZE for uncompressed ones */ - ulint page_size_shift;/*!< bit shift corresponding to - page_size */ - my_bool is_system; /*!< TRUE for system tablespace, FALSE - otherwise */ + page_size_t page_size; /*!< page size */ xb_read_filt_t* read_filter; /*!< read filter */ xb_read_filt_ctxt_t read_filter_ctxt; /*!< read filter context */ @@ -61,6 +55,17 @@ struct xb_fil_cur_t { uint thread_n; /*!< thread number for diagnostics */ ulint space_id; /*!< ID of tablespace */ ulint space_size; /*!< space size in pages */ + + /** TODO: remove this default constructor */ + xb_fil_cur_t() : page_size(0), read_filter(0), read_filter_ctxt() {} + + /** @return whether this is not a file-per-table tablespace */ + bool is_system() const + { + ut_ad(space_id != SRV_TMP_SPACE_ID); + return(space_id == TRX_SYS_SPACE + || srv_is_undo_tablespace(space_id)); + } }; typedef enum { @@ -81,7 +86,8 @@ xb_fil_cur_open( xb_fil_cur_t* cursor, /*!< out: source file cursor */ xb_read_filt_t* read_filter, /*!< in/out: the read filter */ fil_node_t* node, /*!< in: source tablespace node */ - uint thread_n); /*!< thread number for diagnostics */ + uint thread_n, /*!< thread number for diagnostics */ + ulonglong max_file_size = ULLONG_MAX); /************************************************************************ Reads and verifies the next block of pages from the source diff --git a/extra/mariabackup/innobackupex.cc b/extra/mariabackup/innobackupex.cc index 5382f876f74..952d1f4ec63 100644 --- a/extra/mariabackup/innobackupex.cc +++ b/extra/mariabackup/innobackupex.cc @@ -45,7 +45,6 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <mysql.h> #include <my_dir.h> #include <ut0mem.h> -#include <os0sync.h> #include <os0file.h> #include <srv0start.h> #include <algorithm> @@ -70,7 +69,6 @@ using std::max; my_bool opt_ibx_version = FALSE; my_bool opt_ibx_help = FALSE; my_bool opt_ibx_apply_log = FALSE; -my_bool opt_ibx_redo_only = FALSE; my_bool opt_ibx_incremental = FALSE; my_bool opt_ibx_notimestamp = FALSE; @@ -95,8 +93,6 @@ char *opt_ibx_host = NULL; char *opt_ibx_defaults_group = NULL; char *opt_ibx_socket = NULL; uint opt_ibx_port = 0; -char *opt_ibx_login_path = NULL; - ulong opt_ibx_lock_wait_query_type; ulong opt_ibx_kill_long_query_type; @@ -226,21 +222,11 @@ static struct my_option ibx_long_options[] = GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"apply-log", OPT_APPLY_LOG, "Prepare a backup in BACKUP-DIR by " - "applying the transaction log file named \"xtrabackup_logfile\" " - "located in the same directory. Also, create new transaction logs. " + "applying the redo log 'ib_logfile0' and creating new redo log. " "The InnoDB configuration is read from the file \"backup-my.cnf\".", (uchar*) &opt_ibx_apply_log, (uchar*) &opt_ibx_apply_log, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"redo-only", OPT_REDO_ONLY, "This option should be used when " - "preparing the base full backup and when merging all incrementals " - "except the last one. This forces xtrabackup to skip the \"rollback\" " - "phase and do a \"redo\" only. This is necessary if the backup will " - "have incremental changes applied to it later. See the xtrabackup " - "documentation for details.", - (uchar *) &opt_ibx_redo_only, (uchar *) &opt_ibx_redo_only, 0, - GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"copy-back", OPT_COPY_BACK, "Copy all the files in a previously made " "backup from the backup directory to their original locations.", (uchar *) &opt_ibx_copy_back, (uchar *) &opt_ibx_copy_back, 0, @@ -682,7 +668,7 @@ innobackupex [--compress] [--compress-threads=NUMBER-OF-THREADS] [--compress-chu \n\ innobackupex --apply-log [--use-memory=B]\n\ [--defaults-file=MY.CNF]\n\ - [--export] [--redo-only] [--ibbackup=IBBACKUP-BINARY]\n\ + [--export] [--ibbackup=IBBACKUP-BINARY]\n\ BACKUP-DIR\n\ \n\ innobackupex --copy-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME] BACKUP-DIR\n\ @@ -710,7 +696,7 @@ process.\n\ \n\ The --apply-log command prepares a backup for starting a MySQL\n\ server on the backup. This command recovers InnoDB data files as specified\n\ -in BACKUP-DIR/backup-my.cnf using BACKUP-DIR/xtrabackup_logfile,\n\ +in BACKUP-DIR/backup-my.cnf using BACKUP-DIR/ib_logfile0,\n\ and creates new InnoDB log files as specified in BACKUP-DIR/backup-my.cnf.\n\ The BACKUP-DIR should be the path to a backup directory created by\n\ xtrabackup. This command runs xtrabackup as a child process, but it does not \n\ @@ -752,7 +738,7 @@ ibx_get_one_option(int optid, exit(0); break; case 'v': - msg("innobackupex version %s %s (%s)\n", + printf("innobackupex version %s %s (%s)", MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); exit(0); @@ -909,7 +895,6 @@ ibx_init() opt_defaults_group = opt_ibx_defaults_group; opt_socket = opt_ibx_socket; opt_port = opt_ibx_port; - opt_login_path = opt_ibx_login_path; opt_lock_wait_query_type = opt_ibx_lock_wait_query_type; opt_kill_long_query_type = opt_ibx_kill_long_query_type; @@ -980,9 +965,6 @@ ibx_init() switch (ibx_mode) { case IBX_MODE_APPLY_LOG: xtrabackup_prepare = TRUE; - if (opt_ibx_redo_only) { - xtrabackup_apply_log_only = TRUE; - } xtrabackup_target_dir = ibx_position_arg; run = "apply-log"; break; diff --git a/extra/mariabackup/read_filt.cc b/extra/mariabackup/read_filt.cc index 787f1ca0641..72f63bf972a 100644 --- a/extra/mariabackup/read_filt.cc +++ b/extra/mariabackup/read_filt.cc @@ -127,10 +127,11 @@ rf_bitmap_get_next_batch( of pages */ { ulint start_page_id; + const ulint page_size = ctxt->page_size.physical(); - start_page_id = (ulint)(ctxt->offset / ctxt->page_size); + start_page_id = (ulint)(ctxt->offset / page_size); - xb_a (ctxt->offset % ctxt->page_size == 0); + xb_a (ctxt->offset % page_size == 0); if (start_page_id == ctxt->filter_batch_end) { @@ -146,7 +147,7 @@ rf_bitmap_get_next_batch( return; } - ctxt->offset = next_page_id * ctxt->page_size; + ctxt->offset = next_page_id * page_size; /* Find the end of the current changed page block by searching for the next cleared bitmap bit */ @@ -162,7 +163,7 @@ rf_bitmap_get_next_batch( remaining pages. */ *read_batch_len = ctxt->data_file_size - ctxt->offset; } else { - *read_batch_len = ctxt->filter_batch_end * ctxt->page_size + *read_batch_len = ctxt->filter_batch_end * page_size - ctxt->offset; } @@ -175,9 +176,9 @@ rf_bitmap_get_next_batch( } ctxt->offset += *read_batch_len; - xb_a (ctxt->offset % ctxt->page_size == 0); - xb_a (*read_batch_start % ctxt->page_size == 0); - xb_a (*read_batch_len % ctxt->page_size == 0); + xb_a (ctxt->offset % page_size == 0); + xb_a (*read_batch_start % page_size == 0); + xb_a (*read_batch_len % page_size == 0); } /****************************************************************//** diff --git a/extra/mariabackup/read_filt.h b/extra/mariabackup/read_filt.h index edc395c5c30..e1faa96ef0c 100644 --- a/extra/mariabackup/read_filt.h +++ b/extra/mariabackup/read_filt.h @@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include "changed_page_bitmap.h" +typedef ulint space_id_t; + struct xb_fil_cur_t; /* The read filter context */ @@ -34,15 +36,17 @@ struct xb_read_filt_ctxt_t { ib_int64_t offset; /*!< current file offset */ ib_int64_t data_file_size; /*!< data file size */ size_t buffer_capacity;/*!< read buffer capacity */ - ib_int64_t space_id; /*!< space id */ + space_id_t space_id; /*!< space id */ /* The following fields used only in bitmap filter */ /* Move these to union if any other filters are added in future */ xb_page_bitmap_range *bitmap_range; /*!< changed page bitmap range iterator for space_id */ - size_t page_size; /*!< page size */ + page_size_t page_size; /*!< page size */ ulint filter_batch_end;/*!< the ending page id of the current changed page block in the bitmap */ + /** TODO: remove this default constructor */ + xb_read_filt_ctxt_t() : page_size(0) {} }; /* The read filter */ diff --git a/extra/mariabackup/write_filt.cc b/extra/mariabackup/write_filt.cc index d84f1dfe248..d72c11978a9 100644 --- a/extra/mariabackup/write_filt.cc +++ b/extra/mariabackup/write_filt.cc @@ -68,33 +68,30 @@ wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name, xb_fil_cur_t *cursor) { char meta_name[FN_REFLEN]; - xb_delta_info_t info; xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt); ctxt->cursor = cursor; /* allocate buffer for incremental backup (4096 pages) */ - cp->delta_buf_size = (cursor->page_size / 4) * cursor->page_size; - cp->delta_buf = (unsigned char *)os_mem_alloc_large(&cp->delta_buf_size, false); + cp->delta_buf_size = (cursor->page_size.physical() / 4) + * cursor->page_size.physical(); + cp->delta_buf = (unsigned char *)os_mem_alloc_large(&cp->delta_buf_size); if (!cp->delta_buf) { - msg("[%02u] mariabackup: Error: " - "cannot allocate %zu bytes\n", - cursor->thread_n, (size_t) cp->delta_buf_size); + msg(cursor->thread_n,"Can't allocate %zu bytes", + (size_t) cp->delta_buf_size); return (FALSE); } /* write delta meta info */ snprintf(meta_name, sizeof(meta_name), "%s%s", dst_name, XB_DELTA_INFO_SUFFIX); - info.page_size = cursor->page_size; - info.zip_size = cursor->zip_size; - info.space_id = cursor->space_id; + const xb_delta_info_t info(cursor->page_size, cursor->space_id); if (!xb_write_delta_metadata(meta_name, &info)) { - msg("[%02u] mariabackup: Error: " - "failed to write meta info for %s\n", - cursor->thread_n, cursor->rel_path); + msg(cursor->thread_n,"Error: " + "failed to write meta info for %s", + cursor->rel_path); return(FALSE); } @@ -117,8 +114,9 @@ wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) { ulint i; xb_fil_cur_t *cursor = ctxt->cursor; - ulint page_size = cursor->page_size; byte *page; + const ulint page_size + = cursor->page_size.physical(); xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt); for (i = 0, page = cursor->buf; i < cursor->buf_npages; @@ -163,7 +161,8 @@ static my_bool wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) { xb_fil_cur_t *cursor = ctxt->cursor; - ulint page_size = cursor->page_size; + const ulint page_size + = cursor->page_size.physical(); xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt); if (cp->npages != page_size / 4) { diff --git a/extra/mariabackup/wsrep.cc b/extra/mariabackup/wsrep.cc index eab3d7b64d6..ce702096a32 100644 --- a/extra/mariabackup/wsrep.cc +++ b/extra/mariabackup/wsrep.cc @@ -46,7 +46,6 @@ permission notice: #include <trx0sys.h> #include "common.h" -#include "backup_wsrep.h" #ifdef WITH_WSREP #define WSREP_XID_PREFIX "WSREPXid" #define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN @@ -194,7 +193,7 @@ xb_write_galera_info(bool incremental_prepare) fp = fopen(XB_GALERA_INFO_FILENAME, "w"); if (fp == NULL) { - msg("mariabackup: error: " + die( "could not create " XB_GALERA_INFO_FILENAME ", errno = %d\n", errno); @@ -208,11 +207,10 @@ xb_write_galera_info(bool incremental_prepare) if (fprintf(fp, "%s:%lld", uuid_str, (long long) seqno) < 0) { - msg("mariabackup: error: " + die( "could not write to " XB_GALERA_INFO_FILENAME ", errno = %d\n", - errno); - exit(EXIT_FAILURE); + errno);; } fclose(fp); diff --git a/extra/mariabackup/xb0xb.h b/extra/mariabackup/xb0xb.h index 1e79c0b4268..b82fd2ba27b 100644 --- a/extra/mariabackup/xb0xb.h +++ b/extra/mariabackup/xb0xb.h @@ -21,44 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #ifndef xb0xb_h #define xb0xb_h - -extern void os_io_init_simple(void); -extern pfs_os_file_t files[1000]; extern const char *innodb_checksum_algorithm_names[]; extern TYPELIB innodb_checksum_algorithm_typelib; -extern dberr_t open_or_create_data_files( - bool* create_new_db, -#ifdef UNIV_LOG_ARCHIVE - lsn_t* min_arch_log_no, - lsn_t* max_arch_log_no, -#endif - lsn_t* flushed_lsn, - ulint* sum_of_new_sizes) - ; -int -fil_file_readdir_next_file( -/*=======================*/ -dberr_t* err, /*!< out: this is set to DB_ERROR if an error - was encountered, otherwise not changed */ - const char* dirname,/*!< in: directory name or path */ - os_file_dir_t dir, /*!< in: directory stream */ - os_file_stat_t* info) /*!< in/out: buffer where the - info is returned */; -fil_space_t* -fil_space_get_by_name(const char *); -ibool -recv_check_cp_is_consistent(const byte* buf); -void -innodb_log_checksum_func_update( -/*============================*/ -ulint algorithm) /*!< in: algorithm */; -dberr_t recv_find_max_checkpoint(log_group_t** max_group, ulint* max_field); -dberr_t -srv_undo_tablespaces_init( -/*======================*/ -ibool create_new_db, -ibool backup_mode, -const ulint n_conf_tablespaces, -ulint* n_opened); #endif diff --git a/extra/mariabackup/xbstream.c b/extra/mariabackup/xbstream.cc index 59e0095f63c..5d33f27cbb3 100644 --- a/extra/mariabackup/xbstream.c +++ b/extra/mariabackup/xbstream.cc @@ -45,7 +45,6 @@ datasink_t datasink_archive; datasink_t datasink_xbstream; datasink_t datasink_compress; datasink_t datasink_tmpfile; -datasink_t datasink_buffer; static run_mode_t opt_mode; static char * opt_directory = NULL; @@ -106,7 +105,7 @@ main(int argc, char **argv) } if (opt_mode == RUN_MODE_NONE) { - msg("%s: either -c or -x must be specified.\n", my_progname); + msg("%s: either -c or -x must be specified.", my_progname); goto err; } @@ -184,7 +183,7 @@ int set_run_mode(run_mode_t mode) { if (opt_mode != RUN_MODE_NONE) { - msg("%s: can't set specify both -c and -x.\n", my_progname); + msg("%s: can't set specify both -c and -x.", my_progname); return 1; } @@ -233,7 +232,7 @@ stream_one_file(File file, xb_wstream_file_t *xbfile) while ((bytes = (ssize_t)my_read(file, buf, XBSTREAM_BUFFER_SIZE, MYF(MY_WME))) > 0) { if (xb_stream_write_data(xbfile, buf, bytes)) { - msg("%s: xb_stream_write_data() failed.\n", + msg("%s: xb_stream_write_data() failed.", my_progname); my_free(buf); return 1; @@ -262,13 +261,13 @@ mode_create(int argc, char **argv) xb_wstream_t *stream; if (argc < 1) { - msg("%s: no files are specified.\n", my_progname); + msg("%s: no files are specified.", my_progname); return 1; } stream = xb_stream_write_new(); if (stream == NULL) { - msg("%s: xb_stream_write_new() failed.\n", my_progname); + msg("%s: xb_stream_write_new() failed.", my_progname); return 1; } @@ -281,13 +280,13 @@ mode_create(int argc, char **argv) goto err; } if (!MY_S_ISREG(mystat.st_mode)) { - msg("%s: %s is not a regular file, exiting.\n", + msg("%s: %s is not a regular file, exiting.", my_progname, filepath); goto err; } if ((src_file = my_open(filepath, O_RDONLY, MYF(MY_WME))) < 0) { - msg("%s: failed to open %s.\n", my_progname, filepath); + msg("%s: failed to open %s.", my_progname, filepath); goto err; } @@ -297,7 +296,7 @@ mode_create(int argc, char **argv) } if (opt_verbose) { - msg("%s\n", filepath); + msg("%s", filepath); } if (stream_one_file(src_file, file) || @@ -338,12 +337,12 @@ file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen) file = ds_open(ctxt->ds_ctxt, path, NULL); if (file == NULL) { - msg("%s: failed to create file.\n", my_progname); + msg("%s: failed to create file.", my_progname); goto err; } if (opt_verbose) { - msg("%s\n", entry->path); + msg("%s", entry->path); } entry->file = file; @@ -425,7 +424,7 @@ extract_worker_thread_func(void *arg) break; } if (my_hash_insert(ctxt->filehash, (uchar *) entry)) { - msg("%s: my_hash_insert() failed.\n", + msg("%s: my_hash_insert() failed.", my_progname); pthread_mutex_unlock(ctxt->mutex); break; @@ -454,7 +453,7 @@ extract_worker_thread_func(void *arg) if (entry->offset != chunk.offset) { msg("%s: out-of-order chunk: real offset = 0x%llx, " - "expected offset = 0x%llx\n", my_progname, + "expected offset = 0x%llx", my_progname, chunk.offset, entry->offset); pthread_mutex_unlock(&entry->mutex); res = XB_STREAM_READ_ERROR; @@ -462,7 +461,7 @@ extract_worker_thread_func(void *arg) } if (ds_write(entry->file, chunk.data, chunk.length)) { - msg("%s: my_write() failed.\n", my_progname); + msg("%s: my_write() failed.", my_progname); pthread_mutex_unlock(&entry->mutex); res = XB_STREAM_READ_ERROR; break; @@ -500,12 +499,12 @@ mode_extract(int n_threads, int argc __attribute__((unused)), if (my_hash_init(&filehash, &my_charset_bin, START_FILE_HASH_SIZE, 0, 0, (my_hash_get_key) get_file_entry_key, (my_hash_free_key) file_entry_free, MYF(0))) { - msg("%s: failed to initialize file hash.\n", my_progname); + msg("%s: failed to initialize file hash.", my_progname); return 1; } if (pthread_mutex_init(&mutex, NULL)) { - msg("%s: failed to initialize mutex.\n", my_progname); + msg("%s: failed to initialize mutex.", my_progname); my_hash_free(&filehash); return 1; } @@ -520,7 +519,7 @@ mode_extract(int n_threads, int argc __attribute__((unused)), stream = xb_stream_read_new(); if (stream == NULL) { - msg("%s: xb_stream_read_new() failed.\n", my_progname); + msg("%s: xb_stream_read_new() failed.", my_progname); pthread_mutex_destroy(&mutex); ret = 1; goto exit; @@ -531,8 +530,8 @@ mode_extract(int n_threads, int argc __attribute__((unused)), ctxt.ds_ctxt = ds_ctxt; ctxt.mutex = &mutex; - tids = malloc(sizeof(pthread_t) * n_threads); - retvals = malloc(sizeof(void*) * n_threads); + tids = (pthread_t *)calloc(n_threads, sizeof(pthread_t)); + retvals = (void **)calloc(n_threads, sizeof(void*)); for (i = 0; i < n_threads; i++) pthread_create(tids + i, NULL, extract_worker_thread_func, @@ -542,7 +541,7 @@ mode_extract(int n_threads, int argc __attribute__((unused)), pthread_join(tids[i], retvals + i); for (i = 0; i < n_threads; i++) { - if ((ulong)retvals[i] == XB_STREAM_READ_ERROR) { + if ((size_t)retvals[i] == XB_STREAM_READ_ERROR) { ret = 1; goto exit; } diff --git a/extra/mariabackup/xbstream.h b/extra/mariabackup/xbstream.h index 702f2764734..1b36ec249b6 100644 --- a/extra/mariabackup/xbstream.h +++ b/extra/mariabackup/xbstream.h @@ -101,6 +101,6 @@ xb_rstream_result_t xb_stream_read_chunk(xb_rstream_t *stream, int xb_stream_read_done(xb_rstream_t *stream); -int xb_stream_validate_checksum(xb_rstream_chunk_t *chunk); +xb_rstream_result_t xb_stream_validate_checksum(xb_rstream_chunk_t *chunk); #endif diff --git a/extra/mariabackup/xbstream_read.c b/extra/mariabackup/xbstream_read.cc index 546578d055a..74f2f888ef7 100644 --- a/extra/mariabackup/xbstream_read.c +++ b/extra/mariabackup/xbstream_read.cc @@ -67,15 +67,15 @@ validate_chunk_type(uchar code) } } -int +xb_rstream_result_t xb_stream_validate_checksum(xb_rstream_chunk_t *chunk) { ulong checksum; - checksum = crc32_iso3309(0, chunk->data, (uint)chunk->length); + checksum = crc32_iso3309(0, (unsigned char *)chunk->data, (uint)chunk->length); if (checksum != chunk->checksum) { msg("xb_stream_read_chunk(): invalid checksum at offset " - "0x%llx: expected 0x%lx, read 0x%lx.\n", + "0x%llx: expected 0x%lx, read 0x%lx.", (ulonglong) chunk->checksum_offset, chunk->checksum, checksum); return XB_STREAM_READ_ERROR; @@ -86,8 +86,8 @@ xb_stream_validate_checksum(xb_rstream_chunk_t *chunk) #define F_READ(buf,len) \ do { \ - if (xb_read_full(fd, buf, len) < len) { \ - msg("xb_stream_read_chunk(): my_read() failed.\n"); \ + if (xb_read_full(fd, (uchar *)buf, len) < len) { \ + msg("xb_stream_read_chunk(): my_read() failed."); \ goto err; \ } \ } while (0) @@ -111,7 +111,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) return XB_STREAM_READ_EOF; } else if (tbytes < CHUNK_HEADER_CONSTANT_LEN) { msg("xb_stream_read_chunk(): unexpected end of stream at " - "offset 0x%llx.\n", stream->offset); + "offset 0x%llx.", stream->offset); goto err; } @@ -120,7 +120,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) /* Chunk magic value */ if (memcmp(tmpbuf, XB_STREAM_CHUNK_MAGIC, 8)) { msg("xb_stream_read_chunk(): wrong chunk magic at offset " - "0x%llx.\n", (ulonglong) stream->offset); + "0x%llx.", (ulonglong) stream->offset); goto err; } ptr += 8; @@ -135,7 +135,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) if (chunk->type == XB_CHUNK_TYPE_UNKNOWN && !(chunk->flags & XB_STREAM_FLAG_IGNORABLE)) { msg("xb_stream_read_chunk(): unknown chunk type 0x%lu at " - "offset 0x%llx.\n", (ulong) *ptr, + "offset 0x%llx.", (ulong) *ptr, (ulonglong) stream->offset); goto err; } @@ -146,7 +146,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) pathlen = uint4korr(ptr); if (pathlen >= FN_REFLEN) { msg("xb_stream_read_chunk(): path length (%lu) is too large at " - "offset 0x%llx.\n", (ulong) pathlen, stream->offset); + "offset 0x%llx.", (ulong) pathlen, stream->offset); goto err; } chunk->pathlen = pathlen; @@ -170,7 +170,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) ullval = uint8korr(tmpbuf); if (ullval > (ulonglong) SIZE_T_MAX) { msg("xb_stream_read_chunk(): chunk length is too large at " - "offset 0x%llx: 0x%llx.\n", (ulonglong) stream->offset, + "offset 0x%llx: 0x%llx.", (ulonglong) stream->offset, ullval); goto err; } @@ -181,7 +181,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) ullval = uint8korr(tmpbuf + 8); if (ullval > (ulonglong) MY_OFF_T_MAX) { msg("xb_stream_read_chunk(): chunk offset is too large at " - "offset 0x%llx: 0x%llx.\n", (ulonglong) stream->offset, + "offset 0x%llx: 0x%llx.", (ulonglong) stream->offset, ullval); goto err; } @@ -194,7 +194,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) MYF(MY_WME | MY_ALLOW_ZERO_PTR)); if (chunk->data == NULL) { msg("xb_stream_read_chunk(): failed to increase buffer " - "to %lu bytes.\n", (ulong) chunk->length); + "to %lu bytes.", (ulong) chunk->length); goto err; } chunk->buflen = chunk->length; diff --git a/extra/mariabackup/xbstream_write.c b/extra/mariabackup/xbstream_write.cc index df8740a8ddb..abaf89f8a6a 100644 --- a/extra/mariabackup/xbstream_write.c +++ b/extra/mariabackup/xbstream_write.cc @@ -55,7 +55,7 @@ xb_stream_default_write_callback(xb_wstream_file_t *file __attribute__((unused)) void *userdata __attribute__((unused)), const void *buf, size_t len) { - if (my_write(my_fileno(stdout), buf, len, MYF(MY_WME | MY_NABP))) + if (my_write(my_fileno(stdout), (const uchar *)buf, len, MYF(MY_WME | MY_NABP))) return -1; return len; } @@ -83,7 +83,7 @@ xb_stream_write_open(xb_wstream_t *stream, const char *path, path_len = strlen(path); if (path_len > FN_REFLEN) { - msg("xb_stream_write_open(): file path is too long.\n"); + msg("xb_stream_write_open(): file path is too long."); return NULL; } @@ -216,7 +216,7 @@ xb_stream_write_chunk(xb_wstream_file_t *file, const void *buf, size_t len) int8store(ptr, len); /* Payload length */ ptr += 8; - checksum = crc32_iso3309(0, buf, (uint)len); /* checksum */ + checksum = crc32_iso3309(0, (const uchar *)buf, (uint)len); /* checksum */ pthread_mutex_lock(&stream->mutex); diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 40539b1e632..bc7149a87fd 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4,6 +4,8 @@ MariaBackup: hot backup tool for InnoDB Originally Created 3/3/2009 Yasufumi Kinoshita Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. +(c) 2017, 2019, MariaDB Corporation. +Portions written by Marko Mäkelä. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,6 +43,8 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA //#define XTRABACKUP_TARGET_IS_PLUGIN +#include <my_config.h> +#include <unireg.h> #include <mysql_version.h> #include <my_base.h> #include <my_getopt.h> @@ -61,9 +65,11 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <dict0priv.h> #include <lock0lock.h> #include <log0recv.h> +#include <log0crypt.h> #include <row0mysql.h> #include <row0quiesce.h> #include <srv0start.h> +#include "trx0sys.h" #include <buf0dblwr.h> #include <list> @@ -97,58 +103,52 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <crc_glue.h> #include <log.h> -/* TODO: replace with appropriate macros used in InnoDB 5.6 */ -#define PAGE_ZIP_MIN_SIZE_SHIFT 10 -#define DICT_TF_ZSSIZE_SHIFT 1 -#define DICT_TF_FORMAT_ZIP 1 -#define DICT_TF_FORMAT_SHIFT 5 - int sys_var_init(); -my_bool innodb_inited= 0; - /* === xtrabackup specific options === */ char xtrabackup_real_target_dir[FN_REFLEN] = "./xtrabackup_backupfiles/"; char *xtrabackup_target_dir= xtrabackup_real_target_dir; -my_bool xtrabackup_version = FALSE; -my_bool xtrabackup_backup = FALSE; -my_bool xtrabackup_prepare = FALSE; -my_bool xtrabackup_copy_back = FALSE; -my_bool xtrabackup_move_back = FALSE; -my_bool xtrabackup_decrypt_decompress = FALSE; -my_bool xtrabackup_print_param = FALSE; +static my_bool xtrabackup_version; +static my_bool verbose; +my_bool xtrabackup_backup; +my_bool xtrabackup_prepare; +my_bool xtrabackup_copy_back; +my_bool xtrabackup_move_back; +my_bool xtrabackup_decrypt_decompress; +my_bool xtrabackup_print_param; -my_bool xtrabackup_export = FALSE; -my_bool xtrabackup_apply_log_only = FALSE; +my_bool xtrabackup_export; -longlong xtrabackup_use_memory = 100*1024*1024L; -my_bool xtrabackup_create_ib_logfile = FALSE; +longlong xtrabackup_use_memory; uint opt_protocol; -long xtrabackup_throttle = 0; /* 0:unlimited */ -lint io_ticket; -os_event_t wait_throttle = NULL; -os_event_t log_copying_stop = NULL; +long xtrabackup_throttle; /* 0:unlimited */ +static lint io_ticket; +static os_event_t wait_throttle; +static os_event_t log_copying_stop; -char *xtrabackup_incremental = NULL; +char *xtrabackup_incremental; lsn_t incremental_lsn; lsn_t incremental_to_lsn; lsn_t incremental_last_lsn; -xb_page_bitmap *changed_page_bitmap = NULL; +xb_page_bitmap *changed_page_bitmap; -char *xtrabackup_incremental_basedir = NULL; /* for --backup */ -char *xtrabackup_extra_lsndir = NULL; /* for --backup with --extra-lsndir */ -char *xtrabackup_incremental_dir = NULL; /* for --prepare */ +char *xtrabackup_incremental_basedir; /* for --backup */ +char *xtrabackup_extra_lsndir; /* for --backup with --extra-lsndir */ +char *xtrabackup_incremental_dir; /* for --prepare */ char xtrabackup_real_incremental_basedir[FN_REFLEN]; char xtrabackup_real_extra_lsndir[FN_REFLEN]; char xtrabackup_real_incremental_dir[FN_REFLEN]; + char *xtrabackup_tmpdir; -char *xtrabackup_tables = NULL; -char *xtrabackup_tables_file = NULL; -char *xtrabackup_tables_exclude = NULL; +char *xtrabackup_tables; +char *xtrabackup_tables_file; +char *xtrabackup_tables_exclude; +char *xb_rocksdb_datadir; +my_bool xb_backup_rocksdb = 1; typedef std::list<regex_t> regex_list_t; static regex_list_t regex_include_list; @@ -172,17 +172,11 @@ struct xb_filter_entry_struct{ }; typedef struct xb_filter_entry_struct xb_filter_entry_t; -static ulint thread_nr[SRV_MAX_N_IO_THREADS + 6]; -static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 6]; - lsn_t checkpoint_lsn_start; lsn_t checkpoint_no_start; -lsn_t log_copy_scanned_lsn; -ibool log_copying = TRUE; -ibool log_copying_running = FALSE; -ibool io_watching_thread_running = FALSE; - -ibool xtrabackup_logfile_is_renamed = FALSE; +static lsn_t log_copy_scanned_lsn; +static bool log_copying_running; +static bool io_watching_thread_running; int xtrabackup_parallel; @@ -191,7 +185,7 @@ xb_stream_fmt_t xtrabackup_stream_fmt = XB_STREAM_FMT_NONE; ibool xtrabackup_stream = FALSE; const char *xtrabackup_compress_alg = NULL; -ibool xtrabackup_compress = FALSE; +uint xtrabackup_compress = FALSE; uint xtrabackup_compress_threads; ulonglong xtrabackup_compress_chunk_size = 0; @@ -201,25 +195,22 @@ ulint xtrabackup_log_copy_interval = 1000; static ulong max_buf_pool_modified_pct; /* Ignored option (--log) for MySQL option compatibility */ -char* log_ignored_opt = NULL; +static char* log_ignored_opt; extern my_bool opt_use_ssl; my_bool opt_ssl_verify_server_cert; my_bool opt_extended_validation; -my_bool opt_backup_encrypted; +my_bool opt_encrypted_backup; /* === metadata of backup === */ #define XTRABACKUP_METADATA_FILENAME "xtrabackup_checkpoints" -char metadata_type[30] = ""; /*[full-backuped|log-applied| - full-prepared|incremental]*/ -lsn_t metadata_from_lsn = 0; -lsn_t metadata_to_lsn = 0; -lsn_t metadata_last_lsn = 0; - -#define XB_LOG_FILENAME "xtrabackup_logfile" +char metadata_type[30] = ""; /*[full-backuped|log-applied|incremental]*/ +static lsn_t metadata_from_lsn; +lsn_t metadata_to_lsn; +static lsn_t metadata_last_lsn; -ds_file_t *dst_log_file = NULL; +static ds_file_t* dst_log_file; static char mysql_data_home_buff[2]; @@ -230,52 +221,34 @@ const char *defaults_group = "mysqld"; #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */ #define HA_INNOBASE_RANGE_COUNT 100 -ulong innobase_large_page_size = 0; - /* The default values for the following, type long or longlong, start-up parameters are declared in mysqld.cc: */ -long innobase_additional_mem_pool_size = 1*1024*1024L; long innobase_buffer_pool_awe_mem_mb = 0; long innobase_file_io_threads = 4; long innobase_read_io_threads = 4; long innobase_write_io_threads = 4; -long innobase_force_recovery = 0; long innobase_log_buffer_size = 1024*1024L; -long innobase_log_files_in_group = 2; long innobase_open_files = 300L; longlong innobase_page_size = (1LL << 14); /* 16KB */ -static ulong innobase_log_block_size = 512; -char* innobase_doublewrite_file = NULL; char* innobase_buffer_pool_filename = NULL; -longlong innobase_log_file_size = 48*1024*1024L; - /* The default values for the following char* start-up parameters are determined in innobase_init below: */ -char* innobase_ignored_opt = NULL; -char* innobase_data_home_dir = NULL; -char* innobase_data_file_path = NULL; +static char* innobase_ignored_opt; +char* innobase_data_home_dir; +char* innobase_data_file_path; /* The following has a misleading name: starting from 4.0.5, this also affects Windows: */ -char* innobase_unix_file_flush_method = NULL; - -/* Below we have boolean-valued start-up parameters, and their default -values */ +char* innobase_unix_file_flush_method; -ulong innobase_fast_shutdown = 1; -my_bool innobase_use_doublewrite = TRUE; -my_bool innobase_use_checksums = TRUE; -my_bool innobase_use_large_pages = FALSE; -my_bool innobase_file_per_table = FALSE; -my_bool innobase_locks_unsafe_for_binlog = FALSE; -my_bool innobase_rollback_on_timeout = FALSE; -my_bool innobase_create_status_file = FALSE; -my_bool innobase_adaptive_hash_index = TRUE; - -static char *internal_innobase_data_file_path = NULL; +my_bool innobase_use_doublewrite; +my_bool innobase_file_per_table; +my_bool innobase_locks_unsafe_for_binlog; +my_bool innobase_rollback_on_timeout; +my_bool innobase_create_status_file; /* The following counter is used to convey information to InnoDB about server activity: in selects it is not sensible to call @@ -296,7 +269,7 @@ lsn_t flushed_lsn= 0; ulong xb_open_files_limit= 0; char *xb_plugin_dir; char *xb_plugin_load; -my_bool xb_close_files= FALSE; +my_bool xb_close_files; /* Datasinks */ ds_ctxt_t *ds_data = NULL; @@ -305,10 +278,6 @@ ds_ctxt_t *ds_redo = NULL; static bool innobackupex_mode = false; -static long innobase_log_files_in_group_save; -static char *srv_log_group_home_dir_save; -static longlong innobase_log_file_size_save; - /* String buffer used by --print-param to accumulate server options as they are parsed from the defaults file */ static std::ostringstream print_param_str; @@ -319,6 +288,7 @@ std::set<std::string> param_set; static ulonglong global_max_value; extern "C" sig_handler handle_fatal_signal(int sig); +extern LOGGER logger; my_bool opt_galera_info = FALSE; my_bool opt_slave_info = FALSE; @@ -329,7 +299,10 @@ my_bool opt_force_non_empty_dirs = FALSE; my_bool opt_noversioncheck = FALSE; my_bool opt_no_backup_locks = FALSE; my_bool opt_decompress = FALSE; -my_bool opt_remove_original = FALSE; +my_bool opt_remove_original; + +my_bool opt_lock_ddl_per_table = FALSE; +static my_bool opt_check_privileges; static const char *binlog_info_values[] = {"off", "lockless", "on", "auto", NullS}; @@ -337,17 +310,16 @@ static TYPELIB binlog_info_typelib = {array_elements(binlog_info_values)-1, "", binlog_info_values, NULL}; ulong opt_binlog_info; -char *opt_incremental_history_name = NULL; -char *opt_incremental_history_uuid = NULL; +char *opt_incremental_history_name; +char *opt_incremental_history_uuid; -char *opt_user = NULL; -char *opt_password = NULL; -char *opt_host = NULL; -char *opt_defaults_group = NULL; -char *opt_socket = NULL; -uint opt_port = 0; -char *opt_login_path = NULL; -char *opt_log_bin = NULL; +char *opt_user; +char *opt_password; +char *opt_host; +char *opt_defaults_group; +char *opt_socket; +uint opt_port; +char *opt_log_bin; const char *query_type_names[] = { "ALL", "UPDATE", "SELECT", NullS}; @@ -366,6 +338,27 @@ uint opt_safe_slave_backup_timeout = 0; const char *opt_history = NULL; +char mariabackup_exe[FN_REFLEN]; +char orig_argv1[FN_REFLEN]; + +pthread_mutex_t backup_mutex; +pthread_cond_t scanned_lsn_cond; + +typedef std::map<space_id_t,std::string> space_id_to_name_t; + +struct ddl_tracker_t { + /** Tablspaces with their ID and name, as they were copied to backup.*/ + space_id_to_name_t tables_in_backup; + /** Tablespaces for that optimized DDL without redo log was found.*/ + std::set<space_id_t> optimized_ddl; + /** Drop operations found in redo log. */ + std::set<space_id_t> drops; + /* For DDL operation found in redo log, */ + space_id_to_name_t id_to_name; +}; + +static ddl_tracker_t ddl_tracker; + /* Simple datasink creation tracking...add datasinks in the reverse order you want them destroyed. */ #define XTRABACKUP_MAX_DATASINKS 10 @@ -379,15 +372,29 @@ xtrabackup_add_datasink(ds_ctxt_t *ds) datasinks[actual_datasinks] = ds; actual_datasinks++; } + +typedef void (*process_single_tablespace_func_t)(const char *dirname, const char *filname, bool is_remote); +static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback); + + +/* ======== Datafiles iterator ======== */ +struct datafiles_iter_t { + fil_system_t *system; + fil_space_t *space; + fil_node_t *node; + ibool started; + pthread_mutex_t mutex; +}; + /* ======== Datafiles iterator ======== */ +static datafiles_iter_t * datafiles_iter_new(fil_system_t *f_system) { datafiles_iter_t *it; - it = static_cast<datafiles_iter_t *> - (ut_malloc(sizeof(datafiles_iter_t))); - it->mutex = os_mutex_create(); + it = static_cast<datafiles_iter_t *>(malloc(sizeof(datafiles_iter_t))); + pthread_mutex_init(&it->mutex, NULL); it->system = f_system; it->space = NULL; @@ -397,12 +404,13 @@ datafiles_iter_new(fil_system_t *f_system) return it; } +static fil_node_t * datafiles_iter_next(datafiles_iter_t *it) { fil_node_t *new_node; - os_mutex_enter(it->mutex); + pthread_mutex_lock(&it->mutex); if (it->node == NULL) { if (it->started) @@ -419,7 +427,7 @@ datafiles_iter_next(datafiles_iter_t *it) UT_LIST_GET_NEXT(space_list, it->space); while (it->space != NULL && - (it->space->purpose != FIL_TABLESPACE || + (it->space->purpose != FIL_TYPE_TABLESPACE || UT_LIST_GET_LEN(it->space->chain) == 0)) it->space = UT_LIST_GET_NEXT(space_list, it->space); if (it->space == NULL) @@ -429,16 +437,255 @@ datafiles_iter_next(datafiles_iter_t *it) end: new_node = it->node; - os_mutex_exit(it->mutex); + pthread_mutex_unlock(&it->mutex); return new_node; } +static void datafiles_iter_free(datafiles_iter_t *it) { - os_mutex_free(it->mutex); - ut_free(it); + pthread_mutex_destroy(&it->mutex); + free(it); +} + +#ifndef DBUG_OFF +struct dbug_thread_param_t +{ + MYSQL *con; + const char *query; + int expect_err; + int expect_errno; + os_event_t done_event; +}; + + +/* Thread procedure used in dbug_start_query_thread. */ +extern "C" +os_thread_ret_t +DECLARE_THREAD(dbug_execute_in_new_connection)(void *arg) +{ + mysql_thread_init(); + dbug_thread_param_t *par= (dbug_thread_param_t *)arg; + int err = mysql_query(par->con, par->query); + int err_no = mysql_errno(par->con); + DBUG_ASSERT(par->expect_err == err); + if (err && par->expect_errno) + DBUG_ASSERT(err_no == par->expect_errno); + mysql_close(par->con); + mysql_thread_end(); + os_event_t done = par->done_event; + delete par; + os_event_set(done); + os_thread_exit(); + return os_thread_ret_t(0); +} + +/* +Execute query from a new connection, in own thread. + +@param query - query to be executed +@param wait_state - if not NULL, wait until query from new connection + reaches this state (value of column State in I_S.PROCESSLIST) +@param expected_err - if 0, query is supposed to finish successfully, + otherwise query should return error. +@param expected_errno - if not 0, and query finished with error, + expected mysql_errno() +*/ +static os_event_t dbug_start_query_thread( + const char *query, + const char *wait_state, + int expected_err, + int expected_errno) + +{ + dbug_thread_param_t *par = new dbug_thread_param_t; + par->query = query; + par->expect_err = expected_err; + par->expect_errno = expected_errno; + par->done_event = os_event_create(0); + par->con = xb_mysql_connect(); + os_thread_create(dbug_execute_in_new_connection, par, 0); + + if (!wait_state) + return par->done_event; + + char q[256]; + snprintf(q, sizeof(q), + "SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST where ID=%lu" + " AND Command='Query' AND State='%s'", + mysql_thread_id(par->con), wait_state); + for (;;) { + MYSQL_RES *result = xb_mysql_query(mysql_connection,q, true, true); + bool exists = mysql_fetch_row(result) != NULL; + mysql_free_result(result); + if (exists) { + goto end; + } + msg("Waiting for query '%s' on connection %lu to " + " reach state '%s'", query, mysql_thread_id(par->con), + wait_state); + my_sleep(1000); + } +end: + msg("query '%s' on connection %lu reached state '%s'", query, + mysql_thread_id(par->con), wait_state); + return par->done_event; +} + +os_event_t dbug_alter_thread_done; +#endif + +void mdl_lock_all() +{ + mdl_lock_init(); + datafiles_iter_t *it = datafiles_iter_new(fil_system); + if (!it) + return; + + while (fil_node_t *node = datafiles_iter_next(it)){ + if (fil_is_user_tablespace_id(node->space->id) + && check_if_skip_table(node->space->name)) + continue; + + mdl_lock_table(node->space->id); + } + datafiles_iter_free(it); +} + + +// Convert non-null terminated filename to space name +std::string filename_to_spacename(const byte *filename, size_t len) +{ + // null- terminate filename + char *f = (char *)malloc(len + 1); + ut_a(f); + memcpy(f, filename, len); + f[len] = 0; + for (size_t i = 0; i < len; i++) + if (f[i] == '\\') + f[i] = '/'; + char *p = strrchr(f, '.'); + ut_a(p); + *p = 0; + char *table = strrchr(f, '/'); + ut_a(table); + *table = 0; + char *db = strrchr(f, '/'); + ut_a(db); + *table = '/'; + std::string s(db+1); + free(f); + return s; +} + +/** Report an operation to create, delete, or rename a file during backup. +@param[in] space_id tablespace identifier +@param[in] flags tablespace flags (NULL if not create) +@param[in] name file name (not NUL-terminated) +@param[in] len length of name, in bytes +@param[in] new_name new file name (NULL if not rename) +@param[in] new_len length of new_name, in bytes (0 if NULL) */ +static void backup_file_op(ulint space_id, const byte* flags, + const byte* name, ulint len, + const byte* new_name, ulint new_len) +{ + + ut_ad(!flags || !new_name); + ut_ad(name); + ut_ad(len); + ut_ad(!new_name == !new_len); + pthread_mutex_lock(&backup_mutex); + + if (flags) { + ddl_tracker.id_to_name[space_id] = filename_to_spacename(name, len); + msg("DDL tracking : create %zu \"%.*s\": %x", + space_id, int(len), name, mach_read_from_4(flags)); + } + else if (new_name) { + ddl_tracker.id_to_name[space_id] = filename_to_spacename(new_name, new_len); + msg("DDL tracking : rename %zu \"%.*s\",\"%.*s\"", + space_id, int(len), name, int(new_len), new_name); + } else { + ddl_tracker.drops.insert(space_id); + msg("DDL tracking : delete %zu \"%.*s\"", space_id, int(len), name); + } + pthread_mutex_unlock(&backup_mutex); +} + + +/* + This callback is called if DDL operation is detected, + at the end of backup + + Normally, DDL operations are blocked due to FTWRL, + but in rare cases of --no-lock, they are not. + + We will abort backup in this case. +*/ +static void backup_file_op_fail(ulint space_id, const byte* flags, + const byte* name, ulint len, + const byte* new_name, ulint new_len) +{ + ut_a(opt_no_lock); + bool fail; + if (flags) { + msg("DDL tracking : create %zu \"%.*s\": %x", + space_id, int(len), name, mach_read_from_4(flags)); + std::string spacename = filename_to_spacename(name, len); + fail = !check_if_skip_table(spacename.c_str()); + } + else if (new_name) { + msg("DDL tracking : rename %zu \"%.*s\",\"%.*s\"", + space_id, int(len), name, int(new_len), new_name); + std::string spacename = filename_to_spacename(name, len); + std::string new_spacename = filename_to_spacename(new_name, new_len); + fail = !check_if_skip_table(spacename.c_str()) || !check_if_skip_table(new_spacename.c_str()); + } + else { + std::string spacename = filename_to_spacename(name, len); + fail = !check_if_skip_table(spacename.c_str()); + msg("DDL tracking : delete %zu \"%.*s\"", space_id, int(len), name); + } + if (fail) { + die("DDL operation detected in the late phase of backup." + "Backup is inconsistent. Remove --no-lock option to fix."); + } +} + + +/** Callback whenever MLOG_INDEX_LOAD happens. +@param[in] space_id space id to check */ +static void backup_optimized_ddl_op(ulint space_id) +{ + pthread_mutex_lock(&backup_mutex); + ddl_tracker.optimized_ddl.insert(space_id); + pthread_mutex_unlock(&backup_mutex); +} + +/* + Optimized DDL callback at the end of backup that + run with --no-lock. Usually aborts the backup. +*/ +static void backup_optimized_ddl_op_fail(ulint space_id) { + ut_a(opt_no_lock); + msg("DDL tracking : optimized DDL on space %zu", space_id); + if (ddl_tracker.tables_in_backup.find(space_id) != ddl_tracker.tables_in_backup.end()) { + msg("ERROR : Optimized DDL operation detected in the late phase of backup." + "Backup is inconsistent. Remove --no-lock option to fix."); + exit(EXIT_FAILURE); + } +} + + +/** Callback whenever MLOG_TRUNCATE happens. */ +static void backup_truncate_fail() +{ + msg("mariabackup: Incompatible TRUNCATE operation detected.%s", + opt_lock_ddl_per_table + ? "" + : " Use --lock-ddl-per-table to lock all tables before backup."); } @@ -479,7 +726,7 @@ typedef struct { datafiles_iter_t *it; uint num; uint *count; - os_ib_mutex_t count_mutex; + pthread_mutex_t* count_mutex; os_thread_id_t id; } data_thread_ctxt_t; @@ -493,7 +740,6 @@ enum options_xtrabackup OPT_XTRA_BACKUP, OPT_XTRA_PREPARE, OPT_XTRA_EXPORT, - OPT_XTRA_APPLY_LOG_ONLY, OPT_XTRA_PRINT_PARAM, OPT_XTRA_USE_MEMORY, OPT_XTRA_THROTTLE, @@ -506,22 +752,19 @@ enum options_xtrabackup OPT_XTRA_TABLES_FILE, OPT_XTRA_DATABASES, OPT_XTRA_DATABASES_FILE, - OPT_XTRA_CREATE_IB_LOGFILE, OPT_XTRA_PARALLEL, OPT_XTRA_EXTENDED_VALIDATION, - OPT_XTRA_BACKUP_ENCRYPTED, + OPT_XTRA_ENCRYPTED_BACKUP, OPT_XTRA_STREAM, OPT_XTRA_COMPRESS, OPT_XTRA_COMPRESS_THREADS, OPT_XTRA_COMPRESS_CHUNK_SIZE, OPT_LOG, OPT_INNODB, - OPT_INNODB_CHECKSUMS, OPT_INNODB_DATA_FILE_PATH, OPT_INNODB_DATA_HOME_DIR, OPT_INNODB_ADAPTIVE_HASH_INDEX, OPT_INNODB_DOUBLEWRITE, - OPT_INNODB_FAST_SHUTDOWN, OPT_INNODB_FILE_PER_TABLE, OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT, OPT_INNODB_FLUSH_METHOD, @@ -531,7 +774,6 @@ enum options_xtrabackup OPT_INNODB_MAX_PURGE_LAG, OPT_INNODB_ROLLBACK_ON_TIMEOUT, OPT_INNODB_STATUS_FILE, - OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE, OPT_INNODB_AUTOEXTEND_INCREMENT, OPT_INNODB_BUFFER_POOL_SIZE, OPT_INNODB_COMMIT_CONCURRENCY, @@ -542,28 +784,19 @@ enum options_xtrabackup OPT_INNODB_WRITE_IO_THREADS, OPT_INNODB_USE_NATIVE_AIO, OPT_INNODB_PAGE_SIZE, - OPT_INNODB_LOG_BLOCK_SIZE, - OPT_INNODB_DOUBLEWRITE_FILE, OPT_INNODB_BUFFER_POOL_FILENAME, - OPT_INNODB_FORCE_RECOVERY, OPT_INNODB_LOCK_WAIT_TIMEOUT, OPT_INNODB_LOG_BUFFER_SIZE, OPT_INNODB_LOG_FILE_SIZE, OPT_INNODB_LOG_FILES_IN_GROUP, - OPT_INNODB_MIRRORED_LOG_GROUPS, OPT_INNODB_OPEN_FILES, - OPT_INNODB_SYNC_SPIN_LOOPS, - OPT_INNODB_THREAD_CONCURRENCY, - OPT_INNODB_THREAD_SLEEP_DELAY, OPT_XTRA_DEBUG_SYNC, OPT_INNODB_CHECKSUM_ALGORITHM, OPT_INNODB_UNDO_DIRECTORY, OPT_INNODB_UNDO_TABLESPACES, - OPT_INNODB_LOG_CHECKSUM_ALGORITHM, + OPT_INNODB_LOG_CHECKSUMS, OPT_XTRA_INCREMENTAL_FORCE_SCAN, OPT_DEFAULTS_GROUP, - OPT_PLUGIN_LOAD, - OPT_INNODB_ENCRYPT_LOG, OPT_CLOSE_FILES, OPT_CORE_FILE, @@ -595,11 +828,18 @@ enum options_xtrabackup OPT_XTRA_TABLES_EXCLUDE, OPT_XTRA_DATABASES_EXCLUDE, OPT_PROTOCOL, - OPT_INNODB_COMPRESSION_LEVEL + OPT_INNODB_COMPRESSION_LEVEL, + OPT_LOCK_DDL_PER_TABLE, + OPT_ROCKSDB_DATADIR, + OPT_BACKUP_ROCKSDB, + OPT_XTRA_CHECK_PRIVILEGES }; struct my_option xb_client_options[] = { + {"verbose", 'V', "display verbose output", + (G_PTR*) &verbose, (G_PTR*) &verbose, 0, GET_BOOL, NO_ARG, + FALSE, 0, 0, 0, 0, 0}, {"version", 'v', "print xtrabackup version information", (G_PTR *) &xtrabackup_version, (G_PTR *) &xtrabackup_version, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -614,10 +854,6 @@ struct my_option xb_client_options[] = {"export", OPT_XTRA_EXPORT, "create files to import to another database when prepare.", (G_PTR*) &xtrabackup_export, (G_PTR*) &xtrabackup_export, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"apply-log-only", OPT_XTRA_APPLY_LOG_ONLY, - "stop recovery process not to progress LSN after applying log when prepare.", - (G_PTR*) &xtrabackup_apply_log_only, (G_PTR*) &xtrabackup_apply_log_only, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"print-param", OPT_XTRA_PRINT_PARAM, "print parameter of mysqld needed for copyback.", (G_PTR*) &xtrabackup_print_param, (G_PTR*) &xtrabackup_print_param, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -669,9 +905,6 @@ struct my_option xb_client_options[] = "Note that this option has a higher priority than --databases.", (G_PTR*) &xtrabackup_databases_exclude, (G_PTR*) &xtrabackup_databases_exclude, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"create-ib-logfile", OPT_XTRA_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. ###", - (G_PTR*) &xtrabackup_create_ib_logfile, (G_PTR*) &xtrabackup_create_ib_logfile, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"stream", OPT_XTRA_STREAM, "Stream all backup files to the standard output " "in the specified format." @@ -957,6 +1190,11 @@ struct my_option xb_client_options[] = uint xb_client_options_count = array_elements(xb_client_options); +#ifndef DBUG_OFF +/** Parameters to DBUG */ +static const char *dbug_option; +#endif + struct my_option xb_server_options[] = { {"datadir", 'h', "Path to the database root.", (G_PTR*) &mysql_data_home, @@ -985,12 +1223,12 @@ struct my_option xb_server_options[] = (G_PTR*)&opt_extended_validation, 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, - {"backup_encrypted", OPT_XTRA_BACKUP_ENCRYPTED, + {"encrypted_backup", OPT_XTRA_ENCRYPTED_BACKUP, "In --backup, assume that nonzero key_version implies that the page" - " is encrypted. Use --backup --skip-backup-encrypted to allow" + " is encrypted. Use --backup --skip-encrypted-backup to allow" " copying unencrypted that were originally created before MySQL 5.1.48.", - (G_PTR*)&opt_backup_encrypted, - (G_PTR*)&opt_backup_encrypted, + (G_PTR*)&opt_encrypted_backup, + (G_PTR*)&opt_encrypted_backup, 0, GET_BOOL, NO_ARG, TRUE, 0, 0, 0, 0, 0}, {"log", OPT_LOG, "Ignored option for MySQL option compatibility", @@ -998,40 +1236,34 @@ struct my_option xb_server_options[] = GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log_bin", OPT_LOG, "Base name for the log sequence", - &opt_log_bin, &opt_log_bin, 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, + &opt_log_bin, &opt_log_bin, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"innodb", OPT_INNODB, "Ignored option for MySQL option compatibility", (G_PTR*) &innobase_ignored_opt, (G_PTR*) &innobase_ignored_opt, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - +#ifdef BTR_CUR_HASH_ADAPT {"innodb_adaptive_hash_index", OPT_INNODB_ADAPTIVE_HASH_INDEX, "Enable InnoDB adaptive hash index (enabled by default). " "Disable with --skip-innodb-adaptive-hash-index.", - (G_PTR*) &innobase_adaptive_hash_index, - (G_PTR*) &innobase_adaptive_hash_index, + &btr_search_enabled, + &btr_search_enabled, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"innodb_additional_mem_pool_size", OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE, - "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.", - (G_PTR*) &innobase_additional_mem_pool_size, - (G_PTR*) &innobase_additional_mem_pool_size, 0, GET_LONG, REQUIRED_ARG, - 1*1024*1024L, 512*1024L, LONG_MAX, 0, 1024, 0}, +#endif /* BTR_CUR_HASH_ADAPT */ {"innodb_autoextend_increment", OPT_INNODB_AUTOEXTEND_INCREMENT, "Data file autoextend increment in megabytes", - (G_PTR*) &srv_auto_extend_increment, - (G_PTR*) &srv_auto_extend_increment, + (G_PTR*) &sys_tablespace_auto_extend_increment, + (G_PTR*) &sys_tablespace_auto_extend_increment, 0, GET_ULONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0}, - {"innodb_checksums", OPT_INNODB_CHECKSUMS, "Enable InnoDB checksums validation (enabled by default). \ -Disable with --skip-innodb-checksums.", (G_PTR*) &innobase_use_checksums, - (G_PTR*) &innobase_use_checksums, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH, "Path to individual files and their sizes.", &innobase_data_file_path, - &innobase_data_file_path, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &innobase_data_file_path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_data_home_dir", OPT_INNODB_DATA_HOME_DIR, "The common part for InnoDB table spaces.", &innobase_data_home_dir, - &innobase_data_home_dir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"innodb_doublewrite", OPT_INNODB_DOUBLEWRITE, "Enable InnoDB doublewrite buffer (enabled by default). \ -Disable with --skip-innodb-doublewrite.", (G_PTR*) &innobase_use_doublewrite, - (G_PTR*) &innobase_use_doublewrite, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"innodb_doublewrite", OPT_INNODB_DOUBLEWRITE, + "Enable InnoDB doublewrite buffer during --prepare.", + (G_PTR*) &innobase_use_doublewrite, + (G_PTR*) &innobase_use_doublewrite, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_io_capacity", OPT_INNODB_IO_CAPACITY, "Number of IOPs the server can do. Tunes the background IO rate", (G_PTR*) &srv_io_capacity, (G_PTR*) &srv_io_capacity, @@ -1059,29 +1291,22 @@ Disable with --skip-innodb-doublewrite.", (G_PTR*) &innobase_use_doublewrite, (G_PTR*) &innobase_unix_file_flush_method, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -/* ####### Should we use this option? ####### */ - {"innodb_force_recovery", OPT_INNODB_FORCE_RECOVERY, - "Helps to save your data in case the disk image of the database becomes corrupt.", - (G_PTR*) &innobase_force_recovery, (G_PTR*) &innobase_force_recovery, 0, - GET_LONG, REQUIRED_ARG, 0, 0, 6, 0, 1, 0}, - {"innodb_log_buffer_size", OPT_INNODB_LOG_BUFFER_SIZE, "The size of the buffer which InnoDB uses to write log to the log files on disk.", (G_PTR*) &innobase_log_buffer_size, (G_PTR*) &innobase_log_buffer_size, 0, GET_LONG, REQUIRED_ARG, 1024*1024L, 256*1024L, LONG_MAX, 0, 1024, 0}, {"innodb_log_file_size", OPT_INNODB_LOG_FILE_SIZE, - "Size of each log file in a log group.", - (G_PTR*) &innobase_log_file_size, (G_PTR*) &innobase_log_file_size, 0, - GET_LL, REQUIRED_ARG, 48*1024*1024L, 1*1024*1024L, LONGLONG_MAX, 0, - 1024*1024L, 0}, + "Ignored for mysqld option compatibility", + (G_PTR*) &srv_log_file_size, (G_PTR*) &srv_log_file_size, 0, + GET_ULL, REQUIRED_ARG, 48 << 20, 1 << 20, log_group_max_size, 0, + UNIV_PAGE_SIZE_MAX, 0}, {"innodb_log_files_in_group", OPT_INNODB_LOG_FILES_IN_GROUP, - "Number of log files in the log group. InnoDB writes to the files in a " - "circular fashion. Value 3 is recommended here.", - &innobase_log_files_in_group, &innobase_log_files_in_group, - 0, GET_LONG, REQUIRED_ARG, 2, 2, 100, 0, 1, 0}, + "Ignored for mysqld option compatibility", + &srv_n_log_files, &srv_n_log_files, + 0, GET_LONG, REQUIRED_ARG, 1, 1, 100, 0, 1, 0}, {"innodb_log_group_home_dir", OPT_INNODB_LOG_GROUP_HOME_DIR, "Path to InnoDB log files.", &srv_log_group_home_dir, - &srv_log_group_home_dir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &srv_log_group_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, "Percentage of dirty pages allowed in bufferpool.", (G_PTR*) &srv_max_buf_pool_modified_pct, (G_PTR*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, @@ -1093,28 +1318,24 @@ Disable with --skip-innodb-doublewrite.", (G_PTR*) &innobase_use_doublewrite, "Use native AIO if supported on this platform.", (G_PTR*) &srv_use_native_aio, (G_PTR*) &srv_use_native_aio, 0, GET_BOOL, NO_ARG, - FALSE, 0, 0, 0, 0, 0}, + TRUE, 0, 0, 0, 0, 0}, {"innodb_page_size", OPT_INNODB_PAGE_SIZE, "The universal page size of the database.", (G_PTR*) &innobase_page_size, (G_PTR*) &innobase_page_size, 0, /* Use GET_LL to support numeric suffixes in 5.6 */ GET_LL, REQUIRED_ARG, (1LL << 14), (1LL << 12), (1LL << UNIV_PAGE_SIZE_SHIFT_MAX), 0, 1L, 0}, - {"innodb_log_block_size", OPT_INNODB_LOG_BLOCK_SIZE, - "The log block size of the transaction log file. " - "Changing for created log file is not supported. Use on your own risk!", - (G_PTR*) &innobase_log_block_size, (G_PTR*) &innobase_log_block_size, 0, - GET_ULONG, REQUIRED_ARG, 512, 512, 1 << UNIV_PAGE_SIZE_SHIFT_MAX, 0, 1L, 0}, - {"innodb_doublewrite_file", OPT_INNODB_DOUBLEWRITE_FILE, - "Path to special datafile for doublewrite buffer. (default is "": not used)", - (G_PTR*) &innobase_doublewrite_file, (G_PTR*) &innobase_doublewrite_file, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_buffer_pool_filename", OPT_INNODB_BUFFER_POOL_FILENAME, - "Filename to/from which to dump/load the InnoDB buffer pool", + "Ignored for mysqld option compatibility", (G_PTR*) &innobase_buffer_pool_filename, (G_PTR*) &innobase_buffer_pool_filename, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DBUG_OFF /* unfortunately "debug" collides with existing options */ + {"dbug", '#', "Built in DBUG debugger.", + &dbug_option, &dbug_option, 0, GET_STR, OPT_ARG, + 0, 0, 0, 0, 0, 0}, +#endif #ifndef __WIN__ {"debug-sync", OPT_XTRA_DEBUG_SYNC, "Debug sync point. This is only used by the xtrabackup test suite", @@ -1127,15 +1348,11 @@ Disable with --skip-innodb-doublewrite.", (G_PTR*) &innobase_use_doublewrite, "The algorithm InnoDB uses for page checksumming. [CRC32, STRICT_CRC32, " "INNODB, STRICT_INNODB, NONE, STRICT_NONE]", &srv_checksum_algorithm, &srv_checksum_algorithm, &innodb_checksum_algorithm_typelib, GET_ENUM, - REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_INNODB, 0, 0, 0, 0, 0}, - {"innodb_log_checksum_algorithm", OPT_INNODB_LOG_CHECKSUM_ALGORITHM, - "The algorithm InnoDB uses for log checksumming. [CRC32, STRICT_CRC32, " - "INNODB, STRICT_INNODB, NONE, STRICT_NONE]", &srv_log_checksum_algorithm, - &srv_log_checksum_algorithm, &innodb_checksum_algorithm_typelib, GET_ENUM, - REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_INNODB, 0, 0, 0, 0, 0}, + REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_CRC32, 0, 0, 0, 0, 0}, + {"innodb_undo_directory", OPT_INNODB_UNDO_DIRECTORY, "Directory where undo tablespace files live, this path can be absolute.", - &srv_undo_dir, &srv_undo_dir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, + &srv_undo_dir, &srv_undo_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_undo_tablespaces", OPT_INNODB_UNDO_TABLESPACES, @@ -1158,19 +1375,36 @@ Disable with --skip-innodb-doublewrite.", (G_PTR*) &innobase_use_doublewrite, &xb_plugin_dir, &xb_plugin_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "plugin-load", OPT_PLUGIN_LOAD, "encrypton plugin to load during 'prepare' phase.", - &xb_plugin_load, &xb_plugin_load, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"innodb-log-checksums", OPT_INNODB_LOG_CHECKSUMS, + "Whether to require checksums for InnoDB redo log blocks", + &innodb_log_checksums, &innodb_log_checksums, + 0, GET_BOOL, REQUIRED_ARG, 1, 0, 0, 0, 0, 0 }, - { "innodb-encrypt-log", OPT_INNODB_ENCRYPT_LOG, "encrypton plugin to load", - &srv_encrypt_log, &srv_encrypt_log, - 0, GET_BOOL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - {"open_files_limit", OPT_OPEN_FILES_LIMIT, "the maximum number of file " "descriptors to reserve with setrlimit().", (G_PTR*) &xb_open_files_limit, (G_PTR*) &xb_open_files_limit, 0, GET_ULONG, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0}, + {"lock-ddl-per-table", OPT_LOCK_DDL_PER_TABLE, "Lock DDL for each table " + "before xtrabackup starts to copy it and until the backup is completed.", + (uchar*) &opt_lock_ddl_per_table, (uchar*) &opt_lock_ddl_per_table, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + + {"rocksdb-datadir", OPT_ROCKSDB_DATADIR, "RocksDB data directory." + "This option is only used with --copy-back or --move-back option", + &xb_rocksdb_datadir, &xb_rocksdb_datadir, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + + { "rocksdb-backup", OPT_BACKUP_ROCKSDB, "Backup rocksdb data, if rocksdb plugin is installed." + "Used only with --backup option. Can be useful for partial backups, to exclude all rocksdb data", + &xb_backup_rocksdb, &xb_backup_rocksdb, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, + + {"check-privileges", OPT_XTRA_CHECK_PRIVILEGES, "Check database user " + "privileges fro the backup user", + &opt_check_privileges, &opt_check_privileges, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1210,14 +1444,13 @@ debug_sync_point(const char *name) xtrabackup_target_dir); fp = fopen(pid_path, "w"); if (fp == NULL) { - msg("mariabackup: Error: cannot open %s\n", pid_path); - exit(EXIT_FAILURE); + die("Can't open open %s", pid_path); } fprintf(fp, "%u\n", (uint) pid); fclose(fp); msg("mariabackup: DEBUG: Suspending at debug sync point '%s'. " - "Resume with 'kill -SIGCONT %u'.\n", name, (uint) pid); + "Resume with 'kill -SIGCONT %u'.", name, (uint) pid); debug_sync_resumed= 0; kill(pid, SIGSTOP); @@ -1226,16 +1459,123 @@ debug_sync_point(const char *name) } /* On resume */ - msg("mariabackup: DEBUG: removing the pid file.\n"); + msg("mariabackup: DEBUG: removing the pid file."); my_delete(pid_path, MYF(MY_WME)); #endif } -static const char *xb_client_default_groups[]={ - "xtrabackup", "mariabackup", - "client", "client-server", - "client-mariadb", - 0, 0, 0 + +static std::set<std::string> tables_for_export; + +static void append_export_table(const char *dbname, const char *tablename, bool is_remote) +{ + if(dbname && tablename && !is_remote) + { + char buf[3*FN_REFLEN]; + snprintf(buf,sizeof(buf),"%s/%s",dbname, tablename); + // trim .ibd + char *p=strrchr(buf, '.'); + if (p) *p=0; + + std::string name=ut_get_name(0, buf); + /* Strip partition name comment from table name, if any */ + if (ends_with(name.c_str(), "*/")) + { + size_t pos= name.rfind("/*"); + if (pos != std::string::npos) + name.resize(pos); + } + tables_for_export.insert(name); + } +} + + +#define BOOTSTRAP_FILENAME "mariabackup_prepare_for_export.sql" + +static int create_bootstrap_file() +{ + FILE *f= fopen(BOOTSTRAP_FILENAME,"wb"); + if(!f) + return -1; + + fputs("SET NAMES UTF8;\n",f); + enumerate_ibd_files(append_export_table); + for (std::set<std::string>::iterator it = tables_for_export.begin(); + it != tables_for_export.end(); it++) + { + const char *tab = it->c_str(); + fprintf(f, + "BEGIN NOT ATOMIC " + "DECLARE CONTINUE HANDLER FOR NOT FOUND,SQLEXCEPTION BEGIN END;" + "FLUSH TABLES %s FOR EXPORT;" + "END;\n" + "UNLOCK TABLES;\n", + tab); + } + fclose(f); + return 0; +} + +static int prepare_export() +{ + int err= -1; + + char cmdline[2*FN_REFLEN]; + FILE *outf; + + if (create_bootstrap_file()) + return -1; + + // Process defaults-file , it can have some --lc-language stuff, + // which is* unfortunately* still necessary to get mysqld up + if (strncmp(orig_argv1,"--defaults-file=",16) == 0) + { + snprintf(cmdline, sizeof cmdline, + IF_WIN("\"","") "\"%s\" --mysqld \"%s\" " + " --defaults-extra-file=./backup-my.cnf --defaults-group-suffix=%s --datadir=." + " --innodb --innodb-fast-shutdown=0 --loose-partition" + " --innodb_purge_rseg_truncate_frequency=1 --innodb-buffer-pool-size=%llu" + " --console --skip-log-error --bootstrap < " BOOTSTRAP_FILENAME IF_WIN("\"",""), + mariabackup_exe, + orig_argv1, (my_defaults_group_suffix?my_defaults_group_suffix:""), + xtrabackup_use_memory); + } + else + { + sprintf(cmdline, + IF_WIN("\"","") "\"%s\" --mysqld" + " --defaults-file=./backup-my.cnf --defaults-group-suffix=%s --datadir=." + " --innodb --innodb-fast-shutdown=0 --loose-partition" + " --innodb_purge_rseg_truncate_frequency=1 --innodb-buffer-pool-size=%llu" + " --console --log-error= --bootstrap < " BOOTSTRAP_FILENAME IF_WIN("\"",""), + mariabackup_exe, + (my_defaults_group_suffix?my_defaults_group_suffix:""), + xtrabackup_use_memory); + } + + msg("Prepare export : executing %s\n", cmdline); + fflush(stderr); + + outf= popen(cmdline,"r"); + if (!outf) + goto end; + + char outline[FN_REFLEN]; + while(fgets(outline, sizeof(outline)-1, outf)) + fprintf(stderr,"%s",outline); + + err = pclose(outf); +end: + unlink(BOOTSTRAP_FILENAME); + return err; +} + + +static const char *xb_client_default_groups[]={ + "xtrabackup", "mariabackup", + "client", "client-server", + "client-mariadb", + 0, 0, 0 }; static const char *xb_server_default_groups[]={ @@ -1251,7 +1591,7 @@ static const char *xb_server_default_groups[]={ static void print_version(void) { - msg("%s based on MariaDB server %s %s (%s) \n", + fprintf(stderr, "%s based on MariaDB server %s %s (%s)\n", my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); } @@ -1331,13 +1671,7 @@ xb_get_one_option(int optid, break; case OPT_INNODB_LOG_FILES_IN_GROUP: - - ADD_PRINT_PARAM_OPT(innobase_log_files_in_group); - break; - case OPT_INNODB_LOG_FILE_SIZE: - - ADD_PRINT_PARAM_OPT(innobase_log_file_size); break; case OPT_INNODB_FLUSH_METHOD: @@ -1350,16 +1684,6 @@ xb_get_one_option(int optid, ADD_PRINT_PARAM_OPT(innobase_page_size); break; - case OPT_INNODB_LOG_BLOCK_SIZE: - - ADD_PRINT_PARAM_OPT(innobase_log_block_size); - break; - - case OPT_INNODB_DOUBLEWRITE_FILE: - - ADD_PRINT_PARAM_OPT(innobase_doublewrite_file); - break; - case OPT_INNODB_UNDO_DIRECTORY: ADD_PRINT_PARAM_OPT(srv_undo_dir); @@ -1377,13 +1701,6 @@ xb_get_one_option(int optid, ADD_PRINT_PARAM_OPT(innodb_checksum_algorithm_names[srv_checksum_algorithm]); break; - case OPT_INNODB_LOG_CHECKSUM_ALGORITHM: - - ut_a(srv_log_checksum_algorithm <= SRV_CHECKSUM_ALGORITHM_STRICT_NONE); - - ADD_PRINT_PARAM_OPT(innodb_checksum_algorithm_names[srv_log_checksum_algorithm]); - break; - case OPT_INNODB_COMPRESSION_LEVEL: ADD_PRINT_PARAM_OPT(page_zip_level); break; @@ -1402,7 +1719,7 @@ xb_get_one_option(int optid, xtrabackup_stream_fmt = XB_STREAM_FMT_XBSTREAM; else { - msg("Invalid --stream argument: %s\n", argument); + msg("Invalid --stream argument: %s", argument); return 1; } xtrabackup_stream = TRUE; @@ -1412,7 +1729,7 @@ xb_get_one_option(int optid, xtrabackup_compress_alg = "quicklz"; else if (strcasecmp(argument, "quicklz")) { - msg("Invalid --compress argument: %s\n", argument); + msg("Invalid --compress argument: %s", argument); return 1; } xtrabackup_compress = TRUE; @@ -1471,46 +1788,15 @@ xb_get_one_option(int optid, return 0; } -/*********************************************************************** -Initializes log_block_size */ -static -ibool -xb_init_log_block_size(void) -{ - srv_log_block_size = 0; - if (innobase_log_block_size != 512) { - uint n_shift = (uint)get_bit_shift(innobase_log_block_size);; - - if (n_shift > 0) { - srv_log_block_size = (ulint)(1LL << n_shift); - msg("InnoDB: The log block size is set to %lu.\n", - srv_log_block_size); - } - } else { - srv_log_block_size = 512; - } - if (!srv_log_block_size) { - msg("InnoDB: Error: %lu is not valid value for " - "innodb_log_block_size.\n", innobase_log_block_size); - return FALSE; - } - - return TRUE; -} - static my_bool innodb_init_param(void) { - /* innobase_init */ - static char current_dir[3]; /* Set if using current lib */ - my_bool ret; - char *default_path; srv_is_being_started = TRUE; /* === some variables from mysqld === */ memset((G_PTR) &mysql_tmpdir_list, 0, sizeof(mysql_tmpdir_list)); if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) - exit(EXIT_FAILURE); + die("init_tmpdir() failed"); xtrabackup_tmpdir = my_tmpdir(&mysql_tmpdir_list); /* dummy for initialize all_charsets[] */ get_charset_name(0); @@ -1524,61 +1810,36 @@ innodb_init_param(void) if (n_shift >= 12 && n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX) { srv_page_size_shift = n_shift; srv_page_size = 1 << n_shift; - msg("InnoDB: The universal page size of the " - "database is set to %lu.\n", srv_page_size); + msg("InnoDB: The page size of the " + "database is set to %lu.", srv_page_size); } else { - msg("InnoDB: Error: invalid value of " + die("invalid value of " "innobase_page_size: %lld", innobase_page_size); - exit(EXIT_FAILURE); } } else { srv_page_size_shift = 14; srv_page_size = (1 << srv_page_size_shift); } - if (!xb_init_log_block_size()) { - goto error; - } - /* Check that values don't overflow on 32-bit systems. */ if (sizeof(ulint) == 4) { if (xtrabackup_use_memory > UINT_MAX32) { msg("mariabackup: use-memory can't be over 4GB" - " on 32-bit systems\n"); - } - - if (innobase_log_file_size > UINT_MAX32) { - msg("mariabackup: innobase_log_file_size can't be " - "over 4GB on 32-bit systemsi\n"); - - goto error; + " on 32-bit systems"); } } - os_innodb_umask = (ulint)0664; - - /* First calculate the default path for innodb_data_home_dir etc., - in case the user has not given any value. - - Note that when using the embedded server, the datadirectory is not - necessarily the current directory of this program. */ - - /* It's better to use current lib, to keep paths short */ - current_dir[0] = FN_CURLIB; - current_dir[1] = FN_LIBCHAR; - current_dir[2] = 0; - default_path = current_dir; - - ut_a(default_path); + static char default_path[2] = { FN_CURLIB, 0 }; + fil_path_to_mysql_datadir = default_path; /* Set InnoDB initialization parameters according to the values read from MySQL .cnf file */ if (xtrabackup_backup) { - msg("mariabackup: using the following InnoDB configuration:\n"); + msg("mariabackup: using the following InnoDB configuration:"); } else { msg("mariabackup: using the following InnoDB configuration " - "for recovery:\n"); + "for recovery:"); } /*--------------- Data files -------------------------*/ @@ -1587,7 +1848,7 @@ innodb_init_param(void) srv_data_home = (xtrabackup_backup && innobase_data_home_dir ? innobase_data_home_dir : default_path); - msg("mariabackup: innodb_data_home_dir = %s\n", srv_data_home); + msg("innodb_data_home_dir = %s", srv_data_home); /* Set default InnoDB data file size to 10 MB and let it be auto-extending. Thus users can use InnoDB in >= 4.0 without having @@ -1596,40 +1857,23 @@ innodb_init_param(void) if (!innobase_data_file_path) { innobase_data_file_path = (char*) "ibdata1:10M:autoextend"; } - msg("mariabackup: innodb_data_file_path = %s\n", + msg("innodb_data_file_path = %s", innobase_data_file_path); - /* Since InnoDB edits the argument in the next call, we make another - copy of it: */ + /* This is the first time univ_page_size is used. + It was initialized to 16k pages before srv_page_size was set */ + univ_page_size.copy_from( + page_size_t(srv_page_size, srv_page_size, false)); - internal_innobase_data_file_path = strdup(innobase_data_file_path); + srv_sys_space.set_space_id(TRX_SYS_SPACE); + srv_sys_space.set_name("innodb_system"); + srv_sys_space.set_path(srv_data_home); + srv_sys_space.set_flags(FSP_FLAGS_PAGE_SSIZE()); - ret = (my_bool) srv_parse_data_file_paths_and_sizes( - internal_innobase_data_file_path); - if (ret == FALSE) { - msg("mariabackup: syntax error in innodb_data_file_path\n"); -mem_free_and_error: - free(internal_innobase_data_file_path); - internal_innobase_data_file_path = NULL; + if (!srv_sys_space.parse_params(innobase_data_file_path, true)) { goto error; } - if (xtrabackup_prepare) { - /* "--prepare" needs filenames only */ - ulint i; - - for (i=0; i < srv_n_data_files; i++) { - char *p; - - p = srv_data_file_names[i]; - while ((p = strchr(p, SRV_PATH_SEPARATOR)) != NULL) - { - p++; - srv_data_file_names[i] = p; - } - } - } - /* -------------- Log files ---------------------------*/ /* The default dir for log files is the datadir of MySQL */ @@ -1640,61 +1884,38 @@ mem_free_and_error: if (xtrabackup_prepare && xtrabackup_incremental_dir) { srv_log_group_home_dir = xtrabackup_incremental_dir; } - msg("mariabackup: innodb_log_group_home_dir = %s\n", + msg("innodb_log_group_home_dir = %s", srv_log_group_home_dir); - srv_normalize_path_for_win(srv_log_group_home_dir); + os_normalize_path(srv_log_group_home_dir); if (strchr(srv_log_group_home_dir, ';')) { - msg("syntax error in innodb_log_group_home_dir, "); - - goto mem_free_and_error; + goto error; } srv_adaptive_flushing = FALSE; - srv_use_sys_malloc = TRUE; srv_file_format = 1; /* Barracuda */ srv_max_file_format_at_startup = UNIV_FORMAT_MIN; /* on */ /* --------------------------------------------------*/ srv_file_flush_method_str = innobase_unix_file_flush_method; - srv_n_log_files = (ulint) innobase_log_files_in_group; - srv_log_file_size = (ulint) innobase_log_file_size; - msg("mariabackup: innodb_log_files_in_group = %ld\n", - srv_n_log_files); - msg("mariabackup: innodb_log_file_size = %lld\n", - (long long int) srv_log_file_size); - srv_log_buffer_size = (ulint) innobase_log_buffer_size; /* We set srv_pool_size here in units of 1 kB. InnoDB internally changes the value so that it becomes the number of database pages. */ - srv_buf_pool_size = (ulint) xtrabackup_use_memory; - srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size; + srv_buf_pool_size = (ulint) xtrabackup_use_memory; + srv_buf_pool_chunk_unit = srv_buf_pool_size; + srv_buf_pool_instances = 1; srv_n_file_io_threads = (ulint) innobase_file_io_threads; srv_n_read_io_threads = (ulint) innobase_read_io_threads; srv_n_write_io_threads = (ulint) innobase_write_io_threads; - srv_force_recovery = (ulint) innobase_force_recovery; - srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite; - if (!innobase_use_checksums) { - - srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_NONE; - } - - btr_search_enabled = (char) innobase_adaptive_hash_index; - btr_search_index_num = 1; - - os_use_large_pages = (ibool) innobase_use_large_pages; - os_large_page_size = (ulint) innobase_large_page_size; - static char default_dir[3] = "./"; - srv_arch_dir = default_dir; row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout; srv_file_per_table = (my_bool) innobase_file_per_table; @@ -1704,7 +1925,7 @@ mem_free_and_error: srv_max_n_open_files = (ulint) innobase_open_files; srv_innodb_status = (ibool) innobase_create_status_file; - srv_print_verbose_log = 1; + srv_print_verbose_log = verbose ? 2 : 1; /* Store the default charset-collation number of this MySQL installation */ @@ -1712,18 +1933,8 @@ mem_free_and_error: /* We cannot treat characterset here for now!! */ data_mysql_default_charset_coll = (ulint)default_charset_info->number; - ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL == - my_charset_latin1.number); ut_a(DATA_MYSQL_BINARY_CHARSET_COLL == my_charset_bin.number); - /* Store the latin1_swedish_ci character ordering table to InnoDB. For - non-latin1_swedish_ci charsets we use the MySQL comparison functions, - and consequently we do not need to know the ordering internally in - InnoDB. */ - - ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); - srv_latin1_ordering = my_charset_latin1.sort_order; - //innobase_commit_concurrency_init_default(); /* Since we in this module access directly the fields of a trx @@ -1737,37 +1948,13 @@ mem_free_and_error: innobase_start_or_create_for_mysql(). As we don't call it in xtrabackup, we have to duplicate checks from that function here. */ -#ifdef __WIN__ - switch (os_get_os_version()) { - case OS_WIN95: - case OS_WIN31: - case OS_WINNT: - /* On Win 95, 98, ME, Win32 subsystem for Windows 3.1, - and NT use simulated aio. In NT Windows provides async i/o, - but when run in conjunction with InnoDB Hot Backup, it seemed - to corrupt the data files. */ - - srv_use_native_aio = FALSE; - break; - - case OS_WIN2000: - case OS_WINXP: - /* On 2000 and XP, async IO is available. */ - srv_use_native_aio = TRUE; - break; - - default: - /* Vista and later have both async IO and condition variables */ - srv_use_native_aio = TRUE; - srv_use_native_conditions = TRUE; - break; - } +#ifdef _WIN32 + srv_use_native_aio = TRUE; #elif defined(LINUX_NATIVE_AIO) if (srv_use_native_aio) { - ut_print_timestamp(stderr); - msg(" InnoDB: Using Linux native AIO\n"); + msg("InnoDB: Using Linux native AIO"); } #else /* Currently native AIO is supported only on windows and linux @@ -1784,70 +1971,29 @@ mem_free_and_error: directory. */ if (!srv_undo_dir || !xtrabackup_backup) { - my_free(srv_undo_dir); - srv_undo_dir = my_strdup(".", MYF(MY_FAE)); + srv_undo_dir = (char*) "."; } - innodb_log_checksum_func_update(srv_log_checksum_algorithm); + log_checksum_algorithm_ptr = innodb_log_checksums || srv_encrypt_log + ? log_block_calc_checksum_crc32 + : log_block_calc_checksum_none; return(FALSE); error: - msg("mariabackup: innodb_init_param(): Error occured.\n"); + msg("innodb_init_param(): Error occured."); return(TRUE); } -static my_bool -innodb_init(void) +static bool innodb_init() { - int err; - srv_is_being_started = TRUE; - err = innobase_start_or_create_for_mysql(); - + dberr_t err = innobase_start_or_create_for_mysql(); if (err != DB_SUCCESS) { - free(internal_innobase_data_file_path); - internal_innobase_data_file_path = NULL; - goto error; + die("mariabackup: innodb_init() returned %d (%s).", + err, ut_strerr(err)); } - /* They may not be needed for now */ -// (void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0, -// (hash_get_key) innobase_get_key, 0, 0); -// pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST); -// pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); -// pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); -// pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); -// pthread_cond_init(&commit_cond, NULL); - - innodb_inited= 1; - return(FALSE); - -error: - msg("mariabackup: innodb_init(): Error occured.\n"); - return(TRUE); -} - -static void -innodb_end() -{ - srv_fast_shutdown = (ulint) innobase_fast_shutdown; - innodb_inited = 0; - - msg("mariabackup: starting shutdown with innodb_fast_shutdown = %lu\n", - srv_fast_shutdown); - - innodb_shutdown(); - free(internal_innobase_data_file_path); - internal_innobase_data_file_path = NULL; - - /* They may not be needed for now */ -// hash_free(&innobase_open_tables); -// pthread_mutex_destroy(&innobase_share_mutex); -// pthread_mutex_destroy(&prepare_commit_mutex); -// pthread_mutex_destroy(&commit_threads_m); -// pthread_mutex_destroy(&commit_cond_m); -// pthread_cond_destroy(&commit_cond); } /* ================= common ================= */ @@ -1864,7 +2010,7 @@ xtrabackup_read_metadata(char *filename) fp = fopen(filename,"r"); if(!fp) { - msg("mariabackup: Error: cannot open %s\n", filename); + msg("Error: cannot open %s", filename); return(FALSE); } @@ -1938,8 +2084,7 @@ xtrabackup_stream_metadata(ds_ctxt_t *ds_ctxt) stream = ds_open(ds_ctxt, XTRABACKUP_METADATA_FILENAME, &mystat); if (stream == NULL) { - msg("mariabackup: Error: cannot open output stream " - "for %s\n", XTRABACKUP_METADATA_FILENAME); + msg("Error: cannot open output stream for %s", XTRABACKUP_METADATA_FILENAME); return(FALSE); } @@ -1971,7 +2116,7 @@ xtrabackup_write_metadata(const char *filepath) fp = fopen(filepath, "w"); if(!fp) { - msg("mariabackup: Error: cannot open %s\n", filepath); + msg("Error: cannot open %s", filepath); return(FALSE); } if (fwrite(buf, len, 1, fp) < 1) { @@ -1996,8 +2141,7 @@ xb_read_delta_metadata(const char *filepath, xb_delta_info_t *info) my_bool r = TRUE; /* set defaults */ - info->page_size = ULINT_UNDEFINED; - info->zip_size = ULINT_UNDEFINED; + ulint page_size = ULINT_UNDEFINED, zip_size = 0; info->space_id = ULINT_UNDEFINED; fp = fopen(filepath, "r"); @@ -2009,9 +2153,9 @@ xb_read_delta_metadata(const char *filepath, xb_delta_info_t *info) while (!feof(fp)) { if (fscanf(fp, "%50s = %50s\n", key, value) == 2) { if (strcmp(key, "page_size") == 0) { - info->page_size = strtoul(value, NULL, 10); + page_size = strtoul(value, NULL, 10); } else if (strcmp(key, "zip_size") == 0) { - info->zip_size = strtoul(value, NULL, 10); + zip_size = strtoul(value, NULL, 10); } else if (strcmp(key, "space_id") == 0) { info->space_id = strtoul(value, NULL, 10); } @@ -2020,14 +2164,18 @@ xb_read_delta_metadata(const char *filepath, xb_delta_info_t *info) fclose(fp); - if (info->page_size == ULINT_UNDEFINED) { - msg("mariabackup: page_size is required in %s\n", filepath); + if (page_size == ULINT_UNDEFINED) { + msg("page_size is required in %s", filepath); r = FALSE; + } else { + info->page_size = page_size_t(zip_size ? zip_size : page_size, + page_size, zip_size != 0); } + if (info->space_id == ULINT_UNDEFINED) { msg("mariabackup: Warning: This backup was taken with XtraBackup 2.0.1 " "or earlier, some DDL operations between full and incremental " - "backups may be handled incorrectly\n"); + "backups may be handled incorrectly"); } return(r); @@ -2046,10 +2194,13 @@ xb_write_delta_metadata(const char *filename, const xb_delta_info_t *info) MY_STAT mystat; snprintf(buf, sizeof(buf), - "page_size = %lu\n" - "zip_size = %lu\n" - "space_id = %lu\n", - info->page_size, info->zip_size, info->space_id); + "page_size = " ULINTPF "\n" + "zip_size = " ULINTPF " \n" + "space_id = " ULINTPF "\n", + info->page_size.logical(), + info->page_size.is_compressed() + ? info->page_size.physical() : 0, + info->space_id); len = strlen(buf); mystat.st_size = len; @@ -2057,8 +2208,7 @@ xb_write_delta_metadata(const char *filename, const xb_delta_info_t *info) f = ds_open(ds_meta, filename, &mystat); if (f == NULL) { - msg("mariabackup: Error: cannot open output stream for %s\n", - filename); + msg("Error: Can't open output stream for %s",filename); return(FALSE); } @@ -2206,7 +2356,7 @@ check_if_skip_database_by_path( return(FALSE); } - const char* db_name = strrchr(path, SRV_PATH_SEPARATOR); + const char* db_name = strrchr(path, OS_PATH_SEPARATOR); if (db_name == NULL) { db_name = path; } else { @@ -2314,46 +2464,6 @@ check_if_skip_table( return(FALSE); } -/*********************************************************************** -Reads the space flags from a given data file and returns the compressed -page size, or 0 if the space is not compressed. */ -ulint -xb_get_zip_size(fil_node_t* file) -{ - byte *buf; - byte *page; - ulint zip_size = ULINT_UNDEFINED; - ibool success; - ulint space; - - buf = static_cast<byte *>(ut_malloc(2 * UNIV_PAGE_SIZE)); - page = static_cast<byte *>(ut_align(buf, UNIV_PAGE_SIZE)); - - success = os_file_read(file->handle, page, 0, UNIV_PAGE_SIZE); - if (!success) { - goto end; - } - - space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - zip_size = (space == 0 ) ? 0 : - dict_tf_get_zip_size(fsp_header_get_flags(page)); - - if (!file->space->crypt_data) { - fil_system_enter(); - if (!file->space->crypt_data) { - file->space->crypt_data = fil_space_read_crypt_data( - space, page, - fsp_header_get_crypt_offset(zip_size)); - } - fil_system_exit(); - } - -end: - ut_free(buf); - - return(zip_size); -} - const char* xb_get_copy_action(const char *dflt) { @@ -2380,7 +2490,7 @@ xb_get_copy_action(const char *dflt) static my_bool -xtrabackup_copy_datafile(fil_node_t* node, uint thread_n) +xtrabackup_copy_datafile(fil_node_t* node, uint thread_n, const char *dest_name=0, ulonglong max_size=ULLONG_MAX) { char dst_name[FN_REFLEN]; ds_file_t *dstfile = NULL; @@ -2390,7 +2500,6 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n) xb_write_filt_ctxt_t write_filt_ctxt; const char *action; xb_read_filt_t *read_filter; - ibool is_system; my_bool rc = FALSE; /* Get the name and the path for the tablespace. node->name always @@ -2405,27 +2514,38 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n) const char* const node_name = node->space->name; const char* const node_path = node->name; - is_system = !fil_is_user_tablespace_id(node->space->id); - - if (!is_system && check_if_skip_table(node_name)) { - msg("[%02u] Skipping %s.\n", thread_n, node_name); + if (fil_is_user_tablespace_id(node->space->id) + && check_if_skip_table(node_name)) { + msg(thread_n, "Skipping %s.", node_name); return(FALSE); } + bool was_dropped; + pthread_mutex_lock(&backup_mutex); + was_dropped = (ddl_tracker.drops.find(node->space->id) != ddl_tracker.drops.end()); + pthread_mutex_unlock(&backup_mutex); + if (was_dropped) { + fil_space_close(node->space->name); + goto skip; + } + if (!changed_page_bitmap) { read_filter = &rf_pass_through; } else { read_filter = &rf_bitmap; } - res = xb_fil_cur_open(&cursor, read_filter, node, thread_n); + + res = xb_fil_cur_open(&cursor, read_filter, node, thread_n,max_size); if (res == XB_FIL_CUR_SKIP) { goto skip; } else if (res == XB_FIL_CUR_ERROR) { goto error; } - strncpy(dst_name, cursor.rel_path, sizeof(dst_name)); + strncpy(dst_name, dest_name ? dest_name : cursor.rel_path, + sizeof dst_name - 1); + dst_name[sizeof dst_name - 1] = '\0'; /* Setup the page write filter */ if (xtrabackup_incremental) { @@ -2439,26 +2559,22 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n) if (write_filter->init != NULL && !write_filter->init(&write_filt_ctxt, dst_name, &cursor)) { - msg("[%02u] mariabackup: error: " - "failed to initialize page write filter.\n", thread_n); + msg (thread_n, "mariabackup: error: failed to initialize page write filter."); goto error; } dstfile = ds_open(ds_data, dst_name, &cursor.statinfo); if (dstfile == NULL) { - msg("[%02u] mariabackup: error: " - "cannot open the destination stream for %s\n", - thread_n, dst_name); + msg(thread_n,"mariabackup: error: can't open the destination stream for %s", dst_name); goto error; } action = xb_get_copy_action(); if (xtrabackup_stream) { - msg_ts("[%02u] %s %s\n", thread_n, action, node_path); + msg(thread_n, "%s %s", action, node_path); } else { - msg_ts("[%02u] %s %s to %s\n", thread_n, action, - node_path, dstfile->path); + msg(thread_n, "%s %s to %s", action, node_path, dstfile->path); } /* The main copy loop */ @@ -2477,8 +2593,12 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n) goto error; } + pthread_mutex_lock(&backup_mutex); + ddl_tracker.tables_in_backup[node->space->id] = node_name; + pthread_mutex_unlock(&backup_mutex); + /* close */ - msg_ts("[%02u] ...done\n", thread_n); + msg(thread_n," ...done"); xb_fil_cur_close(&cursor); if (ds_close(dstfile)) { rc = TRUE; @@ -2496,8 +2616,7 @@ error: if (write_filter && write_filter->deinit) { write_filter->deinit(&write_filt_ctxt);; } - msg("[%02u] mariabackup: Error: " - "xtrabackup_copy_datafile() failed.\n", thread_n); + msg(thread_n, "mariabackup: xtrabackup_copy_datafile() failed."); return(TRUE); /*ERROR*/ skip: @@ -2508,365 +2627,172 @@ skip: if (write_filter && write_filter->deinit) { write_filter->deinit(&write_filt_ctxt); } - msg("[%02u] mariabackup: Warning: We assume the " - "table was dropped during xtrabackup execution " - "and ignore the file.\n", thread_n); - msg("[%02u] mariabackup: Warning: skipping tablespace %s.\n", - thread_n, node_name); + msg(thread_n,"Warning: We assume the table was dropped during xtrabackup execution and ignore the tablespace %s", node_name); return(FALSE); } -static -void -xtrabackup_choose_lsn_offset(lsn_t start_lsn) +/** Copy redo log blocks to the data sink. +@param start_lsn buffer start LSN +@param end_lsn buffer end LSN +@param last whether we are copying the final part of the log +@return last scanned LSN +@retval 0 on failure */ +static lsn_t xtrabackup_copy_log(lsn_t start_lsn, lsn_t end_lsn, bool last) { -#if SUPPORT_PERCONA_5_5 - ulint no, alt_no, expected_no; - ulint blocks_in_group; - lsn_t tmp_offset, end_lsn; - int lsn_chosen = 0; - log_group_t *group; - - start_lsn = ut_uint64_align_down(start_lsn, OS_FILE_LOG_BLOCK_SIZE); - end_lsn = start_lsn + RECV_SCAN_SIZE; - - group = UT_LIST_GET_FIRST(log_sys->log_groups); - - if (mysql_server_version < 50500 || mysql_server_version > 50600) { - /* only make sense for Percona Server 5.5 */ - return; - } - - if (server_flavor == FLAVOR_PERCONA_SERVER) { - /* it is Percona Server 5.5 */ - group->alt_offset_chosen = true; - group->lsn_offset = group->lsn_offset_alt; - return; - } - - if (group->lsn_offset_alt == group->lsn_offset || - group->lsn_offset_alt == (lsn_t) -1) { - /* we have only one option */ - return; - } - - no = alt_no = (ulint) -1; - lsn_chosen = 0; - - blocks_in_group = log_block_convert_lsn_to_no( - log_group_get_capacity(group)) - 1; - - /* read log block number from usual offset */ - if (group->lsn_offset < group->file_size * group->n_files && - (log_group_calc_lsn_offset(start_lsn, group) % - UNIV_PAGE_SIZE) % OS_MIN_LOG_BLOCK_SIZE == 0) { - log_group_read_log_seg(LOG_RECOVER, log_sys->buf, - group, start_lsn, end_lsn); - no = log_block_get_hdr_no(log_sys->buf); - } - - /* read log block number from Percona Server 5.5 offset */ - tmp_offset = group->lsn_offset; - group->lsn_offset = group->lsn_offset_alt; - - if (group->lsn_offset < group->file_size * group->n_files && - (log_group_calc_lsn_offset(start_lsn, group) % - UNIV_PAGE_SIZE) % OS_MIN_LOG_BLOCK_SIZE == 0) { - log_group_read_log_seg(LOG_RECOVER, log_sys->buf, - group, start_lsn, end_lsn); - alt_no = log_block_get_hdr_no(log_sys->buf); - } - - expected_no = log_block_convert_lsn_to_no(start_lsn); - - ut_a(!(no == expected_no && alt_no == expected_no)); + lsn_t scanned_lsn = start_lsn; + const byte* log_block = log_sys->buf; + bool more_data = false; - group->lsn_offset = tmp_offset; + for (ulint scanned_checkpoint = 0; + scanned_lsn < end_lsn; + log_block += OS_FILE_LOG_BLOCK_SIZE) { + ulint checkpoint = log_block_get_checkpoint_no(log_block); - if ((no <= expected_no && - ((expected_no - no) % blocks_in_group) == 0) || - ((expected_no | 0x40000000UL) - no) % blocks_in_group == 0) { - /* default offset looks ok */ - ++lsn_chosen; - } - - if ((alt_no <= expected_no && - ((expected_no - alt_no) % blocks_in_group) == 0) || - ((expected_no | 0x40000000UL) - alt_no) % blocks_in_group == 0) { - /* PS 5.5 style offset looks ok */ - ++lsn_chosen; - group->alt_offset_chosen = true; - group->lsn_offset = group->lsn_offset_alt; - } - - /* We are in trouble, because we can not make a - decision to choose one over the other. Die just - like a Buridan's ass */ - ut_a(lsn_chosen == 1); -#endif -} - -extern ibool log_block_checksum_is_ok_or_old_format(const byte* block); - -/*******************************************************//** -Scans log from a buffer and writes new log data to the outpud datasinc. -@return true if success */ -static -bool -xtrabackup_scan_log_recs( -/*===============*/ - log_group_t* group, /*!< in: log group */ - bool is_last, /*!< in: whether it is last segment - to copy */ - lsn_t start_lsn, /*!< in: buffer start lsn */ - lsn_t* contiguous_lsn, /*!< in/out: it is known that all log - groups contain contiguous log data up - to this lsn */ - lsn_t* group_scanned_lsn,/*!< out: scanning succeeded up to - this lsn */ - bool* finished, /*!< out: false if is not able to scan - any more in this log group */ - bool* must_reread_log) /*!< out: should re-read buffer from disk, incomplete read*/ -{ - lsn_t scanned_lsn; - ulint data_len; - ulint write_size; - const byte* log_block; - - ulint scanned_checkpoint_no = 0; - - *finished = false; - *must_reread_log = false; - scanned_lsn = start_lsn; - log_block = log_sys->buf; - - while (log_block < log_sys->buf + RECV_SCAN_SIZE && !*finished) { - ulint no = log_block_get_hdr_no(log_block); - ulint scanned_no = log_block_convert_lsn_to_no(scanned_lsn); - ibool checksum_is_ok = - log_block_checksum_is_ok_or_old_format(log_block); - - if (no != scanned_no && checksum_is_ok) { - ulint blocks_in_group; - - blocks_in_group = log_block_convert_lsn_to_no( - log_group_get_capacity(group)) - 1; - - if ((no < scanned_no && - ((scanned_no - no) % blocks_in_group) == 0) || - no == 0 || - /* Log block numbers wrap around at 0x3FFFFFFF */ - ((scanned_no | 0x40000000UL) - no) % - blocks_in_group == 0) { - - /* old log block, do nothing */ - *finished = true; - break; - } - - msg("mariabackup: error:" - " log block numbers mismatch:\n" - "mariabackup: error: expected log block no. %lu," - " but got no. %lu from the log file.\n", - (ulong) scanned_no, (ulong) no); - - if ((no - scanned_no) % blocks_in_group == 0) { - msg("mariabackup: error:" - " it looks like InnoDB log has wrapped" - " around before xtrabackup could" - " process all records due to either" - " log copying being too slow, or " - " log files being too small.\n"); - } - - return(false); - } else if (!checksum_is_ok) { - /* Garbage or an incompletely written log block */ - - msg("mariabackup: warning: Log block checksum mismatch" - " (block no %lu at lsn " LSN_PF "): \n" - "expected %lu, calculated checksum %lu\n", - (ulong) no, - scanned_lsn, - (ulong) log_block_get_checksum(log_block), - (ulong) log_block_calc_checksum(log_block)); - msg("mariabackup: warning: this is possible when the " - "log block has not been fully written by the " - "server, will retry later.\n"); - *finished = false; - *must_reread_log = true; - my_sleep(1000); - return false; + if (scanned_checkpoint > checkpoint + && scanned_checkpoint - checkpoint >= 0x80000000UL) { + /* Garbage from a log buffer flush which was made + before the most recent database recovery */ + msg(0,"checkpoint wrap: " LSN_PF ",%zx,%zx", + scanned_lsn, scanned_checkpoint, checkpoint); + break; } - if (log_block_get_flush_bit(log_block)) { - /* This block was a start of a log flush operation: - we know that the previous flush operation must have - been completed for all log groups before this block - can have been flushed to any of the groups. Therefore, - we know that log data is contiguous up to scanned_lsn - in all non-corrupt log groups. */ - - if (scanned_lsn > *contiguous_lsn) { + scanned_checkpoint = checkpoint; - *contiguous_lsn = scanned_lsn; - } - } + ulint data_len = log_block_get_data_len(log_block); - data_len = log_block_get_data_len(log_block); + more_data = recv_sys_add_to_parsing_buf( + log_block, + scanned_lsn + data_len); - if ( - (scanned_checkpoint_no > 0) - && (log_block_get_checkpoint_no(log_block) - < scanned_checkpoint_no) - && (scanned_checkpoint_no - - log_block_get_checkpoint_no(log_block) - > 0x80000000UL)) { + recv_sys->scanned_lsn = scanned_lsn + data_len; - /* Garbage from a log buffer flush which was made - before the most recent database recovery */ - - *finished = true; + if (data_len == OS_FILE_LOG_BLOCK_SIZE) { + /* We got a full log block. */ + scanned_lsn += data_len; + } else if (data_len + >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE + || data_len <= LOG_BLOCK_HDR_SIZE) { + /* We got a garbage block (abrupt end of the log). */ + msg(0,"garbage block: " LSN_PF ",%zu",scanned_lsn, data_len); + break; + } else { + /* We got a partial block (abrupt end of the log). */ + scanned_lsn += data_len; break; } + } - scanned_lsn = scanned_lsn + data_len; - scanned_checkpoint_no = log_block_get_checkpoint_no(log_block); + if (more_data && recv_parse_log_recs(0, STORE_NO, false)) { - if (data_len < OS_FILE_LOG_BLOCK_SIZE) { - /* Log data for this group ends here */ + msg("Error: copying the log failed"); - *finished = true; - } else { - log_block += OS_FILE_LOG_BLOCK_SIZE; - } + return(0); } - *group_scanned_lsn = scanned_lsn; + recv_sys_justify_left_parsing_buf(); - /* ===== write log to 'xtrabackup_logfile' ====== */ - if (!*finished) { - write_size = RECV_SCAN_SIZE; - } else { - write_size = (ulint)(ut_uint64_align_up(scanned_lsn, - OS_FILE_LOG_BLOCK_SIZE) - start_lsn); - if (!is_last && scanned_lsn % OS_FILE_LOG_BLOCK_SIZE) { - write_size -= OS_FILE_LOG_BLOCK_SIZE; - } - } + log_sys->log.scanned_lsn = scanned_lsn; - if (write_size == 0) { - return(true); - } + end_lsn = last + ? ut_uint64_align_up(scanned_lsn, OS_FILE_LOG_BLOCK_SIZE) + : scanned_lsn & ~lsn_t(OS_FILE_LOG_BLOCK_SIZE - 1); - if (srv_encrypt_log) { - log_encrypt_before_write(scanned_checkpoint_no, - log_sys->buf, start_lsn, write_size); - } + if (ulint write_size = ulint(end_lsn - start_lsn)) { + if (srv_encrypt_log) { + log_crypt(log_sys->buf, start_lsn, write_size); + } - if (ds_write(dst_log_file, log_sys->buf, write_size)) { - msg("mariabackup: Error: " - "write to logfile failed\n"); - return(false); + if (ds_write(dst_log_file, log_sys->buf, write_size)) { + msg("Error: write to logfile failed\n"); + return(0); + } } - return(true); + return(scanned_lsn); } -static my_bool -xtrabackup_copy_logfile(lsn_t from_lsn, my_bool is_last) +/** Copy redo log until the current end of the log is reached +@param last whether we are copying the final part of the log +@return whether the operation failed */ +static bool xtrabackup_copy_logfile(bool last = false) { - /* definition from recv_recovery_from_checkpoint_start() */ - log_group_t* group; - lsn_t group_scanned_lsn; - lsn_t contiguous_lsn; - ut_a(dst_log_file != NULL); + ut_ad(recv_sys != NULL); - /* read from checkpoint_lsn_start to current */ - contiguous_lsn = ut_uint64_align_down(from_lsn, OS_FILE_LOG_BLOCK_SIZE); - - /* TODO: We must check the contiguous_lsn still exists in log file.. */ - - group = UT_LIST_GET_FIRST(log_sys->log_groups); - - while (group) { - bool finished; - lsn_t start_lsn; - lsn_t end_lsn; - - /* reference recv_group_scan_log_recs() */ - finished = false; - - start_lsn = contiguous_lsn; - - while (!finished) { - - end_lsn = start_lsn + RECV_SCAN_SIZE; - - xtrabackup_io_throttling(); - - mutex_enter(&log_sys->mutex); + lsn_t start_lsn; + lsn_t end_lsn; - bool scan_ok = false; - bool must_reread_log; - int retries = 0; - do { + recv_sys->parse_start_lsn = log_copy_scanned_lsn; + recv_sys->scanned_lsn = log_copy_scanned_lsn; - log_group_read_log_seg(LOG_RECOVER, log_sys->buf, - group, start_lsn, end_lsn, false); + start_lsn = ut_uint64_align_down(log_copy_scanned_lsn, + OS_FILE_LOG_BLOCK_SIZE); + do { + end_lsn = start_lsn + RECV_SCAN_SIZE; - scan_ok = xtrabackup_scan_log_recs(group, is_last, - start_lsn, &contiguous_lsn, &group_scanned_lsn, - &finished, &must_reread_log); + xtrabackup_io_throttling(); - } while (!scan_ok && must_reread_log && retries++ < 100); - - if (!scan_ok) { - goto error; + log_mutex_enter(); + lsn_t lsn= start_lsn; + for (int retries= 0; retries < 100; retries++) { + if (log_group_read_log_seg(log_sys->buf, &log_sys->log, + &lsn, end_lsn) + || lsn != start_lsn) { + break; } - - mutex_exit(&log_sys->mutex); - - start_lsn = end_lsn; - + msg("Retrying read of log at LSN=" LSN_PF, lsn); + my_sleep(1000); } - group->scanned_lsn = group_scanned_lsn; - - msg_ts(">> log scanned up to (" LSN_PF ")\n", - group->scanned_lsn); - - group = UT_LIST_GET_NEXT(log_groups, group); + if (lsn == start_lsn) { + start_lsn = 0; + } else { + mutex_enter(&recv_sys->mutex); + start_lsn = xtrabackup_copy_log(start_lsn, lsn, last); + mutex_exit(&recv_sys->mutex); + } - /* update global variable*/ - log_copy_scanned_lsn = group_scanned_lsn; + log_mutex_exit(); - /* innodb_mirrored_log_groups must be 1, no other groups */ - ut_a(group == NULL); + if (!start_lsn) { + msg(recv_sys->found_corrupt_log + ? "xtrabackup_copy_logfile() failed: corrupt log." + : "xtrabackup_copy_logfile() failed."); + return true; + } + } while (start_lsn == end_lsn); - debug_sync_point("xtrabackup_copy_logfile_pause"); + ut_ad(start_lsn == log_sys->log.scanned_lsn); - } + msg(">> log scanned up to (" LSN_PF ")", start_lsn); + /* update global variable*/ + pthread_mutex_lock(&backup_mutex); + log_copy_scanned_lsn = start_lsn; + pthread_cond_broadcast(&scanned_lsn_cond); + pthread_mutex_unlock(&backup_mutex); - return(FALSE); + debug_sync_point("xtrabackup_copy_logfile_pause"); + return(false); +} -error: - mutex_exit(&log_sys->mutex); - ds_close(dst_log_file); - msg("mariabackup: Error: xtrabackup_copy_logfile() failed.\n"); - return(TRUE); +/** +Wait until redo log copying thread processes given lsn +*/ +void backup_wait_for_lsn(lsn_t lsn) { + bool completed = false; + pthread_mutex_lock(&backup_mutex); + do { + pthread_cond_wait(&scanned_lsn_cond, &backup_mutex); + completed = log_copy_scanned_lsn >= lsn; + } while (!completed); + pthread_mutex_unlock(&backup_mutex); } -static -#ifndef __WIN__ -void* -#else -ulint -#endif -log_copying_thread( - void* arg __attribute__((unused))) +extern lsn_t server_lsn_after_lock; + +static os_thread_ret_t log_copying_thread(void*) { /* Initialize mysys thread-specific memory so we can @@ -2874,54 +2800,38 @@ log_copying_thread( */ my_thread_init(); - ut_a(dst_log_file != NULL); - - log_copying_running = TRUE; - - while(log_copying) { + for (;;) { os_event_reset(log_copying_stop); os_event_wait_time_low(log_copying_stop, xtrabackup_log_copy_interval * 1000ULL, 0); - if (log_copying) { - if(xtrabackup_copy_logfile(log_copy_scanned_lsn, - FALSE)) { - - exit(EXIT_FAILURE); - } + if (xtrabackup_copy_logfile()) { + break; } - } - - /* last copying */ - if(xtrabackup_copy_logfile(log_copy_scanned_lsn, TRUE)) { - exit(EXIT_FAILURE); + log_mutex_enter(); + bool completed = metadata_to_lsn + && metadata_to_lsn <= log_copy_scanned_lsn; + log_mutex_exit(); + if (completed) { + break; + } } - log_copying_running = FALSE; + log_copying_running = false; my_thread_end(); - os_thread_exit(NULL); + os_thread_exit(); return(0); } /* io throttle watching (rough) */ -static -#ifndef __WIN__ -void* -#else -ulint -#endif -io_watching_thread( - void* arg) +static os_thread_ret_t io_watching_thread(void*) { - (void)arg; /* currently, for --backup only */ ut_a(xtrabackup_backup); - io_watching_thread_running = TRUE; - - while (log_copying) { + while (log_copying_running && !metadata_to_lsn) { os_thread_sleep(1000000); /*1 sec*/ io_ticket = xtrabackup_throttle; os_event_set(wait_throttle); @@ -2931,48 +2841,49 @@ io_watching_thread( xtrabackup_throttle = 0; os_event_set(wait_throttle); - io_watching_thread_running = FALSE; + io_watching_thread_running = false; - os_thread_exit(NULL); + os_thread_exit(); return(0); } -/************************************************************************ -I/o-handler thread function. */ -static - -#ifndef __WIN__ -void* -#else -ulint -#endif -io_handler_thread( -/*==============*/ - void* arg) +#ifndef DBUG_OFF +/* +In debug mode, execute SQL statement that was passed via environment. +To use this facility, you need to + +1. Add code DBUG_EXECUTE_MARIABACKUP_EVENT("my_event_name", key);); + to the code. key is usually a table name +2. Set environment variable my_event_name_$key SQL statement you want to execute + when event occurs, in DBUG_EXECUTE_IF from above. + In mtr , you can set environment via 'let' statement (do not use $ as the first char + for the variable) +3. start mariabackup with --dbug=+d,debug_mariabackup_events +*/ +static void dbug_mariabackup_event(const char *event,const char *key) { - ulint segment; - - - segment = *((ulint*)arg); - - while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) { - fil_aio_wait(segment); + char envvar[FN_REFLEN]; + if (key) { + snprintf(envvar, sizeof(envvar), "%s_%s", event, key); + char *slash = strchr(envvar, '/'); + if (slash) + *slash = '_'; + } else { + strncpy(envvar, event, sizeof envvar - 1); + envvar[sizeof envvar - 1] = '\0'; + } + char *sql = getenv(envvar); + if (sql) { + msg("dbug_mariabackup_event : executing '%s'", sql); + xb_mysql_query(mysql_connection, sql, false, true); } - /* We count the number of threads in os_thread_exit(). A created - thread should always use that to exit and not use return() to exit. - The thread actually never comes here because it is exited in an - os_event_wait(). */ - - os_thread_exit(NULL); - -#ifndef __WIN__ - return(NULL); /* Not reached */ +} +#define DBUG_MARIABACKUP_EVENT(A, B) DBUG_EXECUTE_IF("mariabackup_events", dbug_mariabackup_event(A,B);); #else - return(0); +#define DBUG_MARIABACKUP_EVENT(A,B) #endif -} /************************************************************************** Datafiles copying thread.*/ @@ -2995,21 +2906,22 @@ data_copy_thread_func( debug_sync_point("data_copy_thread_func"); while ((node = datafiles_iter_next(ctxt->it)) != NULL) { - + DBUG_MARIABACKUP_EVENT("before_copy", node->space->name); /* copy the datafile */ if(xtrabackup_copy_datafile(node, num)) { - msg("[%02u] mariabackup: Error: " - "failed to copy datafile.\n", num); - exit(EXIT_FAILURE); + die("failed to copy datafile."); } + + DBUG_MARIABACKUP_EVENT("after_copy", node->space->name); + } - os_mutex_enter(ctxt->count_mutex); + pthread_mutex_lock(ctxt->count_mutex); (*ctxt->count)--; - os_mutex_exit(ctxt->count_mutex); + pthread_mutex_unlock(ctxt->count_mutex); my_thread_end(); - os_thread_exit(NULL); + os_thread_exit(); OS_THREAD_DUMMY_RETURN; } @@ -3019,7 +2931,7 @@ Initialize the appropriate datasink(s). Both local backups and streaming in the Otherwise (i.e. when streaming in the 'tar' format) we need 2 separate datasinks for the data stream (and don't allow parallel data copying) and for metainfo -files (including xtrabackup_logfile). The second datasink writes to temporary +files (including ib_logfile0). The second datasink writes to temporary files first, and then streams them in a serialized way when closed. */ static void xtrabackup_init_datasinks(void) @@ -3105,41 +3017,257 @@ static void xtrabackup_destroy_datasinks(void) ds_redo = NULL; } -#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 -/************************************************************************ -@return TRUE if table should be opened. */ +/** Initialize the tablespace cache subsystem. */ static -ibool -xb_check_if_open_tablespace( - const char* db, - const char* table) +void +xb_fil_io_init() { - char buf[FN_REFLEN]; - - snprintf(buf, sizeof(buf), "%s/%s", db, table); + fil_init(srv_file_per_table ? 50000 : 5000, LONG_MAX); + fsp_init(); +} - return !check_if_skip_table(buf); +static +Datafile* +xb_new_datafile(const char *name, bool is_remote) +{ + if (is_remote) { + RemoteDatafile *remote_file = new RemoteDatafile(); + remote_file->set_name(name); + return(remote_file); + } else { + Datafile *file = new Datafile(); + file->set_name(name); + file->make_filepath(".", name, IBD); + return(file); + } } -/************************************************************************ -Initializes the I/O and tablespace cache subsystems. */ + static void -xb_fil_io_init(void) -/*================*/ +xb_load_single_table_tablespace( + const char *dirname, + const char *filname, + bool is_remote) { - srv_n_file_io_threads = srv_n_read_io_threads; + ut_ad(srv_operation == SRV_OPERATION_BACKUP + || srv_operation == SRV_OPERATION_RESTORE_DELTA); + /* Ignore .isl files on XtraBackup recovery. All tablespaces must be + local. */ + if (is_remote && srv_operation == SRV_OPERATION_RESTORE_DELTA) { + return; + } + if (check_if_skip_table(filname)) { + return; + } - os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD, - srv_n_read_io_threads, - srv_n_write_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + /* The name ends in .ibd or .isl; + try opening the file */ + char* name; + size_t dirlen = dirname == NULL ? 0 : strlen(dirname); + size_t namelen = strlen(filname); + ulint pathlen = dirname == NULL ? namelen + 1: dirlen + namelen + 2; + lsn_t flush_lsn; + dberr_t err; + fil_space_t *space; - fil_init(srv_file_per_table ? 50000 : 5000, LONG_MAX); + name = static_cast<char*>(ut_malloc_nokey(pathlen)); - fsp_init(); + if (dirname != NULL) { + snprintf(name, pathlen, "%s/%s", dirname, filname); + name[pathlen - 5] = 0; + } else { + snprintf(name, pathlen, "%s", filname); + name[pathlen - 5] = 0; + } + + Datafile *file = xb_new_datafile(name, is_remote); + + if (file->open_read_only(true) != DB_SUCCESS) { + die("Can't open datafile %s", name); + } + + for (int i = 0; i < 10; i++) { + err = file->validate_first_page(&flush_lsn); + if (err != DB_CORRUPTION) { + break; + } + + my_sleep(1000); + } + + bool is_empty_file = file->exists() && file->is_empty_file(); + + if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) { + os_offset_t node_size = os_file_get_size(file->handle()); + os_offset_t n_pages; + + ut_a(node_size != (os_offset_t) -1); + + n_pages = node_size / page_size_t(file->flags()).physical(); + + space = fil_space_create( + name, file->space_id(), file->flags(), + FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */); + + ut_a(space != NULL); + + space->add(file->filepath(), OS_FILE_CLOSED, ulint(n_pages), + false, false); + /* by opening the tablespace we forcing node and space objects + in the cache to be populated with fields from space header */ + fil_space_open(space->name); + + if (srv_operation == SRV_OPERATION_RESTORE_DELTA + || xb_close_files) { + fil_space_close(space->name); + } + } + + ut_free(name); + + delete file; + + if (err != DB_SUCCESS && xtrabackup_backup && !is_empty_file) { + die("Failed to not validate first page of the file %s, error %d",name, (int)err); + } +} + +/** Scan the database directories under the MySQL datadir, looking for +.ibd files and determining the space id in each of them. +@return DB_SUCCESS or error number */ + +static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback) +{ + int ret; + char* dbpath = NULL; + ulint dbpath_len = 100; + os_file_dir_t dir; + os_file_dir_t dbdir; + os_file_stat_t dbinfo; + os_file_stat_t fileinfo; + dberr_t err = DB_SUCCESS; + size_t len; + + /* The datadir of MySQL is always the default directory of mysqld */ + + dir = os_file_opendir(fil_path_to_mysql_datadir, true); + + if (dir == NULL) { + + return(DB_ERROR); + } + + dbpath = static_cast<char*>(ut_malloc_nokey(dbpath_len)); + + /* Scan all directories under the datadir. They are the database + directories of MySQL. */ + + ret = fil_file_readdir_next_file(&err, fil_path_to_mysql_datadir, dir, + &dbinfo); + while (ret == 0) { + + /* General tablespaces are always at the first level of the + data home dir */ + if (dbinfo.type == OS_FILE_TYPE_FILE) { + bool is_isl = ends_with(dbinfo.name, ".isl"); + bool is_ibd = !is_isl && ends_with(dbinfo.name,".ibd"); + + if (is_isl || is_ibd) { + (*callback)(NULL, dbinfo.name, is_isl); + } + } + + if (dbinfo.type == OS_FILE_TYPE_FILE + || dbinfo.type == OS_FILE_TYPE_UNKNOWN) { + + goto next_datadir_item; + } + + /* We found a symlink or a directory; try opening it to see + if a symlink is a directory */ + + len = strlen(fil_path_to_mysql_datadir) + + strlen (dbinfo.name) + 2; + if (len > dbpath_len) { + dbpath_len = len; + + if (dbpath) { + ut_free(dbpath); + } + + dbpath = static_cast<char*>(ut_malloc_nokey(dbpath_len)); + } + snprintf(dbpath, dbpath_len, + "%s/%s", fil_path_to_mysql_datadir, dbinfo.name); + os_normalize_path(dbpath); + + if (check_if_skip_database_by_path(dbpath)) { + fprintf(stderr, "Skipping db: %s\n", dbpath); + goto next_datadir_item; + } + + /* We want wrong directory permissions to be a fatal error for + XtraBackup. */ + dbdir = os_file_opendir(dbpath, true); + + if (dbdir != NULL) { + + /* We found a database directory; loop through it, + looking for possible .ibd files in it */ + + for (ret = fil_file_readdir_next_file(&err, dbpath, + dbdir, + &fileinfo); + ret == 0; + ret = fil_file_readdir_next_file(&err, dbpath, + dbdir, + &fileinfo)) { + if (fileinfo.type == OS_FILE_TYPE_DIR) { + continue; + } + + /* We found a symlink or a file */ + if (strlen(fileinfo.name) > 4) { + bool is_isl= false; + if (ends_with(fileinfo.name, ".ibd") || ((is_isl = ends_with(fileinfo.name, ".isl")))) + (*callback)(dbinfo.name, fileinfo.name, is_isl); + } + } + + if (0 != os_file_closedir(dbdir)) { + fprintf(stderr, "InnoDB: Warning: could not" + " close database directory %s\n", + dbpath); + + err = DB_ERROR; + } + + } else { + + err = DB_ERROR; + break; + + } + +next_datadir_item: + ret = fil_file_readdir_next_file(&err, + fil_path_to_mysql_datadir, + dir, &dbinfo); + } + + ut_free(dbpath); + + if (0 != os_file_closedir(dir)) { + fprintf(stderr, + "InnoDB: Error: could not close MySQL datadir\n"); + + return(DB_ERROR); + } + + return(err); } /** Assign srv_undo_space_id_start variable if there are undo tablespace present. @@ -3149,63 +3277,57 @@ the first slot rollback segments of TRX_SYS_PAGE_NO. @retval DB_SUCCESS if srv_undo_space_id assigned successfully. */ static dberr_t xb_assign_undo_space_start() { - ulint dirnamelen; - char name[1000]; + pfs_os_file_t file; byte* buf; byte* page; - ibool ret; + bool ret; dberr_t error = DB_SUCCESS; - ulint space, page_no; + ulint space; + int n_retries = 5; if (srv_undo_tablespaces == 0) { return error; } - srv_normalize_path_for_win(srv_data_home); - dirnamelen = strlen(srv_data_home); - memcpy(name, srv_data_home, dirnamelen); - - if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { - name[dirnamelen++] = SRV_PATH_SEPARATOR; - } - - ut_snprintf(name + dirnamelen, (sizeof name) - dirnamelen, - "%s", "ibdata1"); - - file = os_file_create(innodb_file_data_key, name, OS_FILE_OPEN, - OS_FILE_NORMAL, OS_DATA_FILE, &ret, 0); + file = os_file_create(0, srv_sys_space.first_datafile()->filepath(), + OS_FILE_OPEN, OS_FILE_NORMAL, OS_DATA_FILE, true, &ret); - if (ret == FALSE) { - fprintf(stderr, "InnoDB: Error in opening %s\n", name); + if (!ret) { + msg("Error opening %s", srv_sys_space.first_datafile()->filepath()); return DB_ERROR; } - buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE)); + buf = static_cast<byte*>(ut_malloc_nokey(2 * UNIV_PAGE_SIZE)); page = static_cast<byte*>(ut_align(buf, UNIV_PAGE_SIZE)); retry: - ret = os_file_read(file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, - UNIV_PAGE_SIZE); - - if (!ret) { - fprintf(stderr, "InnoDB: Reading TRX_SYS page failed."); + if (os_file_read(IORequestRead, file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, + UNIV_PAGE_SIZE) != DB_SUCCESS) { + msg("Reading TRX_SYS page failed."); error = DB_ERROR; goto func_exit; } /* TRX_SYS page can't be compressed or encrypted. */ - if (buf_page_is_corrupted(false, page, 0, NULL)) { - goto retry; + if (buf_page_is_corrupted(false, page, univ_page_size)) { + if (n_retries--) { + os_thread_sleep(1000); + goto retry; + } else { + msg("mariabackup: TRX_SYS page corrupted.\n"); + error = DB_ERROR; + goto func_exit; + } } /* 0th slot always points to system tablespace. 1st slot should point to first undotablespace which is minimum. */ - page_no = mach_read_ulint(TRX_SYS + TRX_SYS_RSEGS - + TRX_SYS_RSEG_SLOT_SIZE - + TRX_SYS_RSEG_PAGE_NO + page, MLOG_4BYTES); - ut_ad(page_no != FIL_NULL); + ut_ad(mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS + + TRX_SYS_RSEG_SLOT_SIZE + + TRX_SYS_RSEG_PAGE_NO + page) + != FIL_NULL); space = mach_read_ulint(TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_SLOT_SIZE @@ -3225,51 +3347,38 @@ func_exit: Populates the tablespace memory cache by scanning for and opening data files. @returns DB_SUCCESS or error code.*/ static -ulint -xb_load_tablespaces(void) -/*=====================*/ +dberr_t +xb_load_tablespaces() { - ulint i; bool create_new_db; - ulint err; + dberr_t err; ulint sum_of_new_sizes; - lsn_t min_arch_logno, max_arch_logno; + lsn_t flush_lsn; - for (i = 0; i < srv_n_file_io_threads; i++) { - thread_nr[i] = i; + ut_ad(srv_operation == SRV_OPERATION_BACKUP + || srv_operation == SRV_OPERATION_RESTORE_DELTA); - os_thread_create(io_handler_thread, thread_nr + i, - thread_ids + i); - } + err = srv_sys_space.check_file_spec(&create_new_db, 0); - os_thread_sleep(200000); /*0.2 sec*/ + /* create_new_db must not be true. */ + if (err != DB_SUCCESS || create_new_db) { + msg("Could not find data files at the specified datadir"); + return(DB_ERROR); + } - err = open_or_create_data_files(&create_new_db, - &min_arch_logno, &max_arch_logno, - &flushed_lsn, - &sum_of_new_sizes); - if (err != DB_SUCCESS) { - msg("mariabackup: Could not open or create data files.\n" - "mariabackup: If you tried to add new data files, and it " - "failed here,\n" - "mariabackup: you should now edit innodb_data_file_path in " - "my.cnf back\n" - "mariabackup: to what it was, and remove the new ibdata " - "files InnoDB created\n" - "mariabackup: in this failed attempt. InnoDB only wrote " - "those files full of\n" - "mariabackup: zeros, but did not yet use them in any way. " - "But be careful: do not\n" - "mariabackup: remove old data files which contain your " - "precious data!\n"); - return(err); + for (int i= 0; i < 10; i++) { + err = srv_sys_space.open_or_create(false, false, &sum_of_new_sizes, + &flush_lsn); + if (err == DB_PAGE_CORRUPTED || err == DB_CORRUPTION) { + my_sleep(1000); + } + else + break; } - /* create_new_db must not be TRUE.. */ - if (create_new_db) { - msg("mariabackup: could not find data files at the " - "specified datadir\n"); - return(DB_ERROR); + if (err != DB_SUCCESS) { + msg("Could not open data files.\n"); + return(err); } /* Add separate undo tablespaces to fil_system */ @@ -3280,27 +3389,25 @@ xb_load_tablespaces(void) return err; } - err = srv_undo_tablespaces_init(FALSE, - TRUE, - srv_undo_tablespaces, - &srv_undo_tablespaces_open); + err = srv_undo_tablespaces_init(false); + if (err != DB_SUCCESS) { return(err); } - /* It is important to call fil_load_single_table_tablespace() after + /* It is important to call xb_load_single_table_tablespaces() after srv_undo_tablespaces_init(), because fil_is_user_tablespace_id() * relies on srv_undo_tablespaces_open to be properly initialized */ - msg("mariabackup: Generating a list of tablespaces\n"); + msg("mariabackup: Generating a list of tablespaces"); - err = fil_load_single_table_tablespaces(xb_check_if_open_tablespace); + err = enumerate_ibd_files(xb_load_single_table_tablespace); if (err != DB_SUCCESS) { return(err); } debug_sync_point("xtrabackup_load_tablespaces_pause"); - + DBUG_MARIABACKUP_EVENT("after_load_tablespaces", 0); return(DB_SUCCESS); } @@ -3308,9 +3415,9 @@ xb_load_tablespaces(void) Initialize the tablespace memory cache and populate it by scanning for and opening data files. @returns DB_SUCCESS or error code.*/ -ulint -xb_data_files_init(void) -/*====================*/ +static +dberr_t +xb_data_files_init() { xb_fil_io_init(); @@ -3319,46 +3426,15 @@ xb_data_files_init(void) /************************************************************************ Destroy the tablespace memory cache. */ +static void -xb_data_files_close(void) -/*====================*/ +xb_data_files_close() { - ulint i; - - /* Shutdown the aio threads. This has been copied from - innobase_shutdown_for_mysql(). */ - - srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; - - for (i = 0; i < 1000; i++) { - os_aio_wake_all_threads_at_shutdown(); - - if (os_thread_count == 0) { - break; - } - os_thread_sleep(10000); - } - - if (i == 1000) { - msg("mariabackup: Warning: %lu threads created by InnoDB" - " had not exited at shutdown!\n", - (ulong) os_thread_count); - } - - os_aio_free(); - + ut_ad(!os_thread_count); fil_close_all_files(); - - /* Free the double write data structures. */ if (buf_dblwr) { buf_dblwr_free(); } - - /* Reset srv_file_io_threads to its default value to avoid confusing - warning on --prepare in innobase_start_or_create_for_mysql()*/ - srv_n_file_io_threads = 4; - - srv_shutdown_state = SRV_SHUTDOWN_NONE; } /*********************************************************************** @@ -3377,7 +3453,7 @@ xb_new_filter_entry( ut_a(namelen <= NAME_LEN * 2 + 1); entry = static_cast<xb_filter_entry_t *> - (ut_malloc(sizeof(xb_filter_entry_t) + namelen + 1)); + (malloc(sizeof(xb_filter_entry_t) + namelen + 1)); memset(entry, '\0', sizeof(xb_filter_entry_t) + namelen + 1); entry->name = ((char*)entry) + sizeof(xb_filter_entry_t); strcpy(entry->name, name); @@ -3426,13 +3502,11 @@ xb_validate_name( /* perform only basic validation. validate length and path symbols */ if (len > NAME_LEN) { - msg("mariabackup: name `%s` is too long.\n", name); - exit(EXIT_FAILURE); + die("name `%s` is too long.", name); } p = strpbrk(name, "/\\~"); - if (p && p - name < NAME_LEN) { - msg("mariabackup: name `%s` is not valid.\n", name); - exit(EXIT_FAILURE); + if (p && (uint) (p - name) < NAME_LEN) { + die("name `%s` is not valid.", name); } } @@ -3510,8 +3584,7 @@ xb_register_table( const char* name) /*!< in: name of table */ { if (strchr(name, '.') == NULL) { - msg("mariabackup: `%s` is not fully qualified name.\n", name); - exit(EXIT_FAILURE); + die("`%s` is not fully qualified name.", name); } xb_register_include_filter_entry(name); @@ -3532,7 +3605,7 @@ xb_add_regex_to_list( if (ret != 0) { regerror(ret, &compiled_regex, errbuf, sizeof(errbuf)); - msg("mariabackup: error: %s regcomp(%s): %s\n", + msg("mariabackup: error: %s regcomp(%s): %s", error_context, regex, errbuf); exit(EXIT_FAILURE); } @@ -3601,17 +3674,15 @@ xb_load_list_file( /* read and store the filenames */ fp = fopen(filename, "r"); if (!fp) { - msg("mariabackup: cannot open %s\n", + die("Can't open %s", filename); - exit(EXIT_FAILURE); } while (fgets(name_buf, sizeof(name_buf), fp) != NULL) { char* p = strchr(name_buf, '\n'); if (p) { *p = '\0'; } else { - msg("mariabackup: `%s...` name is too long", name_buf); - exit(EXIT_FAILURE); + die("`%s...` name is too long", name_buf); } ins(name_buf); @@ -3676,7 +3747,7 @@ xb_filter_hash_free(hash_table_t* hash) HASH_DELETE(xb_filter_entry_t, name_hash, hash, ut_fold_string(prev_table->name), prev_table); - ut_free(prev_table); + free(prev_table); } } @@ -3719,94 +3790,35 @@ xb_filters_free() } /*********************************************************************//** -Creates or opens the log files and closes them. -@return DB_SUCCESS or error code */ +Create log file metadata. */ static -ulint +void open_or_create_log_file( /*====================*/ - ibool create_new_db, /*!< in: TRUE if we should create a - new database */ - ibool* log_file_created, /*!< out: TRUE if new log file - created */ - ibool log_file_has_been_opened,/*!< in: TRUE if a log file has been - opened before: then it is an error - to try to create another log file */ - ulint k, /*!< in: log group number */ + fil_space_t* space, ulint i) /*!< in: log file number in group */ { - ibool ret; - os_offset_t size; - char name[10000]; + char name[FN_REFLEN]; ulint dirnamelen; - UT_NOT_USED(create_new_db); - UT_NOT_USED(log_file_has_been_opened); - UT_NOT_USED(k); - ut_ad(k == 0); - - *log_file_created = FALSE; - - srv_normalize_path_for_win(srv_log_group_home_dir); + os_normalize_path(srv_log_group_home_dir); dirnamelen = strlen(srv_log_group_home_dir); ut_a(dirnamelen < (sizeof name) - 10 - sizeof "ib_logfile"); memcpy(name, srv_log_group_home_dir, dirnamelen); /* Add a path separator if needed. */ - if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { - name[dirnamelen++] = SRV_PATH_SEPARATOR; - } - - sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i); - - files[i] = os_file_create(innodb_file_log_key, name, - OS_FILE_OPEN, OS_FILE_NORMAL, - OS_LOG_FILE, &ret,0); - if (ret == FALSE) { - fprintf(stderr, "InnoDB: Error in opening %s\n", name); - - return(DB_ERROR); - } - - size = os_file_get_size(files[i]); - - if (size != srv_log_file_size * UNIV_PAGE_SIZE) { - - fprintf(stderr, - "InnoDB: Error: log file %s is" - " of different size " UINT64PF " bytes\n" - "InnoDB: than specified in the .cnf" - " file " UINT64PF " bytes!\n", - name, size, srv_log_file_size * UNIV_PAGE_SIZE); - - return(DB_ERROR); + if (dirnamelen && name[dirnamelen - 1] != OS_PATH_SEPARATOR) { + name[dirnamelen++] = OS_PATH_SEPARATOR; } - ret = os_file_close(files[i]); - ut_a(ret); - - if (i == 0) { - /* Create in memory the file space object - which is for this log group */ - - fil_space_create(name, - 2 * k + SRV_LOG_SPACE_FIRST_ID, 0, FIL_LOG, 0, 0); - } + sprintf(name + dirnamelen, "%s%zu", "ib_logfile", i); ut_a(fil_validate()); - ut_a(fil_node_create(name, (ulint)srv_log_file_size, - 2 * k + SRV_LOG_SPACE_FIRST_ID, FALSE)); - if (i == 0) { - log_group_init(k, srv_n_log_files, - srv_log_file_size * UNIV_PAGE_SIZE, - 2 * k + SRV_LOG_SPACE_FIRST_ID, - SRV_LOG_SPACE_FIRST_ID + 1); /* dummy arch - space id */ - } - - return(DB_SUCCESS); + space->add(name, OS_FILE_CLOSED, + ulint(srv_log_file_size >> srv_page_size_shift), + false, false); } /*********************************************************************//** @@ -3817,20 +3829,8 @@ void xb_normalize_init_values(void) /*==========================*/ { - ulint i; - - for (i = 0; i < srv_n_data_files; i++) { - srv_data_file_sizes[i] = srv_data_file_sizes[i] - * ((1024 * 1024) / UNIV_PAGE_SIZE); - } - - srv_last_file_size_max = srv_last_file_size_max - * ((1024 * 1024) / UNIV_PAGE_SIZE); - - srv_log_file_size = srv_log_file_size / UNIV_PAGE_SIZE; - - srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE; - + srv_sys_space.normalize(); + srv_log_buffer_size /= UNIV_PAGE_SIZE; srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE); } @@ -3891,30 +3891,135 @@ end: #endif } -void -xtrabackup_backup_func(void) +static void stop_backup_threads() +{ + if (log_copying_stop && log_copying_running) { + os_event_set(log_copying_stop); + fputs("mariabackup: Stopping log copying thread", stderr); + fflush(stderr); + while (log_copying_running) { + putc('.', stderr); + fflush(stderr); + os_thread_sleep(200000); /*0.2 sec*/ + } + putc('\n', stderr); + os_event_destroy(log_copying_stop); + } + + if (wait_throttle) { + /* wait for io_watching_thread completion */ + while (io_watching_thread_running) { + os_thread_sleep(1000000); + } + os_event_destroy(wait_throttle); + } +} + +/** Implement the core of --backup +@return whether the operation succeeded */ +static bool xtrabackup_backup_low() +{ + ut_ad(!metadata_to_lsn); + + /* read the latest checkpoint lsn */ + { + ulint max_cp_field; + + log_mutex_enter(); + + if (recv_find_max_checkpoint(&max_cp_field) == DB_SUCCESS + && log_sys->log.format != 0) { + if (max_cp_field == LOG_CHECKPOINT_1) { + log_group_header_read(&log_sys->log, + max_cp_field); + } + metadata_to_lsn = mach_read_from_8( + log_sys->checkpoint_buf + LOG_CHECKPOINT_LSN); + msg("The latest check point" + " (for incremental): '" LSN_PF "'", + metadata_to_lsn); + } else { + msg("Error: recv_find_max_checkpoint() failed."); + } + log_mutex_exit(); + } + + stop_backup_threads(); + + if (metadata_to_lsn && xtrabackup_copy_logfile(true)) { + ds_close(dst_log_file); + dst_log_file = NULL; + return false; + } + + if (ds_close(dst_log_file) || !metadata_to_lsn) { + dst_log_file = NULL; + return false; + } + + dst_log_file = NULL; + + if(!xtrabackup_incremental) { + strcpy(metadata_type, "full-backuped"); + metadata_from_lsn = 0; + } else { + strcpy(metadata_type, "incremental"); + metadata_from_lsn = incremental_lsn; + } + metadata_last_lsn = log_copy_scanned_lsn; + + if (!xtrabackup_stream_metadata(ds_meta)) { + msg("Error: failed to stream metadata."); + return false; + } + if (xtrabackup_extra_lsndir) { + char filename[FN_REFLEN]; + + sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, + XTRABACKUP_METADATA_FILENAME); + if (!xtrabackup_write_metadata(filename)) { + msg("Error: failed to write metadata " + "to '%s'.", filename); + return false; + } + sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, + XTRABACKUP_INFO); + if (!write_xtrabackup_info(mysql_connection, filename, false)) { + msg("Error: failed to write info " + "to '%s'.", filename); + return false; + } + } + + return true; +} + +/** Implement --backup +@return whether the operation succeeded */ +static bool xtrabackup_backup_func() { MY_STAT stat_info; - lsn_t latest_cp; uint i; uint count; - os_ib_mutex_t count_mutex; + pthread_mutex_t count_mutex; data_thread_ctxt_t *data_threads; + pthread_mutex_init(&backup_mutex, NULL); + pthread_cond_init(&scanned_lsn_cond, NULL); #ifdef USE_POSIX_FADVISE - msg("mariabackup: uses posix_fadvise().\n"); + msg("uses posix_fadvise()."); #endif /* cd to datadir */ if (my_setwd(mysql_real_data_home,MYF(MY_WME))) { - msg("mariabackup: cannot my_setwd %s\n", mysql_real_data_home); - exit(EXIT_FAILURE); + msg("my_setwd() failed , %s", mysql_real_data_home); + return(false); } - msg("mariabackup: cd to %s\n", mysql_real_data_home); - - msg("mariabackup: open files limit requested %u, set to %u\n", + msg("cd to %s", mysql_real_data_home); + encryption_plugin_backup_init(mysql_connection); + msg("open files limit requested %u, set to %u", (uint) xb_open_files_limit, xb_set_max_open_files(xb_open_files_limit)); @@ -3925,54 +4030,59 @@ xtrabackup_backup_func(void) srv_n_purge_threads = 1; srv_read_only_mode = TRUE; - srv_backup_mode = TRUE; - srv_close_files = (bool)xb_close_files; - - if (srv_close_files) - msg("mariabackup: warning: close-files specified. Use it " - "at your own risk. If there are DDL operations like table DROP TABLE " - "or RENAME TABLE during the backup, inconsistent backup will be " - "produced.\n"); + srv_operation = SRV_OPERATION_BACKUP; + log_file_op = backup_file_op; + metadata_to_lsn = 0; /* initialize components */ - if(innodb_init_param()) - exit(EXIT_FAILURE); + if(innodb_init_param()) { +fail: + metadata_to_lsn = log_copying_running; + stop_backup_threads(); + log_file_op = NULL; + if (dst_log_file) { + ds_close(dst_log_file); + dst_log_file = NULL; + } + if (fil_system) { + innodb_shutdown(); + } + return(false); + } xb_normalize_init_values(); - if (srv_file_flush_method_str == NULL) { - /* These are the default options */ - srv_unix_file_flush_method = SRV_UNIX_FSYNC; + /* These are the default options */ + srv_file_flush_method = SRV_FSYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, "fsync")) { - srv_unix_file_flush_method = SRV_UNIX_FSYNC; + srv_file_flush_method = SRV_FSYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DSYNC")) { - srv_unix_file_flush_method = SRV_UNIX_O_DSYNC; + srv_file_flush_method = SRV_O_DSYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DIRECT")) { - srv_unix_file_flush_method = SRV_UNIX_O_DIRECT; - msg("mariabackup: using O_DIRECT\n"); + srv_file_flush_method = SRV_O_DIRECT; + msg("using O_DIRECT"); } else if (0 == ut_strcmp(srv_file_flush_method_str, "littlesync")) { - srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC; - + srv_file_flush_method = SRV_LITTLESYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, "nosync")) { - srv_unix_file_flush_method = SRV_UNIX_NOSYNC; + srv_file_flush_method = SRV_NOSYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, "ALL_O_DIRECT")) { - srv_unix_file_flush_method = SRV_UNIX_ALL_O_DIRECT; - msg("mariabackup: using ALL_O_DIRECT\n"); + srv_file_flush_method = SRV_ALL_O_DIRECT_FSYNC; + msg("using ALL_O_DIRECT"); } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DIRECT_NO_FSYNC")) { - srv_unix_file_flush_method = SRV_UNIX_O_DIRECT_NO_FSYNC; - msg("mariabackup: using O_DIRECT_NO_FSYNC\n"); + srv_file_flush_method = SRV_O_DIRECT_NO_FSYNC; + msg("using O_DIRECT_NO_FSYNC"); } else { - msg("mariabackup: Unrecognized value %s for " - "innodb_flush_method\n", srv_file_flush_method_str); - exit(EXIT_FAILURE); + msg("Unrecognized value %s for " + "innodb_flush_method", srv_file_flush_method_str); + goto fail; } #ifdef _WIN32 - srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; - srv_use_native_aio = FALSE; + srv_file_flush_method = SRV_ALL_O_DIRECT_FSYNC; + srv_use_native_aio = TRUE; #endif if (srv_buf_pool_size >= 1000 * 1024 * 1024) { @@ -3992,263 +4102,225 @@ xtrabackup_backup_func(void) computers */ } - srv_general_init(); + sync_check_init(); + ut_d(sync_check_enable()); + /* Reset the system variables in the recovery module. */ + recv_sys_var_init(); + trx_pool_init(); + ut_crc32_init(); crc_init(); + recv_sys_init(); #ifdef WITH_INNODB_DISALLOW_WRITES - srv_allow_writes_event = os_event_create(); + srv_allow_writes_event = os_event_create(0); os_event_set(srv_allow_writes_event); #endif xb_filters_init(); - { - ibool log_file_created; - ibool log_created = FALSE; - ibool log_opened = FALSE; - ulint err; - ulint i; - xb_fil_io_init(); + srv_n_file_io_threads = srv_n_read_io_threads; - log_init(); - - lock_sys_create(srv_lock_table_size); - - for (i = 0; i < srv_n_log_files; i++) { - err = open_or_create_log_file(FALSE, &log_file_created, - log_opened, 0, i); - if (err != DB_SUCCESS) { - - //return((int) err); - exit(EXIT_FAILURE); - } + os_aio_init(srv_n_read_io_threads, srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS); - if (log_file_created) { - log_created = TRUE; - } else { - log_opened = TRUE; - } - if ((log_opened && log_created)) { - msg( - "mariabackup: Error: all log files must be created at the same time.\n" - "mariabackup: All log files must be created also in database creation.\n" - "mariabackup: If you want bigger or smaller log files, shut down the\n" - "mariabackup: database and make sure there were no errors in shutdown.\n" - "mariabackup: Then delete the existing log files. Edit the .cnf file\n" - "mariabackup: and start the database again.\n"); - - //return(DB_ERROR); - exit(EXIT_FAILURE); - } - } + log_sys_init(); + log_init(srv_n_log_files); + fil_space_t* space = fil_space_create( + "innodb_redo_log", SRV_LOG_SPACE_FIRST_ID, 0, + FIL_TYPE_LOG, NULL); - /* log_file_created must not be TRUE, if online */ - if (log_file_created) { - msg("mariabackup: Something wrong with source files...\n"); - exit(EXIT_FAILURE); - } + lock_sys_create(srv_lock_table_size); + for (ulint i = 0; i < srv_n_log_files; i++) { + open_or_create_log_file(space, i); } /* create extra LSN dir if it does not exist. */ if (xtrabackup_extra_lsndir &&!my_stat(xtrabackup_extra_lsndir,&stat_info,MYF(0)) && (my_mkdir(xtrabackup_extra_lsndir,0777,MYF(0)) < 0)) { - msg("mariabackup: Error: cannot mkdir %d: %s\n", + msg("Error: cannot mkdir %d: %s\n", my_errno, xtrabackup_extra_lsndir); - exit(EXIT_FAILURE); + goto fail; } /* create target dir if not exist */ if (!xtrabackup_stream_str && !my_stat(xtrabackup_target_dir,&stat_info,MYF(0)) && (my_mkdir(xtrabackup_target_dir,0777,MYF(0)) < 0)){ - msg("mariabackup: Error: cannot mkdir %d: %s\n", + msg("Error: cannot mkdir %d: %s\n", my_errno, xtrabackup_target_dir); - exit(EXIT_FAILURE); + goto fail; } { - fil_system_t* f_system = fil_system; - /* definition from recv_recovery_from_checkpoint_start() */ - log_group_t* max_cp_group; ulint max_cp_field; - byte* buf; - byte* log_hdr_buf_; - byte* log_hdr_buf; - ulint err; /* start back ground thread to copy newer log */ os_thread_id_t log_copying_thread_id; - datafiles_iter_t *it; - - log_hdr_buf_ = static_cast<byte *> - (ut_malloc(LOG_FILE_HDR_SIZE + UNIV_PAGE_SIZE_MAX)); - log_hdr_buf = static_cast<byte *> - (ut_align(log_hdr_buf_, UNIV_PAGE_SIZE_MAX)); /* get current checkpoint_lsn */ /* Look for the latest checkpoint from any of the log groups */ - mutex_enter(&log_sys->mutex); + log_mutex_enter(); - err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); +reread_log_header: + dberr_t err = recv_find_max_checkpoint(&max_cp_field); if (err != DB_SUCCESS) { - - ut_free(log_hdr_buf_); - exit(EXIT_FAILURE); + msg("Error: cannot read redo log header"); + log_mutex_exit(); + goto fail; } - log_group_read_checkpoint_info(max_cp_group, max_cp_field); - buf = log_sys->checkpoint_buf; - - checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); - checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO); - - mutex_exit(&log_sys->mutex); - -reread_log_header: - fil_io(OS_FILE_READ | OS_FILE_LOG, true, max_cp_group->space_id, - 0, - 0, 0, LOG_FILE_HDR_SIZE, - log_hdr_buf, max_cp_group, NULL); - - /* check consistency of log file header to copy */ - mutex_enter(&log_sys->mutex); - - err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); - - if (err != DB_SUCCESS) { - - ut_free(log_hdr_buf_); - exit(EXIT_FAILURE); - } + if (log_sys->log.format == 0) { + msg("Error: cannot process redo log before MariaDB 10.2.2"); + log_mutex_exit(); + goto fail; + } - log_group_read_checkpoint_info(max_cp_group, max_cp_field); - buf = log_sys->checkpoint_buf; + const byte* buf = log_sys->checkpoint_buf; + checkpoint_lsn_start = log_sys->log.lsn; + checkpoint_no_start = log_sys->next_checkpoint_no; - if(checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO)) { + log_group_header_read(&log_sys->log, max_cp_field); - checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); - checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO); - mutex_exit(&log_sys->mutex); + if (checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO) + || checkpoint_lsn_start != mach_read_from_8(buf + LOG_CHECKPOINT_LSN) + || log_sys->log.lsn_offset + != mach_read_from_8(buf + LOG_CHECKPOINT_OFFSET)) goto reread_log_header; - } - mutex_exit(&log_sys->mutex); + log_mutex_exit(); xtrabackup_init_datasinks(); if (!select_history()) { - exit(EXIT_FAILURE); + goto fail; } /* open the log file */ memset(&stat_info, 0, sizeof(MY_STAT)); - dst_log_file = ds_open(ds_redo, XB_LOG_FILENAME, &stat_info); + dst_log_file = ds_open(ds_redo, "ib_logfile0", &stat_info); if (dst_log_file == NULL) { - msg("mariabackup: error: failed to open the target stream for " - "'%s'.\n", XB_LOG_FILENAME); - ut_free(log_hdr_buf_); - exit(EXIT_FAILURE); + msg("Error: failed to open the target stream for " + "'ib_logfile0'."); + goto fail; } /* label it */ - strcpy((char*) log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - "xtrabkup "); - ut_sprintf_timestamp( - (char*) log_hdr_buf + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP - + (sizeof "xtrabkup ") - 1)); - - if (ds_write(dst_log_file, log_hdr_buf, LOG_FILE_HDR_SIZE)) { - msg("mariabackup: error: write to logfile failed\n"); - ut_free(log_hdr_buf_); - exit(EXIT_FAILURE); - } - - ut_free(log_hdr_buf_); - - /* start flag */ - log_copying = TRUE; - + byte MY_ALIGNED(OS_FILE_LOG_BLOCK_SIZE) log_hdr_buf[LOG_FILE_HDR_SIZE]; + memset(log_hdr_buf, 0, sizeof log_hdr_buf); + + byte *log_hdr_field = log_hdr_buf; + mach_write_to_4(LOG_HEADER_FORMAT + log_hdr_field, log_sys->log.format); + mach_write_to_4(LOG_HEADER_SUBFORMAT + log_hdr_field, log_sys->log.subformat); + mach_write_to_8(LOG_HEADER_START_LSN + log_hdr_field, checkpoint_lsn_start); + strcpy(reinterpret_cast<char*>(LOG_HEADER_CREATOR + log_hdr_field), + "Backup " MYSQL_SERVER_VERSION); + log_block_set_checksum(log_hdr_field, + log_block_calc_checksum_crc32(log_hdr_field)); + + /* copied from log_group_checkpoint() */ + log_hdr_field += + (log_sys->next_checkpoint_no & 1) ? LOG_CHECKPOINT_2 : LOG_CHECKPOINT_1; + /* The least significant bits of LOG_CHECKPOINT_OFFSET must be + stored correctly in the copy of the ib_logfile. The most significant + bits, which identify the start offset of the log block in the file, + we did choose freely, as LOG_FILE_HDR_SIZE. */ + ut_ad(!((log_sys->log.lsn ^ checkpoint_lsn_start) + & (OS_FILE_LOG_BLOCK_SIZE - 1))); + /* Adjust the checkpoint page. */ + memcpy(log_hdr_field, log_sys->checkpoint_buf, OS_FILE_LOG_BLOCK_SIZE); + mach_write_to_8(log_hdr_field + LOG_CHECKPOINT_OFFSET, + (checkpoint_lsn_start & (OS_FILE_LOG_BLOCK_SIZE - 1)) + | LOG_FILE_HDR_SIZE); + log_block_set_checksum(log_hdr_field, + log_block_calc_checksum_crc32(log_hdr_field)); + + /* Write log header*/ + if (ds_write(dst_log_file, log_hdr_buf, sizeof(log_hdr_buf))) { + msg("error: write to logfile failed"); + goto fail; + } + + log_copying_running = true; /* start io throttle */ if(xtrabackup_throttle) { os_thread_id_t io_watching_thread_id; io_ticket = xtrabackup_throttle; - wait_throttle = os_event_create(); + wait_throttle = os_event_create(0); + io_watching_thread_running = true; os_thread_create(io_watching_thread, NULL, &io_watching_thread_id); } - mutex_enter(&log_sys->mutex); - xtrabackup_choose_lsn_offset(checkpoint_lsn_start); - mutex_exit(&log_sys->mutex); + /* Populate fil_system with tablespaces to copy */ + err = xb_load_tablespaces(); + if (err != DB_SUCCESS) { + msg("merror: xb_load_tablespaces() failed with" + " error %s.", ut_strerr(err)); +fail_before_log_copying_thread_start: + log_copying_running = false; + goto fail; + } /* copy log file by current position */ - if(xtrabackup_copy_logfile(checkpoint_lsn_start, FALSE)) - exit(EXIT_FAILURE); + log_copy_scanned_lsn = checkpoint_lsn_start; + recv_sys->recovered_lsn = log_copy_scanned_lsn; + log_optimized_ddl_op = backup_optimized_ddl_op; + log_truncate = backup_truncate_fail; + if (xtrabackup_copy_logfile()) + goto fail_before_log_copying_thread_start; - log_copying_stop = os_event_create(); + log_copying_stop = os_event_create(0); os_thread_create(log_copying_thread, NULL, &log_copying_thread_id); - /* Populate fil_system with tablespaces to copy */ - err = xb_load_tablespaces(); - if (err != DB_SUCCESS) { - msg("mariabackup: error: xb_load_tablespaces() failed with" - "error code %lu\n", err); - exit(EXIT_FAILURE); - } - /* FLUSH CHANGED_PAGE_BITMAPS call */ if (!flush_changed_page_bitmaps()) { - exit(EXIT_FAILURE); + goto fail; } debug_sync_point("xtrabackup_suspend_at_start"); - if (xtrabackup_incremental) { - if (!xtrabackup_incremental_force_scan) { - changed_page_bitmap = xb_page_bitmap_init(); - } - if (!changed_page_bitmap) { - msg("mariabackup: using the full scan for incremental " - "backup\n"); - } else if (incremental_lsn != checkpoint_lsn_start) { - /* Do not print that bitmaps are used when dummy bitmap - is build for an empty LSN range. */ - msg("mariabackup: using the changed page bitmap\n"); - } - } ut_a(xtrabackup_parallel > 0); if (xtrabackup_parallel > 1) { msg("mariabackup: Starting %u threads for parallel data " - "files transfer\n", xtrabackup_parallel); + "files transfer", xtrabackup_parallel); + } + + if (opt_lock_ddl_per_table) { + mdl_lock_all(); + + DBUG_EXECUTE_IF("check_mdl_lock_works", + dbug_alter_thread_done = + dbug_start_query_thread("ALTER TABLE test.t ADD COLUMN mdl_lock_column int", + "Waiting for table metadata lock", 1, ER_QUERY_INTERRUPTED);); } - it = datafiles_iter_new(f_system); + datafiles_iter_t *it = datafiles_iter_new(fil_system); if (it == NULL) { - msg("mariabackup: Error: datafiles_iter_new() failed.\n"); - exit(EXIT_FAILURE); + msg("mariabackup: Error: datafiles_iter_new() failed."); + goto fail; } /* Create data copying threads */ data_threads = (data_thread_ctxt_t *) - ut_malloc(sizeof(data_thread_ctxt_t) * xtrabackup_parallel); + malloc(sizeof(data_thread_ctxt_t) * xtrabackup_parallel); count = xtrabackup_parallel; - count_mutex = os_mutex_create(); + pthread_mutex_init(&count_mutex, NULL); for (i = 0; i < (uint) xtrabackup_parallel; i++) { data_threads[i].it = it; data_threads[i].num = i+1; data_threads[i].count = &count; - data_threads[i].count_mutex = count_mutex; + data_threads[i].count_mutex = &count_mutex; os_thread_create(data_copy_thread_func, data_threads + i, &data_threads[i].id); } @@ -4256,411 +4328,235 @@ reread_log_header: /* Wait for threads to exit */ while (1) { os_thread_sleep(1000000); - os_mutex_enter(count_mutex); - if (count == 0) { - os_mutex_exit(count_mutex); + pthread_mutex_lock(&count_mutex); + bool stop = count == 0; + pthread_mutex_unlock(&count_mutex); + if (stop) { break; } - os_mutex_exit(count_mutex); } - os_mutex_free(count_mutex); - ut_free(data_threads); + pthread_mutex_destroy(&count_mutex); + free(data_threads); datafiles_iter_free(it); - - if (changed_page_bitmap) { - xb_page_bitmap_deinit(changed_page_bitmap); - } } - if (!backup_start()) { - exit(EXIT_FAILURE); - } + bool ok = backup_start(); - /* read the latest checkpoint lsn */ - latest_cp = 0; - { - log_group_t* max_cp_group; - ulint max_cp_field; - ulint err; + if (ok) { + ok = xtrabackup_backup_low(); - mutex_enter(&log_sys->mutex); + backup_release(); - err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); + DBUG_EXECUTE_IF("check_mdl_lock_works", + os_event_wait(dbug_alter_thread_done); + os_event_destroy(dbug_alter_thread_done); + ); - if (err != DB_SUCCESS) { - msg("mariabackup: Error: recv_find_max_checkpoint() failed.\n"); - mutex_exit(&log_sys->mutex); - goto skip_last_cp; + if (ok) { + backup_finish(); } - - log_group_read_checkpoint_info(max_cp_group, max_cp_field); - - xtrabackup_choose_lsn_offset(checkpoint_lsn_start); - - latest_cp = mach_read_from_8(log_sys->checkpoint_buf + - LOG_CHECKPOINT_LSN); - - mutex_exit(&log_sys->mutex); - - msg("mariabackup: The latest check point (for incremental): " - "'" LSN_PF "'\n", latest_cp); - } -skip_last_cp: - /* stop log_copying_thread */ - log_copying = FALSE; - os_event_set(log_copying_stop); - msg("mariabackup: Stopping log copying thread.\n"); - while (log_copying_running) { - msg("."); - os_thread_sleep(200000); /*0.2 sec*/ - } - msg("\n"); - - os_event_free(log_copying_stop); - if (ds_close(dst_log_file)) { - exit(EXIT_FAILURE); } - if(!xtrabackup_incremental) { - strcpy(metadata_type, "full-backuped"); - metadata_from_lsn = 0; - } else { - strcpy(metadata_type, "incremental"); - metadata_from_lsn = incremental_lsn; + if (!ok) { + goto fail; } - metadata_to_lsn = latest_cp; - metadata_last_lsn = log_copy_scanned_lsn; - if (!xtrabackup_stream_metadata(ds_meta)) { - msg("mariabackup: Error: failed to stream metadata.\n"); - exit(EXIT_FAILURE); - } - if (xtrabackup_extra_lsndir) { - char filename[FN_REFLEN]; - - sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, - XTRABACKUP_METADATA_FILENAME); - if (!xtrabackup_write_metadata(filename)) { - msg("mariabackup: Error: failed to write metadata " - "to '%s'.\n", filename); - exit(EXIT_FAILURE); - } - - } - - if (!backup_finish()) { - exit(EXIT_FAILURE); + if (changed_page_bitmap) { + xb_page_bitmap_deinit(changed_page_bitmap); } - xtrabackup_destroy_datasinks(); - if (wait_throttle) { - /* wait for io_watching_thread completion */ - while (io_watching_thread_running) { - os_thread_sleep(1000000); - } - os_event_free(wait_throttle); - wait_throttle = NULL; - } - - msg("mariabackup: Transaction log of lsn (" LSN_PF ") to (" LSN_PF - ") was copied.\n", checkpoint_lsn_start, log_copy_scanned_lsn); + msg("Redo log (from LSN " LSN_PF " to " LSN_PF + ") was copied.", checkpoint_lsn_start, log_copy_scanned_lsn); xb_filters_free(); xb_data_files_close(); - /* Make sure that the latest checkpoint made it to xtrabackup_logfile */ - if (latest_cp > log_copy_scanned_lsn) { - msg("mariabackup: error: last checkpoint LSN (" LSN_PF - ") is larger than last copied LSN (" LSN_PF ").\n", - latest_cp, log_copy_scanned_lsn); - exit(EXIT_FAILURE); + /* Make sure that the latest checkpoint was included */ + if (metadata_to_lsn > log_copy_scanned_lsn) { + msg("Error: failed to copy enough redo log (" + "LSN=" LSN_PF "; checkpoint LSN=" LSN_PF ").", + log_copy_scanned_lsn, metadata_to_lsn); + goto fail; } -} -/* ================= prepare ================= */ - -static my_bool -xtrabackup_init_temp_log(void) -{ - pfs_os_file_t src_file; - char src_path[FN_REFLEN]; - char dst_path[FN_REFLEN]; - ibool success; + innodb_shutdown(); + log_file_op = NULL; + pthread_mutex_destroy(&backup_mutex); + pthread_cond_destroy(&scanned_lsn_cond); + return(true); +} - ulint field; - byte* log_buf= (byte *)malloc(UNIV_PAGE_SIZE_MAX * 128); /* 2 MB */ - ib_int64_t file_size; +/** +This function handles DDL changes at the end of backup, under protection of +FTWRL. This ensures consistent backup in presence of DDL. - lsn_t max_no = 0; - lsn_t max_lsn = 0; +- New tables, that were created during backup, are now copied into backup. + Also, tablespaces with optimized (no redo loggin DDL) are re-copied into + backup. This tablespaces will get the extension ".new" in the backup - ulint fold; +- Tables that were renamed during backup, are marked as renamed + For these, file <old_name>.ren will be created. + The content of the file is the new tablespace name. - if (!log_buf) { - goto error; - } +- Tables that were deleted during backup, are marked as deleted + For these , an empty file <name>.del will be created - if (!xb_init_log_block_size()) { - goto error; - } + It is the responsibility of the prepare phase to deal with .new, .ren, and .del + files. +*/ +void backup_fix_ddl(void) +{ + std::set<std::string> new_tables; + std::set<std::string> dropped_tables; + std::map<std::string, std::string> renamed_tables; - if(!xtrabackup_incremental_dir) { - sprintf(dst_path, "%s/ib_logfile0", xtrabackup_target_dir); - sprintf(src_path, "%s/%s", xtrabackup_target_dir, - XB_LOG_FILENAME); - } else { - sprintf(dst_path, "%s/ib_logfile0", xtrabackup_incremental_dir); - sprintf(src_path, "%s/%s", xtrabackup_incremental_dir, - XB_LOG_FILENAME); - } + /* Disable further DDL on backed up tables (only needed for --no-lock).*/ + pthread_mutex_lock(&backup_mutex); + log_file_op = backup_file_op_fail; + log_optimized_ddl_op = backup_optimized_ddl_op_fail; + pthread_mutex_unlock(&backup_mutex); - srv_normalize_path_for_win(dst_path); - srv_normalize_path_for_win(src_path); -retry: - src_file = os_file_create_simple_no_error_handling(0, src_path, - OS_FILE_OPEN, - OS_FILE_READ_WRITE, - &success,0); - if (!success) { - /* The following call prints an error message */ - os_file_get_last_error(TRUE); + DBUG_MARIABACKUP_EVENT("backup_fix_ddl",0); - msg("mariabackup: Warning: cannot open %s. will try to find.\n", - src_path); + for (space_id_to_name_t::iterator iter = ddl_tracker.tables_in_backup.begin(); + iter != ddl_tracker.tables_in_backup.end(); + iter++) { - /* check if ib_logfile0 may be xtrabackup_logfile */ - src_file = os_file_create_simple_no_error_handling(0, dst_path, - OS_FILE_OPEN, - OS_FILE_READ_WRITE, - &success,0); - if (!success) { - os_file_get_last_error(TRUE); - msg("mariabackup: Fatal error: cannot find %s.\n", - src_path); + const std::string name = iter->second; + ulint id = iter->first; - goto error; - } - - success = os_file_read(src_file, log_buf, 0, - LOG_FILE_HDR_SIZE); - if (!success) { - goto error; + if (ddl_tracker.drops.find(id) != ddl_tracker.drops.end()) { + dropped_tables.insert(name); + continue; } - if ( ut_memcmp(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - (byte*)"xtrabkup", (sizeof "xtrabkup") - 1) == 0) { - msg("mariabackup: 'ib_logfile0' seems to be " - "'xtrabackup_logfile'. will retry.\n"); - - os_file_close(src_file); - src_file = XB_FILE_UNDEFINED; + bool has_optimized_ddl = + ddl_tracker.optimized_ddl.find(id) != ddl_tracker.optimized_ddl.end(); - /* rename and try again */ - success = os_file_rename(0, dst_path, src_path); - if (!success) { - goto error; + if (ddl_tracker.id_to_name.find(id) == ddl_tracker.id_to_name.end()) { + if (has_optimized_ddl) { + new_tables.insert(name); } - - goto retry; + continue; } - msg("mariabackup: Fatal error: cannot find %s.\n", src_path); - - os_file_close(src_file); - src_file = XB_FILE_UNDEFINED; - - goto error; + /* tablespace was affected by DDL. */ + const std::string new_name = ddl_tracker.id_to_name[id]; + if (new_name != name) { + if (has_optimized_ddl) { + /* table was renamed, but we need a full copy + of it because of optimized DDL. We emulate a drop/create.*/ + dropped_tables.insert(name); + new_tables.insert(new_name); + } else { + /* Renamed, and no optimized DDL*/ + renamed_tables[name] = new_name; + } + } else if (has_optimized_ddl) { + /* Table was recreated, or optimized DDL ran. + In both cases we need a full copy in the backup.*/ + new_tables.insert(name); + } } - file_size = os_file_get_size(src_file); - - - /* TODO: We should skip the following modifies, if it is not the first time. */ - - /* read log file header */ - success = os_file_read(src_file, log_buf, 0, LOG_FILE_HDR_SIZE); - if (!success) { - goto error; - } + /* Find tables that were created during backup (and not removed).*/ + for(space_id_to_name_t::iterator iter = ddl_tracker.id_to_name.begin(); + iter != ddl_tracker.id_to_name.end(); + iter++) { - if ( ut_memcmp(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - (byte*)"xtrabkup", (sizeof "xtrabkup") - 1) != 0 ) { - msg("mariabackup: notice: xtrabackup_logfile was already used " - "to '--prepare'.\n"); - goto skip_modify; - } else { - /* clear it later */ - //memset(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - // ' ', 4); - } + ulint id = iter->first; + std::string name = iter->second; - /* read last checkpoint lsn */ - for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2; - field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) { - if (!recv_check_cp_is_consistent(const_cast<const byte *> - (log_buf + field))) + if (ddl_tracker.tables_in_backup.find(id) != ddl_tracker.tables_in_backup.end()) { + /* already processed above */ continue; + } - lsn_t checkpoint_no = mach_read_from_8(log_buf + field + - LOG_CHECKPOINT_NO); - - if (checkpoint_no >= max_no) { - - max_no = checkpoint_no; - max_lsn = mach_read_from_8(log_buf + field + - LOG_CHECKPOINT_LSN); + if (ddl_tracker.drops.find(id) == ddl_tracker.drops.end()) { + dropped_tables.erase(name); + new_tables.insert(name); } } - if (!max_lsn) { - msg("mariabackup: No valid checkpoint found.\n"); - goto error; + // Mark tablespaces for rename + for (std::map<std::string, std::string>::iterator iter = renamed_tables.begin(); + iter != renamed_tables.end(); ++iter) { + const std::string old_name = iter->first; + std::string new_name = iter->second; + backup_file_printf((old_name + ".ren").c_str(), "%s", new_name.c_str()); } - /* It seems to be needed to overwrite the both checkpoint area. */ - mach_write_to_8(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN, - max_lsn); - mach_write_to_4(log_buf + LOG_CHECKPOINT_1 - + LOG_CHECKPOINT_OFFSET_LOW32, - LOG_FILE_HDR_SIZE + - (ulint)(max_lsn - - ut_uint64_align_down(max_lsn, - OS_FILE_LOG_BLOCK_SIZE))); - mach_write_to_4(log_buf + LOG_CHECKPOINT_1 - + LOG_CHECKPOINT_OFFSET_HIGH32, 0); - fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_1, LOG_CHECKPOINT_CHECKSUM_1); - mach_write_to_4(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_CHECKSUM_1, fold); - - fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN, - LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN); - mach_write_to_4(log_buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_CHECKSUM_2, fold); - - mach_write_to_8(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN, - max_lsn); - mach_write_to_4(log_buf + LOG_CHECKPOINT_2 - + LOG_CHECKPOINT_OFFSET_LOW32, - LOG_FILE_HDR_SIZE + - (ulint)(max_lsn - - ut_uint64_align_down(max_lsn, - OS_FILE_LOG_BLOCK_SIZE))); - mach_write_to_4(log_buf + LOG_CHECKPOINT_2 - + LOG_CHECKPOINT_OFFSET_HIGH32, 0); - fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_2, LOG_CHECKPOINT_CHECKSUM_1); - mach_write_to_4(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_CHECKSUM_1, fold); - - fold = ut_fold_binary(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN, - LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN); - mach_write_to_4(log_buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_CHECKSUM_2, fold); - - - success = os_file_write(src_path, src_file, log_buf, 0, - LOG_FILE_HDR_SIZE); - if (!success) { - goto error; + // Mark tablespaces for drop + for (std::set<std::string>::iterator iter = dropped_tables.begin(); + iter != dropped_tables.end(); + iter++) { + const std::string name(*iter); + backup_file_printf((name + ".del").c_str(), "%s", ""); } - /* expand file size (9/8) and align to UNIV_PAGE_SIZE_MAX */ - - if (file_size % UNIV_PAGE_SIZE_MAX) { - memset(log_buf, 0, UNIV_PAGE_SIZE_MAX); - success = os_file_write(src_path, src_file, log_buf, - file_size, - UNIV_PAGE_SIZE_MAX - - (ulint) (file_size - % UNIV_PAGE_SIZE_MAX)); - if (!success) { - goto error; - } - - file_size = os_file_get_size(src_file); + // Load and copy new tables. + // Close all datanodes first, reload only new tables. + std::vector<fil_node_t *> all_nodes; + datafiles_iter_t *it = datafiles_iter_new(fil_system); + if (!it) + return; + while (fil_node_t *node = datafiles_iter_next(it)) { + all_nodes.push_back(node); } - - /* TODO: We should judge whether the file is already expanded or not... */ - { - ulint expand; - - memset(log_buf, 0, UNIV_PAGE_SIZE_MAX * 128); - expand = (ulint) (file_size / UNIV_PAGE_SIZE_MAX / 8); - - for (; expand > 128; expand -= 128) { - success = os_file_write(src_path, src_file, log_buf, - file_size, - UNIV_PAGE_SIZE_MAX * 128); - if (!success) { - goto error; - } - file_size += UNIV_PAGE_SIZE_MAX * 128; - } - - if (expand) { - success = os_file_write(src_path, src_file, log_buf, - file_size, - expand * UNIV_PAGE_SIZE_MAX); - if (!success) { - goto error; - } - file_size += UNIV_PAGE_SIZE_MAX * expand; - } + for (size_t i = 0; i < all_nodes.size(); i++) { + fil_node_t *n = all_nodes[i]; + if (n->space->id == 0) + continue; + fil_space_close(n->space->name); + fil_space_free(n->space->id, false); } + datafiles_iter_free(it); - /* make larger than 2MB */ - if (file_size < 2*1024*1024L) { - memset(log_buf, 0, UNIV_PAGE_SIZE_MAX); - while (file_size < 2*1024*1024L) { - success = os_file_write(src_path, src_file, log_buf, - file_size, - UNIV_PAGE_SIZE_MAX); - if (!success) { - goto error; - } - file_size += UNIV_PAGE_SIZE_MAX; + for (std::set<std::string>::iterator iter = new_tables.begin(); + iter != new_tables.end(); iter++) { + const char *space_name = iter->c_str(); + if (check_if_skip_table(space_name)) + continue; + std::string name(*iter); + bool is_remote = access((name + ".ibd").c_str(), R_OK) != 0; + const char *extension = is_remote ? ".isl" : ".ibd"; + name.append(extension); + char buf[FN_REFLEN]; + strncpy(buf, name.c_str(), sizeof buf - 1); + buf[sizeof buf - 1] = '\0'; + const char *dbname = buf; + char *p = strchr(buf, '/'); + if (p == 0) { + msg("Unexpected tablespace %s filename %s", space_name, name.c_str()); + ut_a(0); } - file_size = os_file_get_size(src_file); + ut_a(p); + *p = 0; + const char *tablename = p + 1; + xb_load_single_table_tablespace(dbname, tablename, is_remote); } - msg("mariabackup: xtrabackup_logfile detected: size=" INT64PF ", " - "start_lsn=(" LSN_PF ")\n", file_size, max_lsn); - - os_file_close(src_file); - src_file = XB_FILE_UNDEFINED; - - /* fake InnoDB */ - innobase_log_files_in_group_save = innobase_log_files_in_group; - srv_log_group_home_dir_save = srv_log_group_home_dir; - innobase_log_file_size_save = innobase_log_file_size; - - srv_log_group_home_dir = NULL; - innobase_log_file_size = file_size; - innobase_log_files_in_group = 1; - - srv_thread_concurrency = 0; + it = datafiles_iter_new(fil_system); + if (!it) + return; - /* rename 'xtrabackup_logfile' to 'ib_logfile0' */ - success = os_file_rename(0, src_path, dst_path); - if (!success) { - goto error; + while (fil_node_t *node = datafiles_iter_next(it)) { + fil_space_t * space = node->space; + if (!fil_is_user_tablespace_id(space->id)) + continue; + std::string dest_name(node->space->name); + dest_name.append(".new"); + xtrabackup_copy_datafile(node, 0, dest_name.c_str()/*, do_full_copy ? ULONGLONG_MAX:UNIV_PAGE_SIZE */); } - xtrabackup_logfile_is_renamed = TRUE; - free(log_buf); - return(FALSE); -skip_modify: - free(log_buf); - os_file_close(src_file); - src_file = XB_FILE_UNDEFINED; - return(FALSE); - -error: - free(log_buf); - if (src_file != XB_FILE_UNDEFINED) - os_file_close(src_file); - msg("mariabackup: Error: xtrabackup_init_temp_log() failed.\n"); - return(TRUE); /*ERROR*/ + datafiles_iter_free(it); } +/* ================= prepare ================= */ + /*********************************************************************** Generates path to the meta file path from a given path to an incremental .delta by replacing trailing ".delta" with ".meta", or returns error if 'delta_path' @@ -4690,39 +4586,37 @@ file. Code adopted from fil_create_new_single_table_tablespace with the main difference that only disk file is created without updating the InnoDB in-memory dictionary data structures. -@return TRUE on success, FALSE on error. */ +@return true on success, false on error. */ static -ibool +bool xb_space_create_file( /*==================*/ const char* path, /*!<in: path to tablespace */ ulint space_id, /*!<in: space id */ - ulint flags __attribute__((unused)),/*!<in: tablespace - flags */ + ulint flags, /*!<in: tablespace flags */ pfs_os_file_t* file) /*!<out: file handle */ { - ibool ret; + bool ret; byte* buf; byte* page; - *file = os_file_create_simple_no_error_handling(0, path, OS_FILE_CREATE, - OS_FILE_READ_WRITE, - &ret,0); + *file = os_file_create_simple_no_error_handling( + 0, path, OS_FILE_CREATE, OS_FILE_READ_WRITE, false, &ret); if (!ret) { - msg("mariabackup: cannot create file %s\n", path); + msg("Can't create file %s", path); return ret; } ret = os_file_set_size(path, *file, FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE); if (!ret) { - msg("mariabackup: cannot set size for file %s\n", path); + msg("mariabackup: cannot set size for file %s", path); os_file_close(*file); os_file_delete(0, path); return ret; } - buf = static_cast<byte *>(ut_malloc(3 * UNIV_PAGE_SIZE)); + buf = static_cast<byte *>(malloc(3 * UNIV_PAGE_SIZE)); /* Align the memory for file i/o if we might have O_DIRECT set */ page = static_cast<byte *>(ut_align(buf, UNIV_PAGE_SIZE)); @@ -4731,19 +4625,19 @@ xb_space_create_file( fsp_header_init_fields(page, space_id, flags); mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id); - if (!fsp_flags_is_compressed(flags)) { - buf_flush_init_for_writing(page, NULL, 0); + const page_size_t page_size(flags); - ret = os_file_write(path, *file, page, 0, UNIV_PAGE_SIZE); - } - else { - page_zip_des_t page_zip; - ulint zip_size; + if (!page_size.is_compressed()) { + buf_flush_init_for_writing(NULL, page, NULL, 0); - zip_size = fsp_flags_get_zip_size(flags); + ret = os_file_write(IORequestWrite, path, *file, page, 0, + UNIV_PAGE_SIZE); + } else { + page_zip_des_t page_zip; + ulint zip_size = page_size.physical(); page_zip_set_size(&page_zip, zip_size); page_zip.data = page + UNIV_PAGE_SIZE; - fprintf(stderr, "zip_size = %lu\n", zip_size); + fprintf(stderr, "zip_size = " ULINTPF "\n", zip_size); #ifdef UNIV_DEBUG page_zip.m_start = @@ -4751,16 +4645,16 @@ xb_space_create_file( page_zip.m_end = page_zip.m_nonempty = page_zip.n_blobs = 0; - buf_flush_init_for_writing(page, &page_zip, 0); + buf_flush_init_for_writing(NULL, page, &page_zip, 0); - ret = os_file_write(path, *file, page_zip.data, 0, - zip_size); + ret = os_file_write(IORequestWrite, path, *file, + page_zip.data, 0, zip_size); } - ut_free(buf); + free(buf); - if (!ret) { - msg("mariabackup: could not write the first page to %s\n", + if (ret != DB_SUCCESS) { + msg("mariabackup: could not write the first page to %s", path); os_file_close(*file); os_file_delete(0, path); @@ -4782,35 +4676,32 @@ pfs_os_file_t xb_delta_open_matching_space( const char* dbname, /* in: path to destination database dir */ const char* name, /* in: name of delta file (without .delta) */ - ulint space_id, /* in: space id of delta file */ - ulint zip_size, /* in: zip_size of tablespace */ + const xb_delta_info_t& info, char* real_name, /* out: full path of destination file */ size_t real_name_len, /* out: buffer size for real_name */ - ibool* success) /* out: indicates error. TRUE = success */ + bool* success) /* out: indicates error. true = success */ { char dest_dir[FN_REFLEN]; char dest_space_name[FN_REFLEN]; - ibool ok; fil_space_t* fil_space; pfs_os_file_t file; - ulint tablespace_flags; xb_filter_entry_t* table; ut_a(dbname != NULL || - !fil_is_user_tablespace_id(space_id) || - space_id == ULINT_UNDEFINED); + !fil_is_user_tablespace_id(info.space_id) || + info.space_id == ULINT_UNDEFINED); - *success = FALSE; + *success = false; if (dbname) { snprintf(dest_dir, FN_REFLEN, "%s/%s", xtrabackup_target_dir, dbname); - srv_normalize_path_for_win(dest_dir); + os_normalize_path(dest_dir); snprintf(dest_space_name, FN_REFLEN, "%s/%s", dbname, name); } else { snprintf(dest_dir, FN_REFLEN, "%s", xtrabackup_target_dir); - srv_normalize_path_for_win(dest_dir); + os_normalize_path(dest_dir); snprintf(dest_space_name, FN_REFLEN, "%s", name); } @@ -4818,23 +4709,36 @@ xb_delta_open_matching_space( snprintf(real_name, real_name_len, "%s/%s", xtrabackup_target_dir, dest_space_name); - srv_normalize_path_for_win(real_name); + os_normalize_path(real_name); /* Truncate ".ibd" */ dest_space_name[strlen(dest_space_name) - 4] = '\0'; /* Create the database directory if it doesn't exist yet */ if (!os_file_create_directory(dest_dir, FALSE)) { - msg("mariabackup: error: cannot create dir %s\n", dest_dir); + msg("mariabackup: error: cannot create dir %s", dest_dir); return file; } - if (!fil_is_user_tablespace_id(space_id)) { - goto found; + log_mutex_enter(); + if (!fil_is_user_tablespace_id(info.space_id)) { +found: + /* open the file and return its handle */ + + file = os_file_create_simple_no_error_handling( + 0, real_name, + OS_FILE_OPEN, OS_FILE_READ_WRITE, false, success); + + if (!*success) { + msg("mariabackup: Cannot open file %s\n", real_name); + } +exit: + log_mutex_exit(); + return file; } /* remember space name for further reference */ table = static_cast<xb_filter_entry_t *> - (ut_malloc(sizeof(xb_filter_entry_t) + + (malloc(sizeof(xb_filter_entry_t) + strlen(dest_space_name) + 1)); table->name = ((char*)table) + sizeof(xb_filter_entry_t); @@ -4847,50 +4751,54 @@ xb_delta_open_matching_space( mutex_exit(&fil_system->mutex); if (fil_space != NULL) { - if (fil_space->id == space_id || space_id == ULINT_UNDEFINED) { + if (fil_space->id == info.space_id + || info.space_id == ULINT_UNDEFINED) { /* we found matching space */ goto found; } else { char tmpname[FN_REFLEN]; - snprintf(tmpname, FN_REFLEN, "%s/xtrabackup_tmp_#%lu", + snprintf(tmpname, FN_REFLEN, "%s/xtrabackup_tmp_#" ULINTPF, dbname, fil_space->id); - msg("mariabackup: Renaming %s to %s.ibd\n", + msg("mariabackup: Renaming %s to %s.ibd", fil_space->name, tmpname); - if (!fil_rename_tablespace(NULL, fil_space->id, - tmpname, NULL)) + if (!fil_rename_tablespace( + fil_space->id, + fil_space->chain.start->name, + tmpname, NULL)) { - msg("mariabackup: Cannot rename %s to %s\n", + msg("mariabackup: Cannot rename %s to %s", fil_space->name, tmpname); goto exit; } } } - if (space_id == ULINT_UNDEFINED) + if (info.space_id == ULINT_UNDEFINED) { - msg("mariabackup: Error: Cannot handle DDL operation on tablespace " + die("Can't handle DDL operation on tablespace " "%s\n", dest_space_name); - exit(EXIT_FAILURE); } mutex_enter(&fil_system->mutex); - fil_space = fil_space_get_by_id(space_id); + fil_space = fil_space_get_by_id(info.space_id); mutex_exit(&fil_system->mutex); if (fil_space != NULL) { char tmpname[FN_REFLEN]; strncpy(tmpname, dest_space_name, FN_REFLEN); - msg("mariabackup: Renaming %s to %s\n", + msg("mariabackup: Renaming %s to %s", fil_space->name, dest_space_name); - if (!fil_rename_tablespace(NULL, fil_space->id, tmpname, + if (!fil_rename_tablespace(fil_space->id, + fil_space->chain.start->name, + tmpname, NULL)) { - msg("mariabackup: Cannot rename %s to %s\n", + msg("mariabackup: Cannot rename %s to %s", fil_space->name, dest_space_name); goto exit; } @@ -4899,49 +4807,29 @@ xb_delta_open_matching_space( } /* No matching space found. create the new one. */ - - if (!fil_space_create(dest_space_name, space_id, 0, - FIL_TABLESPACE, 0, false)) { - msg("mariabackup: Cannot create tablespace %s\n", - dest_space_name); - goto exit; - } - - /* Calculate correct tablespace flags for compressed tablespaces. */ - if (!zip_size || zip_size == ULINT_UNDEFINED) { - tablespace_flags = 0; - } - else { - tablespace_flags - = (get_bit_shift(zip_size >> PAGE_ZIP_MIN_SIZE_SHIFT - << 1) - << DICT_TF_ZSSIZE_SHIFT) - | DICT_TF_COMPACT - | (DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT); - ut_a(dict_tf_get_zip_size(tablespace_flags) - == zip_size); - } - *success = xb_space_create_file(real_name, space_id, tablespace_flags, - &file); - goto exit; - -found: - /* open the file and return it's handle */ - - file = os_file_create_simple_no_error_handling(0, real_name, - OS_FILE_OPEN, - OS_FILE_READ_WRITE, - &ok,0); - - if (ok) { - *success = TRUE; + const ulint flags = info.page_size.is_compressed() + ? get_bit_shift(info.page_size.physical() + >> (UNIV_ZIP_SIZE_SHIFT_MIN - 1)) + << FSP_FLAGS_POS_ZIP_SSIZE + | FSP_FLAGS_MASK_POST_ANTELOPE + | FSP_FLAGS_MASK_ATOMIC_BLOBS + | (info.page_size.logical() == UNIV_PAGE_SIZE_ORIG + ? 0 + : get_bit_shift(info.page_size.logical() + >> (UNIV_ZIP_SIZE_SHIFT_MIN - 1)) + << FSP_FLAGS_POS_PAGE_SSIZE) + : FSP_FLAGS_PAGE_SSIZE(); + ut_ad(page_size_t(flags).equals_to(info.page_size)); + + if (fil_space_create(dest_space_name, info.space_id, flags, + FIL_TYPE_TABLESPACE, 0)) { + *success = xb_space_create_file(real_name, info.space_id, + flags, &file); } else { - msg("mariabackup: Cannot open file %s\n", real_name); + msg("Can't create tablespace %s\n", dest_space_name); } -exit: - - return file; + goto exit; } /************************************************************************ @@ -4962,13 +4850,13 @@ xtrabackup_apply_delta( char dst_path[FN_REFLEN]; char meta_path[FN_REFLEN]; char space_name[FN_REFLEN]; - ibool success; + bool success; ibool last_buffer = FALSE; ulint page_in_buffer; ulint incremental_buffers = 0; - xb_delta_info_t info; + xb_delta_info_t info(univ_page_size, SRV_TMP_SPACE_ID); ulint page_size; ulint page_size_shift; byte* incremental_buffer_base = NULL; @@ -4999,42 +4887,41 @@ xtrabackup_apply_delta( goto error; } - srv_normalize_path_for_win(dst_path); - srv_normalize_path_for_win(src_path); - srv_normalize_path_for_win(meta_path); + os_normalize_path(dst_path); + os_normalize_path(src_path); + os_normalize_path(meta_path); if (!xb_read_delta_metadata(meta_path, &info)) { goto error; } - page_size = info.page_size; + page_size = info.page_size.physical(); page_size_shift = get_bit_shift(page_size); - msg("mariabackup: page size for %s is %lu bytes\n", + msg("page size for %s is %zu bytes", src_path, page_size); if (page_size_shift < 10 || page_size_shift > UNIV_PAGE_SIZE_SHIFT_MAX) { - msg("mariabackup: error: invalid value of page_size " - "(%lu bytes) read from %s\n", page_size, meta_path); + msg("error: invalid value of page_size " + "(%zu bytes) read from %s", page_size, meta_path); goto error; } - src_file = os_file_create_simple_no_error_handling(0, src_path, - OS_FILE_OPEN, - OS_FILE_READ_WRITE, - &success,0); + src_file = os_file_create_simple_no_error_handling( + 0, src_path, + OS_FILE_OPEN, OS_FILE_READ_WRITE, false, &success); if (!success) { os_file_get_last_error(TRUE); - msg("mariabackup: error: cannot open %s\n", src_path); + msg("error: can't open %s", src_path); goto error; } posix_fadvise(src_file, 0, 0, POSIX_FADV_SEQUENTIAL); dst_file = xb_delta_open_matching_space( - dbname, space_name, info.space_id, info.zip_size, + dbname, space_name, info, dst_path, sizeof(dst_path), &success); if (!success) { - msg("mariabackup: error: cannot open %s\n", dst_path); + msg("error: can't open %s", dst_path); goto error; } @@ -5042,13 +4929,12 @@ xtrabackup_apply_delta( /* allocate buffer for incremental backup (4096 pages) */ incremental_buffer_base = static_cast<byte *> - (ut_malloc((page_size / 4 + 1) * - page_size)); + (malloc((page_size / 4 + 1) * page_size)); incremental_buffer = static_cast<byte *> (ut_align(incremental_buffer_base, page_size)); - msg("Applying %s to %s...\n", src_path, dst_path); + msg("Applying %s to %s...", src_path, dst_path); while (!last_buffer) { ulint cluster_header; @@ -5057,9 +4943,9 @@ xtrabackup_apply_delta( /* first block of block cluster */ offset = ((incremental_buffers * (page_size / 4)) << page_size_shift); - success = os_file_read(src_file, incremental_buffer, - offset, page_size); - if (!success) { + success = os_file_read(IORequestRead, src_file, + incremental_buffer, offset, page_size); + if (success != DB_SUCCESS) { goto error; } @@ -5071,11 +4957,14 @@ xtrabackup_apply_delta( last_buffer = TRUE; break; default: - msg("mariabackup: error: %s seems not " - ".delta file.\n", src_path); + msg("error: %s seems not " + ".delta file.", src_path); goto error; } + /* FIXME: If the .delta modifies FSP_SIZE on page 0, + extend the file to that size. */ + for (page_in_buffer = 1; page_in_buffer < page_size / 4; page_in_buffer++) { if (mach_read_from_4(incremental_buffer + page_in_buffer * 4) @@ -5086,9 +4975,10 @@ xtrabackup_apply_delta( ut_a(last_buffer || page_in_buffer == page_size / 4); /* read whole of the cluster */ - success = os_file_read(src_file, incremental_buffer, - offset, page_in_buffer * page_size); - if (!success) { + success = os_file_read(IORequestRead, src_file, + incremental_buffer, + offset, page_in_buffer * page_size); + if (success != DB_SUCCESS) { goto error; } @@ -5109,32 +4999,35 @@ xtrabackup_apply_delta( if (off == 0) { /* Read tablespace size from page 0, - extend the tablespace to specified size. */ - os_offset_t n_pages = mach_read_from_4(buf + FSP_HEADER_OFFSET + FSP_SIZE); - ulint space_id = mach_read_from_4(buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - if (space_id != TRX_SYS_SPACE) { - if (!os_file_set_size(dst_path, dst_file, n_pages*page_size)) + and extend the file to specified size.*/ + os_offset_t n_pages = mach_read_from_4( + buf + FSP_HEADER_OFFSET + FSP_SIZE); + if (mach_read_from_4(buf + + FIL_PAGE_SPACE_ID)) { + if (!os_file_set_size( + dst_path, dst_file, + n_pages * page_size)) goto error; - } else { - /* System tablespace needs special handling , since - it can consist of multiple files. The first one has full - tablespace size in page 0, but only last file should be extended. */ - mutex_enter(&fil_system->mutex); - fil_space_t* space = fil_space_get_by_id(space_id); - mutex_exit(&fil_system->mutex); - DBUG_ASSERT(space); - fil_node_t* n = UT_LIST_GET_FIRST(space->chain); - if(strcmp(n->name, dst_path) == 0) { - /* Got first tablespace file, with correct size */ - ulint actual_size; - if (!fil_extend_space_to_desired_size(&actual_size, 0, (ulint)n_pages)) - goto error; - } + } else if (fil_space_t* space + = fil_space_acquire(0)) { + /* The system tablespace can + consist of multiple files. The + first one has full tablespace + size in page 0, but only the last + file should be extended. */ + fil_node_t* n = UT_LIST_GET_FIRST( + space->chain); + bool fail = !strcmp(n->name, dst_path) + && !fil_space_extend( + space, (ulint)n_pages); + fil_space_release(space); + if (fail) goto error; } } - success = os_file_write(dst_path, dst_file, buf, off, page_size); - if (!success) { + success = os_file_write(IORequestWrite, + dst_path, dst_file, buf, off, page_size); + if (success != DB_SUCCESS) { goto error; } } @@ -5149,29 +5042,46 @@ xtrabackup_apply_delta( incremental_buffers++; } - if (incremental_buffer_base) - ut_free(incremental_buffer_base); - if (src_file != XB_FILE_UNDEFINED) { + free(incremental_buffer_base); + if (src_file != OS_FILE_CLOSED) { os_file_close(src_file); - /* Remove .delta file after it was successfully applied.*/ os_file_delete(0,src_path); } - if (dst_file != XB_FILE_UNDEFINED) + if (dst_file != OS_FILE_CLOSED) os_file_close(dst_file); return TRUE; error: - if (incremental_buffer_base) - ut_free(incremental_buffer_base); - if (src_file != XB_FILE_UNDEFINED) + free(incremental_buffer_base); + if (src_file != OS_FILE_CLOSED) os_file_close(src_file); - if (dst_file != XB_FILE_UNDEFINED) + if (dst_file != OS_FILE_CLOSED) os_file_close(dst_file); - msg("mariabackup: Error: xtrabackup_apply_delta(): " + msg("Error: xtrabackup_apply_delta(): " "failed to apply %s to %s.\n", src_path, dst_path); return FALSE; } + +std::string change_extension(std::string filename, std::string new_ext) { + DBUG_ASSERT(new_ext.size() == 3); + std::string new_name(filename); + new_name.resize(new_name.size() - new_ext.size()); + new_name.append(new_ext); + return new_name; +} + + +static void rename_file(const char *from,const char *to) { + msg("Renaming %s to %s\n", from, to); + if (my_rename(from, to, MY_WME)) { + die("Can't rename %s to %s errno %d", from, to, errno); + } +} + +static void rename_file(const std::string& from, const std::string &to) { + rename_file(from.c_str(), to.c_str()); +} /************************************************************************ Callback to handle datadir entry. Function of this type will be called for each entry which matches the mask by xb_process_datadir. @@ -5183,6 +5093,37 @@ typedef ibool (*handle_datadir_entry_func_t)( const char* file_name, /*!<in: file name with suffix */ void* arg); /*!<in: caller-provided data */ +/** Rename, and replace destination file, if exists */ +static void rename_force(const char *from, const char *to) { + if (access(to, R_OK) == 0) { + msg("Removing %s", to); + if (my_delete(to, MYF(MY_WME))) { + msg("Can't remove %s, errno %d", to, errno); + exit(EXIT_FAILURE); + } + } + rename_file(from,to); +} + +/* During prepare phase, rename ".new" files , that were created in backup_fix_ddl(), + to ".ibd".*/ +static ibool prepare_handle_new_files( + const char* data_home_dir, /*!<in: path to datadir */ + const char* db_name, /*!<in: database name */ + const char* file_name, /*!<in: file name with suffix */ + void *) +{ + + std::string src_path = std::string(data_home_dir) + '/' + std::string(db_name) + '/' + file_name; + std::string dest_path = src_path; + + size_t index = dest_path.find(".new"); + DBUG_ASSERT(index != std::string::npos); + dest_path.replace(index, 4, ".ibd"); + rename_force(src_path.c_str(),dest_path.c_str()); + return TRUE; +} + /************************************************************************ Callback to handle datadir entry. Deletes entry if it has no matching fil_space in fil_system directory. @@ -5226,9 +5167,7 @@ xb_process_datadir( const char* path, /*!<in: datadir path */ const char* suffix, /*!<in: suffix to match against */ - handle_datadir_entry_func_t func, /*!<in: callback */ - void* data) /*!<in: additional argument for - callback */ + handle_datadir_entry_func_t func) /*!<in: callback */ { ulint ret; char dbpath[OS_FILE_MAX_PATH]; @@ -5263,7 +5202,7 @@ xb_process_datadir( suffix)) { if (!func( path, NULL, - fileinfo.name, data)) + fileinfo.name, NULL)) { os_file_closedir(dbdir); return(FALSE); @@ -5277,16 +5216,14 @@ next_file_item_1: os_file_closedir(dbdir); } else { - msg("mariabackup: Cannot open dir %s\n", - path); + msg("Can't open dir %s", path); } /* single table tablespaces */ dir = os_file_opendir(path, FALSE); if (dir == NULL) { - msg("mariabackup: Cannot open dir %s\n", - path); + msg("Can't open dir %s", path); } ret = fil_file_readdir_next_file(&err, path, dir, @@ -5298,8 +5235,13 @@ next_file_item_1: goto next_datadir_item; } - snprintf(dbpath, sizeof(dbpath), "%s/%s", path, dbinfo.name); - srv_normalize_path_for_win(dbpath); + snprintf(dbpath, sizeof(dbpath), "%.*s/%.*s", + OS_FILE_MAX_PATH/2-1, + path, + OS_FILE_MAX_PATH/2-1, + dbinfo.name); + + os_normalize_path(dbpath); dbdir = os_file_opendir(dbpath, FALSE); @@ -5324,7 +5266,7 @@ next_file_item_1: if (!func( path, dbinfo.name, - fileinfo.name, data)) + fileinfo.name, NULL)) { os_file_closedir(dbdir); os_file_closedir(dir); @@ -5358,464 +5300,156 @@ ibool xtrabackup_apply_deltas() { return xb_process_datadir(xtrabackup_incremental_dir, ".delta", - xtrabackup_apply_delta, NULL); -} - -static my_bool -xtrabackup_close_temp_log(my_bool clear_flag) -{ - pfs_os_file_t src_file; - char src_path[FN_REFLEN]; - char dst_path[FN_REFLEN]; - ibool success; - byte log_buf[UNIV_PAGE_SIZE_MAX]; - - if (!xtrabackup_logfile_is_renamed) - return(FALSE); - - /* rename 'ib_logfile0' to 'xtrabackup_logfile' */ - if(!xtrabackup_incremental_dir) { - sprintf(dst_path, "%s/ib_logfile0", xtrabackup_target_dir); - sprintf(src_path, "%s/%s", xtrabackup_target_dir, - XB_LOG_FILENAME); - } else { - sprintf(dst_path, "%s/ib_logfile0", xtrabackup_incremental_dir); - sprintf(src_path, "%s/%s", xtrabackup_incremental_dir, - XB_LOG_FILENAME); - } - - srv_normalize_path_for_win(dst_path); - srv_normalize_path_for_win(src_path); - - success = os_file_rename(0, dst_path, src_path); - if (!success) { - goto error; - } - xtrabackup_logfile_is_renamed = FALSE; - - if (!clear_flag) - return(FALSE); - - /* clear LOG_FILE_WAS_CREATED_BY_HOT_BACKUP field */ - src_file = os_file_create_simple_no_error_handling(0, src_path, - OS_FILE_OPEN, - OS_FILE_READ_WRITE, - &success,0); - if (!success) { - goto error; - } - - success = os_file_read(src_file, log_buf, 0, LOG_FILE_HDR_SIZE); - if (!success) { - goto error; - } - - memset(log_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, ' ', 4); - - success = os_file_write(src_path, src_file, log_buf, 0, - LOG_FILE_HDR_SIZE); - if (!success) { - goto error; - } - - os_file_close(src_file); - src_file = XB_FILE_UNDEFINED; - - innobase_log_files_in_group = innobase_log_files_in_group_save; - srv_log_group_home_dir = srv_log_group_home_dir_save; - innobase_log_file_size = innobase_log_file_size_save; - - return(FALSE); -error: - if (src_file != XB_FILE_UNDEFINED) - os_file_close(src_file); - msg("mariabackup: Error: xtrabackup_close_temp_log() failed.\n"); - return(TRUE); /*ERROR*/ + xtrabackup_apply_delta); } -/*********************************************************************//** -Write the meta data (index user fields) config file. -@return true in case of success otherwise false. */ static -bool -xb_export_cfg_write_index_fields( -/*===========================*/ - const dict_index_t* index, /*!< in: write the meta data for - this index */ - FILE* file) /*!< in: file to write to */ +void +innodb_free_param() { - byte row[sizeof(ib_uint32_t) * 2]; - - for (ulint i = 0; i < index->n_fields; ++i) { - byte* ptr = row; - const dict_field_t* field = &index->fields[i]; - - mach_write_to_4(ptr, field->prefix_len); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, field->fixed_len); - - if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { - - msg("mariabackup: Error: writing index fields."); - - return(false); - } - - /* Include the NUL byte in the length. */ - ib_uint32_t len = (ib_uint32_t)strlen(field->name) + 1; - ut_a(len > 1); - - mach_write_to_4(row, len); - - if (fwrite(row, 1, sizeof(len), file) != sizeof(len) - || fwrite(field->name, 1, len, file) != len) { - - msg("mariabackup: Error: writing index column."); - - return(false); - } - } - - return(true); + srv_sys_space.shutdown(); + free_tmpdir(&mysql_tmpdir_list); } -/*********************************************************************//** -Write the meta data config file index information. -@return true in case of success otherwise false. */ -static __attribute__((nonnull, warn_unused_result)) -bool -xb_export_cfg_write_indexes( -/*======================*/ - const dict_table_t* table, /*!< in: write the meta data for - this table */ - FILE* file) /*!< in: file to write to */ -{ - { - byte row[sizeof(ib_uint32_t)]; - - /* Write the number of indexes in the table. */ - mach_write_to_4(row, UT_LIST_GET_LEN(table->indexes)); - - if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { - msg("mariabackup: Error: writing index count."); - - return(false); - } - } - - bool ret = true; - - /* Write the index meta data. */ - for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); - index != 0 && ret; - index = UT_LIST_GET_NEXT(indexes, index)) { - - byte* ptr; - byte row[sizeof(ib_uint64_t) - + sizeof(ib_uint32_t) * 8]; - - ptr = row; - - ut_ad(sizeof(ib_uint64_t) == 8); - mach_write_to_8(ptr, index->id); - ptr += sizeof(ib_uint64_t); - - mach_write_to_4(ptr, index->space); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->page); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->type); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->trx_id_offset); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->n_user_defined_cols); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->n_uniq); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->n_nullable); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, index->n_fields); - - if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { - - msg("mariabackup: Error: writing index meta-data."); - return(false); - } - - /* Write the length of the index name. - NUL byte is included in the length. */ - ib_uint32_t len = (ib_uint32_t)strlen(index->name) + 1; - ut_a(len > 1); - - mach_write_to_4(row, len); - - if (fwrite(row, 1, sizeof(len), file) != sizeof(len) - || fwrite(index->name, 1, len, file) != len) { - - msg("mariabackup: Error: writing index name."); - - return(false); - } - - ret = xb_export_cfg_write_index_fields(index, file); - } - - return(ret); -} - -/*********************************************************************//** -Write the meta data (table columns) config file. Serialise the contents of -dict_col_t structure, along with the column name. All fields are serialized -as ib_uint32_t. -@return true in case of success otherwise false. */ -static __attribute__((nonnull, warn_unused_result)) -bool -xb_export_cfg_write_table( -/*====================*/ - const dict_table_t* table, /*!< in: write the meta data for - this table */ - FILE* file) /*!< in: file to write to */ +/** Check if file exists*/ +static bool file_exists(std::string name) { - dict_col_t* col; - byte row[sizeof(ib_uint32_t) * 7]; - - col = table->cols; - - for (ulint i = 0; i < table->n_cols; ++i, ++col) { - byte* ptr = row; - - mach_write_to_4(ptr, col->prtype); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, col->mtype); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, col->len); - ptr += sizeof(ib_uint32_t); - - /* FIXME: This will not work if mbminlen>4. - This field is also redundant, because the lengths - are a property of the character set encoding, which - in turn is encodedin prtype above. */ - mach_write_to_4(ptr, col->mbmaxlen * 5 + col->mbminlen); - - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, col->ind); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, col->ord_part); - ptr += sizeof(ib_uint32_t); - - mach_write_to_4(ptr, col->max_prefix); - - if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { - msg("mariabackup: Error: writing table column data."); - - return(false); - } - - /* Write out the column name as [len, byte array]. The len - includes the NUL byte. */ - ib_uint32_t len; - const char* col_name; - - col_name = dict_table_get_col_name(table, dict_col_get_no(col)); - - /* Include the NUL byte in the length. */ - len = (ib_uint32_t)strlen(col_name) + 1; - ut_a(len > 1); - - mach_write_to_4(row, len); - - if (fwrite(row, 1, sizeof(len), file) != sizeof(len) - || fwrite(col_name, 1, len, file) != len) { - - msg("mariabackup: Error: writing column name."); - - return(false); - } - } - - return(true); + return access(name.c_str(), R_OK) == 0 ; } -/*********************************************************************//** -Write the meta data config file header. -@return true in case of success otherwise false. */ -static __attribute__((nonnull, warn_unused_result)) -bool -xb_export_cfg_write_header( -/*=====================*/ - const dict_table_t* table, /*!< in: write the meta data for - this table */ - FILE* file) /*!< in: file to write to */ -{ - byte value[sizeof(ib_uint32_t)]; - - /* Write the meta-data version number. */ - mach_write_to_4(value, IB_EXPORT_CFG_VERSION_V1); - - if (fwrite(&value, 1, sizeof(value), file) != sizeof(value)) { - msg("mariabackup: Error: writing meta-data version number."); - - return(false); +/** Read file content into STL string */ +static std::string read_file_as_string(const std::string file) { + char content[FN_REFLEN]; + FILE *f = fopen(file.c_str(), "r"); + if (!f) { + msg("Can not open %s", file.c_str()); } + size_t len = fread(content, 1, FN_REFLEN, f); + fclose(f); + return std::string(content, len); +} - /* Write the server hostname. */ - ib_uint32_t len; - const char* hostname = "Hostname unknown"; - - /* The server hostname includes the NUL byte. */ - len = (ib_uint32_t)strlen(hostname) + 1; - mach_write_to_4(value, len); - - if (fwrite(&value, 1, sizeof(value), file) != sizeof(value) - || fwrite(hostname, 1, len, file) != len) { - - msg("mariabackup: Error: writing hostname."); - - return(false); +/** Delete file- Provide verbose diagnostics and exit, if operation fails. */ +static void delete_file(const std::string& file, bool if_exists = false) { + if (if_exists && !file_exists(file)) + return; + if (my_delete(file.c_str(), MYF(MY_WME))) { + die("Can't remove %s, errno %d", file.c_str(), errno); } +} - /* The table name includes the NUL byte. */ - ut_a(table->name != 0); - len = (ib_uint32_t)strlen(table->name) + 1; - - /* Write the table name. */ - mach_write_to_4(value, len); - - if (fwrite(&value, 1, sizeof(value), file) != sizeof(value) - || fwrite(table->name, 1, len, file) != len) { - - msg("mariabackup: Error: writing table name."); - - return(false); +/** +Rename tablespace during prepare. +Backup in its end phase may generate some .ren files, recording +tablespaces that should be renamed in --prepare. +*/ +static void rename_table_in_prepare(const std::string &datadir, const std::string& from , const std::string& to, + const char *extension=0) { + if (!extension) { + static const char *extensions_nonincremental[] = { ".ibd", 0 }; + static const char *extensions_incremental[] = { ".ibd.delta", ".ibd.meta", 0 }; + const char **extensions = xtrabackup_incremental_dir ? + extensions_incremental : extensions_nonincremental; + for (size_t i = 0; extensions[i]; i++) { + rename_table_in_prepare(datadir, from, to, extensions[i]); + } + return; } - - byte row[sizeof(ib_uint32_t) * 3]; - - /* Write the next autoinc value. */ - mach_write_to_8(row, table->autoinc); - - if (fwrite(row, 1, sizeof(ib_uint64_t), file) != sizeof(ib_uint64_t)) { - msg("mariabackup: Error: writing table autoinc value."); - - return(false); + std::string src = std::string(datadir) + "/" + from + extension; + std::string dest = std::string(datadir) + "/" + to + extension; + std::string ren2, tmp; + if (file_exists(dest)) { + ren2= std::string(datadir) + "/" + to + ".ren"; + if (!file_exists(ren2)) { + msg("ERROR : File %s was not found, but expected during rename processing\n", ren2.c_str()); + ut_a(0); + } + tmp = to + "#"; + rename_table_in_prepare(datadir, to, tmp); } - - byte* ptr = row; - - /* Write the system page size. */ - mach_write_to_4(ptr, UNIV_PAGE_SIZE); - ptr += sizeof(ib_uint32_t); - - /* Write the table->flags. */ - mach_write_to_4(ptr, table->flags); - ptr += sizeof(ib_uint32_t); - - /* Write the number of columns in the table. */ - mach_write_to_4(ptr, table->n_cols); - - if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { - msg("mariabackup: Error: writing table meta-data."); - - return(false); + rename_file(src, dest); + if (ren2.size()) { + // Make sure the temp. renamed file is processed. + std::string to2 = read_file_as_string(ren2); + rename_table_in_prepare(datadir, tmp, to2); + delete_file(ren2); } - - return(true); } -/*********************************************************************//** -Write MySQL 5.6-style meta data config file. -@return true in case of success otherwise false. */ -static -bool -xb_export_cfg_write( - const fil_node_t* node, - const dict_table_t* table) /*!< in: write the meta data for - this table */ -{ - char file_path[FN_REFLEN]; - FILE* file; - bool success; - - strcpy(file_path, node->name); - strcpy(file_path + strlen(file_path) - 4, ".cfg"); - - file = fopen(file_path, "w+b"); - - if (file == NULL) { - msg("mariabackup: Error: cannot open %s\n", node->name); - - success = false; - } else { +static ibool prepare_handle_ren_files(const char *datadir, const char *db, const char *filename, void *) { - success = xb_export_cfg_write_header(table, file); + std::string ren_file = std::string(datadir) + "/" + db + "/" + filename; + if (!file_exists(ren_file)) + return TRUE; - if (success) { - success = xb_export_cfg_write_table(table, file); - } - - if (success) { - success = xb_export_cfg_write_indexes(table, file); - } - - if (fclose(file) != 0) { - msg("mariabackup: Error: cannot close %s\n", node->name); - success = false; - } - - } - - return(success); + std::string to = read_file_as_string(ren_file); + std::string source_space_name = std::string(db) + "/" + filename; + source_space_name.resize(source_space_name.size() - 4); // remove extension + rename_table_in_prepare(datadir, source_space_name.c_str(), to.c_str()); + delete_file(ren_file); + return TRUE; } -static -void -innodb_free_param() -{ - srv_free_paths_and_sizes(); - free(internal_innobase_data_file_path); - internal_innobase_data_file_path = NULL; - free_tmpdir(&mysql_tmpdir_list); +/* Remove tablespaces during backup, based on */ +static ibool prepare_handle_del_files(const char *datadir, const char *db, const char *filename, void *) { + std::string del_file = std::string(datadir) + "/" + db + "/" + filename; + std::string path(del_file); + path.resize(path.size() - 4); // remove extension; + if (xtrabackup_incremental) { + delete_file(path + ".ibd.delta", true); + delete_file(path + ".ibd.meta", true); + } + else { + delete_file(path + ".ibd", true); + } + delete_file(del_file); + return TRUE; } -static void -xtrabackup_prepare_func(int argc, char ** argv) +/** Implement --prepare +@return whether the operation succeeded */ +static bool xtrabackup_prepare_func(char** argv) { - ulint err; - datafiles_iter_t *it; - fil_node_t *node; - fil_space_t *space; char metadata_path[FN_REFLEN]; /* cd to target-dir */ if (my_setwd(xtrabackup_real_target_dir,MYF(MY_WME))) { - msg("mariabackup: cannot my_setwd %s\n", - xtrabackup_real_target_dir); - exit(EXIT_FAILURE); + msg("can't my_setwd %s", xtrabackup_real_target_dir); + return(false); + } + msg("cd to %s", xtrabackup_real_target_dir); + + fil_path_to_mysql_datadir = "."; + + /* Fix DDL for prepare. Process .del,.ren, and .new files. + The order in which files are processed, is important + (see MDEV-18185, MDEV-18201) + */ + xb_process_datadir(xtrabackup_incremental_dir ? xtrabackup_incremental_dir : ".", + ".del", prepare_handle_del_files); + xb_process_datadir(xtrabackup_incremental_dir? xtrabackup_incremental_dir:".", + ".ren", prepare_handle_ren_files); + if (xtrabackup_incremental_dir) { + xb_process_datadir(xtrabackup_incremental_dir, ".new.meta", prepare_handle_new_files); + xb_process_datadir(xtrabackup_incremental_dir, ".new.delta", prepare_handle_new_files); + } + else { + xb_process_datadir(".", ".new", prepare_handle_new_files); } - msg("mariabackup: cd to %s\n", xtrabackup_real_target_dir); + int argc; for (argc = 0; argv[argc]; argc++) {} encryption_plugin_prepare_init(argc, argv); xtrabackup_target_dir= mysql_data_home_buff; xtrabackup_target_dir[0]=FN_CURLIB; // all paths are relative from here xtrabackup_target_dir[1]=0; + const lsn_t target_lsn = xtrabackup_incremental + ? incremental_to_lsn : metadata_to_lsn; /* read metadata of target @@ -5824,125 +5458,111 @@ xtrabackup_prepare_func(int argc, char ** argv) XTRABACKUP_METADATA_FILENAME); if (!xtrabackup_read_metadata(metadata_path)) { - msg("mariabackup: Error: failed to read metadata from '%s'\n", + msg("Error: failed to read metadata from '%s'\n", metadata_path); - exit(EXIT_FAILURE); + return(false); } if (!strcmp(metadata_type, "full-backuped")) { - msg("mariabackup: This target seems to be not prepared yet.\n"); + if (xtrabackup_incremental) { + msg("error: applying incremental backup " + "needs a prepared target."); + return(false); + } + msg("This target seems to be not prepared yet."); } else if (!strcmp(metadata_type, "log-applied")) { - msg("mariabackup: This target seems to be already " - "prepared with --apply-log-only.\n"); - goto skip_check; - } else if (!strcmp(metadata_type, "full-prepared")) { - msg("mariabackup: This target seems to be already prepared.\n"); + msg("This target seems to be already prepared."); } else { - msg("mariabackup: This target seems not to have correct " - "metadata...\n"); - exit(EXIT_FAILURE); + msg("This target does not have correct metadata."); + return(false); } - if (xtrabackup_incremental) { - msg("mariabackup: error: applying incremental backup " - "needs target prepared with --apply-log-only.\n"); - exit(EXIT_FAILURE); - } -skip_check: - if (xtrabackup_incremental - && metadata_to_lsn != incremental_lsn) { - msg("mariabackup: error: This incremental backup seems " - "not to be proper for the target.\n" - "mariabackup: Check 'to_lsn' of the target and " - "'from_lsn' of the incremental.\n"); - exit(EXIT_FAILURE); + bool ok = !xtrabackup_incremental + || metadata_to_lsn == incremental_lsn; + if (!ok) { + msg("error: This incremental backup seems " + "not to be proper for the target. Check 'to_lsn' of the target and " + "'from_lsn' of the incremental."); + return(false); } - /* Create logfiles for recovery from 'xtrabackup_logfile', before start InnoDB */ srv_max_n_threads = 1000; + srv_undo_logs = 1; srv_n_purge_threads = 1; - ut_mem_init(); - /* temporally dummy value to avoid crash */ - srv_page_size_shift = 14; - srv_page_size = (1 << srv_page_size_shift); - os_sync_init(); - sync_init(); - os_io_init_simple(); - mem_init(srv_mem_pool_size); - ut_crc32_init(); - -#ifdef WITH_INNODB_DISALLOW_WRITES - srv_allow_writes_event = os_event_create(); - os_event_set(srv_allow_writes_event); -#endif xb_filters_init(); - if (xtrabackup_init_temp_log()) - goto error_cleanup; + srv_log_group_home_dir = NULL; + srv_thread_concurrency = 1; - if(innodb_init_param()) { - goto error_cleanup; - } + if (xtrabackup_incremental) { + srv_operation = SRV_OPERATION_RESTORE_DELTA; - xb_normalize_init_values(); + if (innodb_init_param()) { + goto error_cleanup; + } - if (xtrabackup_incremental) { - err = xb_data_files_init(); + xb_normalize_init_values(); + sync_check_init(); + ut_d(sync_check_enable()); + ut_crc32_init(); + recv_sys_init(); + log_sys_init(); + recv_recovery_on = true; + +#ifdef WITH_INNODB_DISALLOW_WRITES + srv_allow_writes_event = os_event_create(0); + os_event_set(srv_allow_writes_event); +#endif + dberr_t err = xb_data_files_init(); if (err != DB_SUCCESS) { msg("mariabackup: error: xb_data_files_init() failed " - "with error code %lu\n", err); + "with error %s\n", ut_strerr(err)); goto error_cleanup; } - } - if (xtrabackup_incremental) { + inc_dir_tables_hash = hash_create(1000); - if(!xtrabackup_apply_deltas()) { - xb_data_files_close(); - xb_filter_hash_free(inc_dir_tables_hash); - goto error_cleanup; - } - } - if (xtrabackup_incremental) { + ok = xtrabackup_apply_deltas(); + xb_data_files_close(); - } - if (xtrabackup_incremental) { - /* Cleanup datadir from tablespaces deleted between full and - incremental backups */ - xb_process_datadir("./", ".ibd", rm_if_not_found, NULL); + if (ok) { + /* Cleanup datadir from tablespaces deleted + between full and incremental backups */ + + xb_process_datadir("./", ".ibd", rm_if_not_found); + } xb_filter_hash_free(inc_dir_tables_hash); - } - if (fil_system) { + fil_close(); +#ifdef WITH_INNODB_DISALLOW_WRITES + os_event_destroy(srv_allow_writes_event); +#endif + innodb_free_param(); + log_shutdown(); + sync_check_close(); + if (!ok) goto error_cleanup; } - mem_close(); - ut_free_all_mem(); + srv_operation = xtrabackup_export + ? SRV_OPERATION_RESTORE_EXPORT : SRV_OPERATION_RESTORE; - innodb_free_param(); - sync_close(); - sync_initialized = FALSE; - - /* Reset the configuration as it might have been changed by - xb_data_files_init(). */ - if(innodb_init_param()) { + if (innodb_init_param()) { goto error_cleanup; } - srv_apply_log_only = (bool) xtrabackup_apply_log_only; - /* increase IO threads */ - if(srv_n_file_io_threads < 10) { + if (srv_n_file_io_threads < 10) { srv_n_read_io_threads = 4; srv_n_write_io_threads = 4; } - msg("mariabackup: Starting InnoDB instance for recovery.\n" - "mariabackup: Using %lld bytes for buffer pool " - "(set by --use-memory parameter)\n", xtrabackup_use_memory); + msg("Starting InnoDB instance for recovery."); + + msg("mariabackup: Using %lld bytes for buffer pool " + "(set by --use-memory parameter)", xtrabackup_use_memory); srv_max_buf_pool_modified_pct = (double)max_buf_pool_modified_pct; @@ -5950,212 +5570,53 @@ skip_check: srv_max_dirty_pages_pct_lwm = srv_max_buf_pool_modified_pct; } - if(innodb_init()) + if (innodb_init()) { goto error_cleanup; + } - if (xtrabackup_export) { - msg("mariabackup: export option is specified.\n"); - pfs_os_file_t info_file; - char info_file_path[FN_REFLEN]; - ibool success; - char table_name[FN_REFLEN]; - - byte* page; - byte* buf = NULL; - - buf = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE * 2)); - page = static_cast<byte *>(ut_align(buf, UNIV_PAGE_SIZE)); - - /* flush insert buffer at shutdwon */ - innobase_fast_shutdown = 0; - - it = datafiles_iter_new(fil_system); - if (it == NULL) { - msg("mariabackup: Error: datafiles_iter_new() " - "failed.\n"); - exit(EXIT_FAILURE); - } - while ((node = datafiles_iter_next(it)) != NULL) { - int len; - char *next, *prev, *p; - dict_table_t* table; - dict_index_t* index; - ulint n_index; - - space = node->space; - - /* treat file_per_table only */ - if (!fil_is_user_tablespace_id(space->id)) { - continue; - } - - /* node exist == file exist, here */ - strcpy(info_file_path, node->name); -#ifdef _WIN32 - for (int i = 0; info_file_path[i]; i++) - if (info_file_path[i] == '\\') - info_file_path[i]= '/'; -#endif - strcpy(info_file_path + - strlen(info_file_path) - - 4, ".exp"); - - len =(ib_uint32_t)strlen(info_file_path); - - p = info_file_path; - prev = NULL; - while ((next = strchr(p, '/')) != NULL) - { - prev = p; - p = next + 1; - } - info_file_path[len - 4] = 0; - strncpy(table_name, prev, FN_REFLEN - 1); - table_name[FN_REFLEN - 1] = '\0'; - - info_file_path[len - 4] = '.'; - - mutex_enter(&(dict_sys->mutex)); - - table = dict_table_get_low(table_name); - if (!table) { - msg("mariabackup: error: " - "cannot find dictionary " - "record of table %s\n", - table_name); - goto next_node; - } - - /* Write MySQL 5.6 .cfg file */ - if (!xb_export_cfg_write(node, table)) { - goto next_node; - } - - index = dict_table_get_first_index(table); - n_index = UT_LIST_GET_LEN(table->indexes); - if (n_index > 31) { - msg("mariabackup: warning: table '%s' has more " - "than 31 indexes, .exp file was not " - "generated. Table will fail to import " - "on server version prior to 5.6.\n", - table->name); - goto next_node; - } - - /* init exp file */ - memset(page, 0, UNIV_PAGE_SIZE); - mach_write_to_4(page , 0x78706f72UL); - mach_write_to_4(page + 4, 0x74696e66UL);/*"xportinf"*/ - mach_write_to_4(page + 8, n_index); - strncpy((char *) page + 12, table_name, FN_REFLEN); - - msg("mariabackup: export metadata of " - "table '%s' to file `%s` " - "(%lu indexes)\n", - table_name, info_file_path, - n_index); - - n_index = 1; - while (index) { - mach_write_to_8(page + n_index * 512, index->id); - mach_write_to_4(page + n_index * 512 + 8, - index->page); - strncpy((char *) page + n_index * 512 + - 12, index->name, 500); - - msg("mariabackup: name=%s, " - "id.low=%lu, page=%lu\n", - index->name, - (ulint)(index->id & - 0xFFFFFFFFUL), - (ulint) index->page); - index = dict_table_get_next_index(index); - n_index++; - } - - srv_normalize_path_for_win(info_file_path); - info_file = os_file_create( - 0, - info_file_path, - OS_FILE_OVERWRITE, - OS_FILE_NORMAL, OS_DATA_FILE, - &success,0); - if (!success) { - os_file_get_last_error(TRUE); - goto next_node; - } - success = os_file_write(info_file_path, - info_file, page, - 0, UNIV_PAGE_SIZE); - if (!success) { - os_file_get_last_error(TRUE); - goto next_node; - } - success = os_file_flush(info_file); - if (!success) { - os_file_get_last_error(TRUE); - goto next_node; - } -next_node: - if (info_file != XB_FILE_UNDEFINED) { - os_file_close(info_file); - info_file = XB_FILE_UNDEFINED; - } - mutex_exit(&(dict_sys->mutex)); + if (ok) { + mtr_t mtr; + mtr.start(); + const trx_sysf_t* sys_header = trx_sysf_get(&mtr); + + if (mach_read_from_4(TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD + + sys_header) + == TRX_SYS_MYSQL_LOG_MAGIC_N) { + ulonglong pos = mach_read_from_8( + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET + + sys_header); + const char* name = reinterpret_cast<const char*>( + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME + + sys_header); + msg("Last binlog file %s, position %llu", name, pos); } - ut_free(buf); + mtr.commit(); } - /* print the binary log position */ - trx_sys_print_mysql_binlog_offset(); - msg("\n"); - /* Check whether the log is applied enough or not. */ - if ((xtrabackup_incremental - && srv_start_lsn < incremental_to_lsn) - ||(!xtrabackup_incremental - && srv_start_lsn < metadata_to_lsn)) { + if ((srv_start_lsn || fil_space_get(SRV_LOG_SPACE_FIRST_ID)) + && srv_start_lsn < target_lsn) { msg("mariabackup: error: " - "The transaction log file is corrupted.\n" - "mariabackup: error: " - "The log was not applied to the intended LSN!\n"); - msg("mariabackup: Log applied to lsn " LSN_PF "\n", - srv_start_lsn); - if (xtrabackup_incremental) { - msg("mariabackup: The intended lsn is " LSN_PF "\n", - incremental_to_lsn); - } else { - msg("mariabackup: The intended lsn is " LSN_PF "\n", - metadata_to_lsn); - } - exit(EXIT_FAILURE); + "The log was only applied up to LSN " LSN_PF + ", instead of " LSN_PF, + srv_start_lsn, target_lsn); + ok = false; } #ifdef WITH_WSREP - xb_write_galera_info(xtrabackup_incremental); + else if (ok) xb_write_galera_info(xtrabackup_incremental); #endif - innodb_end(); - - innodb_free_param(); - - sync_initialized = FALSE; - - /* re-init necessary components */ - ut_mem_init(); - os_sync_init(); - sync_init(); - os_io_init_simple(); - - if(xtrabackup_close_temp_log(TRUE)) - exit(EXIT_FAILURE); + innodb_shutdown(); + innodb_free_param(); /* output to metadata file */ - { + if (ok) { char filename[FN_REFLEN]; - strcpy(metadata_type, srv_apply_log_only ? - "log-applied" : "full-prepared"); + strcpy(metadata_type, "log-applied"); if(xtrabackup_incremental && metadata_to_lsn < incremental_to_lsn) @@ -6168,74 +5629,26 @@ next_node: if (!xtrabackup_write_metadata(filename)) { msg("mariabackup: Error: failed to write metadata " - "to '%s'\n", filename); - exit(EXIT_FAILURE); - } - - if(xtrabackup_extra_lsndir) { + "to '%s'", filename); + ok = false; + } else if (xtrabackup_extra_lsndir) { sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_METADATA_FILENAME); if (!xtrabackup_write_metadata(filename)) { msg("mariabackup: Error: failed to write " - "metadata to '%s'\n", filename); - exit(EXIT_FAILURE); + "metadata to '%s'", filename); + ok = false; } } } - if (!apply_log_finish()) { - exit(EXIT_FAILURE); - } - - sync_close(); - sync_initialized = FALSE; - if (fil_system) { - fil_close(); - } - - ut_free_all_mem(); - - /* start InnoDB once again to create log files */ - - if (!xtrabackup_apply_log_only) { - - /* xtrabackup_incremental_dir is used to indicate that - we are going to apply incremental backup. Here we already - applied incremental backup and are about to do final prepare - of the full backup */ - xtrabackup_incremental_dir = NULL; - - if(innodb_init_param()) { - goto error; - } - - srv_apply_log_only = false; - - /* increase IO threads */ - if(srv_n_file_io_threads < 10) { - srv_n_read_io_threads = 4; - srv_n_write_io_threads = 4; - } - - srv_shutdown_state = SRV_SHUTDOWN_NONE; - - if(innodb_init()) - goto error; - - innodb_end(); - innodb_free_param(); - - } - - xb_filters_free(); + if (ok) ok = apply_log_finish(); - return; + if (ok && xtrabackup_export) + ok= (prepare_export() == 0); error_cleanup: - xtrabackup_close_temp_log(FALSE); xb_filters_free(); - -error: - exit(EXIT_FAILURE); + return ok; } /************************************************************************** @@ -6257,6 +5670,169 @@ append_defaults_group(const char *group, const char *default_groups[], ut_a(appended); } +static const char* +normalize_privilege_target_name(const char* name) +{ + if (strcmp(name, "*") == 0) { + return "\\*"; + } + else { + /* should have no regex special characters. */ + ut_ad(strpbrk(name, ".()[]*+?") == 0); + } + return name; +} + +/******************************************************************//** +Check if specific privilege is granted. +Uses regexp magic to check if requested privilege is granted for given +database.table or database.* or *.* +or if user has 'ALL PRIVILEGES' granted. +@return true if requested privilege is granted, false otherwise. */ +static bool +has_privilege(const std::list<std::string> &granted, + const char* required, + const char* db_name, + const char* table_name) +{ + char buffer[1000]; + regex_t priv_re; + regmatch_t tables_regmatch[1]; + bool result = false; + + db_name = normalize_privilege_target_name(db_name); + table_name = normalize_privilege_target_name(table_name); + + int written = snprintf(buffer, sizeof(buffer), + "GRANT .*(%s)|(ALL PRIVILEGES).* ON (\\*|`%s`)\\.(\\*|`%s`)", + required, db_name, table_name); + if (written < 0 || written == sizeof(buffer) + || regcomp(&priv_re, buffer, REG_EXTENDED)) { + die("regcomp() failed for '%s'", buffer); + } + + typedef std::list<std::string>::const_iterator string_iter; + for (string_iter i = granted.begin(), e = granted.end(); i != e; ++i) { + int res = regexec(&priv_re, i->c_str(), + 1, tables_regmatch, 0); + + if (res != REG_NOMATCH) { + result = true; + break; + } + } + + xb_regfree(&priv_re); + return result; +} + +enum { + PRIVILEGE_OK = 0, + PRIVILEGE_WARNING = 1, + PRIVILEGE_ERROR = 2, +}; + +/******************************************************************//** +Check if specific privilege is granted. +Prints error message if required privilege is missing. +@return PRIVILEGE_OK if requested privilege is granted, error otherwise. */ +static +int check_privilege( + const std::list<std::string> &granted_priv, /* in: list of + granted privileges*/ + const char* required, /* in: required privilege name */ + const char* target_database, /* in: required privilege target + database name */ + const char* target_table, /* in: required privilege target + table name */ + int error = PRIVILEGE_ERROR) /* in: return value if privilege + is not granted */ +{ + if (!has_privilege(granted_priv, + required, target_database, target_table)) { + msg("%s: missing required privilege %s on %s.%s", + (error == PRIVILEGE_ERROR ? "Error" : "Warning"), + required, target_database, target_table); + return error; + } + return PRIVILEGE_OK; +} + + +/******************************************************************//** +Check DB user privileges according to the intended actions. + +Fetches DB user privileges, determines intended actions based on +command-line arguments and prints missing privileges. +May terminate application with EXIT_FAILURE exit code.*/ +static void +check_all_privileges() +{ + if (!mysql_connection) { + /* Not connected, no queries is going to be executed. */ + return; + } + + /* Fetch effective privileges. */ + std::list<std::string> granted_privileges; + MYSQL_ROW row = 0; + MYSQL_RES* result = xb_mysql_query(mysql_connection, "SHOW GRANTS", + true); + while ((row = mysql_fetch_row(result))) { + granted_privileges.push_back(*row); + } + mysql_free_result(result); + + int check_result = PRIVILEGE_OK; + + /* FLUSH TABLES WITH READ LOCK */ + if (!opt_no_lock) + { + check_result |= check_privilege( + granted_privileges, + "RELOAD", "*", "*"); + } + + if (!opt_no_lock) + { + check_result |= check_privilege( + granted_privileges, + "PROCESS", "*", "*"); + } + + /* KILL ... */ + if ((!opt_no_lock && (opt_kill_long_queries_timeout || opt_lock_ddl_per_table)) + /* START SLAVE SQL_THREAD */ + /* STOP SLAVE SQL_THREAD */ + || opt_safe_slave_backup) { + check_result |= check_privilege( + granted_privileges, + "SUPER", "*", "*", + PRIVILEGE_WARNING); + } + + /* SHOW MASTER STATUS */ + /* SHOW SLAVE STATUS */ + if (opt_galera_info || opt_slave_info + || (opt_no_lock && opt_safe_slave_backup)) { + check_result |= check_privilege(granted_privileges, + "REPLICATION CLIENT", "*", "*", + PRIVILEGE_WARNING); + } + + if (check_result & PRIVILEGE_ERROR) { + mysql_close(mysql_connection); + msg("Current privileges, as reported by 'SHOW GRANTS': "); + int n=1; + for (std::list<std::string>::const_iterator it = granted_privileges.begin(); + it != granted_privileges.end(); + it++,n++) { + msg(" %d.%s", n, it->c_str()); + } + die("Insufficient privileges"); + } +} + bool xb_init() { @@ -6270,7 +5846,7 @@ xb_init() && !opt_safe_slave_backup) { msg("Error: --slave-info is used with --no-lock but " "without --safe-slave-backup. The binlog position " - "cannot be consistent with the backup data.\n"); + "cannot be consistent with the backup data."); return(false); } @@ -6321,8 +5897,9 @@ xb_init() if (!get_mysql_vars(mysql_connection)) { return(false); } - - encryption_plugin_backup_init(mysql_connection); + if (opt_check_privileges) { + check_all_privileges(); + } history_start_time = time(NULL); } @@ -6338,7 +5915,8 @@ extern void init_signals(void); /* Messages . Avoid loading errmsg.sys file */ void setup_error_messages() { - static const char *all_msgs[ER_ERROR_LAST - ER_ERROR_FIRST +1]; + static const char *my_msgs[ERRORS_PER_RANGE]; + static const char **all_msgs[] = { my_msgs, my_msgs, my_msgs, my_msgs }; my_default_lc_messages = &my_locale_en_US; my_default_lc_messages->errmsgs->errmsgs = all_msgs; @@ -6365,29 +5943,26 @@ void setup_error_messages() }; for (int i = 0; i < (int)array_elements(all_msgs); i++) - all_msgs[i] = "Unknown error"; + all_msgs[0][i] = "Unknown error"; for (int i = 0; i < (int)array_elements(xb_msgs); i++) - all_msgs[xb_msgs[i].id - ER_ERROR_FIRST] = xb_msgs[i].fmt; + all_msgs[0][xb_msgs[i].id - ER_ERROR_FIRST] = xb_msgs[i].fmt; } -extern my_bool(*dict_check_if_skip_table)(const char* name) ; - void handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) { /* Setup some variables for Innodb.*/ - srv_xtrabackup = true; - + srv_operation = SRV_OPERATION_RESTORE; files_charset_info = &my_charset_utf8_general_ci; - dict_check_if_skip_table = check_if_skip_table; + setup_error_messages(); sys_var_init(); plugin_mutex_init(); - mysql_rwlock_init(key_rwlock_LOCK_system_variables_hash, &LOCK_system_variables_hash); + mysql_prlock_init(key_rwlock_LOCK_system_variables_hash, &LOCK_system_variables_hash); opt_stack_trace = 1; test_flags |= TEST_SIGINT; init_signals(); @@ -6396,7 +5971,7 @@ handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) my_sigset(SIGINT, SIG_DFL); #endif - sf_leaking_memory = 0; /* don't report memory leaks on early exist */ + sf_leaking_memory = 1; /* don't report memory leaks on early exist */ int i; int ho_error; @@ -6493,21 +6068,13 @@ handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) char *optend = strcend((argv)[i], '='); if (optend - argv[i] == 15 && - !strncmp(argv[i], "--defaults-file", optend - argv[i])) { - - msg("mariabackup: Error: --defaults-file " - "must be specified first on the command " - "line\n"); - exit(EXIT_FAILURE); + !strncmp(argv[i], "--defaults-file", optend - argv[i])) { + die("--defaults-file must be specified first on the command line"); } - if (optend - argv[i] == 21 && - !strncmp(argv[i], "--defaults-extra-file", - optend - argv[i])) { - - msg("mariabackup: Error: --defaults-extra-file " - "must be specified first on the command " - "line\n"); - exit(EXIT_FAILURE); + if (optend - argv[i] == 21 && + !strncmp(argv[i], "--defaults-extra-file", + optend - argv[i])) { + die("--defaults-extra-file must be specified first on the command line"); } } @@ -6554,29 +6121,49 @@ handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) if (!server_option) { msg("mariabackup: Error:" - " unknown argument: '%s'\n", opt); + " unknown argument: '%s'", opt); exit(EXIT_FAILURE); } } } } -/* ================= main =================== */ -extern my_bool(*fil_check_if_skip_database_by_path)(const char* name); +static int main_low(char** argv); +static int get_exepath(char *buf, size_t size, const char *argv0); +/* ================= main =================== */ int main(int argc, char **argv) { char **client_defaults, **server_defaults; - char cwd[FN_REFLEN]; - if (argc > 1 && (strcmp(argv[1], "--innobackupex") == 0)) + + if (get_exepath(mariabackup_exe,FN_REFLEN, argv[0])) + strncpy(mariabackup_exe,argv[0], FN_REFLEN-1); + + + if (argc > 1 ) { - argv++; - argc--; - innobackupex_mode = true; + /* In "prepare export", we need to start mysqld + Since it is not always be installed on the machine, + we start "mariabackup --mysqld", which acts as mysqld + */ + if (strcmp(argv[1], "--mysqld") == 0) + { + extern int mysqld_main(int argc, char **argv); + argc--; + argv++; + argv[0]+=2; + return mysqld_main(argc, argv); + } + if(strcmp(argv[1], "--innobackupex") == 0) + { + argv++; + argc--; + innobackupex_mode = true; + } } - - /* Setup skip fil_load_single_tablespaces callback.*/ - fil_check_if_skip_database_by_path = check_if_skip_database_by_path; + + if (argc > 1) + strncpy(orig_argv1,argv[1],sizeof(orig_argv1) -1); init_signals(); MY_INIT(argv[0]); @@ -6590,7 +6177,7 @@ int main(int argc, char **argv) if (mysql_server_init(-1, NULL, NULL)) { - exit(EXIT_FAILURE); + die("mysql_server_init() failed"); } system_charset_info = &my_charset_utf8_general_ci; @@ -6603,28 +6190,62 @@ int main(int argc, char **argv) handle_options(argc, argv, &client_defaults, &server_defaults); - int argc_server; - for (argc_server = 0; server_defaults[argc_server]; argc_server++) {} +#ifndef DBUG_OFF + if (dbug_option) { + DBUG_SET_INITIAL(dbug_option); + DBUG_SET(dbug_option); + } +#endif + + int status = main_low(server_defaults); + + backup_cleanup(); + + if (innobackupex_mode) { + ibx_cleanup(); + } + + free_defaults(client_defaults); + free_defaults(server_defaults); + +#ifndef DBUG_OFF + if (dbug_option) { + DBUG_END(); + } +#endif + + if (THR_THD) + (void) pthread_key_delete(THR_THD); + + logger.cleanup_base(); + mysql_mutex_destroy(&LOCK_error_log); - int argc_client; - for (argc_client = 0; client_defaults[argc_client]; argc_client++) {} + if (status == EXIT_SUCCESS) { + msg("completed OK!"); + } + return status; +} +static int main_low(char** argv) +{ if (innobackupex_mode) { if (!ibx_init()) { - exit(EXIT_FAILURE); + return(EXIT_FAILURE); } } - if ((!xtrabackup_print_param) && (!xtrabackup_prepare) && (strcmp(mysql_data_home, "./") == 0)) { + if (!xtrabackup_print_param && !xtrabackup_prepare + && !strcmp(mysql_data_home, "./")) { if (!xtrabackup_print_param) usage(); - msg("\nmariabackup: Error: Please set parameter 'datadir'\n"); - exit(EXIT_FAILURE); + msg("mariabackup: Error: Please set parameter 'datadir'"); + return(EXIT_FAILURE); } /* Expand target-dir, incremental-basedir, etc. */ + char cwd[FN_REFLEN]; my_getwd(cwd, sizeof(cwd), MYF(0)); my_load_path(xtrabackup_real_target_dir, @@ -6689,8 +6310,8 @@ int main(int argc, char **argv) if (error) { msg("mariabackup: value '%s' may be wrong format for " - "incremental option.\n", xtrabackup_incremental); - exit(EXIT_FAILURE); + "incremental option.", xtrabackup_incremental); + return(EXIT_FAILURE); } } else if (xtrabackup_backup && xtrabackup_incremental_basedir) { char filename[FN_REFLEN]; @@ -6699,8 +6320,8 @@ int main(int argc, char **argv) if (!xtrabackup_read_metadata(filename)) { msg("mariabackup: error: failed to read metadata from " - "%s\n", filename); - exit(EXIT_FAILURE); + "%s", filename); + return(EXIT_FAILURE); } incremental_lsn = metadata_to_lsn; @@ -6712,8 +6333,8 @@ int main(int argc, char **argv) if (!xtrabackup_read_metadata(filename)) { msg("mariabackup: error: failed to read metadata from " - "%s\n", filename); - exit(EXIT_FAILURE); + "%s", filename); + return(EXIT_FAILURE); } incremental_lsn = metadata_from_lsn; @@ -6730,30 +6351,28 @@ int main(int argc, char **argv) } if (xtrabackup_stream && !xtrabackup_backup) { - msg("Warning: --stream parameter is ignored, it only works together with --backup.\n"); + msg("Warning: --stream parameter is ignored, it only works together with --backup."); } if (!xb_init()) { - exit(EXIT_FAILURE); + return(EXIT_FAILURE); } /* --print-param */ if (xtrabackup_print_param) { - printf("%s", print_param_str.str().c_str()); - - exit(EXIT_SUCCESS); + return(EXIT_SUCCESS); } print_version(); if (xtrabackup_incremental) { - msg("incremental backup from " LSN_PF " is enabled.\n", + msg("incremental backup from " LSN_PF " is enabled.", incremental_lsn); } if (xtrabackup_export && innobase_file_per_table == FALSE) { msg("mariabackup: auto-enabling --innodb-file-per-table due to " - "the --export option\n"); + "the --export option"); innobase_file_per_table = TRUE; } @@ -6768,7 +6387,7 @@ int main(int argc, char **argv) if (xtrabackup_decrypt_decompress) num++; if (num != 1) { /* !XOR (for now) */ usage(); - exit(EXIT_FAILURE); + return(EXIT_FAILURE); } } @@ -6779,12 +6398,14 @@ int main(int argc, char **argv) #endif /* --backup */ - if (xtrabackup_backup) - xtrabackup_backup_func(); + if (xtrabackup_backup && !xtrabackup_backup_func()) { + return(EXIT_FAILURE); + } /* --prepare */ - if (xtrabackup_prepare) { - xtrabackup_prepare_func(argc_server, server_defaults); + if (xtrabackup_prepare + && !xtrabackup_prepare_func(argv)) { + return(EXIT_FAILURE); } if (xtrabackup_copy_back || xtrabackup_move_back) { @@ -6792,29 +6413,30 @@ int main(int argc, char **argv) mysql_data_home = get_default_datadir(); } if (!copy_back()) - exit(EXIT_FAILURE); + return(EXIT_FAILURE); } if (xtrabackup_decrypt_decompress && !decrypt_decompress()) { - exit(EXIT_FAILURE); + return(EXIT_FAILURE); } - backup_cleanup(); - - if (innobackupex_mode) { - ibx_cleanup(); - } - - - free_defaults(client_defaults); - free_defaults(server_defaults); + return(EXIT_SUCCESS); +} - if (THR_THD) - (void) pthread_key_delete(THR_THD); - msg_ts("completed OK!\n"); +static int get_exepath(char *buf, size_t size, const char *argv0) +{ +#ifdef _WIN32 + DWORD ret = GetModuleFileNameA(NULL, buf, size); + if (ret > 0) + return 0; +#elif defined(__linux__) + ssize_t ret = readlink("/proc/self/exe", buf, size-1); + if(ret > 0) + return 0; +#endif - exit(EXIT_SUCCESS); + return my_realpath(buf, argv0, 0); } diff --git a/extra/mariabackup/xtrabackup.h b/extra/mariabackup/xtrabackup.h index 50a2adb7b5f..c56e83f7a32 100644 --- a/extra/mariabackup/xtrabackup.h +++ b/extra/mariabackup/xtrabackup.h @@ -26,26 +26,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include "xbstream.h" #include "changed_page_bitmap.h" -#ifdef __WIN__ -#define XB_FILE_UNDEFINED INVALID_HANDLE_VALUE -#else -#define XB_FILE_UNDEFINED (-1) -#endif +struct xb_delta_info_t +{ + xb_delta_info_t(page_size_t page_size, ulint space_id) + : page_size(page_size), space_id(space_id) {} -typedef struct { - ulint page_size; - ulint zip_size; - ulint space_id; -} xb_delta_info_t; - -/* ======== Datafiles iterator ======== */ -typedef struct { - fil_system_t *system; - fil_space_t *space; - fil_node_t *node; - ibool started; - os_ib_mutex_t mutex; -} datafiles_iter_t; + page_size_t page_size; + ulint space_id; +}; /* value of the --incremental option */ extern lsn_t incremental_lsn; @@ -56,6 +44,9 @@ extern char *xtrabackup_incremental_basedir; extern char *innobase_data_home_dir; extern char *innobase_buffer_pool_filename; extern char *xb_plugin_dir; +extern char *xb_rocksdb_datadir; +extern my_bool xb_backup_rocksdb; + extern uint opt_protocol; extern ds_ctxt_t *ds_meta; extern ds_ctxt_t *ds_data; @@ -68,9 +59,7 @@ extern xb_page_bitmap *changed_page_bitmap; extern char *xtrabackup_incremental; extern my_bool xtrabackup_incremental_force_scan; -extern lsn_t metadata_from_lsn; extern lsn_t metadata_to_lsn; -extern lsn_t metadata_last_lsn; extern xb_stream_fmt_t xtrabackup_stream_fmt; extern ibool xtrabackup_stream; @@ -82,37 +71,27 @@ extern char *xtrabackup_databases_file; extern char *xtrabackup_tables_exclude; extern char *xtrabackup_databases_exclude; -extern ibool xtrabackup_compress; +extern uint xtrabackup_compress; extern my_bool xtrabackup_backup; extern my_bool xtrabackup_prepare; -extern my_bool xtrabackup_apply_log_only; extern my_bool xtrabackup_copy_back; extern my_bool xtrabackup_move_back; extern my_bool xtrabackup_decrypt_decompress; extern char *innobase_data_file_path; -extern char *innobase_doublewrite_file; -extern longlong innobase_log_file_size; -extern long innobase_log_files_in_group; extern longlong innobase_page_size; extern int xtrabackup_parallel; extern my_bool xb_close_files; extern const char *xtrabackup_compress_alg; -#ifdef __cplusplus -extern "C"{ -#endif - extern uint xtrabackup_compress_threads; - extern ulonglong xtrabackup_compress_chunk_size; -#ifdef __cplusplus -} -#endif + +extern uint xtrabackup_compress_threads; +extern ulonglong xtrabackup_compress_chunk_size; + extern my_bool xtrabackup_export; -extern char *xtrabackup_incremental_basedir; extern char *xtrabackup_extra_lsndir; -extern char *xtrabackup_incremental_dir; extern ulint xtrabackup_log_copy_interval; extern char *xtrabackup_stream_str; extern long xtrabackup_throttle; @@ -129,7 +108,8 @@ extern my_bool opt_no_backup_locks; extern my_bool opt_decompress; extern my_bool opt_remove_original; extern my_bool opt_extended_validation; -extern my_bool opt_backup_encrypted; +extern my_bool opt_encrypted_backup; +extern my_bool opt_lock_ddl_per_table; extern char *opt_incremental_history_name; extern char *opt_incremental_history_uuid; @@ -140,7 +120,6 @@ extern char *opt_host; extern char *opt_defaults_group; extern char *opt_socket; extern uint opt_port; -extern char *opt_login_path; extern char *opt_log_bin; extern const char *query_type_names[]; @@ -170,24 +149,6 @@ void xtrabackup_io_throttling(void); my_bool xb_write_delta_metadata(const char *filename, const xb_delta_info_t *info); -datafiles_iter_t *datafiles_iter_new(fil_system_t *f_system); -fil_node_t *datafiles_iter_next(datafiles_iter_t *it); -void datafiles_iter_free(datafiles_iter_t *it); - -/************************************************************************ -Initialize the tablespace memory cache and populate it by scanning for and -opening data files */ -ulint xb_data_files_init(void); - -/************************************************************************ -Destroy the tablespace memory cache. */ -void xb_data_files_close(void); - -/*********************************************************************** -Reads the space flags from a given data file and returns the compressed -page size, or 0 if the space is not compressed. */ -ulint xb_get_zip_size(fil_node_t* file); - /************************************************************************ Checks if a table specified as a name in the form "database/name" (InnoDB 5.6) or "./database/name.ibd" (InnoDB 5.5-) should be skipped from backup based on @@ -221,9 +182,6 @@ extern my_bool opt_ssl_verify_server_cert; #endif -void -xtrabackup_backup_func(void); - my_bool xb_get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -232,4 +190,8 @@ xb_get_one_option(int optid, const char* xb_get_copy_action(const char *dflt = "Copying"); +void mdl_lock_init(); +void mdl_lock_table(ulint space_id); +void mdl_unlock_all(); +bool ends_with(const char *str, const char *suffix); #endif /* XB_XTRABACKUP_H */ diff --git a/extra/perror.c b/extra/perror.c index ce072759ba7..a7bb911ccc5 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -222,7 +222,7 @@ static my_bool print_win_error_msg(DWORD error, my_bool verbose) will ignore calls to register already registered error numbers. */ -static const char **get_handler_error_messages(void) +static const char **get_handler_error_messages(int e __attribute__((unused))) { return handler_error_messages; } diff --git a/extra/resolve_stack_dump.c b/extra/resolve_stack_dump.c index 44c43eaeb90..92cd4c0de18 100644 --- a/extra/resolve_stack_dump.c +++ b/extra/resolve_stack_dump.c @@ -192,7 +192,7 @@ static my_long_addr_t read_addr(char** buf) while((c = hex_val(*p++)) != HEX_INVALID) addr = (addr << 4) + c; - *buf = p; + *buf= p-1; return addr; } @@ -203,6 +203,7 @@ static int init_sym_entry(SYM_ENTRY* se, char* buf) if (!se->addr) return -1; + buf++; while (my_isspace(&my_charset_latin1,*buf++)) /* empty */; @@ -281,32 +282,47 @@ static SYM_ENTRY* resolve_addr(uchar* addr, SYM_ENTRY* se) } +/* + Resolve anything that starts with [0x or (+0x or start of line and 0x + Skip '_end' as this is an indication of a wrong symbol (stack?) +*/ + static void do_resolve() { char buf[1024], *p; while (fgets(buf, sizeof(buf), fp_dump)) { - /* skip bracket */ - p= (p= strchr(buf, '[')) ? p+1 : buf; - /* skip space */ - while (my_isspace(&my_charset_latin1,*p)) - ++p; - - if (*p++ == '0' && *p++ == 'x') + for (p= buf ; *p ; p++) { - SYM_ENTRY se ; - uchar* addr = (uchar*)read_addr(&p); - if (resolve_addr(addr, &se)) - fprintf(fp_out, "%p %s + %d\n", addr, se.symbol, - (int) (addr - se.addr)); + int found= 0; + if (p[0] == '[' && p[1] == '0' && p[2] == 'x') + found= 3; + if (p[0] == '(' && p[1] == '+' && p[2] == '0' && p[3] == 'x') + found= 4; + + /* For stdin */ + if (p == buf && p[0] == '0' && p[1] == 'x') + found= 2; + + if (found) + { + SYM_ENTRY se ; + uchar *addr; + char *tmp= p + found; + addr= (uchar*)read_addr(&tmp); + if (resolve_addr(addr, &se) && strcmp(se.symbol, "_end")) + { + fprintf(fp_out, "%c%p %s + %d", *p, addr, se.symbol, + (int) (addr - se.addr)); + p= tmp-1; + } + else + { + fputc(*p, stdout); + } + } else - fprintf(fp_out, "%p (?)\n", addr); - - } - else - { - fputs(buf, fp_out); - continue; + fputc(*p, stdout); } } } diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h index d9850b51c76..fe9beb1356d 100644 --- a/extra/yassl/include/openssl/ssl.h +++ b/extra/yassl/include/openssl/ssl.h @@ -541,7 +541,7 @@ void MD5_Final(unsigned char*, MD5_CTX*); /* yaSSL extensions */ int SSL_set_compression(SSL*); /* turn on yaSSL zlib compression */ -char *yaSSL_ASN1_TIME_to_string(ASN1_TIME *time, char *buf, size_t len); +char *yaSSL_ASN1_TIME_to_string(const ASN1_TIME *time, char *buf, size_t len); #include "transport_types.h" diff --git a/extra/yassl/include/yassl_int.hpp b/extra/yassl/include/yassl_int.hpp index 15fd99450f7..b029f6af5f9 100644 --- a/extra/yassl/include/yassl_int.hpp +++ b/extra/yassl/include/yassl_int.hpp @@ -346,6 +346,7 @@ private: Sessions& GetSessions(); // forward singletons sslFactory& GetSSL_Factory(); Errors& GetErrors(); +bool HasErrors(); // openSSL method and context types diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp index b09a952dd81..c4adb4692be 100644 --- a/extra/yassl/src/ssl.cpp +++ b/extra/yassl/src/ssl.cpp @@ -1514,7 +1514,8 @@ int SSLeay_add_ssl_algorithms() // compatibility only void ERR_remove_state(unsigned long) { - GetErrors().Remove(); + if (HasErrors()) + GetErrors().Remove(); } @@ -1735,7 +1736,7 @@ unsigned long ERR_get_error() // end stunnel needs - char *yaSSL_ASN1_TIME_to_string(ASN1_TIME *time, char *buf, size_t len) + char *yaSSL_ASN1_TIME_to_string(const ASN1_TIME *time, char *buf, size_t len) { tm t; static const char *month_names[12]= diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp index 78e54139471..b36ccd40ac0 100644 --- a/extra/yassl/src/yassl_int.cpp +++ b/extra/yassl/src/yassl_int.cpp @@ -1694,6 +1694,11 @@ Errors& GetErrors() return *errorsInstance; } +bool HasErrors() +{ + return (errorsInstance != 0); +} + typedef Mutex::Lock Lock; diff --git a/extra/yassl/taocrypt/include/misc.hpp b/extra/yassl/taocrypt/include/misc.hpp index ebfb02a7190..8147832d28a 100644 --- a/extra/yassl/taocrypt/include/misc.hpp +++ b/extra/yassl/taocrypt/include/misc.hpp @@ -1,5 +1,6 @@ /* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -599,8 +600,8 @@ inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte* block, word16*) { return (order == BigEndianOrder) - ? block[1] | (block[0] << 8) - : block[0] | (block[1] << 8); + ? word16(block[1] | (word16(block[0]) << 8)) + : word16(block[0] | (word16(block[1]) << 8)); } inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte* block, @@ -625,7 +626,7 @@ inline void UnalignedPutWord(ByteOrder order, byte *block, byte value, block[0] = xorBlock ? (value ^ xorBlock[0]) : value; } -#define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) +#define GETBYTE(x, y) byte((x)>>(8*(y))) inline void UnalignedPutWord(ByteOrder order, byte *block, word16 value, const byte *xorBlock = 0) @@ -827,7 +828,7 @@ word ShiftWordsLeftByBits(word* r, unsigned int n, unsigned int shiftBits) inline -word ShiftWordsRightByBits(word* r, unsigned int n, unsigned int shiftBits) +word ShiftWordsRightByBits(word* r, int n, unsigned int shiftBits) { word u, carry=0; if (shiftBits) diff --git a/extra/yassl/taocrypt/include/modes.hpp b/extra/yassl/taocrypt/include/modes.hpp index db192bf7b59..71d2fd908c5 100644 --- a/extra/yassl/taocrypt/include/modes.hpp +++ b/extra/yassl/taocrypt/include/modes.hpp @@ -1,5 +1,6 @@ /* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -57,7 +58,7 @@ class Mode_BASE : public virtual_base { public: enum { MaxBlockSz = 16 }; - explicit Mode_BASE(int sz, CipherDir dir, Mode mode) + explicit Mode_BASE(unsigned sz, CipherDir dir, Mode mode) : blockSz_(sz), reg_(reinterpret_cast<byte*>(r_)), tmp_(reinterpret_cast<byte*>(t_)), dir_(dir), mode_(mode) {} @@ -67,7 +68,7 @@ public: void SetIV(const byte* iv) { memcpy(reg_, iv, blockSz_); } protected: - int blockSz_; + unsigned blockSz_; byte* reg_; byte* tmp_; diff --git a/extra/yassl/taocrypt/src/algebra.cpp b/extra/yassl/taocrypt/src/algebra.cpp index b24333befc9..f12947a71c4 100644 --- a/extra/yassl/taocrypt/src/algebra.cpp +++ b/extra/yassl/taocrypt/src/algebra.cpp @@ -218,7 +218,7 @@ struct WindowSlider exp >>= skipCount; windowBegin += skipCount; - expWindow = exp % (1 << windowSize); + expWindow = (unsigned int)(exp % (1LL << windowSize)); if (fastNegate && exp.GetBit(windowSize)) { @@ -248,7 +248,7 @@ void AbstractGroup::SimultaneousMultiply(Integer *results, const Integer &base, { exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 0)); exponents[i].FindNextWindow(); - buckets[i].resize(1<<(exponents[i].windowSize-1), Identity()); + buckets[i].resize(size_t(1)<<(exponents[i].windowSize-1), Identity()); } unsigned int expBitPosition = 0; diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp index 44ac324dfb5..6bca7eaa933 100644 --- a/extra/yassl/taocrypt/src/random.cpp +++ b/extra/yassl/taocrypt/src/random.cpp @@ -27,7 +27,6 @@ #include <time.h> #if defined(_WIN32) - #define _WIN32_WINNT 0x0400 #include <windows.h> #include <wincrypt.h> #else |