diff options
Diffstat (limited to 'extra/mariabackup/write_filt.cc')
-rw-r--r-- | extra/mariabackup/write_filt.cc | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/extra/mariabackup/write_filt.cc b/extra/mariabackup/write_filt.cc new file mode 100644 index 00000000..052cea26 --- /dev/null +++ b/extra/mariabackup/write_filt.cc @@ -0,0 +1,236 @@ +/****************************************************** +MariaBackup: hot backup tool for InnoDB +(c) 2009-2013 Percona LLC and/or its affiliates. +Originally Created 3/3/2009 Yasufumi Kinoshita +Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, +Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. + +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; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +*******************************************************/ + +/* Page write filters implementation */ + +#include <my_global.h> +#include <my_base.h> +#include "common.h" +#include "write_filt.h" +#include "fil_cur.h" +#include "xtrabackup.h" + +/************************************************************************ +Write-through page write filter. */ +static my_bool wf_wt_init(ds_ctxt *ds_meta, + xb_write_filt_ctxt_t *ctxt, char *dst_name, + xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages); +static my_bool wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile); + +xb_write_filt_t wf_write_through = { + &wf_wt_init, + &wf_wt_process, + NULL, + NULL +}; + +/************************************************************************ +Incremental page write filter. */ +static my_bool wf_incremental_init(ds_ctxt *ds_meta, + xb_write_filt_ctxt_t *ctxt, char *dst_name, + xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages); +static my_bool wf_incremental_process(xb_write_filt_ctxt_t *ctxt, + ds_file_t *dstfile); +static my_bool wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, + ds_file_t *dstfile); +static void wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt); + +xb_write_filt_t wf_incremental = { + &wf_incremental_init, + &wf_incremental_process, + &wf_incremental_finalize, + &wf_incremental_deinit +}; + +/************************************************************************ +Initialize incremental page write filter. + +@return TRUE on success, FALSE on error. */ +static my_bool +wf_incremental_init(ds_ctxt *ds_meta, + xb_write_filt_ctxt_t *ctxt, char *dst_name, + xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages) +{ + char meta_name[FN_REFLEN]; + xb_wf_incremental_ctxt_t *cp = + &(ctxt->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 *)my_large_malloc(&cp->delta_buf_size, MYF(0)); + + if (!cp->delta_buf) { + 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); + const xb_delta_info_t info(cursor->page_size, cursor->zip_size, + cursor->space_id); + if (!xb_write_delta_metadata(ds_meta, meta_name, &info)) { + msg(cursor->thread_n,"Error: " + "failed to write meta info for %s", + cursor->rel_path); + return(FALSE); + } + + /* change the target file name, since we are only going to write + delta pages */ + strcat(dst_name, ".delta"); + + mach_write_to_4(cp->delta_buf, 0x78747261UL); /*"xtra"*/ + + cp->npages = 1; + cp->corrupted_pages = corrupted_pages; + + return(TRUE); +} + +/************************************************************************ +Run the next batch of pages through incremental page write filter. + +@return TRUE on success, FALSE on error. */ +static my_bool +wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) +{ + unsigned i; + xb_fil_cur_t *cursor = ctxt->cursor; + byte *page; + const ulint page_size = cursor->page_size; + xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt); + + for (i = 0, page = cursor->buf; i < cursor->buf_npages; + i++, page += page_size) { + + if ((!cp->corrupted_pages || + !cp->corrupted_pages->contains({cursor->node->space->id, + cursor->buf_page_no + i})) && + incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN)) + continue; + + /* Check whether TRX_SYS page has been changed */ + if (mach_read_from_4(page + FIL_PAGE_SPACE_ID) + == TRX_SYS_SPACE + && mach_read_from_4(page + FIL_PAGE_OFFSET) + == TRX_SYS_PAGE_NO) { + msg(cursor->thread_n, + "--incremental backup is impossible if " + "the server had been restarted with " + "different innodb_undo_tablespaces."); + return false; + } + + /* updated page */ + if (cp->npages == page_size / 4) { + /* flush buffer */ + if (ds_write(dstfile, cp->delta_buf, + cp->npages * page_size)) { + return(FALSE); + } + + /* clear buffer */ + memset(cp->delta_buf, 0, page_size / 4 * page_size); + /*"xtra"*/ + mach_write_to_4(cp->delta_buf, 0x78747261UL); + cp->npages = 1; + } + + mach_write_to_4(cp->delta_buf + cp->npages * 4, + cursor->buf_page_no + i); + memcpy(cp->delta_buf + cp->npages * page_size, page, + page_size); + + cp->npages++; + } + + return(TRUE); +} + +/************************************************************************ +Flush the incremental page write filter's buffer. + +@return TRUE on success, FALSE on error. */ +static my_bool +wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) +{ + xb_fil_cur_t *cursor = ctxt->cursor; + const ulint page_size = cursor->page_size; + xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt); + + if (cp->npages != page_size / 4) { + mach_write_to_4(cp->delta_buf + cp->npages * 4, 0xFFFFFFFFUL); + } + + /* Mark the final block */ + mach_write_to_4(cp->delta_buf, 0x58545241UL); /*"XTRA"*/ + + /* flush buffer */ + if (ds_write(dstfile, cp->delta_buf, cp->npages * page_size)) { + return(FALSE); + } + + return(TRUE); +} + +/************************************************************************ +Free the incremental page write filter's buffer. */ +static void +wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt) +{ + xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt); + my_large_free(cp->delta_buf, cp->delta_buf_size); +} + +/************************************************************************ +Initialize the write-through page write filter. + +@return TRUE on success, FALSE on error. */ +static my_bool +wf_wt_init(ds_ctxt *ds_meta __attribute__((unused)), + xb_write_filt_ctxt_t *ctxt, char *dst_name __attribute__((unused)), + xb_fil_cur_t *cursor, CorruptedPages *) +{ + ctxt->cursor = cursor; + + return(TRUE); +} + +/************************************************************************ +Write the next batch of pages to the destination datasink. + +@return TRUE on success, FALSE on error. */ +static my_bool +wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) +{ + xb_fil_cur_t *cursor = ctxt->cursor; + + if (ds_write(dstfile, cursor->buf, cursor->buf_read)) { + return(FALSE); + } + + return(TRUE); +} |