From d1e4adcf9163b09844fee09bb0e62d857dfff42b Mon Sep 17 00:00:00 2001 From: Roland Krucker Date: Mon, 29 Feb 2016 14:53:37 +0100 Subject: [PATCH 1/4] Fix incremental range start at restore. --- xtrabackup/restoration_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtrabackup/restoration_tools.py b/xtrabackup/restoration_tools.py index df395b3..73735e0 100644 --- a/xtrabackup/restoration_tools.py +++ b/xtrabackup/restoration_tools.py @@ -67,7 +67,7 @@ def restore_incremental_backups(self, incremental_archive): repository, archive_name = filesystem_utils.split_path( incremental_archive) incremental_target = int(archive_name.split('_')[1]) - for step in range(1, incremental_target + 1): + for step in range(0, incremental_target + 1): self.apply_incremental_backup(repository, step) except: self.logger.error( From 4cc8172165a72a422e8d293369cd9ee28f557a98 Mon Sep 17 00:00:00 2001 From: Roland Krucker Date: Wed, 2 Mar 2016 16:05:41 +0100 Subject: [PATCH 2/4] Add option to restore without stopping MySQL service. --- xtrabackup/restoration.py | 8 +++++++- xtrabackup/restoration_tools.py | 12 ++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/xtrabackup/restoration.py b/xtrabackup/restoration.py index 4bce256..eb95caa 100644 --- a/xtrabackup/restoration.py +++ b/xtrabackup/restoration.py @@ -11,7 +11,8 @@ [--log-file=] \ [--out-file=] \ [--backup-threads=] \ -[--uncompressed-archives] +[--uncompressed-archives] \ +[--without-stop-mysql] \ pyxtrabackup-restore (-h | --help) pyxtrabackup --version @@ -44,6 +45,10 @@ --uncompressed-archives \ Specify that the backup archives are not compressed. \ Use this option if you did backup with --no-compress. + --without-stop-mysql \ + Does not stop the server for restoration. \ +Ensure that --data-dir is defined to a directory differ from data directory of running MySQL server. + """ from docopt import docopt @@ -62,6 +67,7 @@ def main(): restore_tool.start_restoration(arguments['--base-archive'], arguments['--incremental-archive'], arguments['--tmp-dir'], + arguments['--without-stop-mysql'], arguments['--restart']) except Exception: logger = logging.getLogger(__name__) diff --git a/xtrabackup/restoration_tools.py b/xtrabackup/restoration_tools.py index 73735e0..73ec12c 100644 --- a/xtrabackup/restoration_tools.py +++ b/xtrabackup/restoration_tools.py @@ -140,14 +140,18 @@ def clean(self): filesystem_utils.delete_directory_if_exists(self.workdir) def start_restoration(self, base_archive, incremental_archive, - workdir, restart_service): + workdir, without_stop_service, restart_service): self.prepare_workdir(workdir) - self.stop_service() + if not without_stop_service: + self.stop_service() self.clean_data_dir() self.restore_base_backup(base_archive) self.restore_incremental_backups(incremental_archive) self.prepare_data_dir() self.set_data_dir_permissions() self.clean() - if restart_service: - self.start_service() + if restart_service: + if without_stop_service: + self.logger.warning('Both arguments --without-stop-mysql and --restart are used. --restart will be ignored.') + else: + self.start_service() From db77b782f7a276ec8197e608409eed2779df48ba Mon Sep 17 00:00:00 2001 From: Roland Krucker Date: Thu, 3 Mar 2016 09:02:45 +0000 Subject: [PATCH 3/4] Write all incremental backups into the directory of the base backup, independent of the date. --- xtrabackup/backup_tools.py | 4 ++-- xtrabackup/restoration_tools.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/xtrabackup/backup_tools.py b/xtrabackup/backup_tools.py index 0916bc7..3298cac 100644 --- a/xtrabackup/backup_tools.py +++ b/xtrabackup/backup_tools.py @@ -196,7 +196,7 @@ def save_incremental_data(self, incremental): def load_incremental_data(self): try: - self.base_dir = filesystem_utils.retrieve_value_from_file( + self.backup_repository = filesystem_utils.retrieve_value_from_file( '/var/tmp/pyxtrabackup-incremental', '^BASEDIR=(.*)$') self.last_lsn = filesystem_utils.retrieve_value_from_file( @@ -231,12 +231,12 @@ def start_incremental_backup(self, repository, incremental, workdir, user, password, threads): self.check_prerequisites(repository) self.prepare_workdir(workdir) - self.prepare_repository(repository, True) if incremental: self.load_incremental_data() self.prepare_archive_name(incremental, True) self.exec_incremental_backup(user, password, threads) else: + self.prepare_repository(repository, True) self.prepare_archive_name(incremental, True) self.exec_full_backup(user, password, threads) self.save_incremental_data(incremental) diff --git a/xtrabackup/restoration_tools.py b/xtrabackup/restoration_tools.py index 73ec12c..5cfba05 100644 --- a/xtrabackup/restoration_tools.py +++ b/xtrabackup/restoration_tools.py @@ -150,8 +150,9 @@ def start_restoration(self, base_archive, incremental_archive, self.prepare_data_dir() self.set_data_dir_permissions() self.clean() - if restart_service: + if restart_service: if without_stop_service: self.logger.warning('Both arguments --without-stop-mysql and --restart are used. --restart will be ignored.') else: self.start_service() + From b9fd263494ada28785780a2e81873eb4d0eee1b8 Mon Sep 17 00:00:00 2001 From: Roland Krucker Date: Thu, 3 Mar 2016 13:43:37 +0000 Subject: [PATCH 4/4] Create separate sub directories for each backup chain if there are multiple chains per day. --- xtrabackup/backup_tools.py | 19 +++++++++++++++++-- xtrabackup/filesystem_utils.py | 5 +++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/xtrabackup/backup_tools.py b/xtrabackup/backup_tools.py index 3298cac..4cd0fdc 100644 --- a/xtrabackup/backup_tools.py +++ b/xtrabackup/backup_tools.py @@ -6,7 +6,7 @@ import xtrabackup.exception as exception import xtrabackup.timer as timer import logging - +import datetime class BackupTool: @@ -56,7 +56,7 @@ def prepare_workdir(self, path): def prepare_repository(self, repository, incremental): if incremental: - sub_directory = '/INC' + sub_directory = ''.join(['/INC_', str(self.find_base_index(repository, 'INC'))]) else: sub_directory = '' try: @@ -67,6 +67,21 @@ def prepare_repository(self, repository, incremental): exc_info=self.debug) raise + def find_base_index(self, repository, sub_dir_prefix): + try: + existing_inc_dirs = filesystem_utils.get_prefixed_files_in_dir(repository, ''.join([datetime.datetime.now().strftime("%Y%m%d"), '/', sub_dir_prefix])) + max_base_index = 0 + for existing_inc_dir in existing_inc_dirs: + repo_path, inc_dir = filesystem_utils.split_path(existing_inc_dir) + base_index = int(inc_dir.split('_')[1]) + if base_index > max_base_index: + max_base_index = base_index + return max_base_index + 1 + except exception.ProgramError: + self.logger.error('Unable to find base index.', + exc_info=self.debug) + raise + def prepare_archive_name(self, incremental, incremental_cycle): if incremental: backup_prefix = ''.join(['inc_', str(self.incremental_step), '_']) diff --git a/xtrabackup/filesystem_utils.py b/xtrabackup/filesystem_utils.py index e4f77b3..283d5e9 100644 --- a/xtrabackup/filesystem_utils.py +++ b/xtrabackup/filesystem_utils.py @@ -93,3 +93,8 @@ def split_path(path): def get_prefixed_file_in_dir(directory, prefix): files = glob(''.join([directory, '/', prefix, '*'])) return files[0] + +def get_prefixed_files_in_dir(directory, prefix): + files = glob(''.join([directory, '/', prefix, '*'])) + return files +