diff options
41 files changed, 1081 insertions, 767 deletions
diff --git a/extra/mariabackup/innobackupex.cc b/extra/mariabackup/innobackupex.cc index 1341d2c46de..aadf406334e 100644 --- a/extra/mariabackup/innobackupex.cc +++ b/extra/mariabackup/innobackupex.cc @@ -216,7 +216,7 @@ ibx_mode_t ibx_mode = IBX_MODE_BACKUP; static struct my_option ibx_long_options[] = { - {"version", 'v', "print xtrabackup version information", + {"version", 'v', "print version information", (uchar *) &opt_ibx_version, (uchar *) &opt_ibx_version, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -259,12 +259,11 @@ static struct my_option ibx_long_options[] = (uchar *) &opt_ibx_slave_info, (uchar *) &opt_ibx_slave_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"incremental", OPT_INCREMENTAL, "This option tells xtrabackup to " - "create an incremental backup, rather than a full one. It is passed " - "to the xtrabackup child process. When this option is specified, " + {"incremental", OPT_INCREMENTAL, + "Create an incremental backup, rather than a full one. When this option is specified, " "either --incremental-lsn or --incremental-basedir can also be given. " - "If neither option is given, option --incremental-basedir is passed " - "to xtrabackup by default, set to the first timestamped backup " + "If neither option is given, option --incremental-basedir is used " + "by default, set to the first timestamped backup " "directory in the backup base directory.", (uchar *) &opt_ibx_incremental, (uchar *) &opt_ibx_incremental, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -379,14 +378,14 @@ static struct my_option ibx_long_options[] = {"incremental-history-name", OPT_INCREMENTAL_HISTORY_NAME, "This option specifies the name of the backup series stored in the " "PERCONA_SCHEMA.xtrabackup_history history record to base an " - "incremental backup on. Xtrabackup will search the history table " + "incremental backup on. Backup will search the history table " "looking for the most recent (highest innodb_to_lsn), successful " "backup in the series and take the to_lsn value to use as the " "starting lsn for the incremental backup. This will be mutually " "exclusive with --incremental-history-uuid, --incremental-basedir " "and --incremental-lsn. If no valid lsn can be found (no series by " - "that name, no successful backups by that name) xtrabackup will " - "return with an error. It is used with the --incremental option.", + "that name, no successful backups by that name), " + "an error will be returned. It is used with the --incremental option.", (uchar*) &opt_ibx_incremental_history_name, (uchar*) &opt_ibx_incremental_history_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -396,8 +395,8 @@ static struct my_option ibx_long_options[] = "stored in the PERCONA_SCHEMA.xtrabackup_history to base an " "incremental backup on. --incremental-history-name, " "--incremental-basedir and --incremental-lsn. If no valid lsn can be " - "found (no success record with that uuid) xtrabackup will return " - "with an error. It is used with the --incremental option.", + "found (no success record with that uuid), an error will be returned." + " It is used with the --incremental option.", (uchar*) &opt_ibx_incremental_history_uuid, (uchar*) &opt_ibx_incremental_history_uuid, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -426,7 +425,7 @@ static struct my_option ibx_long_options[] = {"include", OPT_INCLUDE, "This option is a regular expression to be matched against table " "names in databasename.tablename format. It is passed directly to " - "xtrabackup's --tables option. See the xtrabackup documentation for " + "--tables option. See the documentation for " "details.", (uchar*) &opt_ibx_include, (uchar*) &opt_ibx_include, 0, GET_STR, @@ -476,12 +475,6 @@ static struct my_option ibx_long_options[] = (uchar*) &opt_ibx_lock_wait_threshold, 0, GET_UINT, REQUIRED_ARG, 60, 0, 0, 0, 0, 0}, - {"debug-sleep-before-unlock", OPT_DEBUG_SLEEP_BEFORE_UNLOCK, - "This is a debug-only option used by the XtraBackup test suite.", - (uchar*) &opt_ibx_debug_sleep_before_unlock, - (uchar*) &opt_ibx_debug_sleep_before_unlock, 0, GET_UINT, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"safe-slave-backup-timeout", OPT_SAFE_SLAVE_BACKUP_TIMEOUT, "How many seconds --safe-slave-backup should wait for " "Slave_open_temp_tables to become zero. (default 300)", @@ -494,22 +487,20 @@ static struct my_option ibx_long_options[] = We put them here with only purpose for them to showup in innobackupex --help output */ - {"close_files", OPT_CLOSE_FILES, "Do not keep files opened. This " - "option is passed directly to xtrabackup. Use at your own risk.", + {"close_files", OPT_CLOSE_FILES, "Do not keep files opened." + " Use at your own risk.", (uchar*) &ibx_xb_close_files, (uchar*) &ibx_xb_close_files, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"compress", OPT_COMPRESS, "This option instructs xtrabackup to " - "compress backup copies of InnoDB data files. It is passed directly " - "to the xtrabackup child process. Try 'xtrabackup --help' for more " - "details.", (uchar*) &ibx_xtrabackup_compress_alg, + {"compress", OPT_COMPRESS, "This option instructs backup to " + "compress backup copies of InnoDB data files." + , (uchar*) &ibx_xtrabackup_compress_alg, (uchar*) &ibx_xtrabackup_compress_alg, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"compress-threads", OPT_COMPRESS_THREADS, "This option specifies the number of worker threads that will be used " - "for parallel compression. It is passed directly to the xtrabackup " - "child process. Try 'xtrabackup --help' for more details.", + "for parallel compression.", (uchar*) &ibx_xtrabackup_compress_threads, (uchar*) &ibx_xtrabackup_compress_threads, 0, GET_UINT, REQUIRED_ARG, 1, 1, UINT_MAX, 0, 0, 0}, @@ -520,17 +511,15 @@ static struct my_option ibx_long_options[] = (uchar*) &ibx_xtrabackup_compress_chunk_size, 0, GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0}, - {"export", OPT_EXPORT, "This option is passed directly to xtrabackup's " - "--export option. It enables exporting individual tables for import " - "into another server. See the xtrabackup documentation for details.", + {"export", OPT_EXPORT, " enables exporting individual tables for import " + "into another server.", (uchar*) &ibx_xtrabackup_export, (uchar*) &ibx_xtrabackup_export, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"extra-lsndir", OPT_EXTRA_LSNDIR, "This option specifies the " "directory in which to save an extra copy of the " "\"xtrabackup_checkpoints\" file. The option accepts a string " - "argument. It is passed directly to xtrabackup's --extra-lsndir " - "option. See the xtrabackup documentation for details.", + "argument.", (uchar*) &ibx_xtrabackup_extra_lsndir, (uchar*) &ibx_xtrabackup_extra_lsndir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -552,7 +541,7 @@ static struct my_option ibx_long_options[] = 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"incremental-force-scan", OPT_INCREMENTAL_FORCE_SCAN, - "This options tells xtrabackup to perform full scan of data files " + "Perform full scan of data files " "for taking an incremental backup even if full changed page bitmap " "data is available to enable the backup without the full scan.", (uchar*)&ibx_xtrabackup_incremental_force_scan, @@ -578,10 +567,8 @@ static struct my_option ibx_long_options[] = 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"parallel", OPT_PARALLEL, "On backup, this option specifies the " - "number of threads the xtrabackup child process should use to back " - "up files concurrently. The option accepts an integer argument. It " - "is passed directly to xtrabackup's --parallel option. See the " - "xtrabackup documentation for details.", + "number of threads to use to back " + "up files concurrently. The option accepts an integer argument.", (uchar*) &ibx_xtrabackup_parallel, (uchar*) &ibx_xtrabackup_parallel, 0, GET_INT, REQUIRED_ARG, 1, 1, INT_MAX, 0, 0, 0}, @@ -589,23 +576,21 @@ static struct my_option ibx_long_options[] = {"stream", OPT_STREAM, "This option specifies the format in which to " "do the streamed backup. The option accepts a string argument. The " "backup will be done to STDOUT in the specified format. Currently, " - "the only supported formats are tar and mbstream/xbstream. This " - "option is passed directly to xtrabackup's --stream option.", + "the only supported formats are tar and mbstream/xbstream.", (uchar*) &ibx_xtrabackup_stream_str, (uchar*) &ibx_xtrabackup_stream_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tables-file", OPT_TABLES_FILE, "This option specifies the file in " "which there are a list of names of the form database. The option " - "accepts a string argument.table, one per line. The option is passed " - "directly to xtrabackup's --tables-file option.", + "accepts a string argument.table, one per line.", (uchar*) &ibx_xtrabackup_tables_file, (uchar*) &ibx_xtrabackup_tables_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"throttle", OPT_THROTTLE, "This option specifies a number of I/O " "operations (pairs of read+write) per second. It accepts an integer " - "argument. It is passed directly to xtrabackup's --throttle option.", + "argument.", (uchar*) &ibx_xtrabackup_throttle, (uchar*) &ibx_xtrabackup_throttle, 0, GET_LONG, REQUIRED_ARG, 0, 0, LONG_MAX, 0, 1, 0}, @@ -617,11 +602,10 @@ static struct my_option ibx_long_options[] = 0, 0, 0, 0, 0, 0}, {"use-memory", OPT_USE_MEMORY, "This option accepts a string argument " - "that specifies the amount of memory in bytes for xtrabackup to use " + "that specifies the amount of memory in bytes to use " "for crash recovery while preparing a backup. Multiples are supported " "providing the unit (e.g. 1MB, 1GB). It is used only with the option " - "--apply-log. It is passed directly to xtrabackup's --use-memory " - "option. See the xtrabackup documentation for details.", + "--apply-log.", (uchar*) &ibx_xtrabackup_use_memory, (uchar*) &ibx_xtrabackup_use_memory, 0, GET_LL, REQUIRED_ARG, 100*1024*1024L, 1024*1024L, LONGLONG_MAX, 0, @@ -643,7 +627,7 @@ static struct my_option ibx_long_options[] = static void usage(void) { - puts("Open source backup tool for InnoDB and XtraDB\n\ + puts("Open source backup tool\n\ \n\ Copyright (C) 2009-2015 Percona LLC and/or its affiliates.\n\ Portions Copyright (C) 2000, 2011, MySQL AB & Innobase Oy. All Rights Reserved.\n\ @@ -694,7 +678,7 @@ innobackupex [--decompress]\n\ \n\ DESCRIPTION\n\ \n\ -The first command line above makes a hot backup of a MySQL database.\n\ +The first command line above makes a hot backup of a database.\n\ By default it creates a backup directory (named by the current date\n\ and time) in the given backup root directory. With the --no-timestamp\n\ option it does not create a time-stamped backup directory, but it puts\n\ @@ -704,22 +688,18 @@ indexes in all databases or in all of the databases specified with the\n\ --databases option. The created backup contains .frm, .MRG, .MYD,\n\ .MYI, .MAD, .MAI, .TRG, .TRN, .ARM, .ARZ, .CSM, CSV, .opt, .par, and\n\ InnoDB data and log files. The MY.CNF options file defines the\n\ -location of the database. This command connects to the MySQL server\n\ -using the mysql client program, and runs xtrabackup as a child\n\ -process.\n\ +location of the database.\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/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\ -connect to the database server.\n\ +The BACKUP-DIR should be the path to a backup directory\n\ \n\ The --copy-back command copies data, index, and log files\n\ from the backup directory back to their original locations.\n\ The MY.CNF options file defines the original location of the database.\n\ -The BACKUP-DIR is the path to a backup directory created by xtrabackup.\n\ +The BACKUP-DIR is the path to a backup directory.\n\ \n\ The --move-back command is similar to --copy-back with the only difference that\n\ it moves files to their original locations rather than copies them. As this\n\ diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 9cead18cdec..c2f76b50af4 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -268,9 +268,6 @@ it every INNOBASE_WAKE_INTERVAL'th step. */ #define INNOBASE_WAKE_INTERVAL 32 ulong innobase_active_counter = 0; -#ifndef _WIN32 -static char *xtrabackup_debug_sync = NULL; -#endif my_bool xtrabackup_incremental_force_scan = FALSE; @@ -1063,7 +1060,7 @@ enum options_xtrabackup 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", + {"version", 'v', "print version information", (G_PTR *) &xtrabackup_version, (G_PTR *) &xtrabackup_version, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"target-dir", OPT_XTRA_TARGET_DIR, "destination directory", @@ -1360,8 +1357,8 @@ struct my_option xb_client_options[]= { "starting lsn for the incremental backup. This will be mutually " "exclusive with --incremental-history-uuid, --incremental-basedir " "and --incremental-lsn. If no valid lsn can be found (no series by " - "that name, no successful backups by that name) xtrabackup will " - "return with an error. It is used with the --incremental option.", + "that name, no successful backups by that name), an error will be returned." + " It is used with the --incremental option.", (uchar *) &opt_incremental_history_name, (uchar *) &opt_incremental_history_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -1371,8 +1368,8 @@ struct my_option xb_client_options[]= { "stored in the PERCONA_SCHEMA.xtrabackup_history to base an " "incremental backup on. --incremental-history-name, " "--incremental-basedir and --incremental-lsn. If no valid lsn can be " - "found (no success record with that uuid) xtrabackup will return " - "with an error. It is used with the --incremental option.", + "found (no success record with that uuid), an error will be returned." + " It is used with the --incremental option.", (uchar *) &opt_incremental_history_uuid, (uchar *) &opt_incremental_history_uuid, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -1429,11 +1426,6 @@ struct my_option xb_client_options[]= { (uchar *) &opt_lock_wait_threshold, (uchar *) &opt_lock_wait_threshold, 0, GET_UINT, REQUIRED_ARG, 60, 0, 0, 0, 0, 0}, - {"debug-sleep-before-unlock", OPT_DEBUG_SLEEP_BEFORE_UNLOCK, - "This is a debug-only option used by the XtraBackup test suite.", - (uchar *) &opt_debug_sleep_before_unlock, - (uchar *) &opt_debug_sleep_before_unlock, 0, GET_UINT, REQUIRED_ARG, 0, 0, - 0, 0, 0, 0}, {"safe-slave-backup-timeout", OPT_SAFE_SLAVE_BACKUP_TIMEOUT, "How many seconds --safe-slave-backup should wait for " @@ -1443,9 +1435,9 @@ struct my_option xb_client_options[]= { 0, 0, 0, 0, 0}, {"binlog-info", OPT_BINLOG_INFO, - "This option controls how XtraBackup should retrieve server's binary log " + "This option controls how backup should retrieve server's binary log " "coordinates corresponding to the backup. Possible values are OFF, ON, " - "LOCKLESS and AUTO. See the XtraBackup manual for more information", + "LOCKLESS and AUTO.", &opt_binlog_info, &opt_binlog_info, &binlog_info_typelib, GET_ENUM, OPT_ARG, BINLOG_INFO_AUTO, 0, 0, 0, 0, 0}, @@ -1615,13 +1607,6 @@ struct my_option xb_server_options[] = &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", - (G_PTR*) &xtrabackup_debug_sync, - (G_PTR*) &xtrabackup_debug_sync, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"innodb_checksum_algorithm", OPT_INNODB_CHECKSUM_ALGORITHM, "The algorithm InnoDB uses for page checksumming. [CRC32, STRICT_CRC32, " @@ -1665,7 +1650,7 @@ struct my_option xb_server_options[] = 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.", + "before backup 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}, @@ -1708,60 +1693,6 @@ struct my_option xb_server_options[] = uint xb_server_options_count = array_elements(xb_server_options); -#ifndef __WIN__ -static int debug_sync_resumed; - -static void sigcont_handler(int sig); - -static void sigcont_handler(int sig __attribute__((unused))) -{ - debug_sync_resumed= 1; -} -#endif - -static inline -void -debug_sync_point(const char *name) -{ -#ifndef __WIN__ - FILE *fp; - pid_t pid; - char pid_path[FN_REFLEN]; - - if (xtrabackup_debug_sync == NULL) { - return; - } - - if (strcmp(xtrabackup_debug_sync, name)) { - return; - } - - pid = getpid(); - - snprintf(pid_path, sizeof(pid_path), "%s/xtrabackup_debug_sync", - xtrabackup_target_dir); - fp = fopen(pid_path, "w"); - if (fp == NULL) { - 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'.", name, (uint) pid); - - debug_sync_resumed= 0; - kill(pid, SIGSTOP); - while (!debug_sync_resumed) { - sleep(1); - } - - /* On resume */ - msg("mariabackup: DEBUG: removing the pid file."); - my_delete(pid_path, MYF(MY_WME)); -#endif -} - static std::set<std::string> tables_for_export; @@ -3108,8 +3039,6 @@ static bool xtrabackup_copy_logfile(bool last = false) log_copy_scanned_lsn = start_lsn; pthread_cond_broadcast(&scanned_lsn_cond); pthread_mutex_unlock(&backup_mutex); - - debug_sync_point("xtrabackup_copy_logfile_pause"); return(false); } @@ -3241,8 +3170,6 @@ DECLARE_THREAD(data_copy_thread_func)( */ my_thread_init(); - debug_sync_point("data_copy_thread_func"); - while ((node = datafiles_iter_next(ctxt->it)) != NULL) { DBUG_MARIABACKUP_EVENT("before_copy", node->space->name); DBUG_EXECUTE_FOR_KEY("wait_innodb_redo_before_copy", node->space->name, @@ -3995,8 +3922,6 @@ xb_load_tablespaces() if (err != DB_SUCCESS) { return(err); } - - debug_sync_point("xtrabackup_load_tablespaces_pause"); DBUG_MARIABACKUP_EVENT("after_load_tablespaces", 0); return(DB_SUCCESS); } @@ -4830,8 +4755,6 @@ fail_before_log_copying_thread_start: if (!flush_changed_page_bitmaps()) { goto fail; } - debug_sync_point("xtrabackup_suspend_at_start"); - ut_a(xtrabackup_parallel > 0); @@ -7132,12 +7055,6 @@ static int main_low(char** argv) } } -#ifndef __WIN__ - if (xtrabackup_debug_sync) { - signal(SIGCONT, sigcont_handler); - } -#endif - /* --backup */ if (xtrabackup_backup && !xtrabackup_backup_func()) { return(EXIT_FAILURE); diff --git a/mysql-test/lib/My/SafeProcess.pm b/mysql-test/lib/My/SafeProcess.pm index 19f2893ea51..b5a7660ed3e 100644 --- a/mysql-test/lib/My/SafeProcess.pm +++ b/mysql-test/lib/My/SafeProcess.pm @@ -622,7 +622,7 @@ sub self2str { sub _verbose { return unless $_verbose; - print STDERR " ## ". @_. "\n"; + print STDERR " ## @_\n"; } diff --git a/mysql-test/main/delete_use_source.result b/mysql-test/main/delete_use_source.result index 22972d0aa4a..0990a551db6 100644 --- a/mysql-test/main/delete_use_source.result +++ b/mysql-test/main/delete_use_source.result @@ -65,8 +65,8 @@ rollback; start transaction; explain delete from v1 where (select count(*) from t1 b where b.c1=v1.c1) = 500; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL c1 NULL NULL NULL 670 Using where -2 DEPENDENT SUBQUERY b ref c1 c1 4 test.t1.c1 167 Using index +1 PRIMARY t1 ALL c1 NULL NULL NULL # Using where +2 DEPENDENT SUBQUERY b ref c1 c1 4 test.t1.c1 # Using index delete from v1 where (select count(*) from t1 b where b.c1=v1.c1) = 500 ; affected rows: 500 select count(*) from v1 where c1=0; diff --git a/mysql-test/main/delete_use_source.test b/mysql-test/main/delete_use_source.test index ed4c62b090c..4aed00da375 100644 --- a/mysql-test/main/delete_use_source.test +++ b/mysql-test/main/delete_use_source.test @@ -64,6 +64,7 @@ rollback; --echo # start transaction; +--replace_column 9 # explain delete from v1 where (select count(*) from t1 b where b.c1=v1.c1) = 500; --enable_info ONCE delete from v1 where (select count(*) from t1 b where b.c1=v1.c1) = 500 ; diff --git a/mysql-test/main/lock_kill.result b/mysql-test/main/lock_kill.result new file mode 100644 index 00000000000..727dd66da7f --- /dev/null +++ b/mysql-test/main/lock_kill.result @@ -0,0 +1,36 @@ +# +# MDEV-17749 Kill during LOCK TABLE ; ALTER TABLE causes assert +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +connect con1,localhost,root,,test; +LOCK TABLE t1 WRITE; +ALTER TABLE t1 ADD COLUMN b INT; +connection default; +Killing connection +connection con1; +connection default; +disconnect con1; +DROP TABLE t1; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +connect con1,localhost,root,,test; +LOCK TABLE t1 WRITE, t2 WRITE; +ALTER TABLE t1 ADD COLUMN b INT; +connection default; +Killing connection +connection con1; +connection default; +disconnect con1; +DROP TABLE t1, t2; +CREATE TABLE t1 (id int(11)) ENGINE=InnoDB; +LOCK TABLES t1 WRITE; +SET max_statement_time= 0.0001; +CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); +SET max_statement_time= default; +DROP TRIGGER IF EXISTS trg16; +Warnings: +Note 1360 Trigger does not exist +DROP TABLE t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/main/lock_kill.test b/mysql-test/main/lock_kill.test new file mode 100644 index 00000000000..d0b83fe1413 --- /dev/null +++ b/mysql-test/main/lock_kill.test @@ -0,0 +1,59 @@ +--source include/have_innodb.inc + +# This test file is for testing killing of queries that are under LOCK TABLES + +--echo # +--echo # MDEV-17749 Kill during LOCK TABLE ; ALTER TABLE causes assert +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +--connect (con1,localhost,root,,test) +LOCK TABLE t1 WRITE; +--let $conid= `SELECT CONNECTION_ID()` +--send ALTER TABLE t1 ADD COLUMN b INT +--connection default +--disable_query_log +--echo Killing connection +eval KILL $conid; +--enable_query_log +--connection con1 +--error 0,2013 +reap; +--connection default +--disconnect con1 +DROP TABLE t1; + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +--connect (con1,localhost,root,,test) +LOCK TABLE t1 WRITE, t2 WRITE; +--let $conid= `SELECT CONNECTION_ID()` +--send ALTER TABLE t1 ADD COLUMN b INT +--connection default +--disable_query_log +--echo Killing connection +eval KILL $conid; +--enable_query_log +--connection con1 +--error 0,2013 +reap; +--connection default +--disconnect con1 +DROP TABLE t1, t2; + +# Similar test for CREATE TRIGGER, which also failed + +CREATE TABLE t1 (id int(11)) ENGINE=InnoDB; +LOCK TABLES t1 WRITE; +SET max_statement_time= 0.0001; +--error 0,1969 +--disable_warnings +CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); +--enable_warnings +SET max_statement_time= default; +DROP TRIGGER IF EXISTS trg16; +DROP TABLE t1; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index 5a436ec5196..3df72cf24f7 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5555,6 +5555,24 @@ Note 1003 /* select#1 */ select (/* select#2 */ select 1 from `test`.`t2` where DEALLOCATE PREPARE stmt; DROP TABLE t1, t2; # +# MDEV-25576: The statement EXPLAIN running as regular statement and +# as prepared statement produces different results for +# UPDATE with subquery +# +CREATE TABLE t1 (c1 INT KEY) ENGINE=MyISAM; +CREATE TABLE t2 (c2 INT) ENGINE=MyISAM; +CREATE TABLE t3 (c3 INT) ENGINE=MyISAM; +EXPLAIN EXTENDED UPDATE t3 SET c3 = ( SELECT COUNT(d1.c1) FROM ( SELECT a11.c1 FROM t1 AS a11 STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1 JOIN t1 AS a12 ON a12.c1 = a11.c1 ) d1 ); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 0 100.00 +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +PREPARE stmt FROM "EXPLAIN EXTENDED UPDATE t3 SET c3 = ( SELECT COUNT(d1.c1) FROM ( SELECT a11.c1 FROM t1 AS a11 STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1 JOIN t1 AS a12 ON a12.c1 = a11.c1 ) d1 )"; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t3 ALL NULL NULL NULL NULL 0 100.00 +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2, t3; # End of 10.2 tests # # diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index 2a468d33ace..837fa6f2b6e 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -4975,7 +4975,21 @@ SHOW WARNINGS; DEALLOCATE PREPARE stmt; DROP TABLE t1, t2; + +--echo # +--echo # MDEV-25576: The statement EXPLAIN running as regular statement and +--echo # as prepared statement produces different results for +--echo # UPDATE with subquery --echo # +CREATE TABLE t1 (c1 INT KEY) ENGINE=MyISAM; +CREATE TABLE t2 (c2 INT) ENGINE=MyISAM; +CREATE TABLE t3 (c3 INT) ENGINE=MyISAM; +EXPLAIN EXTENDED UPDATE t3 SET c3 = ( SELECT COUNT(d1.c1) FROM ( SELECT a11.c1 FROM t1 AS a11 STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1 JOIN t1 AS a12 ON a12.c1 = a11.c1 ) d1 ); +PREPARE stmt FROM "EXPLAIN EXTENDED UPDATE t3 SET c3 = ( SELECT COUNT(d1.c1) FROM ( SELECT a11.c1 FROM t1 AS a11 STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1 JOIN t1 AS a12 ON a12.c1 = a11.c1 ) d1 )"; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2, t3; + --echo # End of 10.2 tests --echo # diff --git a/mysql-test/suite/galera/t/galera_ist_mariabackup.cnf b/mysql-test/suite/galera/t/galera_ist_mariabackup.cnf index 2392071ccfe..f03527dc808 100644 --- a/mysql-test/suite/galera/t/galera_ist_mariabackup.cnf +++ b/mysql-test/suite/galera/t/galera_ist_mariabackup.cnf @@ -12,4 +12,4 @@ wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true' [sst] transferfmt=@ENV.MTR_GALERA_TFMT -streamfmt=xbstream +streamfmt=mbstream diff --git a/mysql-test/suite/galera/t/galera_ist_mariabackup_innodb_flush_logs.cnf b/mysql-test/suite/galera/t/galera_ist_mariabackup_innodb_flush_logs.cnf index e98f37654cc..e4f52aaad0a 100644 --- a/mysql-test/suite/galera/t/galera_ist_mariabackup_innodb_flush_logs.cnf +++ b/mysql-test/suite/galera/t/galera_ist_mariabackup_innodb_flush_logs.cnf @@ -14,4 +14,3 @@ wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true' [sst] transferfmt=@ENV.MTR_GALERA_TFMT -streamfmt=xbstream diff --git a/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf b/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf index 357c8678658..807829f047f 100644 --- a/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf +++ b/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf @@ -8,5 +8,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true' [mysqld.2] wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true' - - diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf index be2ca0d1f09..857a4101406 100644 --- a/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf @@ -13,4 +13,4 @@ wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore [sst] transferfmt=@ENV.MTR_GALERA_TFMT -streamfmt=xbstream +streamfmt=mbstream diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_qpress.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup_qpress.cnf index 0dba13ecffd..e99c819d2e8 100644 --- a/mysql-test/suite/galera/t/galera_sst_mariabackup_qpress.cnf +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_qpress.cnf @@ -10,3 +10,4 @@ transferfmt=@ENV.MTR_GALERA_TFMT compress=quicklz compress-threads=2 compress-chunk-size=32768 +backup-threads=2 diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf index a5c269b74e2..4c57017299f 100644 --- a/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_table_options.cnf @@ -15,4 +15,4 @@ wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore [sst] transferfmt=@ENV.MTR_GALERA_TFMT -streamfmt=xbstream +streamfmt=mbstream diff --git a/mysql-test/suite/galera/t/galera_sst_rsync.cnf b/mysql-test/suite/galera/t/galera_sst_rsync.cnf index 93981d9daa7..29d3a1e6219 100644 --- a/mysql-test/suite/galera/t/galera_sst_rsync.cnf +++ b/mysql-test/suite/galera/t/galera_sst_rsync.cnf @@ -8,4 +8,3 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore [mysqld.2] wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true' - diff --git a/mysql-test/suite/galera/t/galera_sst_rsync2.cnf b/mysql-test/suite/galera/t/galera_sst_rsync2.cnf index 34e67c66403..0159596f99b 100644 --- a/mysql-test/suite/galera/t/galera_sst_rsync2.cnf +++ b/mysql-test/suite/galera/t/galera_sst_rsync2.cnf @@ -12,4 +12,3 @@ log_bin_index=@ENV.MYSQLTEST_VARDIR/tmp/server1_binlog_index.index wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true' log_bin=@ENV.MYSQLTEST_VARDIR/server2_binlog log_bin_index=@ENV.MYSQLTEST_VARDIR/tmp/server2_binlog_index.index - diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_data_dir.cnf b/mysql-test/suite/galera/t/galera_sst_rsync_data_dir.cnf index afe9796a11a..4cc3442bd87 100644 --- a/mysql-test/suite/galera/t/galera_sst_rsync_data_dir.cnf +++ b/mysql-test/suite/galera/t/galera_sst_rsync_data_dir.cnf @@ -9,3 +9,6 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore [mysqld.2] innodb_data_home_dir=@ENV.MYSQL_TMP_DIR/rsync_test_2 wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true' + +[sst] +backup_threads=2 diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf index 8432b1c368c..3b0f0173b35 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf @@ -34,4 +34,3 @@ bind-address=:: [SST] transferfmt=@ENV.MTR_GALERA_TFMT streamfmt=xbstream -sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf index aa3da690416..a3ab9a85707 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf @@ -38,4 +38,5 @@ bind-address=:: [SST] transferfmt=@ENV.MTR_GALERA_TFMT streamfmt=xbstream +# Not needed, but left here for debugging: sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf index 5e77a45210b..c163f798335 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf @@ -24,6 +24,3 @@ wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast. wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' bind-address=:: - -[SST] -sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf index 5e77a45210b..c163f798335 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf @@ -24,6 +24,3 @@ wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast. wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' bind-address=:: - -[SST] -sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf index 809b83bb782..ee92efeff1d 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf @@ -29,6 +29,3 @@ wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast. wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' bind-address=:: - -[SST] -sockopt=",pf=ip6" diff --git a/mysql-test/suite/innodb_gis/r/gis.result b/mysql-test/suite/innodb_gis/r/gis.result index ef56baadd9d..acc65e86a59 100644 --- a/mysql-test/suite/innodb_gis/r/gis.result +++ b/mysql-test/suite/innodb_gis/r/gis.result @@ -1480,9 +1480,20 @@ FROM buildings, bridges WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; count(*) 1 -DROP DATABASE gis_ogs; # # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE # SELECT ST_Union('', ''), md5(1); ERROR HY000: Illegal parameter data type varchar for operation 'st_union' +# +# MDEV-25758 InnoDB spatial indexes miss large geometry +# fields after MDEV-25459 +# +CREATE TABLE t1(l LINESTRING NOT NULL, SPATIAL INDEX(l))ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SELECT GROUP_CONCAT(CONCAT(seq, ' ', seq) SEPARATOR ',') INTO @g FROM seq_0_to_190; +INSERT INTO t1 SET l=ST_GeomFromText(CONCAT('LINESTRING(',@g,',0 0)')); +SELECT COUNT(*) FROM t1 WHERE MBRIntersects(GeomFromText('Polygon((0 0,0 10,10 10,10 0,0 0))'), l); +COUNT(*) +1 +DROP TABLE t1; +DROP DATABASE gis_ogs; diff --git a/mysql-test/suite/innodb_gis/t/gis.test b/mysql-test/suite/innodb_gis/t/gis.test index 629bb94b8c5..851e82308c6 100644 --- a/mysql-test/suite/innodb_gis/t/gis.test +++ b/mysql-test/suite/innodb_gis/t/gis.test @@ -2,6 +2,7 @@ --source include/have_innodb.inc -- source include/have_geometry.inc +--source include/have_sequence.inc SET default_storage_engine=InnoDB; @@ -1424,11 +1425,21 @@ WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; #FROM lakes #WHERE lakes.name = 'Blue Lake'; -DROP DATABASE gis_ogs; - --echo # --echo # Bug#13362660 ASSERTION `FIELD_POS < FIELD_COUNT' FAILED. IN PROTOCOL_TEXT::STORE --echo # --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION SELECT ST_Union('', ''), md5(1); + +--echo # +--echo # MDEV-25758 InnoDB spatial indexes miss large geometry +--echo # fields after MDEV-25459 +--echo # +CREATE TABLE t1(l LINESTRING NOT NULL, SPATIAL INDEX(l))ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SELECT GROUP_CONCAT(CONCAT(seq, ' ', seq) SEPARATOR ',') INTO @g FROM seq_0_to_190; +INSERT INTO t1 SET l=ST_GeomFromText(CONCAT('LINESTRING(',@g,',0 0)')); +SELECT COUNT(*) FROM t1 WHERE MBRIntersects(GeomFromText('Polygon((0 0,0 10,10 10,10 0,0 0))'), l); +DROP TABLE t1; + +DROP DATABASE gis_ogs; diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 952a37f75d2..05944ef6035 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -29,7 +29,9 @@ WSREP_SST_OPT_USER="${WSREP_SST_OPT_USER:-}" WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_PSWD:-}" WSREP_SST_OPT_REMOTE_AUTH="${WSREP_SST_OPT_REMOTE_AUTH:-}" WSREP_SST_OPT_DEFAULT="" +WSREP_SST_OPT_DEFAULTS="" WSREP_SST_OPT_EXTRA_DEFAULT="" +WSREP_SST_OPT_EXTRA_DEFAULTS="" WSREP_SST_OPT_SUFFIX_DEFAULT="" WSREP_SST_OPT_SUFFIX_VALUE="" WSREP_SST_OPT_MYSQLD="" @@ -152,10 +154,12 @@ case "$1" in ;; '--defaults-file') readonly WSREP_SST_OPT_DEFAULT="$1=$2" + readonly WSREP_SST_OPT_DEFAULTS="$1='$2'" shift ;; '--defaults-extra-file') readonly WSREP_SST_OPT_EXTRA_DEFAULT="$1=$2" + readonly WSREP_SST_OPT_EXTRA_DEFAULTS="$1='$2'" shift ;; '--defaults-group-suffix') @@ -295,7 +299,7 @@ case "$1" in value="$1" fi fi - if [ $option == 'h' ]; then + if [ $option = 'h' ]; then if [ -z "$WSREP_SST_OPT_DATA" ]; then MYSQLD_OPT_DATADIR="${value%/}" fi @@ -611,24 +615,54 @@ else MYSQLDUMP="$(command -v mysqldump)" fi +wsrep_log() +{ + # echo everything to stderr so that it gets into common error log + # deliberately made to look different from the rest of the log + local readonly tst="$(date +%Y%m%d\ %H:%M:%S.%N | cut -b -21)" + echo "WSREP_SST: $* ($tst)" >&2 +} + +wsrep_log_error() +{ + wsrep_log "[ERROR] $*" +} + +wsrep_log_warning() +{ + wsrep_log "[WARNING] $*" +} + +wsrep_log_info() +{ + wsrep_log "[INFO] $*" +} + if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then MY_PRINT_DEFAULTS="$SCRIPTS_DIR/my_print_defaults" elif [ -x "$EXTRA_DIR/my_print_defaults" ]; then MY_PRINT_DEFAULTS="$EXTRA_DIR/my_print_defaults" else MY_PRINT_DEFAULTS="$(command -v my_print_defaults)" + if [ -z "$MY_PRINT_DEFAULTS" ]; then + wsrep_log_error "my_print_defaults not found in path" + exit 2 + fi fi +readonly MY_PRINT_DEFAULTS + +wsrep_defaults="$WSREP_SST_OPT_DEFAULTS" +wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_EXTRA_DEFAULTS" +wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT" + +readonly WSREP_SST_OPT_CONF="$wsrep_defaults" + wsrep_defaults="$WSREP_SST_OPT_DEFAULT" -if [ -n "$wsrep_defaults" ]; then - wsrep_defaults="$wsrep_defaults " -fi -wsrep_defaults="$wsrep_defaults$WSREP_SST_OPT_EXTRA_DEFAULT" -if [ -n "$wsrep_defaults" ]; then - wsrep_defaults="$wsrep_defaults " -fi -readonly WSREP_SST_OPT_CONF="$wsrep_defaults$WSREP_SST_OPT_SUFFIX_DEFAULT" -readonly MY_PRINT_DEFAULTS="$MY_PRINT_DEFAULTS $WSREP_SST_OPT_CONF" +wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_EXTRA_DEFAULT" +wsrep_defaults="$wsrep_defaults${wsrep_defaults:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT" + +readonly WSREP_SST_OPT_CONF_UNQUOTED="$wsrep_defaults" # # User can specify mariabackup specific settings that will be used during sst @@ -663,13 +697,21 @@ parse_cnf() # If the group name is the same as the "mysqld" without "--" prefix, # then try to use it together with the group suffix: if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then - reval=$($MY_PRINT_DEFAULTS "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern") + reval=$("$MY_PRINT_DEFAULTS" \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern") if [ -n "$reval" ]; then break fi fi # Let's try to use the group name as it is: - reval=$($MY_PRINT_DEFAULTS "$group" | awk "$pattern") + reval=$("$MY_PRINT_DEFAULTS" \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "$group" | awk "$pattern") if [ -n "$reval" ]; then break fi @@ -710,13 +752,21 @@ in_config() # If the group name is the same as the "mysqld" without "--" prefix, # then try to use it together with the group suffix: if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then - found=$($MY_PRINT_DEFAULTS "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern") + found=$("$MY_PRINT_DEFAULTS" \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern") if [ $found -ne 0 ]; then break fi fi # Let's try to use the group name as it is: - found=$($MY_PRINT_DEFAULTS "$group" | awk "$pattern") + found=$($MY_PRINT_DEFAULTS \ + ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \ + ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \ + ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \ + "$group" | awk "$pattern") if [ $found -ne 0 ]; then break fi @@ -797,29 +847,6 @@ else SST_PROGRESS_FILE="" fi -wsrep_log() -{ - # echo everything to stderr so that it gets into common error log - # deliberately made to look different from the rest of the log - local readonly tst="$(date +%Y%m%d\ %H:%M:%S.%N | cut -b -21)" - echo "WSREP_SST: $* ($tst)" >&2 -} - -wsrep_log_error() -{ - wsrep_log "[ERROR] $*" -} - -wsrep_log_warning() -{ - wsrep_log "[WARNING] $*" -} - -wsrep_log_info() -{ - wsrep_log "[INFO] $*" -} - wsrep_cleanup_progress_file() { [ -n "$SST_PROGRESS_FILE" -a \ @@ -960,35 +987,139 @@ check_sockets_utils() } # +# Check if the port is in the "listen" state. +# The first parameter is the PID of the process that should +# listen on the port - if it is not known, you can specify +# an empty string or zero. +# The second parameter is the port number. +# The third parameter is a list of the names of utilities +# (via "|") that can listen on this port during the state +# transfer. +# +check_port() +{ + local pid="$1" + local port="$2" + local utils="$3" + + [ -z "$pid" ] || [ $pid -eq 0 ] && pid='[0-9]+' + + local rc=1 + + if [ $lsof_available -ne 0 ]; then + lsof -Pnl -i ":$port" 2>/dev/null | \ + grep -q -E "^($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*\\(LISTEN\\)" && rc=0 + elif [ $sockstat_available -ne 0 ]; then + sockstat -p "$port" 2>/dev/null | \ + grep -q -E "[[:space:]]+($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*[[:space:]]LISTEN" && rc=0 + elif [ $ss_available -ne 0 ]; then + ss -nlpH "( sport = :$port )" 2>/dev/null | \ + grep -q -E "users:\\(.*\\(\"($utils)[^[:space:]]*\"[^)]*,pid=$pid(,[^)]*)?\\)" && rc=0 + else + wsrep_log_error "unknown sockets utility" + exit 2 # ENOENT + fi + + return $rc +} + +# # If the ssl_dhparams variable is already set, uses that as a source # of dh parameters for OpenSSL. Otherwise, looks for dhparams.pem in # the datadir, and creates it there if it can't find the file. # check_for_dhparams() { - if [ -z "$ssl_dhparams" ]; then - ssl_dhparams="$DATA/dhparams.pem" - if [ ! -r "$ssl_dhparams" ]; then - get_openssl - if [ -n "$OPENSSL_BINARY" ]; then - wsrep_log_info "Could not find dhparams file, creating $ssl_dhparams" - if ! "$OPENSSL_BINARY" dhparam -out "$ssl_dhparams" 2048 >/dev/null 2>&1 - then - wsrep_log_error "******** ERROR *****************************************" - wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *" - wsrep_log_error "********************************************************" - ssl_dhparams="" - fi - else - # Rollback: if openssl is not installed, then use - # the default parameters: + ssl_dhparams="$DATA/dhparams.pem" + if [ ! -r "$ssl_dhparams" ]; then + get_openssl + if [ -n "$OPENSSL_BINARY" ]; then + wsrep_log_info "Could not find dhparams file, creating $ssl_dhparams" + if ! "$OPENSSL_BINARY" dhparam -out "$ssl_dhparams" 2048 >/dev/null 2>&1 + then + wsrep_log_error "******** ERROR *****************************************" + wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *" + wsrep_log_error "********************************************************" ssl_dhparams="" - fi + fi + else + # Rollback: if openssl is not installed, then use + # the default parameters: + ssl_dhparams="" fi fi } # +# Verifies that the CA file verifies the certificate. +# Doing this here lets us generate better error messages. +# +# 1st param: path to the CA file. +# 2nd param: path to the certificate. +# +verify_ca_matches_cert() +{ + local ca_path="$1" + local cert_path="$2" + + # If the openssl utility is not installed, then + # we will not do this certificate check: + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + return + fi + + if ! "$OPENSSL_BINARY" verify -verbose -CAfile "$ca_path" "$cert_path" >/dev/null 2>&1 + then + wsrep_log_error "******** FATAL ERROR ********************************************" + wsrep_log_error "* The certifcate and CA (certificate authority) do not match. *" + wsrep_log_error "* It does not appear that the certificate was issued by the CA. *" + wsrep_log_error "* Please check your certificate and CA files. *" + wsrep_log_error "*****************************************************************" + exit 22 + fi +} + +# +# Verifies that the certificate matches the private key. +# Doing this will save us having to wait for a timeout that would +# otherwise occur. +# +# 1st param: path to the certificate. +# 2nd param: path to the private key. +# +verify_cert_matches_key() +{ + local cert_path="$1" + local key_path="$2" + + # If the diff utility is not installed, then + # we will not do this certificate check: + if [ -z "$(command -v diff)" ]; then + return + fi + + # If the openssl utility is not installed, then + # we will not do this certificate check: + get_openssl + if [ -z "$OPENSSL_BINARY" ]; then + return + fi + + # Generate the public key from the cert and the key. + # They should match (otherwise we can't create an SSL connection). + if ! diff <("$OPENSSL_BINARY" x509 -in "$cert_path" -pubkey -noout 2>/dev/null) \ + <("$OPENSSL_BINARY" pkey -in "$key_path" -pubout 2>/dev/null) >/dev/null 2>&1 + then + wsrep_log_error "******************* FATAL ERROR ****************" + wsrep_log_error "* The certifcate and private key do not match. *" + wsrep_log_error "* Please check your certificate and key files. *" + wsrep_log_error "************************************************" + exit 22 + fi +} + +# # Compares two version strings. # The first parameter is the version to be checked; # The second parameter is the minimum version required; @@ -996,22 +1127,22 @@ check_for_dhparams() # check_for_version() { - y1=${1#*.} + y1="${1#*.}" [ "$y1" = "$1" ] && y1="" z1=${y1#*.} [ "$z1" = "$y1" ] && z1="" - x1=${1%%.*} - y1=${y1%%.*} - z1=${z1%%.*} + x1="${1%%.*}" + y1="${y1%%.*}" + z1="${z1%%.*}" [ -z "$y1" ] && y1=0 [ -z "$z1" ] && z1=0 - y2=${2#*.} + y2="${2#*.}" [ "$y2" = "$2" ] && y2="" - z2=${y2#*.} + z2="${y2#*.}" [ "$z2" = "$y2" ] && z2="" - x2=${2%%.*} - y2=${y2%%.*} - z2=${z2%%.*} + x2="${2%%.*}" + y2="${y2%%.*}" + z2="${z2%%.*}" [ -z "$y2" ] && y2=0 [ -z "$z2" ] && z2=0 [ $x1 -lt $x2 ] && return 1 @@ -1021,3 +1152,127 @@ check_for_version() [ $z1 -lt $z2 ] && return 1 return 0 } + +trim_string() +{ + if [ -n "$BASH_VERSION" ]; then + local pattern="[![:space:]${2:-}]" + local x="${1#*$pattern}" + local z=${#1} + x=${#x} + if [ $x -ne $z ]; then + local y="${1%$pattern*}" + y=${#y} + x=$(( z-x-1 )) + y=$(( y-x+1 )) + printf '%s' "${1:$x:$y}" + else + printf '' + fi + else + local pattern="[[:space:]${2:-}]" + echo "$1" | sed -E "s/^$pattern+|$pattern+\$//g" + fi +} + +# +# Check whether process is still running. +# The first parameter contains the name of the PID file. +# The second parameter is the flag of the need to delete +# the PID file. +# If the second parameter is not zero and not empty, +# then if the process terminates, the corresponding +# PID file will be deleted. +# This function also sets the CHECK_PID variable to zero +# if the process has already exited, or writes the PID +# of the process there if it is still running. +# +check_pid() +{ + local pid_file="$1" + local remove=${2:-0} + if [ -r "$pid_file" ]; then + local pid=$(cat "$pid_file" 2>/dev/null) + if [ -n "$pid" ]; then + if [ $pid -ne 0 ]; then + if ps -p "$pid" >/dev/null 2>&1; then + CHECK_PID=$pid + return 0 + fi + fi + fi + if [ $remove -eq 1 ]; then + rm -f "$pid_file" + fi + fi + CHECK_PID=0 + return 1 +} + +# +# Checking that the process with the specified PID is still +# running and killing it in this case by sending SIGTERM +# (using the "kill" operation). +# The first parameter contains PID of the process. +# The second and third parameters (both optional) are the names +# of the PID and the configuration files, which should be removed +# after the process ends. +# If the first parameter (PID of the process) is zero, then +# the function immediately deletes the PID and the configuration +# files (if specified), without any additional checks. +# +cleanup_pid() +{ + local pid="$1" + local pid_file="${2:-}" + local config="${3:-}" + + if [ $pid -ne 0 ]; then + if ps -p $pid >/dev/null 2>&1; then + if kill $pid >/dev/null 2>&1; then + sleep 0.5 + local round=0 + local force=0 + while ps -p $pid >/dev/null 2>&1; do + sleep 1 + round=$(( round+1 )) + if [ $round -eq 16 ]; then + if [ $force -eq 0 ]; then + round=8 + force=1 + kill -9 $pid >/dev/null 2>&1 + else + return 1; + fi + fi + done + elif ps -p $pid >/dev/null 2>&1; then + wsrep_log_warning "Unable to kill PID=$pid ($pid_file)" + return 1 + fi + fi + fi + + [ -n "$pid_file" ] && [ -f "$pid_file" ] && rm -f "$pid_file" + [ -n "$config" ] && [ -f "$config" ] && rm -f "$config" + + return 0 +} + +nproc="" + +get_proc() +{ + if [ -z "$nproc" ]; then + set +e + if [ "$OS" = 'Linux' ]; then + nproc=$(grep -c processor /proc/cpuinfo 2>/dev/null) + elif [ "$OS" = 'Darwin' -o "$OS" = 'FreeBSD' ]; then + nproc=$(sysctl -n hw.ncpu) + fi + if [ -z "$nproc" ] || [ $nproc -eq 0 ]; then + nproc=1 + fi + set -e + fi +} diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 5618c704dbc..7f97d9e8dea 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -29,13 +29,10 @@ eformat="" ekey="" ekeyfile="" encrypt=0 -nproc=1 ecode=0 ssyslog="" ssystag="" -MARIABACKUP_PID="" -SST_PORT="" -REMOTEIP="" +BACKUP_PID="" tcert="" tpem="" tkey="" @@ -55,7 +52,7 @@ ib_home_dir="" ib_log_dir="" ib_undo_dir="" -sfmt="tar" +sfmt="" strmcmd="" tfmt="" tcmd="" @@ -79,6 +76,11 @@ compress='none' compress_chunk="" compress_threads="" +backup_threads="" + +encrypt_threads="" +encrypt_chunk="" + readonly SECRET_TAG="secret" # Required for backup locks @@ -92,12 +94,11 @@ fi pcmd="pv $pvopts" declare -a RC -MARIABACKUP_BIN="$(command -v mariabackup)" -if [ ! -x "$MARIABACKUP_BIN" ]; then - wsrep_log_error 'mariabackup binary not found in $PATH' +BACKUP_BIN="$(command -v mariabackup)" +if [ ! -x "$BACKUP_BIN" ]; then + wsrep_log_error 'mariabackup binary not found in path' exit 42 fi -MBSTREAM_BIN=mbstream DATA="$WSREP_SST_OPT_DATA" INFO_FILE="xtrabackup_galera_info" @@ -111,7 +112,8 @@ INNOBACKUPLOG="$DATA/mariabackup.backup.log" # Setting the path for ss and ip export PATH="/usr/sbin:/sbin:$PATH" -timeit(){ +timeit() +{ local stage="$1" shift local cmd="$@" @@ -201,6 +203,12 @@ get_keys() else ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key='$ekey'" fi + if [ -n "$encrypt_threads" ]; then + ecmd="$ecmd --encrypt-threads=$encrypt_threads" + fi + if [ -n "$encrypt_chunk" ]; then + ecmd="$ecmd --encrypt-chunk-size=$encrypt_chunk" + fi else wsrep_log_error "Unknown encryption format='$eformat'" exit 2 @@ -215,8 +223,6 @@ get_keys() get_transfer() { - TSST_PORT="$SST_PORT" - if [ $tfmt = 'nc' ]; then wsrep_log_info "Using netcat as streamer" wsrep_check_programs nc @@ -238,7 +244,7 @@ get_transfer() wsrep_log_info "Using traditional netcat as streamer" tcmd="$tcmd -l -p" fi - tcmd="$tcmd $TSST_PORT" + tcmd="$tcmd $SST_PORT" else # Check to see if netcat supports the '-N' flag. # -N Shutdown the network socket after EOF on stdin @@ -260,7 +266,7 @@ get_transfer() wsrep_log_info "Using traditional netcat as streamer" tcmd="$tcmd -q0" fi - tcmd="$tcmd $WSREP_SST_OPT_HOST_UNESCAPED $TSST_PORT" + tcmd="$tcmd $WSREP_SST_OPT_HOST_UNESCAPED $SST_PORT" fi else tfmt='socat' @@ -268,25 +274,68 @@ get_transfer() wsrep_log_info "Using socat as streamer" wsrep_check_programs socat - if [ $encrypt -eq 2 -o $encrypt -eq 3 ] && ! socat -V | grep -q -F 'WITH_OPENSSL 1'; then - wsrep_log_error "Encryption requested, but socat is not OpenSSL enabled (encrypt=$encrypt)" - exit 2 + if [ -n "$sockopt" ]; then + sockopt=$(trim_string "$sockopt" ',') + if [ -n "$sockopt" ]; then + sockopt=",$sockopt" + fi fi - # Determine the socat version - SOCAT_VERSION=$(socat -V 2>&1 | grep -m1 -oe '[0-9]\.[0-9][\.0-9]*') - if [ -z "$SOCAT_VERSION" ]; then - wsrep_log_error "******** FATAL ERROR ******************" - wsrep_log_error "* Cannot determine the socat version. *" - wsrep_log_error "***************************************" + # Add an option for ipv6 if needed: + if [ $WSREP_SST_OPT_HOST_IPv6 -eq 1 ]; then + # If sockopt contains 'pf=ip6' somewhere in the middle, + # this will not interfere with socat, but exclude the trivial + # cases when sockopt contains 'pf=ip6' as prefix or suffix: + if [ "$sockopt" = "${sockopt#,pf=ip6}" -a \ + "$sockopt" = "${sockopt%,pf=ip6}" ] + then + sockopt=",pf=ip6$sockopt" + fi + fi + + if [ $encrypt -lt 2 ]; then + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcmd="socat -u TCP-LISTEN:$SST_PORT,reuseaddr$sockopt stdio" + else + tcmd="socat -u stdio TCP:$REMOTEIP:$SST_PORT$sockopt" + fi + return + fi + + if ! socat -V | grep -q -F 'WITH_OPENSSL 1'; then + wsrep_log_error "******** FATAL ERROR ************************************************ " + wsrep_log_error "* Encryption requested, but socat is not OpenSSL enabled (encrypt=$encrypt) *" + wsrep_log_error "********************************************************************* " exit 2 fi - if ! check_for_version "$SOCAT_VERSION" "1.7.3"; then - # socat versions < 1.7.3 will have 512-bit dhparams (too small) - # so create 2048-bit dhparams and send that as a parameter: - check_for_dhparams - sockopt=",dhparam='$ssl_dhparams'$sockopt" + local action='Decrypting' + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcmd="socat -u openssl-listen:$SST_PORT,reuseaddr" + else + tcmd="socat -u stdio openssl-connect:$REMOTEIP:$SST_PORT" + action='Encrypting' + fi + + if [ "${sockopt#*,dhparam=}" != "$sockopt" ]; then + if [ -z "$ssl_dhparams" ]; then + # Determine the socat version + SOCAT_VERSION=$(socat -V 2>&1 | grep -m1 -oe '[0-9]\.[0-9][\.0-9]*') + if [ -z "$SOCAT_VERSION" ]; then + wsrep_log_error "******** FATAL ERROR ******************" + wsrep_log_error "* Cannot determine the socat version. *" + wsrep_log_error "***************************************" + exit 2 + fi + if ! check_for_version "$SOCAT_VERSION" '1.7.3'; then + # socat versions < 1.7.3 will have 512-bit dhparams (too small) + # so create 2048-bit dhparams and send that as a parameter: + check_for_dhparams + fi + fi + if [ -n "$ssl_dhparams" ]; then + tcmd="$tcmd,dhparam='$ssl_dhparams'" + fi fi if [ $encrypt -eq 2 ]; then @@ -295,52 +344,60 @@ get_transfer() wsrep_log_error "Both PEM and CRT files required" exit 22 fi - stagemsg="$stagemsg-OpenSSL-Encrypted-2" - if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then - wsrep_log_info "Decrypting with cert=${tpem}, cafile=${tcert}" - tcmd="socat -u openssl-listen:$TSST_PORT,reuseaddr,cert='$tpem',cafile='$tcert'$sockopt stdio" - else - wsrep_log_info "Encrypting with cert=${tpem}, cafile=${tcert}" - tcmd="socat -u stdio openssl-connect:$REMOTEIP:$TSST_PORT,cert='$tpem',cafile='$tcert'$sockopt" + if [ ! -r "$tpem" -o ! -r "$tcert" ]; then + wsrep_log_error "Both PEM and CRT files must be readable" + exit 22 fi - elif [ $encrypt -eq 3 ]; then + verify_ca_matches_cert "$tcert" "$tpem" + tcmd="$tcmd,cert='$tpem',cafile='$tcert'$sockopt" + stagemsg="$stagemsg-OpenSSL-Encrypted-2" + wsrep_log_info "$action with cert=$tpem, cafile=$tcert" + elif [ $encrypt -eq 3 -o $encrypt -eq 4 ]; then wsrep_log_info "Using openssl based encryption with socat: with key and crt" if [ -z "$tpem" -o -z "$tkey" ]; then wsrep_log_error "Both certificate and key files required" exit 22 fi + if [ ! -r "$tpem" -o ! -r "$tkey" ]; then + wsrep_log_error "Both certificate and key files must be readable" + exit 22 + fi + verify_cert_matches_key "$tpem" "$tkey" stagemsg="$stagemsg-OpenSSL-Encrypted-3" if [ -z "$tcert" ]; then - # no verification - if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then - wsrep_log_info "Decrypting with cert=${tpem}, key=${tkey}, verify=0" - tcmd="socat -u openssl-listen:$TSST_PORT,reuseaddr,cert='$tpem',key='$tkey',verify=0$sockopt stdio" - else - wsrep_log_info "Encrypting with cert=${tpem}, key=${tkey}, verify=0" - tcmd="socat -u stdio openssl-connect:$REMOTEIP:$TSST_PORT,cert='$tpem',key='$tkey',verify=0$sockopt" + if [ $encrypt -eq 4 ]; then + wsrep_log_error "Peer certificate required if encrypt=4" + exit 22 fi + # no verification + tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0$sockopt" + wsrep_log_info "$action with cert=$tpem, key=$tkey, verify=0" else # CA verification - if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then - wsrep_log_info "Decrypting with cert=${tpem}, key=${tkey}, cafile=${tcert}" - tcmd="socat -u openssl-listen:$TSST_PORT,reuseaddr,cert='$tpem',key='$tkey',cafile='$tcert'$sockopt stdio" + if [ ! -r "$tcert" ]; then + wsrep_log_error "Certificate file must be readable" + exit 22 + fi + verify_ca_matches_cert "$tcert" "$tpem" + if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then + CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'" + elif [ $encrypt -eq 4 ]; then + CN_option=",commonname=''" + elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then + CN_option=',commonname=localhost' else - CN_option="" - if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then - CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'" - elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then - CN_option=',commonname=localhost' - fi - wsrep_log_info "Encrypting with cert=${tpem}, key=${tkey}, cafile=${tcert}" - tcmd="socat -u stdio openssl-connect:$REMOTEIP:$TSST_PORT,cert='$tpem',key='$tkey',cafile='$tcert'$CN_option$sockopt" + CN_option=",commonname='$WSREP_SST_OPT_HOST_UNSECAPED'" fi + tcmd="$tcmd,cert='$tpem',key='$tkey',cafile='$tcert'$CN_option$sockopt" + wsrep_log_info "$action with cert=$tpem, key=$tkey, cafile=$tcert" fi else - if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then - tcmd="socat -u TCP-LISTEN:$TSST_PORT,reuseaddr$sockopt stdio" - else - tcmd="socat -u stdio TCP:$REMOTEIP:$TSST_PORT$sockopt" - fi + wsrep_log_info "Unknown encryption mode: encrypt=$encrypt" + exit 22 + fi + + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcmd="$tcmd stdio" fi fi } @@ -348,7 +405,7 @@ get_transfer() get_footprint() { pushd "$WSREP_SST_OPT_DATA" 1>/dev/null - payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c | awk 'END { print $1 }') + payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c -s | awk 'END { print $1 }') if [ "$compress" != 'none' ]; then # QuickLZ has around 50% compression ratio # When compression/compaction used, the progress is only an approximate. @@ -412,10 +469,10 @@ read_cnf() tpem=$(parse_cnf 'sst' 'tcert') tkey=$(parse_cnf 'sst' 'tkey') fi - if [ "$tmode" != 'DISABLED' ] - then # backward-incompatible behavior - if [ -z "$tpem" -a -z "$tkey" -a -z "$tcert" ] - then # no old-style SSL config in [sst] + if [ "$tmode" != 'DISABLED' ]; then + # backward-incompatible behavior + if [ -z "$tpem" -a -z "$tkey" -a -z "$tcert" ]; then + # no old-style SSL config in [sst] check_server_ssl_config fi if [ 0 -eq $encrypt -a -n "$tpem" -a -n "$tkey" ] @@ -441,7 +498,7 @@ read_cnf() sockopt=$(parse_cnf sst sockopt "") progress=$(parse_cnf sst progress "") ttime=$(parse_cnf sst time 0) - cpat='.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$' + cpat='.*\.pem$\|.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$' [ "$OS" = 'FreeBSD' ] && cpat=$(echo "$cpat" | sed 's/\\|/|/g') cpat=$(parse_cnf sst cpat "$cpat") scomp=$(parse_cnf sst compressor "") @@ -476,34 +533,38 @@ read_cnf() compress_threads=$(parse_cnf "$encgroups" 'compress-threads') fi fi + + backup_threads=$(parse_cnf "$encgroups" 'backup-threads') + + if [ "$eformat" = 'xbcrypt' ]; then + encrypt_threads=$(parse_cnf "$encgroups" 'encrypt-threads') + encrypt_chunk=$(parse_cnf "$encgroups" 'encrypt-chunk-size') + fi } get_stream() { if [ "$sfmt" = 'mbstream' -o "$sfmt" = 'xbstream' ]; then - wsrep_log_info "Streaming with ${sfmt}" + sfmt='mbstream' + STREAM_BIN="$(command -v mbstream)" + if [ -z "$STREAM_BIN" ]; then + wsrep_log_error "Streaming with $sfmt, but $sfmt not found in path" + exit 42 + fi if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then - strmcmd="$MBSTREAM_BIN -x" + strmcmd="'$STREAM_BIN' -x" else - strmcmd="$MBSTREAM_BIN -c '$INFO_FILE'" + strmcmd="'$STREAM_BIN' -c '$INFO_FILE'" fi else - sfmt="tar" - wsrep_log_info "Streaming with tar" - if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]]; then - strmcmd="tar xfi -" + sfmt='tar' + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + strmcmd='tar xfi -' else strmcmd="tar cf - '$INFO_FILE'" fi fi -} - -get_proc() -{ - set +e - nproc=$(grep -c processor /proc/cpuinfo) - [ -z $nproc -o $nproc -eq 0 ] && nproc=1 - set -e + wsrep_log_info "Streaming with $sfmt" } sig_joiner_cleanup() @@ -512,48 +573,7 @@ sig_joiner_cleanup() [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" } -cleanup_joiner() -{ - # Since this is invoked just after exit NNN - local estatus=$? - if [ $estatus -ne 0 ]; then - wsrep_log_error "Cleanup after exit with status:$estatus" - elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then - wsrep_log_info "Removing the sst_in_progress file" - wsrep_cleanup_progress_file - fi - if [ -n "$progress" -a -p "$progress" ]; then - wsrep_log_info "Cleaning up fifo file $progress" - rm "$progress" - fi - - if [ -n "$STATDIR" ]; then - [ -d "$STATDIR" ] && rm -rf "$STATDIR" - fi - - # Final cleanup - pgid=$(ps -o pgid= $$ | grep -o '[0-9]*') - - # This means no setsid done in mysqld. - # We don't want to kill mysqld here otherwise. - if [ $$ -eq $pgid ]; then - # This means a signal was delivered to the process. - # So, more cleanup. - if [ $estatus -ge 128 ]; then - kill -KILL -$$ || true - fi - fi - - exit $estatus -} - -check_pid() -{ - local pid_file="$1" - [ -r "$pid_file" ] && ps -p $(cat "$pid_file") 2>&1 >/dev/null -} - -cleanup_donor() +cleanup_at_exit() { # Since this is invoked just after exit NNN local estatus=$? @@ -561,16 +581,19 @@ cleanup_donor() wsrep_log_error "Cleanup after exit with status:$estatus" fi - if [ -n "$MARIABACKUP_PID" ]; then - if check_pid $MARIABACKUP_PID - then - wsrep_log_error "mariabackup process is still running. Killing..." - kill_mariabackup + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + wsrep_log_info "Removing the sst_in_progress file" + wsrep_cleanup_progress_file + else + if [ -n "$BACKUP_PID" ]; then + if check_pid "$BACKUP_PID" 1; then + wsrep_log_error "mariabackup process is still running. Killing..." + cleanup_pid $CHECK_PID "$BACKUP_PID" + fi fi + [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" fi - [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" - if [ -n "$progress" -a -p "$progress" ]; then wsrep_log_info "Cleaning up fifo file $progress" rm -f "$progress" || true @@ -578,8 +601,14 @@ cleanup_donor() wsrep_log_info "Cleaning up temporary directories" - [ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || true - [ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || true + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + if [ -n "$STATDIR" ]; then + [ -d "$STATDIR" ] && rm -rf "$STATDIR" + fi + else + [ -n "$xtmpdir" -a -d "$xtmpdir" ] && rm -rf "$xtmpdir" || true + [ -n "$itmpdir" -a -d "$itmpdir" ] && rm -rf "$itmpdir" || true + fi # Final cleanup pgid=$(ps -o pgid= $$ | grep -o '[0-9]*') @@ -590,21 +619,13 @@ cleanup_donor() # This means a signal was delivered to the process. # So, more cleanup. if [ $estatus -ge 128 ]; then - kill -KILL -$$ || true + kill -KILL -- -$$ || true fi fi exit $estatus } -kill_mariabackup() -{ - local PID=$(cat "$MARIABACKUP_PID") - [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || : - wsrep_log_info "Removing mariabackup pid file ($MARIABACKUP_PID)" - rm -f "$MARIABACKUP_PID" || true -} - setup_ports() { SST_PORT="$WSREP_SST_OPT_PORT" @@ -615,51 +636,17 @@ setup_ports() fi } -check_port() -{ - local PORT="$1" - local UTILS="$2" - - local port_info is_util - - if [ $lsof_available -ne 0 ]; then - port_info=$(lsof -i ":$PORT" -Pn 2>/dev/null | \ - grep -F '(LISTEN)') - is_util=$(echo "$port_info" | \ - grep -E "^($UTILS)[^[:space:]]*[[:space:]]+[0-9]+[[:space:]]+") - elif [ $sockstat_available -ne 0 ]; then - port_info=$(sockstat -p "$PORT" 2>/dev/null | \ - grep -F 'LISTEN') - is_util=$(echo "$port_info" | \ - grep -E "[[:space:]]+($UTILS)[^[:space:]]*[[:space:]]+[0-9]+[[:space:]]+") - elif [ $ss_available -ne 0 ]; then - port_info=$(ss -H -p -n -l "( sport = :$PORT )" 2>/dev/null) - is_util=$(echo "$port_info" | \ - grep -E "users:\\(.*\\(\"($UTILS)[^[:space:]]*\".*\<pid=[0-9]+\>.*\\)") - else - wsrep_log_error "unknown sockets utility" - exit 2 # ENOENT - fi - - if [ -z "$is_util" ]; then - return 1 - fi - - return 0 -} - -# waits ~10 seconds for nc to open the port and then reports ready -# (regardless of timeout) +# +# Waits ~30 seconds for socat or nc to open the port and +# then reports ready, regardless of timeout. +# wait_for_listen() { local PORT="$1" local ADDR="$2" local MODULE="$3" - - for i in {1..50} - do - if check_port "$PORT" 'socat|nc' - then + for i in {1..150}; do + if check_port "" "$PORT" 'socat|nc'; then break fi sleep 0.2 @@ -675,8 +662,8 @@ check_extra() if [ "$thread_handling" = 'pool-of-threads' ]; then local eport=$(parse_cnf '--mysqld' 'extra-port') if [ -n "$eport" ]; then - # mariabackup works only locally, hence, - # setting host to 127.0.0.1 unconditionally: + # mariabackup works only locally. + # Hence, setting host to 127.0.0.1 unconditionally: wsrep_log_info "SST through extra_port $eport" INNOEXTRA="$INNOEXTRA --host=127.0.0.1 --port=$eport" use_socket=0 @@ -792,30 +779,29 @@ monitor_process() local sst_stream_pid=$1 while true ; do - if ! ps -p "$WSREP_SST_OPT_PARENT" &>/dev/null; then + if ! ps -p "$WSREP_SST_OPT_PARENT" >/dev/null 2>&1; then wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT) terminated unexpectedly." + kill -- -"$WSREP_SST_OPT_PARENT" exit 32 fi - if ! ps -p "$sst_stream_pid" &>/dev/null; then + if ! ps -p "$sst_stream_pid" >/dev/null 2>&1; then break fi sleep 0.1 done } -wsrep_check_programs "$MARIABACKUP_BIN" - [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" if [ "$WSREP_SST_OPT_ROLE" != 'joiner' -a "$WSREP_SST_OPT_ROLE" != 'donor' ]; then - wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}" + wsrep_log_error "Invalid role '$WSREP_SST_OPT_ROLE'" exit 22 fi read_cnf setup_ports -if "$MARIABACKUP_BIN" --help 2>/dev/null | grep -qw -- '--version-check'; then +if "$BACKUP_BIN" --help 2>/dev/null | grep -qw -- '--version-check'; then disver='--no-version-check' fi @@ -838,7 +824,6 @@ INNODB_DATA_HOME_DIR=$(pwd -P) cd "$OLD_PWD" if [ $ssyslog -eq 1 ]; then - if [ -n "$(command -v logger)" ]; then wsrep_log_info "Logging all stderr of SST/mariabackup to syslog" @@ -856,70 +841,65 @@ if [ $ssyslog -eq 1 ]; then else wsrep_log_error "logger not in path: $PATH. Ignoring" fi - INNOAPPLY="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply" INNOMOVE="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move" INNOBACKUP="2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)" - else + if [ $sstlogarchive -eq 1 ] + then + ARCHIVETIMESTAMP=$(date "+%Y.%m.%d-%H.%M.%S.%N") -if [ $sstlogarchive -eq 1 ] -then - ARCHIVETIMESTAMP=$(date "+%Y.%m.%d-%H.%M.%S.%N") - - if [ -n "$sstlogarchivedir" ]; then - if [ ! -d "$sstlogarchivedir" ]; then - mkdir -p "$sstlogarchivedir" + if [ -n "$sstlogarchivedir" ]; then + if [ ! -d "$sstlogarchivedir" ]; then + mkdir -p "$sstlogarchivedir" + fi fi - fi - if [ -e "$INNOAPPLYLOG" ] - then - if [ -n "$sstlogarchivedir" ] + if [ -e "$INNOAPPLYLOG" ] then - newfile=$(basename "$INNOAPPLYLOG") - newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" - else - newfile="$INNOAPPLYLOG.$ARCHIVETIMESTAMP" + if [ -n "$sstlogarchivedir" ] + then + newfile=$(basename "$INNOAPPLYLOG") + newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" + else + newfile="$INNOAPPLYLOG.$ARCHIVETIMESTAMP" + fi + wsrep_log_info "Moving '$INNOAPPLYLOG' to '$newfile'" + mv "$INNOAPPLYLOG" "$newfile" + gzip "$newfile" fi - wsrep_log_info "Moving '$INNOAPPLYLOG' to '$newfile'" - mv "$INNOAPPLYLOG" "$newfile" - gzip "$newfile" - fi - if [ -e "$INNOMOVELOG" ] - then - if [ -n "$sstlogarchivedir" ] + if [ -e "$INNOMOVELOG" ] then - newfile=$(basename "$INNOMOVELOG") - newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" - else - newfile="$INNOMOVELOG.$ARCHIVETIMESTAMP" + if [ -n "$sstlogarchivedir" ] + then + newfile=$(basename "$INNOMOVELOG") + newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" + else + newfile="$INNOMOVELOG.$ARCHIVETIMESTAMP" + fi + wsrep_log_info "Moving '$INNOMOVELOG' to '$newfile'" + mv "$INNOMOVELOG" "$newfile" + gzip "$newfile" fi - wsrep_log_info "Moving '$INNOMOVELOG' to '$newfile'" - mv "$INNOMOVELOG" "$newfile" - gzip "$newfile" - fi - if [ -e "$INNOBACKUPLOG" ] - then - if [ -n "$sstlogarchivedir" ] + if [ -e "$INNOBACKUPLOG" ] then - newfile=$(basename "$INNOBACKUPLOG") - newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" - else - newfile="$INNOBACKUPLOG.$ARCHIVETIMESTAMP" + if [ -n "$sstlogarchivedir" ] + then + newfile=$(basename "$INNOBACKUPLOG") + newfile="$sstlogarchivedir/$newfile.$ARCHIVETIMESTAMP" + else + newfile="$INNOBACKUPLOG.$ARCHIVETIMESTAMP" + fi + wsrep_log_info "Moving '$INNOBACKUPLOG' to '$newfile'" + mv "$INNOBACKUPLOG" "$newfile" + gzip "$newfile" fi - wsrep_log_info "Moving '$INNOBACKUPLOG' to '$newfile'" - mv "$INNOBACKUPLOG" "$newfile" - gzip "$newfile" fi -fi - - INNOAPPLY="&> '$INNOAPPLYLOG'" - INNOMOVE="&> '$INNOMOVELOG'" + INNOAPPLY="> '$INNOAPPLYLOG' 2>&1" + INNOMOVE="> '$INNOMOVELOG' 2>&1" INNOBACKUP="2> '$INNOBACKUPLOG'" - fi setup_commands() @@ -928,9 +908,9 @@ setup_commands() if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then mysqld_args="--mysqld-args $WSREP_SST_OPT_MYSQLD" fi - INNOAPPLY="$MARIABACKUP_BIN --prepare $disver $iapts $INNOEXTRA --target-dir='$DATA' --datadir='$DATA' $mysqld_args $INNOAPPLY" - INNOMOVE="$MARIABACKUP_BIN $WSREP_SST_OPT_CONF --move-back $disver $impts --force-non-empty-directories --target-dir='$DATA' --datadir='${TDATA:-$DATA}' $INNOMOVE" - INNOBACKUP="$MARIABACKUP_BIN $WSREP_SST_OPT_CONF --backup $disver $iopts $tmpopts $INNOEXTRA --galera-info --stream='$sfmt' --target-dir='$itmpdir' --datadir='$DATA' $mysqld_args $INNOBACKUP" + INNOAPPLY="$BACKUP_BIN --prepare $disver $iapts $INNOEXTRA --target-dir='$DATA' --datadir='$DATA' $mysqld_args $INNOAPPLY" + INNOMOVE="$BACKUP_BIN $WSREP_SST_OPT_CONF --move-back $disver $impts --force-non-empty-directories --target-dir='$DATA' --datadir='${TDATA:-$DATA}' $INNOMOVE" + INNOBACKUP="$BACKUP_BIN $WSREP_SST_OPT_CONF --backup $disver $iopts $tmpopts $INNOEXTRA --galera-info --stream=$sfmt --target-dir='$itmpdir' --datadir='$DATA' $mysqld_args $INNOBACKUP" } get_stream @@ -938,7 +918,7 @@ get_transfer if [ "$WSREP_SST_OPT_ROLE" = 'donor' ] then - trap cleanup_donor EXIT + trap cleanup_at_exit EXIT if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then @@ -951,12 +931,15 @@ then tmpdir=$(parse_cnf "$encgroups" 'tmpdir') if [ -z "$tmpdir" ]; then xtmpdir="$(mktemp -d)" - tmpopts="--tmpdir='$xtmpdir'" - wsrep_log_info "Using $xtmpdir as mariabackup temporary directory" + else + xtmpdir=$(mktemp '-d' "--tmpdir=$tmpdir") fi + wsrep_log_info "Using '$xtmpdir' as mariabackup temporary directory" + tmpopts="--tmpdir='$xtmpdir'" + itmpdir="$(mktemp -d)" - wsrep_log_info "Using $itmpdir as mariabackup temporary directory" + wsrep_log_info "Using '$itmpdir' as mariabackup working directory" usrst=0 if [ -n "$WSREP_SST_OPT_USER" ]; then @@ -997,9 +980,9 @@ then send_donor "$DATA" "$stagemsg-gtid" + # Restore the transport commmand to its original state tcmd="$ttcmd" - # Restore the transport commmand to its original state if [ -n "$progress" ]; then get_footprint tcmd="$pcmd | $tcmd" @@ -1011,7 +994,7 @@ then wsrep_log_info "Sleeping before data transfer for SST" sleep 10 - wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP}:${SST_PORT}" + wsrep_log_info "Streaming the backup to joiner at $REMOTEIP:$SST_PORT" # Add compression to the head of the stream (if specified) if [ -n "$scomp" ]; then @@ -1023,33 +1006,37 @@ then tcmd="$ecmd | $tcmd" fi - iopts="$iopts --databases-exclude='lost+found'" + iopts="--databases-exclude='lost+found' $iopts" if [ ${FORCE_FTWRL:-0} -eq 1 ]; then - wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL" - iopts="$iopts --no-backup-locks" + wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL" + iopts="--no-backup-locks $iopts" fi # if compression is enabled for backup files, then add the # appropriate options to the mariabackup command line: if [ "$compress" != 'none' ]; then - iopts="$iopts --compress${compress:+=$compress}" + iopts="--compress${compress:+=$compress} $iopts" if [ -n "$compress_threads" ]; then - iopts="$iopts --compress-threads=$compress_threads" + iopts="--compress-threads=$compress_threads $iopts" fi if [ -n "$compress_chunk" ]; then - iopts="$iopts --compress-chunk-size=$compress_chunk" + iopts="--compress-chunk-size=$compress_chunk $iopts" fi fi + if [ -n "$backup_threads" ]; then + iopts="--parallel=$backup_threads $iopts" + fi + setup_commands set +e timeit "$stagemsg-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )" set -e if [ ${RC[0]} -ne 0 ]; then - wsrep_log_error "${MARIABACKUP_BIN} finished with error: ${RC[0]}. " \ - "Check syslog or ${INNOBACKUPLOG} for details" + wsrep_log_error "mariabackup finished with error: ${RC[0]}. " \ + "Check syslog or '$INNOBACKUPLOG' for details" exit 22 elif [ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]; then wsrep_log_error "$tcmd finished with error: ${RC[1]}" @@ -1057,7 +1044,7 @@ then fi # mariabackup implicitly writes PID to fixed location in $xtmpdir - MARIABACKUP_PID="$xtmpdir/xtrabackup_pid" + BACKUP_PID="$xtmpdir/xtrabackup_pid" else # BYPASS FOR IST @@ -1109,6 +1096,10 @@ then ib_undo_dir="$INNODB_UNDO_DIR" + if [ -n "$backup_threads" ]; then + impts="--parallel=$backup_threads $impts" + fi + stagemsg='Joiner-Recv' sencrypted=1 @@ -1148,7 +1139,7 @@ then fi trap sig_joiner_cleanup HUP PIPE INT TERM - trap cleanup_joiner EXIT + trap cleanup_at_exit EXIT if [ -n "$progress" ]; then adjust_progress @@ -1171,7 +1162,7 @@ then recv_joiner "$STATDIR" "$stagemsg-gtid" $stimeout 1 1 - if ! ps -p "$WSREP_SST_OPT_PARENT" &>/dev/null + if ! ps -p "$WSREP_SST_OPT_PARENT" >/dev/null 2>&1 then wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT) terminated unexpectedly." exit 32 @@ -1181,7 +1172,7 @@ then then if [ -d "$DATA/.sst" ]; then - wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous state transfer. Removing" + wsrep_log_info "WARNING: Stale temporary SST directory: '$DATA/.sst' from previous state transfer. Removing" rm -rf "$DATA/.sst" fi mkdir -p "$DATA/.sst" @@ -1291,37 +1282,37 @@ then fi - wsrep_log_info "Preparing the backup at ${DATA}" + wsrep_log_info "Preparing the backup at $DATA" setup_commands timeit "mariabackup prepare stage" "$INNOAPPLY" if [ $? -ne 0 ]; then - wsrep_log_error "${MARIABACKUP_BIN} apply finished with errors. Check syslog or ${INNOAPPLYLOG} for details" + wsrep_log_error "mariabackup apply finished with errors. Check syslog or '$INNOAPPLYLOG' for details" exit 22 fi MAGIC_FILE="$TDATA/$INFO_FILE" - wsrep_log_info "Moving the backup to ${TDATA}" - timeit "mariabackup move stage" "$INNOMOVE" + wsrep_log_info "Moving the backup to $TDATA" + timeit "mariabackup move stage" "$INNOMOVE" if [ $? -eq 0 ]; then - wsrep_log_info "Move successful, removing ${DATA}" + wsrep_log_info "Move successful, removing $DATA" rm -rf "$DATA" DATA="$TDATA" else - wsrep_log_error "Move failed, keeping ${DATA} for further diagnosis" - wsrep_log_error "Check syslog or ${INNOMOVELOG} for details" + wsrep_log_error "Move failed, keeping '$DATA' for further diagnosis" + wsrep_log_error "Check syslog or '$INNOMOVELOG' for details" exit 22 fi else - wsrep_log_info "${IST_FILE} received from donor: Running IST" + wsrep_log_info "'$IST_FILE' received from donor: Running IST" fi if [ ! -r "$MAGIC_FILE" ]; then - wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable" + wsrep_log_error "SST magic file '$MAGIC_FILE' not found/readable" exit 2 fi diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index 4aa3f8e63d8..798bee1ac10 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -103,7 +103,7 @@ then DROP PREPARE stmt;" fi -MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF "\ +MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF_UNQUOTED "\ "$AUTH -h$WSREP_SST_OPT_HOST_UNESCAPED "\ "-P$WSREP_SST_OPT_PORT --disable-reconnect --connect_timeout=10" @@ -140,7 +140,7 @@ then fi # NOTE: we don't use --routines here because we're dumping mysql.proc table -MYSQLDUMP="$MYSQLDUMP $WSREP_SST_OPT_CONF $AUTH -S$WSREP_SST_OPT_SOCKET \ +MYSQLDUMP="$MYSQLDUMP $WSREP_SST_OPT_CONF_UNQUOTED $AUTH -S$WSREP_SST_OPT_SOCKET \ --add-drop-database --add-drop-table --skip-add-locks --create-options \ --disable-keys --extended-insert --skip-lock-tables --quick --set-charset \ --skip-comments --flush-privileges --all-databases --events" diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 92f77eec331..19a4d19fded 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -1,7 +1,7 @@ #!/bin/bash -ue -# Copyright (C) 2010-2014 Codership Oy # Copyright (C) 2017-2021 MariaDB +# Copyright (C) 2010-2014 Codership Oy # # 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 @@ -19,9 +19,8 @@ # This is a reference script for rsync-based state snapshot tansfer -RSYNC_PID= # rsync pid file -RSYNC_CONF= # rsync configuration file -RSYNC_REAL_PID= # rsync process id +RSYNC_REAL_PID=0 # rsync process id +STUNNEL_REAL_PID=0 # stunnel process id OS="$(uname)" [ "$OS" = 'Darwin' ] && export -n LD_LIBRARY_PATH @@ -36,95 +35,95 @@ wsrep_check_programs rsync cleanup_joiner() { - wsrep_log_info "Joiner cleanup. rsync PID: $RSYNC_REAL_PID" - [ "0" != "$RSYNC_REAL_PID" ] && \ - kill $RSYNC_REAL_PID && \ - sleep 0.5 && \ - kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || : - [ -f "$RSYNC_CONF" ] && rm -f "$RSYNC_CONF" - [ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF" - [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" - [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" - [ -f "$RSYNC_PID" ] && rm -f "$RSYNC_PID" + local failure=0 + + wsrep_log_info "Joiner cleanup: rsync PID=$RSYNC_REAL_PID, stunnel PID=$STUNNEL_REAL_PID" + + if [ -n "$STUNNEL" ]; then + if cleanup_pid $STUNNEL_REAL_PID "$STUNNEL_PID" "$STUNNEL_CONF"; then + if [ $RSYNC_REAL_PID -eq 0 ]; then + if [ -r "$RSYNC_PID" ]; then + RSYNC_REAL_PID=$(cat "$RSYNC_PID" 2>/dev/null) + if [ -z "$RSYNC_REAL_PID" ]; then + RSYNC_REAL_PID=0 + fi + fi + fi + else + wsrep_log_warning "stunnel cleanup failed." + failure=1 + fi + fi + + if [ $failure -eq 0 ]; then + if cleanup_pid $RSYNC_REAL_PID "$RSYNC_PID" "$RSYNC_CONF"; then + [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" + else + wsrep_log_warning "rsync cleanup failed." + fi + fi + wsrep_log_info "Joiner cleanup done." + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then wsrep_cleanup_progress_file fi } -# Check whether rsync process is still running. -check_pid() -{ - local pid_file="$1" - [ -r "$pid_file" ] && ps -p $(cat "$pid_file") 2>&1 >/dev/null -} - check_pid_and_port() { local pid_file="$1" - local rsync_pid=$2 - local rsync_addr="$3" - local rsync_port="$4" + local pid=$2 + local addr="$3" + local port="$4" - if [ -z "$rsync_port" -o -z "$rsync_addr" -o -z "$rsync_pid" ]; then - wsrep_log_error "check_pid_and_port(): bad arguments" - exit 2 # ENOENT - fi + local utils='rsync|stunnel' - local port_info is_rsync - - if [ $lsof_available -ne 0 ]; then - port_info=$(lsof -i ":$rsync_port" -Pn 2>/dev/null | \ - grep -F '(LISTEN)') - is_rsync=$(echo "$port_info" | \ - grep -E "^(rsync|stunnel)[^[:space:]]*[[:space:]]+$rsync_pid[[:space:]]+") - elif [ $sockstat_available -ne 0 ]; then - port_info=$(sockstat -p "$rsync_port" 2>/dev/null | \ - grep -F 'LISTEN') - is_rsync=$(echo "$port_info" | \ - grep -E "[[:space:]]+(rsync|stunnel)[^[:space:]]*[[:space:]]+$rsync_pid[[:space:]]+") - elif [ $ss_available -ne 0 ]; then - port_info=$(ss -H -p -n -l "( sport = :$rsync_port )" 2>/dev/null) - is_rsync=$(echo "$port_info" | \ - grep -E "users:\\(.*\\(\"(rsync|stunnel)[^[:space:]]*\".*\<pid=$rsync_pid\>.*\\)") - else - wsrep_log_error "unknown sockets utility" - exit 2 # ENOENT - fi + if ! check_port "$pid" "$port" "$utils"; then + local port_info + local busy=0 - if [ -z "$is_rsync" ]; then - local is_listening_all if [ $lsof_available -ne 0 ]; then - is_listening_all=$(echo "$port_info" | \ - grep -E "[[:space:]](\\*|\\[?::\\]?):$rsync_port[[:space:]]") + port_info=$(lsof -Pnl -i ":$port" 2>/dev/null | \ + grep -F '(LISTEN)') + echo "$port_info" | \ + grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port[[:space:]]" && busy=1 else - if [ $sockstat_available -eq 0 ]; then - port_info=$(echo "$port_info" | grep -q -F 'users:(') + local filter='([^[:space:]]+[[:space:]]+){4}[^[:space:]]+' + if [ $sockstat_available -eq 1 ]; then + port_info=$(sockstat -p "$port" 2>/dev/null | \ + grep -E '[[:space:]]LISTEN' | grep -o -E "$filter") + else + port_info=$(ss -nlpH "( sport = :$port )" 2>/dev/null | \ + grep -F 'users:(' | grep -o -E "$filter") fi - port_info=$(echo "$port_info" | \ - grep -E "[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+" -o) - is_listening_all=$(echo "$port_info" | \ - grep -E "[[:space:]](\\*|\\[?::\\]?):$rsync_port\$") + echo "$port_info" | \ + grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port\$" && busy=1 fi - local is_listening_addr=$(echo "$port_info" | \ - grep -w -F -- "$rsync_addr:$rsync_port") - if [ -z "$is_listening_addr" ]; then - is_listening_addr=$(echo "$port_info" | \ - grep -w -F "[$rsync_addr]:$rsync_port") + + if [ $busy -eq 0 ]; then + if echo "$port_info" | grep -qw -F "[$addr]:$port" || \ + echo "$port_info" | grep -qw -F -- "$addr:$port" + then + busy=1 + fi + fi + + if [ $busy -eq 0 ]; then + return 1 fi - if [ -n "$is_listening_all" -o -n "$is_listening_addr" ]; then - wsrep_log_error "rsync or stunnel daemon port '$rsync_port' " \ + + if ! check_port "$pid" "$port" "$utils"; then + wsrep_log_error "rsync or stunnel daemon port '$port' " \ "has been taken by another program" exit 16 # EBUSY fi - return 1 fi - check_pid "$pid_file" && [ $(cat "$pid_file") -eq $rsync_pid ] + check_pid "$pid_file" && [ $CHECK_PID -eq $pid ] } STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf" - STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid" MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" @@ -201,6 +200,8 @@ FILTER="-f '- /lost+found' -f '- /.zfs' -f '- /.fseventsd' -f '- /.Trashes' + -f '- /.pid' + -f '- /.conf' -f '+ /wsrep_sst_binlog.tar' -f '- $INNODB_DATA_HOME_DIR/ib_lru_dump' -f '- $INNODB_DATA_HOME_DIR/ibdata*' @@ -250,19 +251,31 @@ else CAFILE_OPT="" fi +VERIFY_OPT="" +CHECK_OPT="" +CHECK_OPT_LOCAL="" if [ "${SSLMODE#VERIFY}" != "$SSLMODE" ] then case "$SSLMODE" in 'VERIFY_IDENTITY') VERIFY_OPT='verifyPeer = yes' - CHECK_OPT="" ;; 'VERIFY_CA') VERIFY_OPT='verifyChain = yes' - if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then - CHECK_OPT='checkHost = localhost' + if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then + CHECK_OPT="checkHost = $WSREP_SST_OPT_REMOTE_USER" else - CHECK_OPT='checkHost = $WSREP_SST_OPT_HOST_UNESCAPED' + # check if the address is an ip-address (v4 or v6): + if echo "$WSREP_SST_OPT_HOST_UNESCAPED" | \ + grep -q -E '^([0-9]+(\.[0-9]+){3}|[0-9a-fA-F]*(\:[0-9a-fA-F]*)+)$' + then + CHECK_OPT="checkIP = $WSREP_SST_OPT_HOST_UNESCAPED" + else + CHECK_OPT="checkHost = $WSREP_SST_OPT_HOST" + fi + if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then + CHECK_OPT_LOCAL="checkHost = localhost" + fi fi ;; *) @@ -273,9 +286,6 @@ then wsrep_log_error "Can't have ssl-mode='$SSLMODE' without CA file" exit 22 # EINVAL fi -else - VERIFY_OPT="" - CHECK_OPT="" fi STUNNEL="" @@ -294,10 +304,10 @@ then [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" [ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" + [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" if [ -n "$STUNNEL" ] then - [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" cat << EOF > "$STUNNEL_CONF" key = $SSTKEY cert = $SSTCERT @@ -310,7 +320,10 @@ connect = $WSREP_SST_OPT_HOST_UNESCAPED:$WSREP_SST_OPT_PORT TIMEOUTclose = 0 ${VERIFY_OPT} ${CHECK_OPT} +${CHECK_OPT_LOCAL} EOF + else + [ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF" fi if [ $WSREP_SST_OPT_BYPASS -eq 0 ] @@ -319,13 +332,8 @@ EOF FLUSHED="$WSREP_SST_OPT_DATA/tables_flushed" ERROR="$WSREP_SST_OPT_DATA/sst_error" - rm -rf "$FLUSHED" - rm -rf "$ERROR" - - # Use deltaxfer only for WAN - inv=$(basename "$0") - [ "$inv" = "wsrep_sst_rsync_wan" ] && WHOLE_FILE_OPT="" \ - || WHOLE_FILE_OPT="--whole-file" + [ -f "$FLUSHED" ] && rm -f "$FLUSHED" + [ -f "$ERROR" ] && rm -f "$ERROR" echo "flush tables" @@ -340,15 +348,14 @@ EOF if [ -f "$ERROR" ] then # Flush tables operation failed. - rm -rf "$ERROR" + rm -f "$ERROR" exit 255 fi - sleep 0.2 done STATE=$(cat "$FLUSHED") - rm -rf "$FLUSHED" + rm -f "$FLUSHED" sync @@ -375,6 +382,13 @@ EOF cd "$OLD_PWD" fi + # Use deltaxfer only for WAN + inv=$(basename "$0") + WHOLE_FILE_OPT="" + if [ "${inv%wsrep_sst_rsync_wan*}" != "$inv" ]; then + WHOLE_FILE_OPT="--whole-file" + fi + # first, the normal directories, so that we can detect incompatible protocol RC=0 eval rsync ${STUNNEL:+"'--rsh=$STUNNEL'"} \ @@ -426,16 +440,18 @@ EOF fi # then, we parallelize the transfer of database directories, - # use . so that path concatenation works: + # use '.' so that path concatenation works: cd "$WSREP_SST_OPT_DATA" - count=1 - [ "$OS" = 'Linux' ] && count=$(grep -c processor /proc/cpuinfo) - [ "$OS" = 'Darwin' -o "$OS" = 'FreeBSD' ] && count=$(sysctl -n hw.ncpu) + backup_threads=$(parse_cnf "--mysqld|sst" 'backup-threads') + if [ -z "$backup_threads" ]; then + get_proc + backup_threads=$nproc + fi find . -maxdepth 1 -mindepth 1 -type d -not -name 'lost+found' \ - -not -name '.zfs' -print0 | xargs -I{} -0 -P $count \ + -not -name '.zfs' -print0 | xargs -I{} -0 -P $backup_threads \ rsync ${STUNNEL:+--rsh="$STUNNEL"} \ --owner --group --perms --links --specials \ --ignore-times --inplace --recursive --delete --quiet \ @@ -474,35 +490,52 @@ EOF echo "done $STATE" + if [ -n "$STUNNEL" ]; then + [ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF" + [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" + fi + elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' ] then check_sockets_utils - touch "$SST_PROGRESS_FILE" - MYSQLD_PID="$WSREP_SST_OPT_PARENT" + # give some time for lingering stunnel from previous SST to complete + check_round=0 + while check_pid "$STUNNEL_PID" 1 + do + wsrep_log_info "lingering stunnel daemon found at startup, waiting for it to exit" + check_round=$(( check_round + 1 )) + if [ $check_round -eq 10 ]; then + wsrep_log_error "stunnel daemon already running." + exit 114 # EALREADY + fi + sleep 1 + done MODULE="rsync_sst" - RSYNC_PID="$WSREP_SST_OPT_DATA/$MODULE.pid" + RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + # give some time for lingering rsync from previous SST to complete check_round=0 - while check_pid "$RSYNC_PID" && [ $check_round -lt 10 ] + while check_pid "$RSYNC_PID" 1 do wsrep_log_info "lingering rsync daemon found at startup, waiting for it to exit" check_round=$(( check_round + 1 )) + if [ $check_round -eq 10 ]; then + wsrep_log_error "rsync daemon already running." + exit 114 # EALREADY + fi sleep 1 done - if check_pid "$RSYNC_PID" - then - wsrep_log_error "rsync daemon already running." - exit 114 # EALREADY - fi - - [ -f "$RSYNC_PID" ] && rm -f "$RSYNC_PID" [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" [ -f "$BINLOG_TAR_FILE" ] && rm -f "$BINLOG_TAR_FILE" + if [ -z "$STUNNEL" ]; then + [ -f "$STUNNEL_CONF" ] && rm -f "$STUNNEL_CONF" + fi + ADDR="$WSREP_SST_OPT_ADDR" RSYNC_PORT="$WSREP_SST_OPT_PORT" RSYNC_ADDR="$WSREP_SST_OPT_HOST" @@ -512,7 +545,7 @@ then trap "exit 3" INT TERM ABRT trap cleanup_joiner EXIT - RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf" + touch "$SST_PROGRESS_FILE" if [ -n "${MYSQL_TMP_DIR:-}" ]; then SILENT="log file = $MYSQL_TMP_DIR/rsyncd.log" @@ -535,18 +568,18 @@ $SILENT path = $INNODB_DATA_HOME_DIR EOF -# rm -rf "$DATA"/ib_logfile* # we don't want old logs around +# rm -rf "$DATA/ib_logfile"* # we don't want old logs around - # If the IP is local listen only in it + # If the IP is local, listen only on it: if is_local_ip "$RSYNC_ADDR_UNESCAPED" then RSYNC_EXTRA_ARGS="--address $RSYNC_ADDR_UNESCAPED" STUNNEL_ACCEPT="$RSYNC_ADDR_UNESCAPED:$RSYNC_PORT" else - # Not local, possibly a NAT, listen on all interfaces + # Not local, possibly a NAT, listen on all interfaces: RSYNC_EXTRA_ARGS="" STUNNEL_ACCEPT="$RSYNC_PORT" - # Overwrite address with all + # Overwrite address with all: RSYNC_ADDR="*" fi @@ -554,8 +587,9 @@ EOF then rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" $RSYNC_EXTRA_ARGS & RSYNC_REAL_PID=$! + TRANSFER_REAL_PID="$RSYNC_REAL_PID" + TRANSFER_PID=$RSYNC_PID else - [ -f "$STUNNEL_PID" ] && rm -f "$STUNNEL_PID" # Let's check if the path to the config file contains a space? if [ "${RSYNC_CONF#* }" = "$RSYNC_CONF" ]; then cat << EOF > "$STUNNEL_CONF" @@ -566,6 +600,9 @@ foreground = yes pid = $STUNNEL_PID debug = warning client = no +${VERIFY_OPT} +${CHECK_OPT} +${CHECK_OPT_LOCAL} [rsync] accept = $STUNNEL_ACCEPT exec = $(command -v rsync) @@ -583,6 +620,9 @@ foreground = yes pid = $STUNNEL_PID debug = warning client = no +${VERIFY_OPT} +${CHECK_OPT} +${CHECK_OPT_LOCAL} [rsync] accept = $STUNNEL_ACCEPT exec = $SHELL @@ -590,15 +630,11 @@ execargs = $SHELL -c \$RSYNC_CMD EOF fi stunnel "$STUNNEL_CONF" & - RSYNC_REAL_PID=$! - RSYNC_PID="$STUNNEL_PID" + STUNNEL_REAL_PID=$! + TRANSFER_REAL_PID="$STUNNEL_REAL_PID" + TRANSFER_PID=$STUNNEL_PID fi - until check_pid_and_port "$RSYNC_PID" "$RSYNC_REAL_PID" "$RSYNC_ADDR_UNESCAPED" "$RSYNC_PORT" - do - sleep 0.2 - done - if [ "${SSLMODE#VERIFY}" != "$SSLMODE" ] then # backward-incompatible behavior CN="" @@ -619,19 +655,26 @@ EOF ADDR="$CN:$MY_SECRET@$WSREP_SST_OPT_HOST" else MY_SECRET="" # for check down in recv_joiner() - ADDR=$WSREP_SST_OPT_HOST + ADDR="$WSREP_SST_OPT_HOST" fi + until check_pid_and_port "$TRANSFER_PID" $TRANSFER_REAL_PID "$RSYNC_ADDR_UNESCAPED" "$RSYNC_PORT" + do + sleep 0.2 + done + echo "ready $ADDR:$RSYNC_PORT/$MODULE" + MYSQLD_PID="$WSREP_SST_OPT_PARENT" + # wait for SST to complete by monitoring magic file - while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \ - ps -p $MYSQLD_PID >/dev/null + while [ ! -r "$MAGIC_FILE" ] && check_pid "$TRANSFER_PID" && \ + ps -p $MYSQLD_PID >/dev/null 2>&1 do sleep 1 done - if ! ps -p $MYSQLD_PID >/dev/null + if ! ps -p $MYSQLD_PID >/dev/null 2>&1 then wsrep_log_error \ "Parent mysqld process (PID: $MYSQLD_PID) terminated unexpectedly." @@ -682,7 +725,7 @@ EOF echo "rsync process ended without creating '$MAGIC_FILE'" fi - wsrep_cleanup_progress_file +# wsrep_cleanup_progress_file # cleanup_joiner else wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'" diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 24e08501bed..caefa83c443 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2305,25 +2305,6 @@ void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) } } -/* - Change comments specific to handler - - SYNOPSIS - update_table_comment() - comment Original comment - - RETURN VALUE - new comment - - DESCRIPTION - No comment changes so far -*/ - -char *ha_partition::update_table_comment(const char *comment) -{ - return (char*) comment; /* Nothing to change */ -} - /** Handle delete and rename table diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 08b7d7cf8f2..240d71447ec 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -3,7 +3,7 @@ /* Copyright (c) 2005, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB Corporation. + Copyright (c) 2009, 2021, 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 @@ -522,10 +522,6 @@ public: Meta data routines to CREATE, DROP, RENAME table and often used at ALTER TABLE (update_create_info used from ALTER TABLE and SHOW ..). - update_table_comment is used in SHOW TABLE commands to provide a - chance for the handler to add any interesting comments to the table - comments not provided by the users comment. - create_partitioning_metadata is called before opening a new handler object with openfrm to call create. It is used to create any local handler object needed in opening the object in openfrm @@ -539,7 +535,6 @@ public: const char *old_name, int action_flag) override; void update_create_info(HA_CREATE_INFO *create_info) override; - char *update_table_comment(const char *comment) override; int change_partitions(HA_CREATE_INFO *create_info, const char *path, ulonglong * const copied, ulonglong * const deleted, const uchar *pack_frm_data, size_t pack_frm_len) diff --git a/sql/handler.h b/sql/handler.h index 8b56a16bd6c..a179e084605 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3879,8 +3879,6 @@ public: /* end of the list of admin commands */ virtual int indexes_are_disabled(void) {return 0;} - virtual char *update_table_comment(const char * comment) - { return (char*) comment;} virtual void append_create_info(String *packet) {} /** If index == MAX_KEY then a check for table is made and if index < diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 273955b7541..608aee49ca4 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -572,8 +572,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str)); DEBUG_SYNC(thd, "admin_command_kill_before_modify"); - if (thd->is_killed()) - break; strxmov(table_name, db, ".", table->table_name.str, NullS); thd->open_options|= extra_open_options; table->lock_type= lock_type; @@ -588,6 +586,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, : lock_type >= TL_WRITE_ALLOW_WRITE ? MDL_SHARED_WRITE : MDL_SHARED_READ); + if (thd->check_killed()) + { + fatal_error= true; + result_code= HA_ADMIN_FAILED; + goto send_result; + } + /* open only one table from local list of command */ while (1) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d8baa118ef4..a7699db03b5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2644,7 +2644,17 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) /* If no tables left, do an automatic UNLOCK TABLES */ if (thd->lock && thd->lock->table_count == 0) + { + /* + We have to rollback any open transactions here. + This is required in the case where the server has been killed + but some transations are still open (as part of locked tables). + If we don't do this, we will get an assert in unlock_locked_tables(). + */ + ha_rollback_trans(thd, FALSE); + ha_rollback_trans(thd, TRUE); unlock_locked_tables(thd); + } } @@ -9300,6 +9310,21 @@ int dynamic_column_error_message(enum_dyncol_func_result rc) return rc; } + +/** + Turn on the SELECT_DESCRIBE flag for the primary SELECT_LEX of the statement + being processed in case the statement is EXPLAIN UPDATE/DELETE. + + @param lex current LEX +*/ + +void promote_select_describe_flag_if_needed(LEX *lex) +{ + if (lex->describe) + lex->first_select_lex()->options|= SELECT_DESCRIBE; +} + + /** @} (end of group Data_Dictionary) */ diff --git a/sql/sql_base.h b/sql/sql_base.h index 28a787c56dd..5d30c3611dc 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -512,6 +512,8 @@ bool extend_table_list(THD *thd, TABLE_LIST *tables, Prelocking_strategy *prelocking_strategy, bool has_prelocking_list); +void promote_select_describe_flag_if_needed(LEX *lex); + /** A context of open_tables() function, used to recover from a failed open_table() or open_routine() attempt. diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 9fa1e015274..b295be5e41e 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -378,6 +378,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, query_plan.table= table; query_plan.updating_a_view= MY_TEST(table_list->view); + promote_select_describe_flag_if_needed(thd->lex); + if (mysql_prepare_delete(thd, table_list, select_lex->with_wild, select_lex->item_list, &conds, &delete_while_scanning)) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 85db99f3a62..bc4c124d7b1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -470,6 +470,8 @@ int mysql_update(THD *thd, want_privilege= (table_list->view ? UPDATE_ACL : table_list->grant.want_privilege); #endif + promote_select_describe_flag_if_needed(thd->lex); + if (mysql_prepare_update(thd, table_list, &conds, order_num, order)) DBUG_RETURN(1); diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp index 4b6bb6a9e62..6679ccd55b0 100644 --- a/storage/connect/tabrest.cpp +++ b/storage/connect/tabrest.cpp @@ -60,12 +60,12 @@ int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename) if (Uri) { if (*Uri == '/' || Http[strlen(Http) - 1] == '/') - sprintf(buf, "%s%s", Http, Uri); + my_snprintf(buf, sizeof(buf)-1, "%s%s", Http, Uri); else - sprintf(buf, "%s/%s", Http, Uri); + my_snprintf(buf, sizeof(buf)-1, "%s/%s", Http, Uri); } else - strcpy(buf, Http); + my_snprintf(buf, sizeof(buf)-1, "%s", Http); #if defined(__WIN__) char cmd[1024]; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c2bd8cb8403..dacb1eb98b4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -14983,70 +14983,6 @@ ha_innobase::check( DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT); } -/*************************************************************//** -Adds information about free space in the InnoDB tablespace to a table comment -which is printed out when a user calls SHOW TABLE STATUS. Adds also info on -foreign keys. -@return table comment + InnoDB free space + info on foreign keys */ -UNIV_INTERN -char* -ha_innobase::update_table_comment( -/*==============================*/ - const char* comment)/*!< in: table comment defined by user */ -{ - uint length = (uint) strlen(comment); - char* str=0; - size_t flen; - std::string fk_str; - - /* We do not know if MySQL can call this function before calling - external_lock(). To be safe, update the thd of the current table - handle. */ - - if (length > 64000 - 3) { - return((char*) comment); /* string too long */ - } - - update_thd(ha_thd()); - - m_prebuilt->trx->op_info = "returning table comment"; - -#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \ - ( std::ostringstream() << std::dec << x ) ).str() - - if (m_prebuilt->table->space) { - fk_str.append("InnoDB free: "); - fk_str.append(SSTR(fsp_get_available_space_in_free_extents( - *m_prebuilt->table->space))); - } - - fk_str.append(dict_print_info_on_foreign_keys( - FALSE, m_prebuilt->trx, - m_prebuilt->table)); - - flen = fk_str.length(); - - if (length + flen + 3 > 64000) { - flen = 64000 - 3 - length; - } - /* allocate buffer for the full string */ - str = (char*) my_malloc(length + flen + 3, MYF(0)); - if (str) { - char* pos = str + length; - if (length) { - memcpy(str, comment, length); - *pos++ = ';'; - *pos++ = ' '; - } - memcpy(pos, fk_str.c_str(), flen); - pos[flen] = 0; - } - - m_prebuilt->trx->op_info = (char*)""; - - return(str ? str : (char*) comment); -} - /*******************************************************************//** Gets the foreign key create info for a table stored in InnoDB. @return own: character string in the form which can be inserted to the diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 619dfca34fb..d27ff67b64c 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -208,7 +208,6 @@ public: int rename_table(const char* from, const char* to) override; inline int defragment_table(const char* name); int check(THD* thd, HA_CHECK_OPT* check_opt) override; - char* update_table_comment(const char* comment) override; char* get_foreign_key_create_info() override; diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 74947b78774..2145ca6b06e 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -152,6 +152,76 @@ row_sel_sec_rec_is_for_blob( return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len)); } +/** Function to read the secondary spatial index, calculate +the minimum bounding rectangle for clustered index record +and secondary index record and compare it. +@param sec_rec secondary index record +@param sec_index spatial secondary index +@param clust_rec clustered index record +@param clust_index clustered index +@retval DB_SUCCESS_LOCKED_REC if the secondary record is equal to the + corresponding fields in the clustered record, when compared with + collation; +@retval DB_SUCCESS if not equal */ +static +dberr_t +row_sel_spatial_sec_rec_is_for_clust_rec( + const rec_t *sec_rec, const dict_index_t *sec_index, + const rec_t *clust_rec, dict_index_t *clust_index) +{ + mem_heap_t *heap= mem_heap_create(256); + rec_offs clust_offsets_[REC_OFFS_NORMAL_SIZE]; + rec_offs *clust_offs= clust_offsets_; + ulint clust_len; + + rec_offs_init(clust_offsets_); + ulint clust_pos= dict_col_get_clust_pos( + dict_index_get_nth_col(sec_index, 0), clust_index); + clust_offs= rec_get_offsets(clust_rec, clust_index, clust_offs, + clust_index->n_core_fields, clust_pos + 1, + &heap); + ut_ad(sec_index->n_user_defined_cols == 1); + const byte *clust_field= rec_get_nth_field(clust_rec, clust_offs, + clust_pos, &clust_len); + if (clust_len == UNIV_SQL_NULL || clust_len < GEO_DATA_HEADER_SIZE) + { + ut_ad("corrupted geometry column" == 0); +err_exit: + mem_heap_free(heap); + return DB_SUCCESS; + } + + /* For externally stored field, we need to get full + geo data to generate the MBR for comparing. */ + if (rec_offs_nth_extern(clust_offs, clust_pos)) + { + clust_field= btr_copy_externally_stored_field( + &clust_len, clust_field, sec_index->table->space->zip_size(), + clust_len, heap); + if (clust_field == NULL) + { + ut_ad("corrupted geometry blob" == 0); + goto err_exit; + } + } + + ut_ad(clust_len >= GEO_DATA_HEADER_SIZE); + rtr_mbr_t tmp_mbr; + rtr_mbr_t sec_mbr; + + rtree_mbr_from_wkb( + clust_field + GEO_DATA_HEADER_SIZE, + static_cast<uint>(clust_len - GEO_DATA_HEADER_SIZE), + SPDIMS, reinterpret_cast<double*>(&tmp_mbr)); + + rtr_read_mbr(sec_rec, &sec_mbr); + + mem_heap_free(heap); + return MBR_EQUAL_CMP(&sec_mbr, &tmp_mbr) + ? DB_SUCCESS_LOCKED_REC + : DB_SUCCESS; +} + /** Returns TRUE if the user-defined column values in a secondary index record are alphabetically the same as the corresponding columns in the clustered index record. @@ -179,12 +249,31 @@ row_sel_sec_rec_is_for_clust_rec( dict_index_t* clust_index, que_thr_t* thr) { + if (rec_get_deleted_flag(clust_rec, + dict_table_is_comp(clust_index->table))) { + /* In delete-marked records, DB_TRX_ID must + always refer to an existing undo log record. */ + ut_ad(rec_get_trx_id(clust_rec, clust_index)); + + /* The clustered index record is delete-marked; + it is not visible in the read view. Besides, + if there are any externally stored columns, + some of them may have already been purged. */ + return DB_SUCCESS; + } + + if (dict_index_is_spatial(sec_index)) { + return row_sel_spatial_sec_rec_is_for_clust_rec( + sec_rec, sec_index, clust_rec, + clust_index); + } + const byte* sec_field; ulint sec_len; const byte* clust_field; ulint n; ulint i; - mem_heap_t* heap = NULL; + mem_heap_t* heap = mem_heap_create(256); rec_offs clust_offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs sec_offsets_[REC_OFFS_SMALL_SIZE]; rec_offs* clust_offs = clust_offsets_; @@ -193,20 +282,7 @@ row_sel_sec_rec_is_for_clust_rec( rec_offs_init(clust_offsets_); rec_offs_init(sec_offsets_); - if (rec_get_deleted_flag(clust_rec, - dict_table_is_comp(clust_index->table))) { - /* In delete-marked records, DB_TRX_ID must - always refer to an existing undo log record. */ - ut_ad(rec_get_trx_id(clust_rec, clust_index)); - - /* The clustered index record is delete-marked; - it is not visible in the read view. Besides, - if there are any externally stored columns, - some of them may have already been purged. */ - return DB_SUCCESS; - } - heap = mem_heap_create(256); ib_vcol_row vc(heap); clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs, @@ -314,43 +390,10 @@ check_for_blob: } } - /* For spatial index, the first field is MBR, we check - if the MBR is equal or not. */ - if (dict_index_is_spatial(sec_index) && i == 0) { - rtr_mbr_t tmp_mbr; - rtr_mbr_t sec_mbr; - byte* dptr = - const_cast<byte*>(clust_field); - - ut_ad(clust_len != UNIV_SQL_NULL); - - /* For externally stored field, we need to get full - geo data to generate the MBR for comparing. */ - if (rec_offs_nth_extern(clust_offs, clust_pos)) { - dptr = btr_copy_externally_stored_field( - &clust_len, dptr, - clust_index->table->space->zip_size(), - len, heap); - } - - rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE, - static_cast<uint>(clust_len - - GEO_DATA_HEADER_SIZE), - SPDIMS, - reinterpret_cast<double*>( - &tmp_mbr)); - rtr_read_mbr(sec_field, &sec_mbr); - - if (!MBR_EQUAL_CMP(&sec_mbr, &tmp_mbr)) { - return DB_SUCCESS; - } - } else { - - if (0 != cmp_data_data(col->mtype, col->prtype, - clust_field, len, - sec_field, sec_len)) { - return DB_SUCCESS; - } + if (0 != cmp_data_data(col->mtype, col->prtype, + clust_field, len, + sec_field, sec_len)) { + return DB_SUCCESS; } } |